aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.editorconfig20
-rw-r--r--.gitignore7
-rw-r--r--404.html24
-rw-r--r--Gemfile33
-rw-r--r--Gemfile.lock84
-rw-r--r--Makefile30
-rw-r--r--_config.yml15
-rw-r--r--_includes/webring.html57
-rw-r--r--_layouts/base.html (renamed from templates/base.html)100
-rw-r--r--_layouts/index.html10
-rw-r--r--_layouts/page.html10
-rw-r--r--_layouts/post.html14
-rw-r--r--_posts/2011-01-13-most-likely-to-succeed-in-year-of-2011.md (renamed from content/posts/2011-01-13-most-likely-to-succeed-in-year-of-2011.md)3
-rw-r--r--_posts/2012-03-09-led-technology-not-so-eco.md (renamed from content/posts/2012-03-09-led-technology-not-so-eco.md)3
-rw-r--r--_posts/2013-10-24-wireless-sensor-networks.md (renamed from content/posts/2013-10-24-wireless-sensor-networks.md)3
-rw-r--r--_posts/2015-11-10-software-development-pitfalls.md (renamed from content/posts/2015-11-10-software-development-pitfalls.md)3
-rw-r--r--_posts/2017-03-07-golang-profiling-simplified.md (renamed from content/posts/2017-03-07-golang-profiling-simplified.md)7
-rw-r--r--_posts/2017-04-17-what-i-ve-learned-developing-ad-server.md (renamed from content/posts/2017-04-17-what-i-ve-learned-developing-ad-server.md)3
-rw-r--r--_posts/2017-04-21-profiling-python-web-applications-with-visual-tools.md (renamed from content/posts/2017-04-21-profiling-python-web-applications-with-visual-tools.md)9
-rw-r--r--_posts/2017-08-11-simple-iot-application.md (renamed from content/posts/2017-08-11-simple-iot-application.md)13
-rw-r--r--_posts/2018-01-16-using-digitalocean-spaces-object-storage-with-fuse.md (renamed from content/posts/2018-01-16-using-digitalocean-spaces-object-storage-with-fuse.md)15
-rw-r--r--_posts/2019-01-03-encoding-binary-data-into-dna-sequence.md (renamed from content/posts/2019-01-03-encoding-binary-data-into-dna-sequence.md)17
-rw-r--r--_posts/2019-10-14-simplifying-and-reducing-clutter.md (renamed from content/posts/2019-10-14-simplifying-and-reducing-clutter.md)3
-rw-r--r--_posts/2019-10-19-using-sentiment-analysis-for-clickbait-detection.md (renamed from content/posts/2019-10-19-using-sentiment-analysis-for-clickbait-detection.md)7
-rw-r--r--_posts/2020-03-22-simple-sse-based-pubsub-server.md (renamed from content/posts/2020-03-22-simple-sse-based-pubsub-server.md)11
-rw-r--r--_posts/2020-03-27-create-placeholder-images-with-sharp.md (renamed from content/posts/2020-03-27-create-placeholder-images-with-sharp.md)3
-rw-r--r--_posts/2020-03-29-the-strange-case-of-elasticsearch-allocation-failure.md (renamed from content/posts/2020-03-29-the-strange-case-of-elasticsearch-allocation-failure.md)3
-rw-r--r--_posts/2020-03-30-my-love-and-hate-relationship-with-nodejs.md (renamed from content/posts/2020-03-30-my-love-and-hate-relationship-with-nodejs.md)3
-rw-r--r--_posts/2020-05-05-remote-work.md (renamed from content/posts/2020-05-05-remote-work.md)3
-rw-r--r--_posts/2020-08-15-systemd-disable-wake-onmouse.md (renamed from content/posts/2020-08-15-systemd-disable-wake-onmouse.md)3
-rw-r--r--_posts/2020-09-06-esp-and-micropython.md (renamed from content/posts/2020-09-06-esp-and-micropython.md)5
-rw-r--r--_posts/2020-09-08-bind-warning-on-login.md (renamed from content/posts/2020-09-08-bind-warning-on-login.md)5
-rw-r--r--_posts/2020-09-09-digitalocean-sync.md (renamed from content/posts/2020-09-09-digitalocean-sync.md)3
-rw-r--r--_posts/2021-01-24-replacing-dropbox-with-s3.md (renamed from content/posts/2021-01-24-replacing-dropbox-with-s3.md)5
-rw-r--r--_posts/2021-01-25-goaccess.md (renamed from content/posts/2021-01-25-goaccess.md)7
-rw-r--r--_posts/2021-06-26-simple-world-clock.md (renamed from content/posts/2021-06-26-simple-world-clock.md)9
-rw-r--r--_posts/2021-07-30-from-internet-consumer-to-full-hominum-again.md (renamed from content/posts/2021-07-30-from-internet-consumer-to-full-hominum-again.md)3
-rw-r--r--_posts/2021-08-01-linux-cheatsheet.md (renamed from content/posts/2021-08-01-linux-cheatsheet.md)3
-rw-r--r--_posts/2021-12-03-debian-based-riced-up-distribution-for-developers.md (renamed from content/posts/2021-12-03-debian-based-riced-up-distribution-for-developers.md)21
-rw-r--r--_posts/2021-12-25-running-golang-application-as-pid1.md (renamed from content/posts/2021-12-25-running-golang-application-as-pid1.md)9
-rw-r--r--_posts/2021-12-30-wap-mobile-web-before-the-web.md (renamed from content/posts/2021-12-30-wap-mobile-web-before-the-web.md)7
-rw-r--r--_posts/2022-06-30-trying-out-helix-editor.md (renamed from content/posts/2022-06-30-trying-out-helix-editor.md)5
-rw-r--r--_posts/2022-07-05-what-would-dna-sound-if-synthesized.md (renamed from content/posts/2022-07-05-what-would-dna-sound-if-synthesized.md)33
-rw-r--r--_posts/2022-08-13-algae-spotted-on-river-sava.md (renamed from content/posts/2022-08-13-algae-spotted-on-river-sava.md)15
-rw-r--r--_posts/2022-10-06-state-of-web-technologies-in-year-2022.md (renamed from content/posts/2022-10-06-state-of-web-technologies-in-year-2022.md)3
-rw-r--r--_posts/2022-10-16-that-sound-that-machine-makes-when-struggling.md (renamed from content/posts/2022-10-16-that-sound-that-machine-makes-when-struggling.md)5
-rw-r--r--_posts/2023-01-26-trying-to-build-a-new-kind-of-terminal-emulator.md (renamed from content/posts/2023-01-26-trying-to-build-a-new-kind-of-terminal-emulator.md)3
-rw-r--r--_posts/2023-05-01-cachebusting-in-hugo.md (renamed from content/notes/2023-05-01-cachebusting-in-hugo.md)7
-rw-r--r--_posts/2023-05-05-run-9front-in-qemu.md (renamed from content/notes/2023-05-05-run-9front-in-qemu.md)3
-rw-r--r--_posts/2023-05-06-git-push-multiple-origins.md (renamed from content/notes/2023-05-06-git-push-multiple-origins.md)3
-rw-r--r--_posts/2023-05-07-mount-plan9-over-network.md (renamed from content/notes/2023-05-07-mount-plan9-over-network.md)3
-rw-r--r--_posts/2023-05-08-write-iso-usb.md (renamed from content/notes/2023-05-08-write-iso-usb.md)3
-rw-r--r--_posts/2023-05-09-catv-weechat-config.md (renamed from content/notes/2023-05-09-catv-weechat-config.md)3
-rw-r--r--_posts/2023-05-10-plan9-screenshot.md (renamed from content/notes/2023-05-10-plan9-screenshot.md)3
-rw-r--r--_posts/2023-05-11-fix-plan9-bootloader.md (renamed from content/notes/2023-05-11-fix-plan9-bootloader.md)3
-rw-r--r--_posts/2023-05-12-install-plan9port-linux.md (renamed from content/notes/2023-05-12-install-plan9port-linux.md)3
-rw-r--r--_posts/2023-05-13-download-youtube-videos.md (renamed from content/notes/2023-05-13-download-youtube-videos.md)3
-rw-r--r--_posts/2023-05-14-convert-mkv.md (renamed from content/notes/2023-05-14-convert-mkv.md)3
-rw-r--r--_posts/2023-05-15-preview-troff-man-pages.md (renamed from content/notes/2023-05-15-preview-troff-man-pages.md)3
-rw-r--r--_posts/2023-05-16-mass-set-permission.md (renamed from content/notes/2023-05-16-mass-set-permission.md)3
-rw-r--r--_posts/2023-05-16-rekindling-my-love-for-programming.md (renamed from content/posts/2023-05-16-rekindling-my-love-for-programming.md)3
-rw-r--r--_posts/2023-05-22-non-blocking-shell-exec-csharp.md (renamed from content/notes/2023-05-22-non-blocking-shell-exec-csharp.md)3
-rw-r--r--_posts/2023-05-23-extend-lua-with-custom-c.md (renamed from content/notes/2023-05-23-extend-lua-with-custom-c.md)5
-rw-r--r--_posts/2023-05-23-i-was-wrong-about-git-workflows.md (renamed from content/posts/2023-05-23-i-was-wrong-about-git-workflows.md)3
-rw-r--r--_posts/2023-05-23-parse-rss-with-lua.md (renamed from content/notes/2023-05-23-parse-rss-with-lua.md)3
-rw-r--r--_posts/2023-05-24-fresh-9front-desktop.md (renamed from content/notes/2023-05-24-fresh-9front-desktop.md)5
-rw-r--r--_posts/2023-05-25-dcss-new-player-guide.md (renamed from content/notes/2023-05-25-dcss-new-player-guide.md)9
-rw-r--r--_posts/2023-05-25-show-xterm-colors.md (renamed from content/notes/2023-05-25-show-xterm-colors.md)5
-rw-r--r--_posts/2023-05-25-tmux-sane-defaults.md (renamed from content/notes/2023-05-25-tmux-sane-defaults.md)3
-rw-r--r--_posts/2023-05-27-cronjobs-github-with-actions.md (renamed from content/notes/2023-05-27-cronjobs-github-with-actions.md)3
-rw-r--r--_posts/2023-05-27-dcss-on-4k-displays.md (renamed from content/notes/2023-05-27-dcss-on-4k-displays.md)3
-rw-r--r--_posts/2023-05-27-drawing-pixels-in-plan9.md (renamed from content/notes/2023-05-27-drawing-pixels-in-plan9.md)5
-rw-r--r--_posts/2023-05-28-easy-time-took-in-bash.md (renamed from content/notes/2023-05-28-easy-time-took-in-bash.md)3
-rw-r--r--_posts/2023-05-29-grep-to-less-maintain-colors.md (renamed from content/notes/2023-05-29-grep-to-less-maintain-colors.md)5
-rw-r--r--_posts/2023-05-31-extending-dte-editor.md (renamed from content/notes/2023-05-31-extending-dte-editor.md)3
-rw-r--r--_posts/2023-05-31-re-inventing-task-runner-that-i-actually-used-daily.md (renamed from content/posts/2023-05-31-re-inventing-task-runner-that-i-actually-used-daily.md)3
-rw-r--r--_posts/2023-06-01-ewd-manuscripts-ebook.md (renamed from content/notes/2023-06-01-ewd-manuscripts-ebook.md)3
-rw-r--r--_posts/2023-06-04-bulk-make-thumbnails.md (renamed from content/notes/2023-06-04-bulk-make-thumbnails.md)3
-rw-r--r--_posts/2023-06-21-presentations-with-markdown.md (renamed from content/notes/2023-06-21-presentations-with-markdown.md)3
-rw-r--r--_posts/2023-06-24-making-cgit-look-nicer.md (renamed from content/notes/2023-06-24-making-cgit-look-nicer.md)3
-rw-r--r--_posts/2023-06-25-alacritty-open-links-with-modifier.md (renamed from content/notes/2023-06-25-alacritty-open-links-with-modifier.md)3
-rw-r--r--_posts/2023-06-25-development-environments-with-nix.md (renamed from content/notes/2023-06-25-development-environments-with-nix.md)5
-rw-r--r--_posts/2023-06-29-10gui-10-finger-multitouch-user-interface.md (renamed from content/notes/2023-06-29-10gui-10-finger-multitouch-user-interface.md)7
-rw-r--r--_posts/2023-06-29-60s-ibm-computers-commercial.md (renamed from content/notes/2023-06-29-60s-ibm-computers-commercial.md)7
-rw-r--r--_posts/2023-07-01-bringing-all-of-my-projects-together-under-one-umbrella.md (renamed from content/posts/2023-07-01-bringing-all-of-my-projects-together-under-one-umbrella.md)3
-rw-r--r--_posts/2023-07-08-who-knows-what-the-world-will-look-like-tomorrow.md (renamed from content/posts/2023-07-08-who-knows-what-the-world-will-look-like-tomorrow.md)3
-rw-r--r--_posts/2023-07-10-fix-screen-tearing-on-debian-12-xorg-and-i3.md (renamed from content/posts/2023-07-10-fix-screen-tearing-on-debian-12-xorg-and-i3.md)3
-rw-r--r--_posts/2023-07-10-online-radio-streaming-with-mpv-from-terminal.md (renamed from content/posts/2023-07-10-online-radio-streaming-with-mpv-from-terminal.md)3
-rw-r--r--_posts/2023-07-14-set-color-temperature-of-displays-on-i3.md (renamed from content/notes/2023-07-14-set-color-temperature-of-displays-on-i3.md)3
-rw-r--r--_posts/2023-08-01-make-b-w-svg-charts-with-matplotlib.md (renamed from content/notes/2023-08-01-make-b-w-svg-charts-with-matplotlib.md)5
-rw-r--r--_posts/2023-08-05-floods-in-slovenia.md20
-rw-r--r--_posts/2023-09-18-aws-eb-pyyaml-fix.md (renamed from content/notes/2023-09-18-aws-eb-pyyaml-fix.md)3
-rw-r--r--_posts/2023-09-25-compile-drawterm-on-fedora-38.md (renamed from content/notes/2023-09-25-compile-drawterm-on-fedora-38.md)3
-rw-r--r--assets/general/9front-cursor.png (renamed from public/general/9front-cursor.png)bin249 -> 249 bytes
-rw-r--r--assets/general/9logo.png (renamed from public/general/9logo.png)bin39825 -> 39825 bytes
-rwxr-xr-xassets/general/alert-dark.svg (renamed from public/general/alert-dark.svg)0
-rwxr-xr-xassets/general/alert-light.svg (renamed from public/general/alert-light.svg)0
-rw-r--r--assets/general/index.css (renamed from public/general/index.css)0
-rw-r--r--assets/general/og-big.jpg (renamed from public/general/og-big.jpg)bin70575 -> 70575 bytes
-rw-r--r--assets/general/og-big.xcf (renamed from public/general/og-big.xcf)bin10025863 -> 10025863 bytes
-rw-r--r--assets/general/og.jpg (renamed from public/general/og.jpg)bin44366 -> 44366 bytes
-rw-r--r--assets/general/og.xcf (renamed from public/general/og.xcf)bin898329 -> 898329 bytes
-rw-r--r--assets/mitjafelicijan.pgp.pub.txt (renamed from public/mitjafelicijan.pgp.pub.txt)0
-rw-r--r--assets/notes/10gui-10-finger-multitouch-user-interface.jpg (renamed from public/notes/10gui-10-finger-multitouch-user-interface.jpg)bin21762 -> 21762 bytes
-rw-r--r--assets/notes/10gui-10-finger-multitouch-user-interface.mp4 (renamed from public/notes/10gui-10-finger-multitouch-user-interface.mp4)bin16587109 -> 16587109 bytes
-rw-r--r--assets/notes/60s-ibm-computers-commercial.jpg (renamed from public/notes/60s-ibm-computers-commercial.jpg)bin32372 -> 32372 bytes
-rw-r--r--assets/notes/60s-ibm-computers-commercial.mp4 (renamed from public/notes/60s-ibm-computers-commercial.mp4)bin35273598 -> 35273598 bytes
-rw-r--r--assets/notes/9front-desktop.png (renamed from public/notes/9front-desktop.png)bin38054 -> 38054 bytes
-rw-r--r--assets/notes/dcss-quickstart.pdf (renamed from public/notes/dcss-quickstart.pdf)bin80328 -> 80328 bytes
-rw-r--r--assets/notes/dcss.jpg (renamed from public/notes/dcss.jpg)bin855457 -> 855457 bytes
-rw-r--r--assets/notes/dcss_manual.pdf (renamed from public/notes/dcss_manual.pdf)bin203302 -> 203302 bytes
-rwxr-xr-xassets/notes/floods/IMG_1461.mp4 (renamed from public/notes/floods/IMG_1461.mp4)bin14410656 -> 14410656 bytes
-rwxr-xr-xassets/notes/floods/IMG_1466.mp4 (renamed from public/notes/floods/IMG_1466.mp4)bin8902148 -> 8902148 bytes
-rwxr-xr-xassets/notes/floods/IMG_1469.webp (renamed from public/notes/floods/IMG_1469.webp)bin816680 -> 816680 bytes
-rwxr-xr-xassets/notes/floods/IMG_1470.webp (renamed from public/notes/floods/IMG_1470.webp)bin933574 -> 933574 bytes
-rwxr-xr-xassets/notes/floods/IMG_1471.mp4 (renamed from public/notes/floods/IMG_1471.mp4)bin10163115 -> 10163115 bytes
-rwxr-xr-xassets/notes/floods/IMG_1474.mp4 (renamed from public/notes/floods/IMG_1474.mp4)bin14032243 -> 14032243 bytes
-rw-r--r--assets/notes/grep-less.png (renamed from public/notes/grep-less.png)bin178000 -> 178000 bytes
-rw-r--r--assets/notes/plan9-pixels.png (renamed from public/notes/plan9-pixels.png)bin12134 -> 12134 bytes
-rw-r--r--assets/notes/plot.svg (renamed from public/notes/plot.svg)0
-rw-r--r--assets/notes/ps1-prompt.png (renamed from public/notes/ps1-prompt.png)bin24272 -> 24272 bytes
-rw-r--r--assets/notes/xterm-palette.png (renamed from public/notes/xterm-palette.png)bin9524 -> 9524 bytes
-rwxr-xr-xassets/posts/algae-sava/dji-algae-0.jpg (renamed from public/posts/algae-sava/dji-algae-0.jpg)bin145615 -> 145615 bytes
-rwxr-xr-xassets/posts/algae-sava/dji-algae-1.jpg (renamed from public/posts/algae-sava/dji-algae-1.jpg)bin154416 -> 154416 bytes
-rwxr-xr-xassets/posts/algae-sava/dji-algae-2.jpg (renamed from public/posts/algae-sava/dji-algae-2.jpg)bin114347 -> 114347 bytes
-rwxr-xr-xassets/posts/algae-sava/dji-algae-3.jpg (renamed from public/posts/algae-sava/dji-algae-3.jpg)bin128019 -> 128019 bytes
-rwxr-xr-xassets/posts/algae-sava/dji-algae-4.jpg (renamed from public/posts/algae-sava/dji-algae-4.jpg)bin217747 -> 217747 bytes
-rwxr-xr-xassets/posts/algae-sava/dji-algae-5.jpg (renamed from public/posts/algae-sava/dji-algae-5.jpg)bin264884 -> 264884 bytes
-rwxr-xr-xassets/posts/cv/avatar.gif (renamed from public/posts/cv/avatar.gif)bin2174 -> 2174 bytes
-rwxr-xr-xassets/posts/dfd-rice/desktop.png (renamed from public/posts/dfd-rice/desktop.png)bin329498 -> 329498 bytes
-rwxr-xr-xassets/posts/dfd-rice/install-00.png (renamed from public/posts/dfd-rice/install-00.png)bin35695 -> 35695 bytes
-rwxr-xr-xassets/posts/dfd-rice/install-01.png (renamed from public/posts/dfd-rice/install-01.png)bin28042 -> 28042 bytes
-rwxr-xr-xassets/posts/dfd-rice/install-02.png (renamed from public/posts/dfd-rice/install-02.png)bin21638 -> 21638 bytes
-rwxr-xr-xassets/posts/dfd-rice/install-03.png (renamed from public/posts/dfd-rice/install-03.png)bin34698 -> 34698 bytes
-rwxr-xr-xassets/posts/dfd-rice/install-04.png (renamed from public/posts/dfd-rice/install-04.png)bin28346 -> 28346 bytes
-rwxr-xr-xassets/posts/dfd-rice/install-05.png (renamed from public/posts/dfd-rice/install-05.png)bin13755 -> 13755 bytes
-rwxr-xr-xassets/posts/dfd-rice/installation.svg (renamed from public/posts/dfd-rice/installation.svg)0
-rwxr-xr-xassets/posts/dfd-rice/layout.png (renamed from public/posts/dfd-rice/layout.png)bin9072 -> 9072 bytes
-rwxr-xr-xassets/posts/dfd-rice/layout.svg (renamed from public/posts/dfd-rice/layout.svg)0
-rwxr-xr-xassets/posts/dfd-rice/script.png (renamed from public/posts/dfd-rice/script.png)bin65747 -> 65747 bytes
-rw-r--r--assets/posts/dna-sequence/benchmarks.csv (renamed from public/posts/dna-sequence/benchmarks.csv)0
-rw-r--r--assets/posts/dna-sequence/chart-size.py (renamed from public/posts/dna-sequence/chart-size.py)0
-rw-r--r--assets/posts/dna-sequence/chart-size.svg (renamed from public/posts/dna-sequence/chart-size.svg)0
-rw-r--r--assets/posts/dna-sequence/chart-speed.py (renamed from public/posts/dna-sequence/chart-speed.py)0
-rw-r--r--assets/posts/dna-sequence/chart-speed.svg (renamed from public/posts/dna-sequence/chart-speed.svg)0
-rwxr-xr-xassets/posts/dna-sequence/dna-basics.jpg (renamed from public/posts/dna-sequence/dna-basics.jpg)bin165883 -> 165883 bytes
-rwxr-xr-xassets/posts/dna-sequence/quote.png (renamed from public/posts/dna-sequence/quote.png)bin1068 -> 1068 bytes
-rwxr-xr-xassets/posts/dna-sequence/sample-binary-file.png (renamed from public/posts/dna-sequence/sample-binary-file.png)bin66417 -> 66417 bytes
-rwxr-xr-xassets/posts/dna-sequence/sample.png (renamed from public/posts/dna-sequence/sample.png)bin65930 -> 65930 bytes
-rwxr-xr-xassets/posts/dna-synthesized/bison/in.txt (renamed from public/posts/dna-synthesized/bison/in.txt)0
-rwxr-xr-xassets/posts/dna-synthesized/bison/out.mp3 (renamed from public/posts/dna-synthesized/bison/out.mp3)bin960469 -> 960469 bytes
-rwxr-xr-xassets/posts/dna-synthesized/bison/spectogram.png (renamed from public/posts/dna-synthesized/bison/spectogram.png)bin52808 -> 52808 bytes
-rwxr-xr-xassets/posts/dna-synthesized/elektron/IMG_0619.jpg (renamed from public/posts/dna-synthesized/elektron/IMG_0619.jpg)bin226025 -> 226025 bytes
-rwxr-xr-xassets/posts/dna-synthesized/elektron/IMG_0620.jpg (renamed from public/posts/dna-synthesized/elektron/IMG_0620.jpg)bin242937 -> 242937 bytes
-rwxr-xr-xassets/posts/dna-synthesized/elektron/IMG_0622.jpg (renamed from public/posts/dna-synthesized/elektron/IMG_0622.jpg)bin279234 -> 279234 bytes
-rwxr-xr-xassets/posts/dna-synthesized/elektron/elektron.mp4 (renamed from public/posts/dna-synthesized/elektron/elektron.mp4)bin22478213 -> 22478213 bytes
-rwxr-xr-xassets/posts/dna-synthesized/elektron/midi-studio.jpg (renamed from public/posts/dna-synthesized/elektron/midi-studio.jpg)bin63633 -> 63633 bytes
-rwxr-xr-xassets/posts/dna-synthesized/mouse/in.txt (renamed from public/posts/dna-synthesized/mouse/in.txt)0
-rwxr-xr-xassets/posts/dna-synthesized/mouse/out.mp3 (renamed from public/posts/dna-synthesized/mouse/out.mp3)bin864547 -> 864547 bytes
-rwxr-xr-xassets/posts/dna-synthesized/mouse/spectogram.png (renamed from public/posts/dna-synthesized/mouse/spectogram.png)bin114261 -> 114261 bytes
-rwxr-xr-xassets/posts/dna-synthesized/quote/in.txt (renamed from public/posts/dna-synthesized/quote/in.txt)0
-rwxr-xr-xassets/posts/dna-synthesized/quote/out.mp3 (renamed from public/posts/dna-synthesized/quote/out.mp3)bin678973 -> 678973 bytes
-rwxr-xr-xassets/posts/dna-synthesized/quote/spectogram.png (renamed from public/posts/dna-synthesized/quote/spectogram.png)bin108863 -> 108863 bytes
-rwxr-xr-xassets/posts/dna-synthesized/symphony-no6-1st-movement.mp3 (renamed from public/posts/dna-synthesized/symphony-no6-1st-movement.mp3)bin11650187 -> 11650187 bytes
-rwxr-xr-xassets/posts/dna-synthesized/symphony-no6-1st-movement.png (renamed from public/posts/dna-synthesized/symphony-no6-1st-movement.png)bin245694 -> 245694 bytes
-rwxr-xr-xassets/posts/dna-synthesized/taurus/in.txt (renamed from public/posts/dna-synthesized/taurus/in.txt)0
-rwxr-xr-xassets/posts/dna-synthesized/taurus/out.mp3 (renamed from public/posts/dna-synthesized/taurus/out.mp3)bin1056599 -> 1056599 bytes
-rwxr-xr-xassets/posts/dna-synthesized/taurus/spectogram.png (renamed from public/posts/dna-synthesized/taurus/spectogram.png)bin109064 -> 109064 bytes
-rwxr-xr-xassets/posts/do-fuse/copy-benchmarks.tsv (renamed from public/posts/do-fuse/copy-benchmarks.tsv)0
-rwxr-xr-xassets/posts/do-fuse/fuse-droplets.png (renamed from public/posts/do-fuse/fuse-droplets.png)bin42891 -> 42891 bytes
-rwxr-xr-xassets/posts/do-fuse/fuse-spaces.png (renamed from public/posts/do-fuse/fuse-spaces.png)bin32450 -> 32450 bytes
-rwxr-xr-xassets/posts/do-fuse/sqlite-benchmarks.tsv (renamed from public/posts/do-fuse/sqlite-benchmarks.tsv)0
-rwxr-xr-xassets/posts/dropbox-sync/dropbox-spaces.png (renamed from public/posts/dropbox-sync/dropbox-spaces.png)bin47661 -> 47661 bytes
-rwxr-xr-xassets/posts/esp8366-micropython/boards.jpg (renamed from public/posts/esp8366-micropython/boards.jpg)bin98162 -> 98162 bytes
-rwxr-xr-xassets/posts/go-profiling/golang-profiling-cpu.pdf (renamed from public/posts/go-profiling/golang-profiling-cpu.pdf)bin16518 -> 16518 bytes
-rwxr-xr-xassets/posts/go-profiling/golang-profiling-mem.pdf (renamed from public/posts/go-profiling/golang-profiling-mem.pdf)bin19221 -> 19221 bytes
-rwxr-xr-xassets/posts/goaccess/goaccess-dash-html.png (renamed from public/posts/goaccess/goaccess-dash-html.png)bin16129 -> 16129 bytes
-rwxr-xr-xassets/posts/goaccess/goaccess-dash-term.png (renamed from public/posts/goaccess/goaccess-dash-term.png)bin9188 -> 9188 bytes
-rw-r--r--assets/posts/godot-dynamic-tile-loading/2d-player-movement.webm (renamed from public/posts/godot-dynamic-tile-loading/2d-player-movement.webm)bin975421 -> 975421 bytes
-rw-r--r--assets/posts/godot-dynamic-tile-loading/cellular-automata.png (renamed from public/posts/godot-dynamic-tile-loading/cellular-automata.png)bin373408 -> 373408 bytes
-rw-r--r--assets/posts/godot-dynamic-tile-loading/example1/index.apple-touch-icon.png (renamed from public/posts/godot-dynamic-tile-loading/example1/index.apple-touch-icon.png)bin18955 -> 18955 bytes
-rw-r--r--assets/posts/godot-dynamic-tile-loading/example1/index.audio.worklet.js (renamed from public/posts/godot-dynamic-tile-loading/example1/index.audio.worklet.js)0
-rw-r--r--assets/posts/godot-dynamic-tile-loading/example1/index.html (renamed from public/posts/godot-dynamic-tile-loading/example1/index.html)0
-rw-r--r--assets/posts/godot-dynamic-tile-loading/example1/index.icon.png (renamed from public/posts/godot-dynamic-tile-loading/example1/index.icon.png)bin3305 -> 3305 bytes
-rw-r--r--assets/posts/godot-dynamic-tile-loading/example1/index.js (renamed from public/posts/godot-dynamic-tile-loading/example1/index.js)0
-rw-r--r--assets/posts/godot-dynamic-tile-loading/example1/index.pck (renamed from public/posts/godot-dynamic-tile-loading/example1/index.pck)bin7056 -> 7056 bytes
-rw-r--r--assets/posts/godot-dynamic-tile-loading/example1/index.png (renamed from public/posts/godot-dynamic-tile-loading/example1/index.png)bin21443 -> 21443 bytes
-rw-r--r--assets/posts/godot-dynamic-tile-loading/example1/index.wasm (renamed from public/posts/godot-dynamic-tile-loading/example1/index.wasm)bin13789463 -> 13789463 bytes
-rw-r--r--assets/posts/godot-dynamic-tile-loading/village-creator.png (renamed from public/posts/godot-dynamic-tile-loading/village-creator.png)bin97628 -> 97628 bytes
-rwxr-xr-xassets/posts/helix-editor/editor.png (renamed from public/posts/helix-editor/editor.png)bin159442 -> 159442 bytes
-rwxr-xr-xassets/posts/iot-application/iot-app-output.png (renamed from public/posts/iot-application/iot-app-output.png)bin23767 -> 23767 bytes
-rwxr-xr-xassets/posts/iot-application/iot-rest-example.png (renamed from public/posts/iot-application/iot-rest-example.png)bin33912 -> 33912 bytes
-rwxr-xr-xassets/posts/iot-application/iot-sqlite-db.png (renamed from public/posts/iot-application/iot-sqlite-db.png)bin199821 -> 199821 bytes
-rwxr-xr-xassets/posts/iot-application/kcachegrind.png (renamed from public/posts/iot-application/kcachegrind.png)bin88486 -> 88486 bytes
-rwxr-xr-xassets/posts/iot-application/profiling-viewer.png (renamed from public/posts/iot-application/profiling-viewer.png)bin173672 -> 173672 bytes
-rwxr-xr-xassets/posts/iot-application/simple-iot-application-overview.svg (renamed from public/posts/iot-application/simple-iot-application-overview.svg)0
-rwxr-xr-xassets/posts/iot-application/simple-iot-application.zip (renamed from public/posts/iot-application/simple-iot-application.zip)bin6406 -> 6406 bytes
-rwxr-xr-xassets/posts/iot-application/snakeviz.png (renamed from public/posts/iot-application/snakeviz.png)bin59601 -> 59601 bytes
-rw-r--r--assets/posts/microsoundtrack/cow.m4v (renamed from public/posts/microsoundtrack/cow.m4v)bin1113250 -> 1113250 bytes
-rwxr-xr-xassets/posts/pid1/boxes.mp4 (renamed from public/posts/pid1/boxes.mp4)bin443830 -> 443830 bytes
-rwxr-xr-xassets/posts/pid1/qemu.log (renamed from public/posts/pid1/qemu.log)0
-rw-r--r--assets/posts/pid1/unikernels.png (renamed from public/posts/pid1/unikernels.png)bin33009 -> 33009 bytes
-rwxr-xr-xassets/posts/pid1/unikernels.svg (renamed from public/posts/pid1/unikernels.svg)0
-rw-r--r--assets/posts/pid1/unikernels.webp (renamed from public/posts/pid1/unikernels.webp)bin23304 -> 23304 bytes
-rwxr-xr-xassets/posts/profile-bind-error/error.jpg (renamed from public/posts/profile-bind-error/error.jpg)bin57047 -> 57047 bytes
-rwxr-xr-xassets/posts/python-profiling/kcachegrind.png (renamed from public/posts/python-profiling/kcachegrind.png)bin88486 -> 88486 bytes
-rwxr-xr-xassets/posts/python-profiling/profiling-viewer.png (renamed from public/posts/python-profiling/profiling-viewer.png)bin173672 -> 173672 bytes
-rwxr-xr-xassets/posts/python-profiling/snakeviz.png (renamed from public/posts/python-profiling/snakeviz.png)bin59601 -> 59601 bytes
-rwxr-xr-xassets/posts/sentiment-analysis/.ipynb_checkpoints/TF Test-checkpoint.ipynb (renamed from public/posts/sentiment-analysis/.ipynb_checkpoints/TF Test-checkpoint.ipynb)0
-rwxr-xr-xassets/posts/sentiment-analysis/.ipynb_checkpoints/sentiment-analysis-checkpoint.ipynb (renamed from public/posts/sentiment-analysis/.ipynb_checkpoints/sentiment-analysis-checkpoint.ipynb)0
-rwxr-xr-xassets/posts/sentiment-analysis/guardian-sa-title-desc-relationship.png (renamed from public/posts/sentiment-analysis/guardian-sa-title-desc-relationship.png)bin15404 -> 15404 bytes
-rwxr-xr-xassets/posts/sentiment-analysis/sentiment-analysis.ipynb (renamed from public/posts/sentiment-analysis/sentiment-analysis.ipynb)0
-rwxr-xr-xassets/posts/simple-pubsub-server/caniuse.png (renamed from public/posts/simple-pubsub-server/caniuse.png)bin56379 -> 56379 bytes
-rwxr-xr-xassets/posts/simple-pubsub-server/chrome-debugging.png (renamed from public/posts/simple-pubsub-server/chrome-debugging.png)bin151160 -> 151160 bytes
-rwxr-xr-xassets/posts/simple-pubsub-server/clients.m4v (renamed from public/posts/simple-pubsub-server/clients.m4v)bin369179 -> 369179 bytes
-rwxr-xr-xassets/posts/simple-pubsub-server/pubsub-overview.png (renamed from public/posts/simple-pubsub-server/pubsub-overview.png)bin18471 -> 18471 bytes
-rwxr-xr-xassets/posts/simple-pubsub-server/sse-pubsub-server.zip (renamed from public/posts/simple-pubsub-server/sse-pubsub-server.zip)bin4158 -> 4158 bytes
-rwxr-xr-xassets/posts/state-of-web/2008-vs-2020.png (renamed from public/posts/state-of-web/2008-vs-2020.png)bin126650 -> 126650 bytes
-rwxr-xr-xassets/posts/state-of-web/compiling-vs-transpiling.png (renamed from public/posts/state-of-web/compiling-vs-transpiling.png)bin41481 -> 41481 bytes
-rwxr-xr-xassets/posts/wap/emulator.mp4 (renamed from public/posts/wap/emulator.mp4)bin892887 -> 892887 bytes
-rwxr-xr-xassets/posts/wap/phones.gif (renamed from public/posts/wap/phones.gif)bin348891 -> 348891 bytes
-rwxr-xr-xassets/posts/world-clock/enclosure.stl (renamed from public/posts/world-clock/enclosure.stl)bin1884 -> 1884 bytes
-rwxr-xr-xassets/posts/world-clock/hardware.jpg (renamed from public/posts/world-clock/hardware.jpg)bin82279 -> 82279 bytes
-rwxr-xr-xassets/posts/world-clock/world-clock.jpg (renamed from public/posts/world-clock/world-clock.jpg)bin148673 -> 148673 bytes
-rwxr-xr-xassets/posts/yapyap/hello.png (renamed from public/posts/yapyap/hello.png)bin25962 -> 25962 bytes
-rwxr-xr-xassets/posts/yapyap/pid1.jpg (renamed from public/posts/yapyap/pid1.jpg)bin394011 -> 394011 bytes
-rwxr-xr-xassets/posts/zed/zed-1.png (renamed from public/posts/zed/zed-1.png)bin450802 -> 450802 bytes
-rwxr-xr-xassets/posts/zed/zed-2.png (renamed from public/posts/zed/zed-2.png)bin812483 -> 812483 bytes
-rw-r--r--bin/webring.rb82
-rw-r--r--config.yaml24
-rw-r--r--content/notes/2023-08-05-floods-in-slovenia.md19
-rw-r--r--content/pages/vault.md405
-rw-r--r--curriculum-vitae.md (renamed from content/pages/curriculum-vitae.md)21
-rw-r--r--index.html30
-rwxr-xr-xpublic/10gui-10-finger-multitouch-user-interface.html48
-rwxr-xr-xpublic/60s-ibm-computers-commercial.html46
-rwxr-xr-xpublic/aerial-photography-of-algae-spotted-on-river-sava.html49
-rwxr-xr-xpublic/alacritty-open-links-with-modifier.html58
-rwxr-xr-xpublic/aws-eb-pyyaml-fix.html56
-rwxr-xr-xpublic/bind-warning-on-login-in-ubuntu.html69
-rwxr-xr-xpublic/bringing-all-of-my-projects-together-under-one-umbrella.html197
-rwxr-xr-xpublic/bulk-make-thumbnails.html52
-rwxr-xr-xpublic/cachebusting-in-hugo.html48
-rwxr-xr-xpublic/catv-weechat-config.html51
-rwxr-xr-xpublic/compile-drawterm-on-fedora-38.html48
-rwxr-xr-xpublic/convert-mkv.html49
-rwxr-xr-xpublic/crafting-stories-in-zed-editor.html57
-rwxr-xr-xpublic/create-placeholder-images-with-sharp.html111
-rwxr-xr-xpublic/cronjobs-github-with-actions.html60
-rwxr-xr-xpublic/curriculum-vitae.html54
-rwxr-xr-xpublic/dcss-new-player-guide.html76
-rwxr-xr-xpublic/dcss-on-4k-display.html55
-rwxr-xr-xpublic/debian-based-riced-up-distribution-for-developers-and-devops-folks.html158
-rwxr-xr-xpublic/development-environments-with-nix.html74
-rwxr-xr-xpublic/digitalocean-spaces-to-sync-between-computers.html98
-rwxr-xr-xpublic/disable-mouse-wake-from-suspend-with-systemd-service.html84
-rwxr-xr-xpublic/download-youtube-videos.html50
-rwxr-xr-xpublic/drawing-pixels-in-plan9.html96
-rwxr-xr-xpublic/easy-time-took-in-bash.html56
-rwxr-xr-xpublic/encoding-binary-data-into-dna-sequence.html219
-rwxr-xr-xpublic/esp8266-and-micropython-guide.html128
-rwxr-xr-xpublic/ewd-manuscripts-ebook.html46
-rwxr-xr-xpublic/extend-lua-with-custom-c.html72
-rwxr-xr-xpublic/extending-dte-editor.html79
-rwxr-xr-xpublic/fix-plan9-bootloader.html50
-rwxr-xr-xpublic/fix-screen-tearing-on-debian-12-xorg-and-i3.html52
-rwxr-xr-xpublic/floods-in-slovenia.html44
-rwxr-xr-xpublic/fresh-9front-desktop.html45
-rwxr-xr-xpublic/from-internet-consumer-to-full-hominum-again.html112
-rwxr-xr-xpublic/git-push-multiple-origins.html47
-rwxr-xr-xpublic/golang-profiling-simplified.html124
-rwxr-xr-xpublic/grep-to-less-maintain-colors.html49
-rwxr-xr-xpublic/i-was-wrong-about-git-workflows.html84
-rwxr-xr-xpublic/index.html44
-rwxr-xr-xpublic/index.xml6103
-rwxr-xr-xpublic/install-plan9port-linux.html51
-rwxr-xr-xpublic/led-technology-not-so-eco.html56
-rwxr-xr-xpublic/linux-cheatsheet.html144
-rwxr-xr-xpublic/make-b-w-svg-charts-with-matplotlib.html86
-rwxr-xr-xpublic/making-cgit-look-nicer.html228
-rwxr-xr-xpublic/mass-set-permission.html46
-rwxr-xr-xpublic/most-likely-to-succeed-in-year-of-2011.html60
-rwxr-xr-xpublic/mount-plan9-over-network.html51
-rwxr-xr-xpublic/my-love-and-hate-relationship-with-nodejs.html110
-rwxr-xr-xpublic/non-blocking-shell-exec-csharp.html69
-rwxr-xr-xpublic/notes.xml1569
-rwxr-xr-xpublic/online-radio-streaming-with-mpv-from-terminal.html47
-rwxr-xr-xpublic/parse-rss-with-lua.html68
-rwxr-xr-xpublic/plan9-screenshot.html52
-rwxr-xr-xpublic/presentations-with-markdown.html102
-rwxr-xr-xpublic/preview-troff-man-pages.html50
-rwxr-xr-xpublic/profiling-python-web-applications-with-visual-tools.html176
-rwxr-xr-xpublic/radio.pls38
-rwxr-xr-xpublic/re-inventing-task-runner-that-i-actually-used-daily.html145
-rwxr-xr-xpublic/rekindling-my-love-for-programming.html85
-rwxr-xr-xpublic/remote-work.html78
-rwxr-xr-xpublic/replacing-dropbox-in-favor-of-digitalocean-spaces.html106
-rwxr-xr-xpublic/robots.txt2
-rwxr-xr-xpublic/run-9front-in-qemu.html56
-rwxr-xr-xpublic/running-golang-application-as-pid1.html222
-rwxr-xr-xpublic/set-color-temperature-of-displays-on-i3.html46
-rwxr-xr-xpublic/simple-iot-application.html472
-rwxr-xr-xpublic/simple-server-sent-events-based-pubsub-server.html343
-rwxr-xr-xpublic/simple-world-clock-with-eiink-display-and-raspberry-pi-zero.html104
-rwxr-xr-xpublic/simplifying-and-reducing-clutter.html80
-rwxr-xr-xpublic/sitemap.xml418
-rwxr-xr-xpublic/software-development-pitfalls.html152
-rwxr-xr-xpublic/state-of-web-technologies-and-web-development-in-year-2022.html220
-rwxr-xr-xpublic/that-sound-that-machine-makes-when-struggling.html64
-rwxr-xr-xpublic/the-strange-case-of-elasticsearch-allocation-failure.html97
-rwxr-xr-xpublic/tmux-sane-defaults.html69
-rwxr-xr-xpublic/trying-to-build-a-new-kind-of-terminal-emulator.html224
-rwxr-xr-xpublic/tying-out-helix-code-editor.html67
-rwxr-xr-xpublic/using-digitalocean-spaces-object-storage-with-fuse.html280
-rwxr-xr-xpublic/using-goaccess-with-nginx-to-replace-google-analytics.html129
-rwxr-xr-xpublic/using-sentiment-analysis-for-clickbait-detection-in-rss-feeds.html88
-rwxr-xr-xpublic/vault.html45
-rwxr-xr-xpublic/wap-mobile-web-before-the-web.html153
-rwxr-xr-xpublic/what-i-ve-learned-developing-ad-server.html159
-rwxr-xr-xpublic/what-would-dna-sound-if-synthesized.html237
-rwxr-xr-xpublic/who-knows-what-the-world-will-look-like-tomorrow.html109
-rwxr-xr-xpublic/wireless-sensor-networks.html71
-rwxr-xr-xpublic/write-iso-usb.html45
-rwxr-xr-xpublic/xterm-color-palette.html112
-rw-r--r--shell.nix6
-rw-r--r--static/general/9front-cursor.pngbin249 -> 0 bytes
-rw-r--r--static/general/9logo.pngbin39825 -> 0 bytes
-rwxr-xr-xstatic/general/alert-dark.svg99
-rwxr-xr-xstatic/general/alert-light.svg99
-rw-r--r--static/general/index.css1
-rw-r--r--static/general/og-big.jpgbin70575 -> 0 bytes
-rw-r--r--static/general/og-big.xcfbin10025863 -> 0 bytes
-rw-r--r--static/general/og.jpgbin44366 -> 0 bytes
-rw-r--r--static/general/og.xcfbin898329 -> 0 bytes
-rw-r--r--static/mitjafelicijan.pgp.pub.txt41
-rw-r--r--static/notes/10gui-10-finger-multitouch-user-interface.jpgbin21762 -> 0 bytes
-rw-r--r--static/notes/10gui-10-finger-multitouch-user-interface.mp4bin16587109 -> 0 bytes
-rw-r--r--static/notes/60s-ibm-computers-commercial.jpgbin32372 -> 0 bytes
-rw-r--r--static/notes/60s-ibm-computers-commercial.mp4bin35273598 -> 0 bytes
-rw-r--r--static/notes/9front-desktop.pngbin38054 -> 0 bytes
-rw-r--r--static/notes/dcss-quickstart.pdfbin80328 -> 0 bytes
-rw-r--r--static/notes/dcss.jpgbin855457 -> 0 bytes
-rw-r--r--static/notes/dcss_manual.pdfbin203302 -> 0 bytes
-rwxr-xr-xstatic/notes/floods/IMG_1461.mp4bin14410656 -> 0 bytes
-rwxr-xr-xstatic/notes/floods/IMG_1466.mp4bin8902148 -> 0 bytes
-rwxr-xr-xstatic/notes/floods/IMG_1469.webpbin816680 -> 0 bytes
-rwxr-xr-xstatic/notes/floods/IMG_1470.webpbin933574 -> 0 bytes
-rwxr-xr-xstatic/notes/floods/IMG_1471.mp4bin10163115 -> 0 bytes
-rwxr-xr-xstatic/notes/floods/IMG_1474.mp4bin14032243 -> 0 bytes
-rw-r--r--static/notes/grep-less.pngbin178000 -> 0 bytes
-rw-r--r--static/notes/plan9-pixels.pngbin12134 -> 0 bytes
-rw-r--r--static/notes/plot.svg1546
-rw-r--r--static/notes/ps1-prompt.pngbin24272 -> 0 bytes
-rw-r--r--static/notes/xterm-palette.pngbin9524 -> 0 bytes
-rwxr-xr-xstatic/posts/algae-sava/dji-algae-0.jpgbin145615 -> 0 bytes
-rwxr-xr-xstatic/posts/algae-sava/dji-algae-1.jpgbin154416 -> 0 bytes
-rwxr-xr-xstatic/posts/algae-sava/dji-algae-2.jpgbin114347 -> 0 bytes
-rwxr-xr-xstatic/posts/algae-sava/dji-algae-3.jpgbin128019 -> 0 bytes
-rwxr-xr-xstatic/posts/algae-sava/dji-algae-4.jpgbin217747 -> 0 bytes
-rwxr-xr-xstatic/posts/algae-sava/dji-algae-5.jpgbin264884 -> 0 bytes
-rwxr-xr-xstatic/posts/cv/avatar.gifbin2174 -> 0 bytes
-rwxr-xr-xstatic/posts/dfd-rice/desktop.pngbin329498 -> 0 bytes
-rwxr-xr-xstatic/posts/dfd-rice/install-00.pngbin35695 -> 0 bytes
-rwxr-xr-xstatic/posts/dfd-rice/install-01.pngbin28042 -> 0 bytes
-rwxr-xr-xstatic/posts/dfd-rice/install-02.pngbin21638 -> 0 bytes
-rwxr-xr-xstatic/posts/dfd-rice/install-03.pngbin34698 -> 0 bytes
-rwxr-xr-xstatic/posts/dfd-rice/install-04.pngbin28346 -> 0 bytes
-rwxr-xr-xstatic/posts/dfd-rice/install-05.pngbin13755 -> 0 bytes
-rwxr-xr-xstatic/posts/dfd-rice/installation.svg1388
-rwxr-xr-xstatic/posts/dfd-rice/layout.pngbin9072 -> 0 bytes
-rwxr-xr-xstatic/posts/dfd-rice/layout.svg28
-rwxr-xr-xstatic/posts/dfd-rice/script.pngbin65747 -> 0 bytes
-rw-r--r--static/posts/dna-sequence/benchmarks.csv7
-rw-r--r--static/posts/dna-sequence/chart-size.py28
-rw-r--r--static/posts/dna-sequence/chart-size.svg1553
-rw-r--r--static/posts/dna-sequence/chart-speed.py23
-rw-r--r--static/posts/dna-sequence/chart-speed.svg1416
-rwxr-xr-xstatic/posts/dna-sequence/dna-basics.jpgbin165883 -> 0 bytes
-rwxr-xr-xstatic/posts/dna-sequence/quote.pngbin1068 -> 0 bytes
-rwxr-xr-xstatic/posts/dna-sequence/sample-binary-file.pngbin66417 -> 0 bytes
-rwxr-xr-xstatic/posts/dna-sequence/sample.pngbin65930 -> 0 bytes
-rwxr-xr-xstatic/posts/dna-synthesized/bison/in.txt11
-rwxr-xr-xstatic/posts/dna-synthesized/bison/out.mp3bin960469 -> 0 bytes
-rwxr-xr-xstatic/posts/dna-synthesized/bison/spectogram.pngbin52808 -> 0 bytes
-rwxr-xr-xstatic/posts/dna-synthesized/elektron/IMG_0619.jpgbin226025 -> 0 bytes
-rwxr-xr-xstatic/posts/dna-synthesized/elektron/IMG_0620.jpgbin242937 -> 0 bytes
-rwxr-xr-xstatic/posts/dna-synthesized/elektron/IMG_0622.jpgbin279234 -> 0 bytes
-rwxr-xr-xstatic/posts/dna-synthesized/elektron/elektron.mp4bin22478213 -> 0 bytes
-rwxr-xr-xstatic/posts/dna-synthesized/elektron/midi-studio.jpgbin63633 -> 0 bytes
-rwxr-xr-xstatic/posts/dna-synthesized/mouse/in.txt9
-rwxr-xr-xstatic/posts/dna-synthesized/mouse/out.mp3bin864547 -> 0 bytes
-rwxr-xr-xstatic/posts/dna-synthesized/mouse/spectogram.pngbin114261 -> 0 bytes
-rwxr-xr-xstatic/posts/dna-synthesized/quote/in.txt8
-rwxr-xr-xstatic/posts/dna-synthesized/quote/out.mp3bin678973 -> 0 bytes
-rwxr-xr-xstatic/posts/dna-synthesized/quote/spectogram.pngbin108863 -> 0 bytes
-rwxr-xr-xstatic/posts/dna-synthesized/symphony-no6-1st-movement.mp3bin11650187 -> 0 bytes
-rwxr-xr-xstatic/posts/dna-synthesized/symphony-no6-1st-movement.pngbin245694 -> 0 bytes
-rwxr-xr-xstatic/posts/dna-synthesized/taurus/in.txt11
-rwxr-xr-xstatic/posts/dna-synthesized/taurus/out.mp3bin1056599 -> 0 bytes
-rwxr-xr-xstatic/posts/dna-synthesized/taurus/spectogram.pngbin109064 -> 0 bytes
-rwxr-xr-xstatic/posts/do-fuse/copy-benchmarks.tsv101
-rwxr-xr-xstatic/posts/do-fuse/fuse-droplets.pngbin42891 -> 0 bytes
-rwxr-xr-xstatic/posts/do-fuse/fuse-spaces.pngbin32450 -> 0 bytes
-rwxr-xr-xstatic/posts/do-fuse/sqlite-benchmarks.tsv1001
-rwxr-xr-xstatic/posts/dropbox-sync/dropbox-spaces.pngbin47661 -> 0 bytes
-rwxr-xr-xstatic/posts/esp8366-micropython/boards.jpgbin98162 -> 0 bytes
-rwxr-xr-xstatic/posts/go-profiling/golang-profiling-cpu.pdfbin16518 -> 0 bytes
-rwxr-xr-xstatic/posts/go-profiling/golang-profiling-mem.pdfbin19221 -> 0 bytes
-rwxr-xr-xstatic/posts/goaccess/goaccess-dash-html.pngbin16129 -> 0 bytes
-rwxr-xr-xstatic/posts/goaccess/goaccess-dash-term.pngbin9188 -> 0 bytes
-rw-r--r--static/posts/godot-dynamic-tile-loading/2d-player-movement.webmbin975421 -> 0 bytes
-rw-r--r--static/posts/godot-dynamic-tile-loading/cellular-automata.pngbin373408 -> 0 bytes
-rw-r--r--static/posts/godot-dynamic-tile-loading/example1/index.apple-touch-icon.pngbin18955 -> 0 bytes
-rw-r--r--static/posts/godot-dynamic-tile-loading/example1/index.audio.worklet.js211
-rw-r--r--static/posts/godot-dynamic-tile-loading/example1/index.html248
-rw-r--r--static/posts/godot-dynamic-tile-loading/example1/index.icon.pngbin3305 -> 0 bytes
-rw-r--r--static/posts/godot-dynamic-tile-loading/example1/index.js796
-rw-r--r--static/posts/godot-dynamic-tile-loading/example1/index.pckbin7056 -> 0 bytes
-rw-r--r--static/posts/godot-dynamic-tile-loading/example1/index.pngbin21443 -> 0 bytes
-rw-r--r--static/posts/godot-dynamic-tile-loading/example1/index.wasmbin13789463 -> 0 bytes
-rw-r--r--static/posts/godot-dynamic-tile-loading/village-creator.pngbin97628 -> 0 bytes
-rwxr-xr-xstatic/posts/helix-editor/editor.pngbin159442 -> 0 bytes
-rwxr-xr-xstatic/posts/iot-application/iot-app-output.pngbin23767 -> 0 bytes
-rwxr-xr-xstatic/posts/iot-application/iot-rest-example.pngbin33912 -> 0 bytes
-rwxr-xr-xstatic/posts/iot-application/iot-sqlite-db.pngbin199821 -> 0 bytes
-rwxr-xr-xstatic/posts/iot-application/kcachegrind.pngbin88486 -> 0 bytes
-rwxr-xr-xstatic/posts/iot-application/profiling-viewer.pngbin173672 -> 0 bytes
-rwxr-xr-xstatic/posts/iot-application/simple-iot-application-overview.svg2
-rwxr-xr-xstatic/posts/iot-application/simple-iot-application.zipbin6406 -> 0 bytes
-rwxr-xr-xstatic/posts/iot-application/snakeviz.pngbin59601 -> 0 bytes
-rw-r--r--static/posts/microsoundtrack/cow.m4vbin1113250 -> 0 bytes
-rwxr-xr-xstatic/posts/pid1/boxes.mp4bin443830 -> 0 bytes
-rwxr-xr-xstatic/posts/pid1/qemu.log320
-rw-r--r--static/posts/pid1/unikernels.pngbin33009 -> 0 bytes
-rwxr-xr-xstatic/posts/pid1/unikernels.svg587
-rw-r--r--static/posts/pid1/unikernels.webpbin23304 -> 0 bytes
-rwxr-xr-xstatic/posts/profile-bind-error/error.jpgbin57047 -> 0 bytes
-rwxr-xr-xstatic/posts/python-profiling/kcachegrind.pngbin88486 -> 0 bytes
-rwxr-xr-xstatic/posts/python-profiling/profiling-viewer.pngbin173672 -> 0 bytes
-rwxr-xr-xstatic/posts/python-profiling/snakeviz.pngbin59601 -> 0 bytes
-rwxr-xr-xstatic/posts/sentiment-analysis/.ipynb_checkpoints/TF Test-checkpoint.ipynb588
-rwxr-xr-xstatic/posts/sentiment-analysis/.ipynb_checkpoints/sentiment-analysis-checkpoint.ipynb170
-rwxr-xr-xstatic/posts/sentiment-analysis/guardian-sa-title-desc-relationship.pngbin15404 -> 0 bytes
-rwxr-xr-xstatic/posts/sentiment-analysis/sentiment-analysis.ipynb170
-rwxr-xr-xstatic/posts/simple-pubsub-server/caniuse.pngbin56379 -> 0 bytes
-rwxr-xr-xstatic/posts/simple-pubsub-server/chrome-debugging.pngbin151160 -> 0 bytes
-rwxr-xr-xstatic/posts/simple-pubsub-server/clients.m4vbin369179 -> 0 bytes
-rwxr-xr-xstatic/posts/simple-pubsub-server/pubsub-overview.pngbin18471 -> 0 bytes
-rwxr-xr-xstatic/posts/simple-pubsub-server/sse-pubsub-server.zipbin4158 -> 0 bytes
-rwxr-xr-xstatic/posts/state-of-web/2008-vs-2020.pngbin126650 -> 0 bytes
-rwxr-xr-xstatic/posts/state-of-web/compiling-vs-transpiling.pngbin41481 -> 0 bytes
-rwxr-xr-xstatic/posts/wap/emulator.mp4bin892887 -> 0 bytes
-rwxr-xr-xstatic/posts/wap/phones.gifbin348891 -> 0 bytes
-rwxr-xr-xstatic/posts/world-clock/enclosure.stlbin1884 -> 0 bytes
-rwxr-xr-xstatic/posts/world-clock/hardware.jpgbin82279 -> 0 bytes
-rwxr-xr-xstatic/posts/world-clock/world-clock.jpgbin148673 -> 0 bytes
-rwxr-xr-xstatic/posts/yapyap/hello.pngbin25962 -> 0 bytes
-rwxr-xr-xstatic/posts/yapyap/pid1.jpgbin394011 -> 0 bytes
-rwxr-xr-xstatic/posts/zed/zed-1.pngbin450802 -> 0 bytes
-rwxr-xr-xstatic/posts/zed/zed-2.pngbin812483 -> 0 bytes
-rw-r--r--templates/includes/.gitkeep0
-rw-r--r--templates/index.html40
-rw-r--r--templates/index.xml21
-rw-r--r--templates/note.html14
-rw-r--r--templates/notes.xml21
-rw-r--r--templates/openring.html12
-rw-r--r--templates/page.html13
-rw-r--r--templates/post.html14
-rw-r--r--templates/radio.pls38
-rw-r--r--templates/robots.txt2
-rw-r--r--templates/sitemap.xml8
-rw-r--r--templates/vault.md20
-rw-r--r--vault.py54
473 files changed, 717 insertions, 28012 deletions
diff --git a/.editorconfig b/.editorconfig
index ae26532..cc53074 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -5,9 +5,27 @@ charset = utf-8
5trim_trailing_whitespace = true 5trim_trailing_whitespace = true
6insert_final_newline = true 6insert_final_newline = true
7end_of_line = lf 7end_of_line = lf
8
9[Makefile]
10indent_style = tab
11indent_size = 4
12
13[*.c]
8indent_style = space 14indent_style = space
9indent_size = 2 15indent_size = 2
10 16
11[Makefile] 17[*.sh]
18indent_style = space
19indent_size = 4
20
21[*.go]
12indent_style = tab 22indent_style = tab
13indent_size = 4 23indent_size = 4
24
25[*.sql]
26indent_style = space
27indent_size = 2
28
29[*.{css,html,js,django}]
30indent_style = space
31indent_size = 2
diff --git a/.gitignore b/.gitignore
index 218224f..f40fbd8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,5 @@
1templates/includes/openring.html 1_site
2.DS_Store \ No newline at end of file 2.sass-cache
3.jekyll-cache
4.jekyll-metadata
5vendor
diff --git a/404.html b/404.html
new file mode 100644
index 0000000..8f598b8
--- /dev/null
+++ b/404.html
@@ -0,0 +1,24 @@
1---
2permalink: /404.html
3layout: base
4---
5
6<hr>
7
8<style type="text/css" media="screen">
9 .container {
10 margin: 40px auto;
11 }
12 h1 {
13 margin: 30px 0;
14 font-size: 4em;
15 line-height: 1;
16 letter-spacing: -1px;
17 }
18</style>
19
20<div class="container">
21 <h1>404</h1>
22 <p><strong>Page not found :(</strong></p>
23 <p>The requested page could not be found. Such is life!</p>
24</div>
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000..ff2c342
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,33 @@
1source "https://rubygems.org"
2# Hello! This is where you manage which Jekyll version is used to run.
3# When you want to use a different version, change it below, save the
4# file and run `bundle install`. Run Jekyll with `bundle exec`, like so:
5#
6# bundle exec jekyll serve
7#
8# This will help ensure the proper Jekyll version is running.
9# Happy Jekylling!
10gem "jekyll", "~> 4.3.2"
11# This is the default theme for new Jekyll sites. You may change this to anything you like.
12gem "minima", "~> 2.5"
13# If you want to use GitHub Pages, remove the "gem "jekyll"" above and
14# uncomment the line below. To upgrade, run `bundle update github-pages`.
15# gem "github-pages", group: :jekyll_plugins
16# If you have any plugins, put them here!
17group :jekyll_plugins do
18 gem "jekyll-feed", "~> 0.12"
19end
20
21# Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem
22# and associated library.
23platforms :mingw, :x64_mingw, :mswin, :jruby do
24 gem "tzinfo", ">= 1", "< 3"
25 gem "tzinfo-data"
26end
27
28# Performance-booster for watching directories on Windows
29gem "wdm", "~> 0.1.1", :platforms => [:mingw, :x64_mingw, :mswin]
30
31# Lock `http_parser.rb` gem to `v0.6.x` on JRuby builds since newer versions of the gem
32# do not have a Java counterpart.
33gem "http_parser.rb", "~> 0.6.0", :platforms => [:jruby]
diff --git a/Gemfile.lock b/Gemfile.lock
new file mode 100644
index 0000000..edc3499
--- /dev/null
+++ b/Gemfile.lock
@@ -0,0 +1,84 @@
1GEM
2 remote: https://rubygems.org/
3 specs:
4 addressable (2.8.5)
5 public_suffix (>= 2.0.2, < 6.0)
6 colorator (1.1.0)
7 concurrent-ruby (1.2.2)
8 em-websocket (0.5.3)
9 eventmachine (>= 0.12.9)
10 http_parser.rb (~> 0)
11 eventmachine (1.2.7)
12 ffi (1.16.3)
13 forwardable-extended (2.6.0)
14 google-protobuf (3.24.4-x86_64-linux)
15 http_parser.rb (0.8.0)
16 i18n (1.14.1)
17 concurrent-ruby (~> 1.0)
18 jekyll (4.3.2)
19 addressable (~> 2.4)
20 colorator (~> 1.0)
21 em-websocket (~> 0.5)
22 i18n (~> 1.0)
23 jekyll-sass-converter (>= 2.0, < 4.0)
24 jekyll-watch (~> 2.0)
25 kramdown (~> 2.3, >= 2.3.1)
26 kramdown-parser-gfm (~> 1.0)
27 liquid (~> 4.0)
28 mercenary (>= 0.3.6, < 0.5)
29 pathutil (~> 0.9)
30 rouge (>= 3.0, < 5.0)
31 safe_yaml (~> 1.0)
32 terminal-table (>= 1.8, < 4.0)
33 webrick (~> 1.7)
34 jekyll-feed (0.17.0)
35 jekyll (>= 3.7, < 5.0)
36 jekyll-sass-converter (3.0.0)
37 sass-embedded (~> 1.54)
38 jekyll-seo-tag (2.8.0)
39 jekyll (>= 3.8, < 5.0)
40 jekyll-watch (2.2.1)
41 listen (~> 3.0)
42 kramdown (2.4.0)
43 rexml
44 kramdown-parser-gfm (1.1.0)
45 kramdown (~> 2.0)
46 liquid (4.0.4)
47 listen (3.8.0)
48 rb-fsevent (~> 0.10, >= 0.10.3)
49 rb-inotify (~> 0.9, >= 0.9.10)
50 mercenary (0.4.0)
51 minima (2.5.1)
52 jekyll (>= 3.5, < 5.0)
53 jekyll-feed (~> 0.9)
54 jekyll-seo-tag (~> 2.1)
55 pathutil (0.16.2)
56 forwardable-extended (~> 2.6)
57 public_suffix (5.0.3)
58 rb-fsevent (0.11.2)
59 rb-inotify (0.10.1)
60 ffi (~> 1.0)
61 rexml (3.2.6)
62 rouge (4.2.0)
63 safe_yaml (1.0.5)
64 sass-embedded (1.69.5-x86_64-linux-gnu)
65 google-protobuf (~> 3.23)
66 terminal-table (3.0.2)
67 unicode-display_width (>= 1.1.1, < 3)
68 unicode-display_width (2.5.0)
69 webrick (1.8.1)
70
71PLATFORMS
72 x86_64-linux
73
74DEPENDENCIES
75 http_parser.rb (~> 0.6.0)
76 jekyll (~> 4.3.2)
77 jekyll-feed (~> 0.12)
78 minima (~> 2.5)
79 tzinfo (>= 1, < 3)
80 tzinfo-data
81 wdm (~> 0.1.1)
82
83BUNDLED WITH
84 2.4.10
diff --git a/Makefile b/Makefile
deleted file mode 100644
index e6161a7..0000000
--- a/Makefile
+++ /dev/null
@@ -1,30 +0,0 @@
1MAKEFLAGS=-j4
2
3# Using: https://github.com/mitjafelicijan/jbmafp
4
5build: openring
6 python3 vault.py
7 jbmafp --build
8 cd public; find . -type f -name '*.html' -exec sed -i 's/<img /<img loading="lazy" /g' {} \;
9
10dev:
11 jbmafp --build --server
12
13openring:
14 openring -l 300 -n 10 -p 1 \
15 -s https://jcs.org/rss \
16 -s https://landley.net/rss.xml \
17 -s https://drewdevault.com/feed.xml \
18 -s https://offbeatpursuit.com/blog/index.rss \
19 -s https://mirzapandzo.com/rss.xml \
20 -s https://journal.valeriansaliou.name/rss/ \
21 -s https://neil.computer/rss/ \
22 -s https://michael.stapelberg.ch/feed.xml \
23 -s https://utcc.utoronto.ca/~cks/space/blog/?atom \
24 -s https://szymonkaliski.com/feed.xml \
25 < templates/openring.html \
26 > templates/includes/openring.html
27
28deploy: build
29 rsync -az --delete public/ root@mitjafelicijan.com:/var/www/html/mitjafelicijan.com/
30 ssh root@mitjafelicijan.com chown www-data:www-data /var/www/html/mitjafelicijan.com/ -Rf
diff --git a/_config.yml b/_config.yml
new file mode 100644
index 0000000..0764b33
--- /dev/null
+++ b/_config.yml
@@ -0,0 +1,15 @@
1title: Mitja Felicijan
2author: Mitja Felicijan
3email: mitja.felicijan@gmail.com
4url: https://mitjafelicijan.com
5lang: en
6
7description: >-
8 You do not learn by relaxing. You learn by violently assaulting your problem
9 until it surrenders its mysteries to you.
10
11markdown: kramdown
12highlighter: rouge
13
14plugins:
15 - jekyll-feed
diff --git a/_includes/webring.html b/_includes/webring.html
new file mode 100644
index 0000000..f310ab5
--- /dev/null
+++ b/_includes/webring.html
@@ -0,0 +1,57 @@
1 <h2>Posts from blogs I follow around the net</h2>
2 <ul> <li>
3 <a href="http://www.landley.net/notes-2023.html#30-10-2023" target="_blank" rel="noopener">October 30, 2023</a>
4
5 <a href="http://www.landley.net/notes-2023.html" target="_blank" rel="noopener">Rob Landley's Blog Thing for 2023</a>
6 <div> Feeling terrible. Very tired. Can't sleep. Still coughing and sneezing and so on. Still drizzle outside, but now it's dropped down to near freezing. Spent 5 minutes outside and wanted gloves. (Which means I don't just have a cold, I have a STEREOTYPICAL cold. Of the "wet and drizzly somehow inexplicably encourage viruses" kind. Next up I'll have joint aches...</div>
7 </li>
8 <li>
9 <a href="https://drewdevault.com/2023/10/31/On-real-names.html" target="_blank" rel="noopener">On &#34;real name&#34; policies</a>
10
11 <a href="https://drewdevault.com" target="_blank" rel="noopener">Drew DeVault's blog</a>
12 <div>Some free software projects reject anonymous or pseudonymous contributions, requiring you to author patches using your &ldquo;real name&rdquo;. Such projects have a so-called &ldquo;real name&rdquo; policy; Linux is one well-known example.1 The root motivations behind such policies vary, but in my experience the most often cited rationale is that it&rsquo;s ...</div>
13 </li>
14 <li>
15 <a href="http://offbeatpursuit.com:80/blog/?id=25" target="_blank" rel="noopener">A fix by any other name</a>
16
17 <a href="<title>WLOG - blog</title>
18<link>http://offbeatpursuit.com:80/blog/" target="_blank" rel="noopener">WLOG - blog</a>
19 <div>tags: i2c, plan9 Another month, another file system. Well, if you can’t fix it in software, fix it in hardware (looking at you, bme680, we’re not done yet). The show must go on, as they say, and I would like my experiments to go on. So a “new” addition to the environmental sensor family connected to the humble “server”: sgp30. I say “new” because it was new ...</div>
20 </li>
21 <li>
22 <a href="https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid" target="_blank" rel="noopener">Next/Image &quot;url&quot; parameter is valid but upstream response is invalid</a>
23
24 <a href="https://mirzapandzo.com/" target="_blank" rel="noopener">Mirza Pandzo&apos;s Blog</a>
25 <div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2</div>
26 </li>
27 <li>
28 <a href="https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/" target="_blank" rel="noopener">Deploy a Nomad Cluster on Alpine Linux with Vultr</a>
29
30 <a href="https://journal.valeriansaliou.name/" target="_blank" rel="noopener">Valerian Saliou</a>
31 <div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler</div>
32 </li>
33 <li>
34 <a href="https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/" target="_blank" rel="noopener">Chart of Accounts for Startups and SaaS Companies</a>
35
36 <a href="https://neil.computer/" target="_blank" rel="noopener">Neil Panchal</a>
37 <div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If</div>
38 </li>
39 <li>
40 <a href="https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/" target="_blank" rel="noopener">My 2023 all-flash ZFS NAS (Network Storage) build</a>
41
42 <a href="https://michael.stapelberg.ch/feed.xml" target="_blank" rel="noopener">Michael Stapelbergs Website</a>
43 <div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers. In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. Design Goals I use my network storage devices primarily for archival (daily backups)...</div>
44 </li>
45 <li>
46 <a href="https://utcc.utoronto.ca/~cks/space/blog/web/RealHTMLCanGetABitCrazy" target="_blank" rel="noopener">Real (email) HTML can get a bit extreme</a>
47
48 <a href="https://utcc.utoronto.ca/~cks/space/blog/" target="_blank" rel="noopener">Chris&#39;s Wiki :: blog</a>
49 <div>Over on the Fediverse, I noted a discovery I'd made recently: It turns out that if you nest a couple hundred &lt;div>s inside each other before you get to the actual content text, GNU Emacs shr (its simple HTML renderer) can't cope with the result and gives you no content. Guess what some HTML-capable email clients do (possibly after the email is repeatedly ...</div>
50 </li>
51 <li>
52 <a href="https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/" target="_blank" rel="noopener">Building a DIY Pen Plotter</a>
53
54 <a href="http://github.com/dylang/node-rss" target="_blank" rel="noopener">Szymon Kaliski</a>
55 <div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023. My ultimate goal is to build my…</div>
56 </li>
57</ul>
diff --git a/templates/base.html b/_layouts/base.html
index 674925c..93c4448 100644
--- a/templates/base.html
+++ b/_layouts/base.html
@@ -1,5 +1,5 @@
1<!DOCTYPE html> 1<!DOCTYPE html>
2<html lang="{{ .Config.Language }}"> 2<html lang="{{ site.lang }}">
3 <head> 3 <head>
4 <meta charset="utf-8"> 4 <meta charset="utf-8">
5 <meta name="viewport" content="width=device-width,initial-scale=1"> 5 <meta name="viewport" content="width=device-width,initial-scale=1">
@@ -7,12 +7,15 @@
7 7
8 <link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel="icon" type="image/x-icon" /> 8 <link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel="icon" type="image/x-icon" />
9 9
10 <title>{{ block "title" . }}{{ .Config.Title }}{{ end }}</title> 10 <title>
11 <meta name="description" content="{{ block "description" . }}{{ .Config.Description }}{{ end }}"> 11 {% if page.title %}{{ page.title | escape }} - {{ site.title | escape }}
12 <meta name="author" content="{{ .Config.Title }}"> 12 {% else %}{{ site.title | escape }}{% endif %}
13 </title>
13 14
14 <link rel="alternate" type="application/rss+xml" title="Mitja Felicijan's posts" href="{{ .Config.BaseURL }}/index.xml"> 15 <meta name="description" content="{{ page.excerpt | default: site.description | strip_html | normalize_whitespace | truncate: 160 | escape }}">
15 <link rel="alternate" type="application/rss+xml" title="Mitja Felicijan's notes" href="{{ .Config.BaseURL }}/notes.xml"> 16 <meta name="author" content="{{ site.author }}">
17
18 <link rel="alternate" type="application/rss+xml" title="{{ site.title | escape }}" href="/feed.xml">
16 19
17 <style> 20 <style>
18 :root { 21 :root {
@@ -42,7 +45,7 @@
42 max-width: 1900px; 45 max-width: 1900px;
43 background: white; 46 background: white;
44 font-family: sans-serif; 47 font-family: sans-serif;
45 line-height: 1.35rem; 48 line-height: 1.4rem;
46 font-size: 16px; 49 font-size: 16px;
47 } 50 }
48 51
@@ -104,25 +107,19 @@
104 pre { 107 pre {
105 text-wrap: nowrap; 108 text-wrap: nowrap;
106 overflow-x: auto; 109 overflow-x: auto;
107 padding: 0 1em; 110 padding: 1em;
108 border: var(--border-size) solid var(--border-color); 111 border: var(--border-size) solid var(--border-color);
109 } 112 }
110 113
111 code { 114 code {
112 padding: 0 3px; 115 font-family: monospace;
113 font-size: 14px;
114 border: 0;
115 background: var(--bg-color); 116 background: var(--bg-color);
116 } 117 font-size: 14px;
117 118 }
118 pre code {
119 line-height: 1.3em;
120 background: white;
121 }
122 119
123 pre, code, pre *, code * { 120 pre code {
124 font-family: monospace; 121 background: transparent;
125 } 122 }
126 123
127 figure { 124 figure {
128 margin-inline-start: 0; 125 margin-inline-start: 0;
@@ -160,6 +157,45 @@
160 border-radius: 0; 157 border-radius: 0;
161 } 158 }
162 159
160 .highlight .hll { background-color: #ffffcc }
161 .highlight { background: #ffffff; }
162 .highlight .c { color: #008000 } /* Comment */
163 /* .highlight .err { border: 1px solid #FF0000 } /* Error */ */
164 .highlight .k { color: #0000ff } /* Keyword */
165 .highlight .ch { color: #008000 } /* Comment.Hashbang */
166 .highlight .cm { color: #008000 } /* Comment.Multiline */
167 .highlight .cp { color: #0000ff } /* Comment.Preproc */
168 .highlight .cpf { color: #008000 } /* Comment.PreprocFile */
169 .highlight .c1 { color: #008000 } /* Comment.Single */
170 .highlight .cs { color: #008000 } /* Comment.Special */
171 .highlight .ge { font-style: italic } /* Generic.Emph */
172 .highlight .gh { font-weight: bold } /* Generic.Heading */
173 .highlight .gp { font-weight: bold } /* Generic.Prompt */
174 .highlight .gs { font-weight: bold } /* Generic.Strong */
175 .highlight .gu { font-weight: bold } /* Generic.Subheading */
176 .highlight .kc { color: #0000ff } /* Keyword.Constant */
177 .highlight .kd { color: #0000ff } /* Keyword.Declaration */
178 .highlight .kn { color: #0000ff } /* Keyword.Namespace */
179 .highlight .kp { color: #0000ff } /* Keyword.Pseudo */
180 .highlight .kr { color: #0000ff } /* Keyword.Reserved */
181 .highlight .kt { color: #2b91af } /* Keyword.Type */
182 .highlight .s { color: #a31515 } /* Literal.String */
183 .highlight .nc { color: #2b91af } /* Name.Class */
184 .highlight .ow { color: #0000ff } /* Operator.Word */
185 .highlight .sa { color: #a31515 } /* Literal.String.Affix */
186 .highlight .sb { color: #a31515 } /* Literal.String.Backtick */
187 .highlight .sc { color: #a31515 } /* Literal.String.Char */
188 .highlight .dl { color: #a31515 } /* Literal.String.Delimiter */
189 .highlight .sd { color: #a31515 } /* Literal.String.Doc */
190 .highlight .s2 { color: #a31515 } /* Literal.String.Double */
191 .highlight .se { color: #a31515 } /* Literal.String.Escape */
192 .highlight .sh { color: #a31515 } /* Literal.String.Heredoc */
193 .highlight .si { color: #a31515 } /* Literal.String.Interpol */
194 .highlight .sx { color: #a31515 } /* Literal.String.Other */
195 .highlight .sr { color: #a31515 } /* Literal.String.Regex */
196 .highlight .s1 { color: #a31515 } /* Literal.String.Single */
197 .highlight .ss { color: #a31515 } /* Literal.String.Symbol */
198
163 @media only screen and (max-width: 600px) { 199 @media only screen and (max-width: 600px) {
164 body { 200 body {
165 padding: 0.5em; 201 padding: 0.5em;
@@ -189,26 +225,17 @@
189 <header> 225 <header>
190 <nav class="main" itemscope itemtype="http://schema.org/SiteNavigationElement" role="navigation" aria-label="Main navigation"> 226 <nav class="main" itemscope itemtype="http://schema.org/SiteNavigationElement" role="navigation" aria-label="Main navigation">
191 <a href="/">Home</a> 227 <a href="/">Home</a>
192 <a href="/#posts">Posts</a>
193 <a href="/#notes">Notes</a>
194 <a href="/#sideprojects" class="hob">Side Projects</a>
195 <a href="/vault.html">Vault</a>
196 <a href="https://github.com/mitjafelicijan" target="_blank">Code</a> 228 <a href="https://github.com/mitjafelicijan" target="_blank">Code</a>
197 <a href="/mitjafelicijan.pgp.pub.txt" target="_blank" class="hob">PGP</a> 229 <a href="/assets/mitjafelicijan.pgp.pub.txt" target="_blank" class="hob">PGP</a>
198 <a href="/curriculum-vitae.html">CV</a> 230 <a href="/curriculum-vitae.html">CV</a>
199 <a href="/index.xml" target="_blank" class="hob">RSS</a> 231 <a href="/feed.xml" target="_blank" class="hob">RSS</a>
200 </nav> 232 </nav>
201 </header> 233 </header>
202 234
203 <main role="main"> 235 <main role="main">
204 {{ block "content" . }}{{ end }} 236 {{ content }}
205 </main> 237 </main>
206 238
207 <section>
208 <hr>
209 {{ template "openring.html" }}
210 </section>
211
212 <footer> 239 <footer>
213 <hr> 240 <hr>
214 <p><big><strong>Want to comment or have something to add?</strong></big></p> 241 <p><big><strong>Want to comment or have something to add?</strong></big></p>
@@ -219,13 +246,8 @@
219 </p> 246 </p>
220 <hr> 247 <hr>
221 <p>This website does not track you. Content is made available under the <a href="https://creativecommons.org/licenses/by/4.0/" target="_blank" rel="noreferrer">CC BY 4.0 license</a> unless 248 <p>This website does not track you. Content is made available under the <a href="https://creativecommons.org/licenses/by/4.0/" target="_blank" rel="noreferrer">CC BY 4.0 license</a> unless
222 specified otherwise. Blog is also available as <a href="/index.xml" target="_blank">RSS feed</a>. 249 specified otherwise. Blog is also available as <a href="/feed.xml" target="_blank">RSS feed</a>.
223 </p> 250 </p>
224 </footer> 251 </footer>
225
226 <script>
227 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
228 </script>
229 <script defer src="/_vercel/insights/script.js"></script>
230 </body> 252 </body>
231</html> 253</html>
diff --git a/_layouts/index.html b/_layouts/index.html
new file mode 100644
index 0000000..3ce3d8f
--- /dev/null
+++ b/_layouts/index.html
@@ -0,0 +1,10 @@
1---
2layout: base
3---
4
5<main>
6 {{ content }}
7
8 <hr>
9 {% include webring.html %}
10</main>
diff --git a/_layouts/page.html b/_layouts/page.html
new file mode 100644
index 0000000..a029b8d
--- /dev/null
+++ b/_layouts/page.html
@@ -0,0 +1,10 @@
1---
2layout: base
3---
4
5<article itemtype="http://schema.org/Article">
6 <h1 itemtype="headline">{{ page.title }}</h1>
7 <div>
8 {{ content }}
9 </div>
10</article>
diff --git a/_layouts/post.html b/_layouts/post.html
new file mode 100644
index 0000000..c1432fa
--- /dev/null
+++ b/_layouts/post.html
@@ -0,0 +1,14 @@
1---
2layout: base
3---
4
5<article itemtype="http://schema.org/Article">
6 <h1 itemtype="headline">{{ page.title }}</h1>
7 <p><cap><u>{{ page.type }}</u></cap>, {{ page.date | date: '%B %d, %Y' }} on <a href="{{ site.url }}">{{ site.author }}'s blog</a></p>
8 <div>
9 {{ content }}
10 </div>
11</article>
12
13<hr>
14{% include webring.html %}
diff --git a/content/posts/2011-01-13-most-likely-to-succeed-in-year-of-2011.md b/_posts/2011-01-13-most-likely-to-succeed-in-year-of-2011.md
index 325bd52..de90494 100644
--- a/content/posts/2011-01-13-most-likely-to-succeed-in-year-of-2011.md
+++ b/_posts/2011-01-13-most-likely-to-succeed-in-year-of-2011.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Most likely to succeed in the year of 2011 2title: Most likely to succeed in the year of 2011
3url: most-likely-to-succeed-in-year-of-2011.html 3permalink: /most-likely-to-succeed-in-year-of-2011.html
4date: 2011-01-13T12:00:00+02:00 4date: 2011-01-13T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
diff --git a/content/posts/2012-03-09-led-technology-not-so-eco.md b/_posts/2012-03-09-led-technology-not-so-eco.md
index 2841d0a..4c5fda3 100644
--- a/content/posts/2012-03-09-led-technology-not-so-eco.md
+++ b/_posts/2012-03-09-led-technology-not-so-eco.md
@@ -1,7 +1,8 @@
1--- 1---
2title: LED technology might not be as eco-friendly as you think 2title: LED technology might not be as eco-friendly as you think
3url: led-technology-not-so-eco.html 3permalink: /led-technology-not-so-eco.html
4date: 2012-03-09T12:00:00+02:00 4date: 2012-03-09T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
diff --git a/content/posts/2013-10-24-wireless-sensor-networks.md b/_posts/2013-10-24-wireless-sensor-networks.md
index bc6b333..6eb3fe1 100644
--- a/content/posts/2013-10-24-wireless-sensor-networks.md
+++ b/_posts/2013-10-24-wireless-sensor-networks.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Wireless sensor networks 2title: Wireless sensor networks
3url: wireless-sensor-networks.html 3permalink: /wireless-sensor-networks.html
4date: 2013-10-24T12:00:00+02:00 4date: 2013-10-24T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
diff --git a/content/posts/2015-11-10-software-development-pitfalls.md b/_posts/2015-11-10-software-development-pitfalls.md
index 6a5d9bd..d7b9c1b 100644
--- a/content/posts/2015-11-10-software-development-pitfalls.md
+++ b/_posts/2015-11-10-software-development-pitfalls.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Software development and my favorite pitfalls 2title: Software development and my favorite pitfalls
3url: software-development-pitfalls.html 3permalink: /software-development-pitfalls.html
4date: 2015-11-10T12:00:00+02:00 4date: 2015-11-10T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
diff --git a/content/posts/2017-03-07-golang-profiling-simplified.md b/_posts/2017-03-07-golang-profiling-simplified.md
index f0821c5..aeea956 100644
--- a/content/posts/2017-03-07-golang-profiling-simplified.md
+++ b/_posts/2017-03-07-golang-profiling-simplified.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Golang profiling simplified 2title: Golang profiling simplified
3url: golang-profiling-simplified.html 3permalink: /golang-profiling-simplified.html
4date: 2017-03-07T12:00:00+02:00 4date: 2017-03-07T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
@@ -121,6 +122,6 @@ go tool pprof -pdf ./cpu cpu.pprof > cpu.pdf
121 122
122This will generate PDF document with visualized profile. 123This will generate PDF document with visualized profile.
123 124
124- [Memory PDF profile example](/posts/go-profiling/golang-profiling-mem.pdf) 125- [Memory PDF profile example](/assets/posts/go-profiling/golang-profiling-mem.pdf)
125- [CPU PDF profile example](/posts/go-profiling/golang-profiling-cpu.pdf) 126- [CPU PDF profile example](/assets/posts/go-profiling/golang-profiling-cpu.pdf)
126 127
diff --git a/content/posts/2017-04-17-what-i-ve-learned-developing-ad-server.md b/_posts/2017-04-17-what-i-ve-learned-developing-ad-server.md
index 3a6410f..10aca0d 100644
--- a/content/posts/2017-04-17-what-i-ve-learned-developing-ad-server.md
+++ b/_posts/2017-04-17-what-i-ve-learned-developing-ad-server.md
@@ -1,7 +1,8 @@
1--- 1---
2title: What I've learned developing ad server 2title: What I've learned developing ad server
3url: what-i-ve-learned-developing-ad-server.html 3permalink: /what-i-ve-learned-developing-ad-server.html
4date: 2017-04-17T12:00:00+02:00 4date: 2017-04-17T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
diff --git a/content/posts/2017-04-21-profiling-python-web-applications-with-visual-tools.md b/_posts/2017-04-21-profiling-python-web-applications-with-visual-tools.md
index 8617abe..70e25f9 100644
--- a/content/posts/2017-04-21-profiling-python-web-applications-with-visual-tools.md
+++ b/_posts/2017-04-21-profiling-python-web-applications-with-visual-tools.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Profiling Python web applications with visual tools 2title: Profiling Python web applications with visual tools
3url: profiling-python-web-applications-with-visual-tools.html 3permalink: /profiling-python-web-applications-with-visual-tools.html
4date: 2017-04-21T12:00:00+02:00 4date: 2017-04-21T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
@@ -21,7 +22,7 @@ If you are using MacOS you should check out [Profiling
21Viewer](http://www.profilingviewer.com/) or 22Viewer](http://www.profilingviewer.com/) or
22[MacCallGrind](http://www.maccallgrind.com/). 23[MacCallGrind](http://www.maccallgrind.com/).
23 24
24![KCachegrind](/posts/python-profiling/kcachegrind.png) 25![KCachegrind](/assets/posts/python-profiling/kcachegrind.png)
25 26
26We will be dividing this post into two main categories: 27We will be dividing this post into two main categories:
27 28
@@ -146,7 +147,7 @@ will be using Profilling Viewer under MacOS. You can open image in new tab. As
146you can see from this example there is hierarchy of execution order of your 147you can see from this example there is hierarchy of execution order of your
147code. 148code.
148 149
149![Profilling Viewer](/posts/python-profiling/profiling-viewer.png) 150![Profilling Viewer](/assets/posts/python-profiling/profiling-viewer.png)
150 151
151> Make sure you convert output of the cProfile output every time you want to 152> Make sure you convert output of the cProfile output every time you want to
152refresh and take a look at your possible optimizations because cProfile updates 153refresh and take a look at your possible optimizations because cProfile updates
@@ -177,7 +178,7 @@ $ snakeviz awesome_random_number.prof
177# shows visualized profile 178# shows visualized profile
178``` 179```
179 180
180![SnakeViz](/posts/python-profiling/snakeviz.png) 181![SnakeViz](/assets/posts/python-profiling/snakeviz.png)
181 182
182Reddit user [ccharles](https://www.reddit.com/user/ccharles) suggested a better 183Reddit user [ccharles](https://www.reddit.com/user/ccharles) suggested a better
183way for installing pip software by targeting user level instead of using sudo. 184way for installing pip software by targeting user level instead of using sudo.
diff --git a/content/posts/2017-08-11-simple-iot-application.md b/_posts/2017-08-11-simple-iot-application.md
index e31ac55..3c9b4f9 100644
--- a/content/posts/2017-08-11-simple-iot-application.md
+++ b/_posts/2017-08-11-simple-iot-application.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Simple IOT application supported by real-time monitoring and data history 2title: Simple IOT application supported by real-time monitoring and data history
3url: simple-iot-application.html 3permalink: /simple-iot-application.html
4date: 2017-08-11T12:00:00+02:00 4date: 2017-08-11T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
@@ -50,7 +51,7 @@ to API and another to serving HTML with chart.
50Schema below represents what we will try to achieve and how different parts 51Schema below represents what we will try to achieve and how different parts
51correlates to each other. 52correlates to each other.
52 53
53![Overview](/posts/iot-application/simple-iot-application-overview.svg) 54![Overview](/assets/posts/iot-application/simple-iot-application-overview.svg)
54 55
55## Simple Python API 56## Simple Python API
56 57
@@ -218,12 +219,12 @@ available via POST method on /api route.
218After testing the service with Restlet Client you should be able to view your 219After testing the service with Restlet Client you should be able to view your
219data in a database file ```data.db```. 220data in a database file ```data.db```.
220 221
221![REST settings example](/posts/iot-application/iot-rest-example.png) 222![REST settings example](/assets/posts/iot-application/iot-rest-example.png)
222 223
223You can also check the contents of new database file by using desktop client 224You can also check the contents of new database file by using desktop client
224for SQLite → [DB Browser for SQLite](http://sqlitebrowser.org/). 225for SQLite → [DB Browser for SQLite](http://sqlitebrowser.org/).
225 226
226![SQLite database example](/posts/iot-application/iot-sqlite-db.png) 227![SQLite database example](/assets/posts/iot-application/iot-sqlite-db.png)
227 228
228Table structure is as simple as it can be. We have ts (timestamp) and value 229Table structure is as simple as it can be. We have ts (timestamp) and value
229(value from Arduino). As you can see timestamp is generated on API side. If you 230(value from Arduino). As you can see timestamp is generated on API side. If you
@@ -585,10 +586,10 @@ every 5 seconds.
585If you navigate to ```http://0.0.0.0:5000``` you should see rendered chart as 586If you navigate to ```http://0.0.0.0:5000``` you should see rendered chart as
586shown on picture below. 587shown on picture below.
587 588
588![Application output](/posts/iot-application/iot-app-output.png) 589![Application output](/assets/posts/iot-application/iot-app-output.png)
589 590
590Complete application with all the code is available for 591Complete application with all the code is available for
591[download](/posts/iot-application/simple-iot-application.zip). 592[download](/assets/posts/iot-application/simple-iot-application.zip).
592 593
593## Conclusion 594## Conclusion
594 595
diff --git a/content/posts/2018-01-16-using-digitalocean-spaces-object-storage-with-fuse.md b/_posts/2018-01-16-using-digitalocean-spaces-object-storage-with-fuse.md
index 5ba7b64..543439f 100644
--- a/content/posts/2018-01-16-using-digitalocean-spaces-object-storage-with-fuse.md
+++ b/_posts/2018-01-16-using-digitalocean-spaces-object-storage-with-fuse.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Using DigitalOcean Spaces Object Storage with FUSE 2title: Using DigitalOcean Spaces Object Storage with FUSE
3url: using-digitalocean-spaces-object-storage-with-fuse.html 3permalink: /using-digitalocean-spaces-object-storage-with-fuse.html
4date: 2018-01-16T12:00:00+02:00 4date: 2018-01-16T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
@@ -55,7 +56,7 @@ Instuctions on how to use SSH keys and how to setup them are available in
55article [How To Use SSH Keys with DigitalOcean 56article [How To Use SSH Keys with DigitalOcean
56Droplets](https://www.digitalocean.com/community/tutorials/how-to-use-ssh-keys-with-digitalocean-droplets). 57Droplets](https://www.digitalocean.com/community/tutorials/how-to-use-ssh-keys-with-digitalocean-droplets).
57 58
58![DigitalOcean Droplets](/posts/do-fuse/fuse-droplets.png) 59![DigitalOcean Droplets](/assets/posts/do-fuse/fuse-droplets.png)
59 60
60After we created Droplet it's time to create new Space. This is done by clicking 61After we created Droplet it's time to create new Space. This is done by clicking
61on a button [Create](https://cloud.digitalocean.com/spaces/new) (right top 62on a button [Create](https://cloud.digitalocean.com/spaces/new) (right top
@@ -68,7 +69,7 @@ key](https://cloud.digitalocean.com/settings/api/tokens). This link will guide
68to the page when you can generate this key. After you create new one, please 69to the page when you can generate this key. After you create new one, please
69save provided Key and Secret because Secret will not be shown again. 70save provided Key and Secret because Secret will not be shown again.
70 71
71![DigitalOcean Spaces](/posts/do-fuse/fuse-spaces.png) 72![DigitalOcean Spaces](/assets/posts/do-fuse/fuse-spaces.png)
72 73
73Now that we have new Space and Access key we should SSH into our machine. 74Now that we have new Space and Access key we should SSH into our machine.
74 75
@@ -147,7 +148,7 @@ please send me your data. I would be interested in seeing results.
147 148
148**Here are plotted results** 149**Here are plotted results**
149 150
150You can download [raw result here](/posts/do-fuse/copy-benchmarks.tsv). 151You can download [raw result here](/assets/posts/do-fuse/copy-benchmarks.tsv).
151Measurements are in seconds. 152Measurements are in seconds.
152 153
153<script src="//cdn.plot.ly/plotly-latest.min.js"></script> 154<script src="//cdn.plot.ly/plotly-latest.min.js"></script>
@@ -155,7 +156,7 @@ Measurements are in seconds.
155<script> 156<script>
156(function(){ 157(function(){
157 var request = new XMLHttpRequest(); 158 var request = new XMLHttpRequest();
158 request.open("GET", "/posts/do-fuse/copy-benchmarks.tsv", true); 159 request.open("GET", "/assets/posts/do-fuse/copy-benchmarks.tsv", true);
159 request.onload = function() { 160 request.onload = function() {
160 if (request.status >= 200 && request.status < 400) { 161 if (request.status >= 200 && request.status < 400) {
161 var payload = request.responseText.trim(); 162 var payload = request.responseText.trim();
@@ -271,7 +272,7 @@ result_time = CLOSE = end_time - start_time
271print("CLOSE: %g seconds" % (result_time)) 272print("CLOSE: %g seconds" % (result_time))
272``` 273```
273 274
274You can download [raw result here](/posts/do-fuse/sqlite-benchmarks.tsv). And 275You can download [raw result here](/assets/posts/do-fuse/sqlite-benchmarks.tsv). And
275again, these results are done on a local block storage and do not represent 276again, these results are done on a local block storage and do not represent
276capabilities of object storage. With my current approach and state of the test 277capabilities of object storage. With my current approach and state of the test
277code these can not be done. I would need to make Python code much more robust 278code these can not be done. I would need to make Python code much more robust
@@ -281,7 +282,7 @@ and check locking etc.
281<script> 282<script>
282(function(){ 283(function(){
283 var request = new XMLHttpRequest(); 284 var request = new XMLHttpRequest();
284 request.open("GET", "/posts/do-fuse/sqlite-benchmarks.tsv", true); 285 request.open("GET", "/assets/posts/do-fuse/sqlite-benchmarks.tsv", true);
285 request.onload = function() { 286 request.onload = function() {
286 if (request.status >= 200 && request.status < 400) { 287 if (request.status >= 200 && request.status < 400) {
287 var payload = request.responseText.trim(); 288 var payload = request.responseText.trim();
diff --git a/content/posts/2019-01-03-encoding-binary-data-into-dna-sequence.md b/_posts/2019-01-03-encoding-binary-data-into-dna-sequence.md
index 2ec9387..0bb774e 100644
--- a/content/posts/2019-01-03-encoding-binary-data-into-dna-sequence.md
+++ b/_posts/2019-01-03-encoding-binary-data-into-dna-sequence.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Encoding binary data into DNA sequence 2title: Encoding binary data into DNA sequence
3url: encoding-binary-data-into-dna-sequence.html 3permalink: /encoding-binary-data-into-dna-sequence.html
4date: 2019-01-03T12:00:00+02:00 4date: 2019-01-03T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
@@ -109,7 +110,7 @@ The nucleotide in DNA consists of a sugar (deoxyribose), one of four bases
109Cytosine and thymine are pyrimidine bases, while adenine and guanine are purine 110Cytosine and thymine are pyrimidine bases, while adenine and guanine are purine
110bases. The sugar and the base together are called a nucleoside. 111bases. The sugar and the base together are called a nucleoside.
111 112
112![DNA](/posts/dna-sequence/dna-basics.jpg) 113![DNA](/assets/posts/dna-sequence/dna-basics.jpg)
113*DNA (a) forms a double stranded helix, and (b) adenine pairs with thymine and 114*DNA (a) forms a double stranded helix, and (b) adenine pairs with thymine and
114cytosine pairs with guanine. (credit a: modification of work by Jerome Walker, 115cytosine pairs with guanine. (credit a: modification of work by Jerome Walker,
115Dennis Myts)* 116Dennis Myts)*
@@ -299,12 +300,12 @@ Then we encode FASTA file from previous operation to encode this data into PNG.
299 300
300After encoding into PNG format this file looks like this. 301After encoding into PNG format this file looks like this.
301 302
302![Encoded Quote in PNG format](/posts/dna-sequence/quote.png) 303![Encoded Quote in PNG format](/assets/posts/dna-sequence/quote.png)
303The larger the input stream is the larger the PNG file would be. 304The larger the input stream is the larger the PNG file would be.
304 305
305Compiled basic Hello World C program with 306Compiled basic Hello World C program with
306[GCC](https://www.gnu.org/software/gcc/) would [look 307[GCC](https://www.gnu.org/software/gcc/) would [look
307like](/posts/dna-sequence/sample.png). 308like](/assets/posts/dna-sequence/sample.png).
308 309
309```c 310```c
310// gcc -O3 -o sample sample.c 311// gcc -O3 -o sample sample.c
@@ -368,7 +369,7 @@ dd if=<(openssl enc -aes-256-ctr -pass pass:"$(dd if=/dev/urandom bs=128 count=
368``` 369```
369 370
370 371
371![Sample binary file 1KB](/posts/dna-sequence/sample-binary-file.png) 372![Sample binary file 1KB](/assets/posts/dna-sequence/sample-binary-file.png)
372Our freshly generated 1KB file looks something like this (its full of 373Our freshly generated 1KB file looks something like this (its full of
373garbage data as intended). 374garbage data as intended).
374 375
@@ -394,13 +395,13 @@ Then we GZIP all the FASTA files to see how much the can be compressed.
394gzip -9 < 10MB.fa > 10MB.fa.gz 395gzip -9 < 10MB.fa > 10MB.fa.gz
395``` 396```
396 397
397![Encode to FASTA](/posts/dna-sequence/chart-speed.svg) 398![Encode to FASTA](/assets/posts/dna-sequence/chart-speed.svg)
398The speed increase that occurs when encoding to FASTA format. 399The speed increase that occurs when encoding to FASTA format.
399 400
400![File sizes](/posts/dna-sequence/chart-size.svg) 401![File sizes](/assets/posts/dna-sequence/chart-size.svg)
401Size of the out file after encoding. 402Size of the out file after encoding.
402 403
403[Download CSV file with benchmarks](/posts/dna-sequence/benchmarks.csv). 404[Download CSV file with benchmarks](/assets/posts/dna-sequence/benchmarks.csv).
404 405
405## References 406## References
406 407
diff --git a/content/posts/2019-10-14-simplifying-and-reducing-clutter.md b/_posts/2019-10-14-simplifying-and-reducing-clutter.md
index 25f9ca0..e804ecb 100644
--- a/content/posts/2019-10-14-simplifying-and-reducing-clutter.md
+++ b/_posts/2019-10-14-simplifying-and-reducing-clutter.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Simplifying and reducing clutter in my life and work 2title: Simplifying and reducing clutter in my life and work
3url: simplifying-and-reducing-clutter.html 3permalink: /simplifying-and-reducing-clutter.html
4date: 2019-10-14T12:00:00+02:00 4date: 2019-10-14T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
diff --git a/content/posts/2019-10-19-using-sentiment-analysis-for-clickbait-detection.md b/_posts/2019-10-19-using-sentiment-analysis-for-clickbait-detection.md
index d5729ed..5aad23c 100644
--- a/content/posts/2019-10-19-using-sentiment-analysis-for-clickbait-detection.md
+++ b/_posts/2019-10-19-using-sentiment-analysis-for-clickbait-detection.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Using sentiment analysis for clickbait detection in RSS feeds 2title: Using sentiment analysis for clickbait detection in RSS feeds
3url: using-sentiment-analysis-for-clickbait-detection-in-rss-feeds.html 3permalink: /using-sentiment-analysis-for-clickbait-detection-in-rss-feeds.html
4date: 2019-10-19T12:00:00+02:00 4date: 2019-10-19T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
@@ -92,12 +93,12 @@ plt.show()
92 longer period of time and then perform analysis again and use either machine 93 longer period of time and then perform analysis again and use either machine
93 learning or deep learning on top of it. 94 learning or deep learning on top of it.
94 95
95![Relationship between title and description](/posts/sentiment-analysis/guardian-sa-title-desc-relationship.png) 96![Relationship between title and description](/assets/posts/sentiment-analysis/guardian-sa-title-desc-relationship.png)
96 97
97Figure above displays difference between title and description sentiment for 98Figure above displays difference between title and description sentiment for
98specific RSS feed item. 1 means positive and -1 means negative sentiment. 99specific RSS feed item. 1 means positive and -1 means negative sentiment.
99 100
100[» Download Jupyter Notebook](/posts/sentiment-analysis/sentiment-analysis.ipynb) 101[» Download Jupyter Notebook](/assets/posts/sentiment-analysis/sentiment-analysis.ipynb)
101 102
102## Going further 103## Going further
103 104
diff --git a/content/posts/2020-03-22-simple-sse-based-pubsub-server.md b/_posts/2020-03-22-simple-sse-based-pubsub-server.md
index cf5a5d9..23a3640 100644
--- a/content/posts/2020-03-22-simple-sse-based-pubsub-server.md
+++ b/_posts/2020-03-22-simple-sse-based-pubsub-server.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Simple Server-Sent Events based PubSub Server 2title: Simple Server-Sent Events based PubSub Server
3url: simple-server-sent-events-based-pubsub-server.html 3permalink: /simple-server-sent-events-based-pubsub-server.html
4date: 2020-03-22T12:00:00+02:00 4date: 2020-03-22T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
@@ -38,7 +39,7 @@ simple. We have subscribers that receive messages, and we have publishers that
38create and post messages. Similar model is also well know pattern that works on 39create and post messages. Similar model is also well know pattern that works on
39a premise of consumers and producers, and they take similar roles. 40a premise of consumers and producers, and they take similar roles.
40 41
41![How PubSub works](/posts/simple-pubsub-server/pubsub-overview.png) 42![How PubSub works](/assets/posts/simple-pubsub-server/pubsub-overview.png)
42 43
43**These are some naive characteristics we want to achieve:** 44**These are some naive characteristics we want to achieve:**
44 45
@@ -74,7 +75,7 @@ page](https://html.spec.whatwg.org/multipage/server-sent-events.html).
74 75
75### Current browser support 76### Current browser support
76 77
77![Browser support](/posts/simple-pubsub-server/caniuse.png) 78![Browser support](/assets/posts/simple-pubsub-server/caniuse.png)
78 79
79Check 80Check
80[https://caniuse.com/#feat=eventsource](https://caniuse.com/#feat=eventsource) 81[https://caniuse.com/#feat=eventsource](https://caniuse.com/#feat=eventsource)
@@ -142,7 +143,7 @@ which is quite nice and available from Developer Tools under Network tab.
142> ones. For debugging server events add `console.log` to `server.js` code and 143> ones. For debugging server events add `console.log` to `server.js` code and
143> print out events. 144> print out events.
144 145
145![Google Chrome Developer Tools EventStream](/posts/simple-pubsub-server/chrome-debugging.png) 146![Google Chrome Developer Tools EventStream](/assets/posts/simple-pubsub-server/chrome-debugging.png)
146 147
147## Server implementation 148## Server implementation
148 149
@@ -281,7 +282,7 @@ nicer and maintanable.
281 282
282### Publisher and subscriber in action 283### Publisher and subscriber in action
283 284
284<video src="/posts/simple-pubsub-server/clients.m4v" controls></video> 285<video src="/assets/posts/simple-pubsub-server/clients.m4v" controls></video>
285 286
286You can download [the code](../simple-pubsub-server/sse-pubsub-server.zip) and 287You can download [the code](../simple-pubsub-server/sse-pubsub-server.zip) and
287follow along. 288follow along.
diff --git a/content/posts/2020-03-27-create-placeholder-images-with-sharp.md b/_posts/2020-03-27-create-placeholder-images-with-sharp.md
index 1c2b042..c129396 100644
--- a/content/posts/2020-03-27-create-placeholder-images-with-sharp.md
+++ b/_posts/2020-03-27-create-placeholder-images-with-sharp.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Create placeholder images with sharp Node.js image processing library 2title: Create placeholder images with sharp Node.js image processing library
3url: create-placeholder-images-with-sharp.html 3permalink: /create-placeholder-images-with-sharp.html
4date: 2020-03-27T12:00:00+02:00 4date: 2020-03-27T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
diff --git a/content/posts/2020-03-29-the-strange-case-of-elasticsearch-allocation-failure.md b/_posts/2020-03-29-the-strange-case-of-elasticsearch-allocation-failure.md
index efe88fa..1aa3536 100644
--- a/content/posts/2020-03-29-the-strange-case-of-elasticsearch-allocation-failure.md
+++ b/_posts/2020-03-29-the-strange-case-of-elasticsearch-allocation-failure.md
@@ -1,7 +1,8 @@
1--- 1---
2title: The strange case of Elasticsearch allocation failure 2title: The strange case of Elasticsearch allocation failure
3url: the-strange-case-of-elasticsearch-allocation-failure.html 3permalink: /the-strange-case-of-elasticsearch-allocation-failure.html
4date: 2020-03-29T12:00:00+02:00 4date: 2020-03-29T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
diff --git a/content/posts/2020-03-30-my-love-and-hate-relationship-with-nodejs.md b/_posts/2020-03-30-my-love-and-hate-relationship-with-nodejs.md
index d083890..0299d9d 100644
--- a/content/posts/2020-03-30-my-love-and-hate-relationship-with-nodejs.md
+++ b/_posts/2020-03-30-my-love-and-hate-relationship-with-nodejs.md
@@ -1,7 +1,8 @@
1--- 1---
2title: My love and hate relationship with Node.js 2title: My love and hate relationship with Node.js
3url: my-love-and-hate-relationship-with-nodejs.html 3permalink: /my-love-and-hate-relationship-with-nodejs.html
4date: 2020-03-30T12:00:00+02:00 4date: 2020-03-30T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
diff --git a/content/posts/2020-05-05-remote-work.md b/_posts/2020-05-05-remote-work.md
index 905d169..8eb75d2 100644
--- a/content/posts/2020-05-05-remote-work.md
+++ b/_posts/2020-05-05-remote-work.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Remote work and how it affects the daily lives of people 2title: Remote work and how it affects the daily lives of people
3url: remote-work.html 3permalink: /remote-work.html
4date: 2020-05-05T12:00:00+02:00 4date: 2020-05-05T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
diff --git a/content/posts/2020-08-15-systemd-disable-wake-onmouse.md b/_posts/2020-08-15-systemd-disable-wake-onmouse.md
index 8f411d6..8122322 100644
--- a/content/posts/2020-08-15-systemd-disable-wake-onmouse.md
+++ b/_posts/2020-08-15-systemd-disable-wake-onmouse.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Disable mouse wake from suspend with systemd service 2title: Disable mouse wake from suspend with systemd service
3url: disable-mouse-wake-from-suspend-with-systemd-service.html 3permalink: /disable-mouse-wake-from-suspend-with-systemd-service.html
4date: 2020-08-15T12:00:00+02:00 4date: 2020-08-15T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
diff --git a/content/posts/2020-09-06-esp-and-micropython.md b/_posts/2020-09-06-esp-and-micropython.md
index fb7e150..9a005af 100644
--- a/content/posts/2020-09-06-esp-and-micropython.md
+++ b/_posts/2020-09-06-esp-and-micropython.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Getting started with MicroPython and ESP8266 2title: Getting started with MicroPython and ESP8266
3url: esp8266-and-micropython-guide.html 3permalink: /esp8266-and-micropython-guide.html
4date: 2020-09-06T12:00:00+02:00 4date: 2020-09-06T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
@@ -19,7 +20,7 @@ but I could easily choose
19contains which tools I use and how I prepared my workspace to code for 20contains which tools I use and how I prepared my workspace to code for
20[ESP8266](https://www.espressif.com/en/products/socs/esp8266). 21[ESP8266](https://www.espressif.com/en/products/socs/esp8266).
21 22
22![ESP8266 and ESP32 boards](/posts/esp8366-micropython/boards.jpg) 23![ESP8266 and ESP32 boards](/assets/posts/esp8366-micropython/boards.jpg)
23 24
24This guide covers: 25This guide covers:
25 26
diff --git a/content/posts/2020-09-08-bind-warning-on-login.md b/_posts/2020-09-08-bind-warning-on-login.md
index cb1e0e5..94b5a5f 100644
--- a/content/posts/2020-09-08-bind-warning-on-login.md
+++ b/_posts/2020-09-08-bind-warning-on-login.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Fix bind warning in .profile on login in Ubuntu 2title: Fix bind warning in .profile on login in Ubuntu
3url: bind-warning-on-login-in-ubuntu.html 3permalink: /bind-warning-on-login-in-ubuntu.html
4date: 2020-09-08T12:00:00+02:00 4date: 2020-09-08T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
@@ -30,7 +31,7 @@ bind '"\e[Z":menu-complete-backward'
30I haven't noticed anything wrong with this and all was working fine until I 31I haven't noticed anything wrong with this and all was working fine until I
31restarted my machine and then I got this error. 32restarted my machine and then I got this error.
32 33
33![Profile bind error](/posts/profile-bind-error/error.jpg) 34![Profile bind error](/assets/posts/profile-bind-error/error.jpg)
34 35
35When I pressed OK, I got into the [Gnome 36When I pressed OK, I got into the [Gnome
36shell](https://wiki.gnome.org/Projects/GnomeShell) and all was working fine, but 37shell](https://wiki.gnome.org/Projects/GnomeShell) and all was working fine, but
diff --git a/content/posts/2020-09-09-digitalocean-sync.md b/_posts/2020-09-09-digitalocean-sync.md
index e16b827..38696a9 100644
--- a/content/posts/2020-09-09-digitalocean-sync.md
+++ b/_posts/2020-09-09-digitalocean-sync.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Using Digitalocean Spaces to sync between computers 2title: Using Digitalocean Spaces to sync between computers
3url: digitalocean-spaces-to-sync-between-computers.html 3permalink: /digitalocean-spaces-to-sync-between-computers.html
4date: 2020-09-09T12:00:00+02:00 4date: 2020-09-09T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
diff --git a/content/posts/2021-01-24-replacing-dropbox-with-s3.md b/_posts/2021-01-24-replacing-dropbox-with-s3.md
index b7fc424..fb4ba68 100644
--- a/content/posts/2021-01-24-replacing-dropbox-with-s3.md
+++ b/_posts/2021-01-24-replacing-dropbox-with-s3.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Replacing Dropbox in favor of DigitalOcean spaces 2title: Replacing Dropbox in favor of DigitalOcean spaces
3url: replacing-dropbox-in-favor-of-digitalocean-spaces.html 3permalink: /replacing-dropbox-in-favor-of-digitalocean-spaces.html
4date: 2021-01-24T12:00:00+02:00 4date: 2021-01-24T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
@@ -105,7 +106,7 @@ You can use this script in a combination with [Cron](https://en.wikipedia.org/wi
105When you start syncing your local stuff with a remote server you can review your 106When you start syncing your local stuff with a remote server you can review your
106items on DigitalOcean. 107items on DigitalOcean.
107 108
108![Dropbox Spaces](/posts/dropbox-sync/dropbox-spaces.png) 109![Dropbox Spaces](/assets/posts/dropbox-sync/dropbox-spaces.png)
109 110
110I have been using this script now for quite some time, and it's working 111I have been using this script now for quite some time, and it's working
111flawlessly. I also uninstalled Dropbox and stopped using it completely. 112flawlessly. I also uninstalled Dropbox and stopped using it completely.
diff --git a/content/posts/2021-01-25-goaccess.md b/_posts/2021-01-25-goaccess.md
index 84ea3cd..4de65e8 100644
--- a/content/posts/2021-01-25-goaccess.md
+++ b/_posts/2021-01-25-goaccess.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Using GoAccess with Nginx to replace Google Analytics 2title: Using GoAccess with Nginx to replace Google Analytics
3url: using-goaccess-with-nginx-to-replace-google-analytics.html 3permalink: /using-goaccess-with-nginx-to-replace-google-analytics.html
4date: 2021-01-25T12:00:00+02:00 4date: 2021-01-25T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
@@ -41,11 +42,11 @@ all the functionalities I need, and it's a single binary. Written in Go.
41 42
42GoAccess can be used in two different modes. 43GoAccess can be used in two different modes.
43 44
44![GoAccess Terminal](/posts/goaccess/goaccess-dash-term.png) 45![GoAccess Terminal](/assets/posts/goaccess/goaccess-dash-term.png)
45 46
46*Running in a terminal* 47*Running in a terminal*
47 48
48![GoAccess HTML](/posts/goaccess/goaccess-dash-html.png) 49![GoAccess HTML](/assets/posts/goaccess/goaccess-dash-html.png)
49 50
50*Running in a browser* 51*Running in a browser*
51 52
diff --git a/content/posts/2021-06-26-simple-world-clock.md b/_posts/2021-06-26-simple-world-clock.md
index ef2f12c..31692e1 100644
--- a/content/posts/2021-06-26-simple-world-clock.md
+++ b/_posts/2021-06-26-simple-world-clock.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Simple world clock with eInk display and Raspberry Pi Zero 2title: Simple world clock with eInk display and Raspberry Pi Zero
3url: simple-world-clock-with-eiink-display-and-raspberry-pi-zero.html 3permalink: /simple-world-clock-with-eiink-display-and-raspberry-pi-zero.html
4date: 2021-06-26T12:00:00+02:00 4date: 2021-06-26T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
@@ -23,7 +24,7 @@ have a bunch of [Raspberry Pi's
23Zero](https://www.raspberrypi.org/products/raspberry-pi-zero/) lying around that 24Zero](https://www.raspberrypi.org/products/raspberry-pi-zero/) lying around that
24I really need to use. 25I really need to use.
25 26
26![Inky pHAT, Raspberry Pi Zero](/posts/world-clock/hardware.jpg) 27![Inky pHAT, Raspberry Pi Zero](/assets/posts/world-clock/hardware.jpg)
27 28
28Since the Inky [Inky 29Since the Inky [Inky
29pHAT](https://shop.pimoroni.com/products/inky-phat?variant=12549254217811) is 30pHAT](https://shop.pimoroni.com/products/inky-phat?variant=12549254217811) is
@@ -94,7 +95,7 @@ Then we add a cronjob with `crontab -e`.
94 95
95So, we end up with a result like this. 96So, we end up with a result like this.
96 97
97![World Clock](/posts/world-clock/world-clock.jpg) 98![World Clock](/assets/posts/world-clock/world-clock.jpg)
98 99
99And for the enclosure that can be 3D printed, but I haven't yet something like 100And for the enclosure that can be 3D printed, but I haven't yet something like
100this can be used. 101this can be used.
@@ -102,6 +103,6 @@ this can be used.
102<iframe id="vs_iframe" src="https://www.viewstl.com/?embedded&url=https%3A%2F%2Fmitjafelicijan.com%2Fposts%2Fworld-clock%2Fenclosure.stl&color=gray&bgcolor=white&edges=no&orientation=front&noborder=no" style="border:0;margin:0;width:100%;height:400px;"></iframe> 103<iframe id="vs_iframe" src="https://www.viewstl.com/?embedded&url=https%3A%2F%2Fmitjafelicijan.com%2Fposts%2Fworld-clock%2Fenclosure.stl&color=gray&bgcolor=white&edges=no&orientation=front&noborder=no" style="border:0;margin:0;width:100%;height:400px;"></iframe>
103 104
104You can download my [STL file for the enclosure 105You can download my [STL file for the enclosure
105here](/posts/world-clock/enclosure.stl), but make sure that dimensions make 106here](/assets/posts/world-clock/enclosure.stl), but make sure that dimensions make
106sense and also opening for USB port should be added or just use a drill and some 107sense and also opening for USB port should be added or just use a drill and some
107hot glue to make it stick in the enclosure. 108hot glue to make it stick in the enclosure.
diff --git a/content/posts/2021-07-30-from-internet-consumer-to-full-hominum-again.md b/_posts/2021-07-30-from-internet-consumer-to-full-hominum-again.md
index 100645b..cbcca37 100644
--- a/content/posts/2021-07-30-from-internet-consumer-to-full-hominum-again.md
+++ b/_posts/2021-07-30-from-internet-consumer-to-full-hominum-again.md
@@ -1,7 +1,8 @@
1--- 1---
2title: My journey from being an internet über consumer to being a full hominum again 2title: My journey from being an internet über consumer to being a full hominum again
3url: from-internet-consumer-to-full-hominum-again.html 3permalink: /from-internet-consumer-to-full-hominum-again.html
4date: 2021-07-30T12:00:00+02:00 4date: 2021-07-30T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
diff --git a/content/posts/2021-08-01-linux-cheatsheet.md b/_posts/2021-08-01-linux-cheatsheet.md
index 20e3382..b416ffa 100644
--- a/content/posts/2021-08-01-linux-cheatsheet.md
+++ b/_posts/2021-08-01-linux-cheatsheet.md
@@ -1,7 +1,8 @@
1--- 1---
2title: List of essential Linux commands for server management 2title: List of essential Linux commands for server management
3url: linux-cheatsheet.html 3permalink: /linux-cheatsheet.html
4date: 2021-08-01T12:00:00+02:00 4date: 2021-08-01T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
diff --git a/content/posts/2021-12-03-debian-based-riced-up-distribution-for-developers.md b/_posts/2021-12-03-debian-based-riced-up-distribution-for-developers.md
index 8c2a870..b469a05 100644
--- a/content/posts/2021-12-03-debian-based-riced-up-distribution-for-developers.md
+++ b/_posts/2021-12-03-debian-based-riced-up-distribution-for-developers.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Debian based riced up distribution for Developers and DevOps folks 2title: Debian based riced up distribution for Developers and DevOps folks
3url: debian-based-riced-up-distribution-for-developers-and-devops-folks.html 3permalink: /debian-based-riced-up-distribution-for-developers-and-devops-folks.html
4date: 2021-12-03T12:00:00+02:00 4date: 2021-12-03T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
@@ -76,35 +77,35 @@ Fonts being applied across the distro and things like that.
76First, I choose terminal installer and left it to load additional components. 77First, I choose terminal installer and left it to load additional components.
77Avoid using graphical installer in this case. 78Avoid using graphical installer in this case.
78 79
79![](/posts/dfd-rice/install-00.png) 80![](/assets/posts/dfd-rice/install-00.png)
80 81
81After that I selected hostname and created a normal user and set password for 82After that I selected hostname and created a normal user and set password for
82that user and root user and choose guided mode for disk partitioning. 83that user and root user and choose guided mode for disk partitioning.
83 84
84![](/posts/dfd-rice/install-01.png) 85![](/assets/posts/dfd-rice/install-01.png)
85 86
86I left it run to install all the things required for the base system and opted 87I left it run to install all the things required for the base system and opted
87out of scanning additional media for use by the package manager. Those will be 88out of scanning additional media for use by the package manager. Those will be
88downloaded from the internet during installation. 89downloaded from the internet during installation.
89 90
90![](/posts/dfd-rice/install-02.png) 91![](/assets/posts/dfd-rice/install-02.png)
91 92
92I opted out of the popularity contest, and **now comes the important part**. 93I opted out of the popularity contest, and **now comes the important part**.
93Uncheck all the boxes in Software selection and only leave 'standard system 94Uncheck all the boxes in Software selection and only leave 'standard system
94utilities'. I also left an SSH server, so I was able to log in to the machine 95utilities'. I also left an SSH server, so I was able to log in to the machine
95from my main PC. 96from my main PC.
96 97
97![](/posts/dfd-rice/install-03.png) 98![](/assets/posts/dfd-rice/install-03.png)
98 99
99At this point, I installed GRUB bootloader on the disk where I installed the 100At this point, I installed GRUB bootloader on the disk where I installed the
100system. 101system.
101 102
102![](/posts/dfd-rice/install-04.png) 103![](/assets/posts/dfd-rice/install-04.png)
103 104
104That concluded the installation of base Debian and after restarting the computer 105That concluded the installation of base Debian and after restarting the computer
105I was prompted with the login screen. 106I was prompted with the login screen.
106 107
107![](/posts/dfd-rice/install-05.png) 108![](/assets/posts/dfd-rice/install-05.png)
108 109
109Now that I had the base installation, it was time to choose what software do I 110Now that I had the base installation, it was time to choose what software do I
110want to include in this so-called distribution. I wanted out of the box 111want to include in this so-called distribution. I wanted out of the box
@@ -141,7 +142,7 @@ What I was doing in Gnome was having windows in a layout like the diagram
141below. This is my common practice. And if you look at it you can clearly see I 142below. This is my common practice. And if you look at it you can clearly see I
142was replicating tiling window manager setup in Gnome. 143was replicating tiling window manager setup in Gnome.
143 144
144![](/posts/dfd-rice/layout.png) 145![](/assets/posts/dfd-rice/layout.png)
145 146
146That made me look into a bunch of tiling window managers and then tested them 147That made me look into a bunch of tiling window managers and then tested them
147out. Candidates I was looking at were: 148out. Candidates I was looking at were:
@@ -211,7 +212,7 @@ something similar.
211 212
212This is some of the output from the installation script. 213This is some of the output from the installation script.
213 214
214![](/posts/dfd-rice/script.png) 215![](/assets/posts/dfd-rice/script.png)
215 216
216Let's take a look at some examples in the installation script. 217Let's take a look at some examples in the installation script.
217 218
@@ -273,4 +274,4 @@ And this is how it looks with two terminals side by side. I really like the
273simplicity and clean interface. I will polish the colors and stuff like that, 274simplicity and clean interface. I will polish the colors and stuff like that,
274but I really do like the results. 275but I really do like the results.
275 276
276![](/posts/dfd-rice/desktop.png) 277![](/assets/posts/dfd-rice/desktop.png)
diff --git a/content/posts/2021-12-25-running-golang-application-as-pid1.md b/_posts/2021-12-25-running-golang-application-as-pid1.md
index d4db07d..1f67ee1 100644
--- a/content/posts/2021-12-25-running-golang-application-as-pid1.md
+++ b/_posts/2021-12-25-running-golang-application-as-pid1.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Running Golang application as PID 1 with Linux kernel 2title: Running Golang application as PID 1 with Linux kernel
3url: running-golang-application-as-pid1.html 3permalink: /running-golang-application-as-pid1.html
4date: 2021-12-25T12:00:00+02:00 4date: 2021-12-25T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
@@ -23,7 +24,7 @@ Really worth a read.
23If we compare a normal operating system to a unikernel side by side, they would 24If we compare a normal operating system to a unikernel side by side, they would
24look something like this. 25look something like this.
25 26
26![Virtual machines vs Containers vs Unikernels](/posts/pid1/unikernels.webp) 27![Virtual machines vs Containers vs Unikernels](/assets/posts/pid1/unikernels.webp)
27 28
28From this image, we can see how the complexity significantly decreases with 29From this image, we can see how the complexity significantly decreases with
29the use of Unikernels. This comes with a price, of course. Unikernels are hard 30the use of Unikernels. This comes with a price, of course. Unikernels are hard
@@ -252,7 +253,7 @@ Hello from Golang
252Hello from Golang 253Hello from Golang
253``` 254```
254 255
255The whole [log file here](/posts/pid1/qemu.log). 256The whole [log file here](/assets/posts/pid1/qemu.log).
256 257
257## Size comparison 258## Size comparison
258 259
@@ -328,7 +329,7 @@ genisoimage -R \
328This will produce `GoAsPID1.iso` which you can use with [Virtualbox](https://www.virtualbox.org/) 329This will produce `GoAsPID1.iso` which you can use with [Virtualbox](https://www.virtualbox.org/)
329or [Gnome Boxes](https://apps.gnome.org/app/org.gnome.Boxes/). 330or [Gnome Boxes](https://apps.gnome.org/app/org.gnome.Boxes/).
330 331
331<video src="/posts/pid1/boxes.mp4" controls></video> 332<video src="/assets/posts/pid1/boxes.mp4" controls></video>
332 333
333## Is running applications as PID 1 even worth it? 334## Is running applications as PID 1 even worth it?
334 335
diff --git a/content/posts/2021-12-30-wap-mobile-web-before-the-web.md b/_posts/2021-12-30-wap-mobile-web-before-the-web.md
index 5e7ff38..058ad55 100644
--- a/content/posts/2021-12-30-wap-mobile-web-before-the-web.md
+++ b/_posts/2021-12-30-wap-mobile-web-before-the-web.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Wireless Application Protocol and the mobile web before the web 2title: Wireless Application Protocol and the mobile web before the web
3url: wap-mobile-web-before-the-web.html 3permalink: /wap-mobile-web-before-the-web.html
4date: 2021-12-30T12:00:00+02:00 4date: 2021-12-30T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
@@ -32,7 +33,7 @@ These phones were rocking:
32 33
33Let's take a look at these beauties. 34Let's take a look at these beauties.
34 35
35![Old phones](/posts/wap/phones.gif) 36![Old phones](/assets/posts/wap/phones.gif)
36 37
37## WAP - Wireless Application Protocol 38## WAP - Wireless Application Protocol
38 39
@@ -184,7 +185,7 @@ emulator. And it was really hard to find one. I found [WAP
184Proof](http://wap-proof.sharewarejunction.com/) on shareware junction, and it 185Proof](http://wap-proof.sharewarejunction.com/) on shareware junction, and it
185did the job well enough. I will try to find and actual device to test it on. 186did the job well enough. I will try to find and actual device to test it on.
186 187
187<video src="/posts/wap/emulator.mp4" controls></video> 188<video src="/assets/posts/wap/emulator.mp4" controls></video>
188 189
189If you are using Nginx to serve the contents, add a directive to the hosts file 190If you are using Nginx to serve the contents, add a directive to the hosts file
190that will automatically server `index.wml` file. 191that will automatically server `index.wml` file.
diff --git a/content/posts/2022-06-30-trying-out-helix-editor.md b/_posts/2022-06-30-trying-out-helix-editor.md
index dc4cfed..c6ebd6f 100644
--- a/content/posts/2022-06-30-trying-out-helix-editor.md
+++ b/_posts/2022-06-30-trying-out-helix-editor.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Trying out Helix code editor as my main editor 2title: Trying out Helix code editor as my main editor
3url: tying-out-helix-code-editor.html 3permalink: /tying-out-helix-code-editor.html
4date: 2022-06-30T12:00:00+02:00 4date: 2022-06-30T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
@@ -47,7 +48,7 @@ popups that show you what the keyboard shortcuts are.
47And it comes us packed with many 48And it comes us packed with many
48[really good themes](https://github.com/helix-editor/helix/wiki/Themes). 49[really good themes](https://github.com/helix-editor/helix/wiki/Themes).
49 50
50![Editor](/posts/helix-editor/editor.png) 51![Editor](/assets/posts/helix-editor/editor.png)
51 52
52It's still young but has this mature feeling to it. It has sane defaults and 53It's still young but has this mature feeling to it. It has sane defaults and
53mimics Vim (works a bit differently, but the overall idea is similar). 54mimics Vim (works a bit differently, but the overall idea is similar).
diff --git a/content/posts/2022-07-05-what-would-dna-sound-if-synthesized.md b/_posts/2022-07-05-what-would-dna-sound-if-synthesized.md
index 136b9f4..7aaac68 100644
--- a/content/posts/2022-07-05-what-would-dna-sound-if-synthesized.md
+++ b/_posts/2022-07-05-what-would-dna-sound-if-synthesized.md
@@ -1,7 +1,8 @@
1--- 1---
2title: What would DNA sound if synthesized to an audio file 2title: What would DNA sound if synthesized to an audio file
3url: what-would-dna-sound-if-synthesized.html 3permalink: /what-would-dna-sound-if-synthesized.html
4date: 2022-07-05T12:00:00+02:00 4date: 2022-07-05T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
@@ -174,10 +175,10 @@ sox output.wav -n spectrogram -o spectrogram.png
174An example spectrogram of Ludwig van Beethoven Symphony No. 6 First movement. 175An example spectrogram of Ludwig van Beethoven Symphony No. 6 First movement.
175 176
176<audio controls> 177<audio controls>
177 <source src="/posts/dna-synthesized/symphony-no6-1st-movement.mp3" type="audio/mpeg"> 178 <source src="/assets/posts/dna-synthesized/symphony-no6-1st-movement.mp3" type="audio/mpeg">
178</audio> 179</audio>
179 180
180![Ludwig van Beethoven Symphony No. 6 First movement](/posts/dna-synthesized/symphony-no6-1st-movement.png) 181![Ludwig van Beethoven Symphony No. 6 First movement](/assets/posts/dna-synthesized/symphony-no6-1st-movement.png)
181 182
182The other option could also be in combination with 183The other option could also be in combination with
183[gnuplot](http://www.gnuplot.info/). This would require an intermediary step, 184[gnuplot](http://www.gnuplot.info/). This would require an intermediary step,
@@ -229,10 +230,10 @@ spectrogram based on a WAV file.
229### Niels Bohr quote 230### Niels Bohr quote
230 231
231<audio controls> 232<audio controls>
232 <source src="/posts/dna-synthesized/quote/out.mp3" type="audio/mpeg"> 233 <source src="/assets/posts/dna-synthesized/quote/out.mp3" type="audio/mpeg">
233</audio> 234</audio>
234 235
235![Spectogram](/posts/dna-synthesized/quote/spectogram.png) 236![Spectogram](/assets/posts/dna-synthesized/quote/spectogram.png)
236 237
237### Mouse 238### Mouse
238 239
@@ -241,10 +242,10 @@ can get [genom data
241here](http://ftp.ensembl.org/pub/release-106/fasta/mus_musculus/dna/). 242here](http://ftp.ensembl.org/pub/release-106/fasta/mus_musculus/dna/).
242 243
243<audio controls> 244<audio controls>
244 <source src="/posts/dna-synthesized/mouse/out.mp3" type="audio/mpeg"> 245 <source src="/assets/posts/dna-synthesized/mouse/out.mp3" type="audio/mpeg">
245</audio> 246</audio>
246 247
247![Spectogram](/posts/dna-synthesized/mouse/spectogram.png) 248![Spectogram](/assets/posts/dna-synthesized/mouse/spectogram.png)
248 249
249### Bison 250### Bison
250 251
@@ -253,10 +254,10 @@ get [genom data
253here](http://ftp.ensembl.org/pub/release-106/fasta/bison_bison_bison/cdna/). 254here](http://ftp.ensembl.org/pub/release-106/fasta/bison_bison_bison/cdna/).
254 255
255<audio controls> 256<audio controls>
256 <source src="/posts/dna-synthesized/bison/out.mp3" type="audio/mpeg"> 257 <source src="/assets/posts/dna-synthesized/bison/out.mp3" type="audio/mpeg">
257</audio> 258</audio>
258 259
259![Spectogram](/posts/dna-synthesized/bison/spectogram.png) 260![Spectogram](/assets/posts/dna-synthesized/bison/spectogram.png)
260 261
261### Taurus 262### Taurus
262 263
@@ -265,10 +266,10 @@ This is part of a taurus genome `Bos_taurus.ARS-UCD1.2.cdna`. You can get
265here](http://ftp.ensembl.org/pub/release-106/fasta/bos_taurus/cdna/). 266here](http://ftp.ensembl.org/pub/release-106/fasta/bos_taurus/cdna/).
266 267
267<audio controls> 268<audio controls>
268 <source src="/posts/dna-synthesized/taurus/out.mp3" type="audio/mpeg"> 269 <source src="/assets/posts/dna-synthesized/taurus/out.mp3" type="audio/mpeg">
269</audio> 270</audio>
270 271
271![Spectogram](/posts/dna-synthesized/taurus/spectogram.png) 272![Spectogram](/assets/posts/dna-synthesized/taurus/spectogram.png)
272 273
273## Making a drummer out of a DNA sequence 274## Making a drummer out of a DNA sequence
274 275
@@ -281,11 +282,11 @@ Elektron is connected to my MacBook via USB cable and audio out is patched to a
281Sony Bluetooth speaker I have that supports 3.5 mm audio in. Elektron doesn't 282Sony Bluetooth speaker I have that supports 3.5 mm audio in. Elektron doesn't
282have internal speakers. 283have internal speakers.
283 284
284![](/posts/dna-synthesized/elektron/IMG_0619.jpg) 285![](/assets/posts/dna-synthesized/elektron/IMG_0619.jpg)
285 286
286![](/posts/dna-synthesized/elektron/IMG_0620.jpg) 287![](/assets/posts/dna-synthesized/elektron/IMG_0620.jpg)
287 288
288![](/posts/dna-synthesized/elektron/IMG_0622.jpg) 289![](/assets/posts/dna-synthesized/elektron/IMG_0622.jpg)
289 290
290For communicating with Elektron, I choose `pygame` Python module that has MIDI 291For communicating with Elektron, I choose `pygame` Python module that has MIDI
291built in. With this, it was rather simple to send notes to the device. All I did 292built in. With this, it was rather simple to send notes to the device. All I did
@@ -294,7 +295,7 @@ was map MIDI notes to the actual Nucleotides.
294Before all of this I also checked Audio MIDI Setup app under MacOS and checked 295Before all of this I also checked Audio MIDI Setup app under MacOS and checked
295MIDI Studio by pressing ⌘-2. 296MIDI Studio by pressing ⌘-2.
296 297
297![](/posts/dna-synthesized/elektron/midi-studio.jpg) 298![](/assets/posts/dna-synthesized/elektron/midi-studio.jpg)
298 299
299The whole script that parses and send notes to the Elektron looks like this. 300The whole script that parses and send notes to the Elektron looks like this.
300 301
@@ -336,7 +337,7 @@ del player
336pygame.midi.quit() 337pygame.midi.quit()
337``` 338```
338 339
339<video src="/posts/dna-synthesized/elektron/elektron.mp4" controls></video> 340<video src="/assets/posts/dna-synthesized/elektron/elektron.mp4" controls></video>
340 341
341All of this could be made much more interesting if I choose different 342All of this could be made much more interesting if I choose different
342instruments for different Nucleotides, or doing more funky stuff with Elektron. 343instruments for different Nucleotides, or doing more funky stuff with Elektron.
diff --git a/content/posts/2022-08-13-algae-spotted-on-river-sava.md b/_posts/2022-08-13-algae-spotted-on-river-sava.md
index 34d891e..2777416 100644
--- a/content/posts/2022-08-13-algae-spotted-on-river-sava.md
+++ b/_posts/2022-08-13-algae-spotted-on-river-sava.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Aerial photography of algae spotted on river Sava 2title: Aerial photography of algae spotted on river Sava
3url: aerial-photography-of-algae-spotted-on-river-sava.html 3permalink: /aerial-photography-of-algae-spotted-on-river-sava.html
4date: 2022-08-13T12:00:00+02:00 4date: 2022-08-13T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
@@ -14,17 +15,17 @@ This is the first time I've seen something like this in my whole life.
14 15
15Below are some photographs taken from a DJI drone capturing the event. 16Below are some photographs taken from a DJI drone capturing the event.
16 17
17![Algae on Sava](/posts/algae-sava/dji-algae-0.jpg) 18![Algae on Sava](/assets/posts/algae-sava/dji-algae-0.jpg)
18 19
19![Algae on Sava](/posts/algae-sava/dji-algae-1.jpg) 20![Algae on Sava](/assets/posts/algae-sava/dji-algae-1.jpg)
20 21
21![Algae on Sava](/posts/algae-sava/dji-algae-2.jpg) 22![Algae on Sava](/assets/posts/algae-sava/dji-algae-2.jpg)
22 23
23![Algae on Sava](/posts/algae-sava/dji-algae-3.jpg) 24![Algae on Sava](/assets/posts/algae-sava/dji-algae-3.jpg)
24 25
25![Algae on Sava](/posts/algae-sava/dji-algae-4.jpg) 26![Algae on Sava](/assets/posts/algae-sava/dji-algae-4.jpg)
26 27
27![Algae on Sava](/posts/algae-sava/dji-algae-5.jpg) 28![Algae on Sava](/assets/posts/algae-sava/dji-algae-5.jpg)
28 29
29I will try to get more photos of this in the future days and if something 30I will try to get more photos of this in the future days and if something
30intriguing shows up will post it again on the blog. 31intriguing shows up will post it again on the blog.
diff --git a/content/posts/2022-10-06-state-of-web-technologies-in-year-2022.md b/_posts/2022-10-06-state-of-web-technologies-in-year-2022.md
index ab07a2d..e7c8d62 100644
--- a/content/posts/2022-10-06-state-of-web-technologies-in-year-2022.md
+++ b/_posts/2022-10-06-state-of-web-technologies-in-year-2022.md
@@ -1,7 +1,8 @@
1--- 1---
2title: State of Web Technologies and Web development in year 2022 2title: State of Web Technologies and Web development in year 2022
3url: state-of-web-technologies-and-web-development-in-year-2022.html 3permalink: /state-of-web-technologies-and-web-development-in-year-2022.html
4date: 2022-10-06T12:00:00+02:00 4date: 2022-10-06T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
diff --git a/content/posts/2022-10-16-that-sound-that-machine-makes-when-struggling.md b/_posts/2022-10-16-that-sound-that-machine-makes-when-struggling.md
index 7eb4029..7b019e9 100644
--- a/content/posts/2022-10-16-that-sound-that-machine-makes-when-struggling.md
+++ b/_posts/2022-10-16-that-sound-that-machine-makes-when-struggling.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Microsoundtrack — That sound that machine makes when struggling 2title: Microsoundtrack — That sound that machine makes when struggling
3url: that-sound-that-machine-makes-when-struggling.html 3permalink: /that-sound-that-machine-makes-when-struggling.html
4date: 2022-10-16T12:00:00+02:00 4date: 2022-10-16T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
@@ -62,5 +63,5 @@ procedure. You can feel your sanity breaking down.
62I also made this little cow animation. Go into full screen to see the effects in 63I also made this little cow animation. Go into full screen to see the effects in
63more details. 64more details.
64 65
65<video src="/posts/microsoundtrack/cow.m4v" controls loop></video> 66<video src="/assets/posts/microsoundtrack/cow.m4v" controls loop></video>
66 67
diff --git a/content/posts/2023-01-26-trying-to-build-a-new-kind-of-terminal-emulator.md b/_posts/2023-01-26-trying-to-build-a-new-kind-of-terminal-emulator.md
index 27e227a..ced58bb 100644
--- a/content/posts/2023-01-26-trying-to-build-a-new-kind-of-terminal-emulator.md
+++ b/_posts/2023-01-26-trying-to-build-a-new-kind-of-terminal-emulator.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Trying to build a New kind of terminal emulator for the modern age 2title: Trying to build a New kind of terminal emulator for the modern age
3url: trying-to-build-a-new-kind-of-terminal-emulator.html 3permalink: /trying-to-build-a-new-kind-of-terminal-emulator.html
4date: 2023-01-26T12:00:00+02:00 4date: 2023-01-26T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
diff --git a/content/notes/2023-05-01-cachebusting-in-hugo.md b/_posts/2023-05-01-cachebusting-in-hugo.md
index b889d6b..f8d92b2 100644
--- a/content/notes/2023-05-01-cachebusting-in-hugo.md
+++ b/_posts/2023-05-01-cachebusting-in-hugo.md
@@ -1,16 +1,17 @@
1--- 1---
2title: Cache busting in Hugo 2title: Cache busting in Hugo
3url: cachebusting-in-hugo.html 3permalink: /cachebusting-in-hugo.html
4date: 2023-05-01T12:00:00+02:00 4date: 2023-05-01T12:00:00+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7tags: [hugo] 8tags: [hugo]
8--- 9---
9 10
10```html 11```html
11{{ $cachebuster := delimit (shuffle (split (md5 "6fab11c6669976d759d2992eff1dd5be") "" )) "" }} 12\{\{ $cachebuster := delimit (shuffle (split (md5 "6fab11c6669976d759d2992eff1dd5be") "" )) "" \}\}
12 13
13<link rel="stylesheet" href="/style.css?v={{ $cachebuster }}"> 14<link rel="stylesheet" href="/style.css?v=\{\{ $cachebuster \}\}">
14``` 15```
15 16
16This `6fab11c6669976d759d2992eff1dd5be` can be random string you generate use. 17This `6fab11c6669976d759d2992eff1dd5be` can be random string you generate use.
diff --git a/content/notes/2023-05-05-run-9front-in-qemu.md b/_posts/2023-05-05-run-9front-in-qemu.md
index b4f3de4..853b2c1 100644
--- a/content/notes/2023-05-05-run-9front-in-qemu.md
+++ b/_posts/2023-05-05-run-9front-in-qemu.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Run 9front in Qemu 2title: Run 9front in Qemu
3url: run-9front-in-qemu.html 3permalink: /run-9front-in-qemu.html
4date: 2023-05-05T12:00:00+02:00 4date: 2023-05-05T12:00:00+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7tags: [plan9, qemu] 8tags: [plan9, qemu]
diff --git a/content/notes/2023-05-06-git-push-multiple-origins.md b/_posts/2023-05-06-git-push-multiple-origins.md
index 2e96a00..ce7e64b 100644
--- a/content/notes/2023-05-06-git-push-multiple-origins.md
+++ b/_posts/2023-05-06-git-push-multiple-origins.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Push to multiple origins at once in Git 2title: Push to multiple origins at once in Git
3url: git-push-multiple-origins.html 3permalink: /git-push-multiple-origins.html
4date: 2023-05-06T12:00:00+02:00 4date: 2023-05-06T12:00:00+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7tags: [git] 8tags: [git]
diff --git a/content/notes/2023-05-07-mount-plan9-over-network.md b/_posts/2023-05-07-mount-plan9-over-network.md
index bb83202..ad68e80 100644
--- a/content/notes/2023-05-07-mount-plan9-over-network.md
+++ b/_posts/2023-05-07-mount-plan9-over-network.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Mount Plan9 over network 2title: Mount Plan9 over network
3url: mount-plan9-over-network.html 3permalink: /mount-plan9-over-network.html
4date: 2023-05-07T12:00:00+02:00 4date: 2023-05-07T12:00:00+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7tags: [plan9] 8tags: [plan9]
diff --git a/content/notes/2023-05-08-write-iso-usb.md b/_posts/2023-05-08-write-iso-usb.md
index 03b2c11..9c0e9fb 100644
--- a/content/notes/2023-05-08-write-iso-usb.md
+++ b/_posts/2023-05-08-write-iso-usb.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Write ISO to USB Key 2title: Write ISO to USB Key
3url: write-iso-usb.html 3permalink: /write-iso-usb.html
4date: 2023-05-08T12:00:00+02:00 4date: 2023-05-08T12:00:00+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7tags: [linux] 8tags: [linux]
diff --git a/content/notes/2023-05-09-catv-weechat-config.md b/_posts/2023-05-09-catv-weechat-config.md
index b730492..78d0907 100644
--- a/content/notes/2023-05-09-catv-weechat-config.md
+++ b/_posts/2023-05-09-catv-weechat-config.md
@@ -1,7 +1,8 @@
1--- 1---
2title: "#cat-v on weechat configuration" 2title: "#cat-v on weechat configuration"
3url: catv-weechat-config.html 3permalink: /catv-weechat-config.html
4date: 2023-05-09T12:00:00+02:00 4date: 2023-05-09T12:00:00+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7tags: [irc] 8tags: [irc]
diff --git a/content/notes/2023-05-10-plan9-screenshot.md b/_posts/2023-05-10-plan9-screenshot.md
index b3ffae3..5aa11bf 100644
--- a/content/notes/2023-05-10-plan9-screenshot.md
+++ b/_posts/2023-05-10-plan9-screenshot.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Take a screenshot in Plan9 2title: Take a screenshot in Plan9
3url: plan9-screenshot.html 3permalink: /plan9-screenshot.html
4date: 2023-05-10T12:00:00+02:00 4date: 2023-05-10T12:00:00+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7tags: [plan9] 8tags: [plan9]
diff --git a/content/notes/2023-05-11-fix-plan9-bootloader.md b/_posts/2023-05-11-fix-plan9-bootloader.md
index b70d42d..de030c9 100644
--- a/content/notes/2023-05-11-fix-plan9-bootloader.md
+++ b/_posts/2023-05-11-fix-plan9-bootloader.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Fix bootloader not being written in Plan9 2title: Fix bootloader not being written in Plan9
3url: fix-plan9-bootloader.html 3permalink: /fix-plan9-bootloader.html
4date: 2023-05-11T12:00:00+02:00 4date: 2023-05-11T12:00:00+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7tags: [plan9] 8tags: [plan9]
diff --git a/content/notes/2023-05-12-install-plan9port-linux.md b/_posts/2023-05-12-install-plan9port-linux.md
index 49a1e4c..c1cce46 100644
--- a/content/notes/2023-05-12-install-plan9port-linux.md
+++ b/_posts/2023-05-12-install-plan9port-linux.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Install Plan9port on Linux 2title: Install Plan9port on Linux
3url: install-plan9port-linux.html 3permalink: /install-plan9port-linux.html
4date: 2023-05-12T12:00:00+02:00 4date: 2023-05-12T12:00:00+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7tags: [plan9] 8tags: [plan9]
diff --git a/content/notes/2023-05-13-download-youtube-videos.md b/_posts/2023-05-13-download-youtube-videos.md
index 33fff05..9ed8221 100644
--- a/content/notes/2023-05-13-download-youtube-videos.md
+++ b/_posts/2023-05-13-download-youtube-videos.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Download list of YouTube files 2title: Download list of YouTube files
3url: download-youtube-videos.html 3permalink: /download-youtube-videos.html
4date: 2023-05-13T12:00:00+02:00 4date: 2023-05-13T12:00:00+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7tags: [youtube] 8tags: [youtube]
diff --git a/content/notes/2023-05-14-convert-mkv.md b/_posts/2023-05-14-convert-mkv.md
index 2219eed..7cc6189 100644
--- a/content/notes/2023-05-14-convert-mkv.md
+++ b/_posts/2023-05-14-convert-mkv.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Convert all MKV files into other formats 2title: Convert all MKV files into other formats
3url: convert-mkv.html 3permalink: /convert-mkv.html
4date: 2023-05-14T12:00:00+02:00 4date: 2023-05-14T12:00:00+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7tags: [ffmpeg] 8tags: [ffmpeg]
diff --git a/content/notes/2023-05-15-preview-troff-man-pages.md b/_posts/2023-05-15-preview-troff-man-pages.md
index 330ce51..2f0ca82 100644
--- a/content/notes/2023-05-15-preview-troff-man-pages.md
+++ b/_posts/2023-05-15-preview-troff-man-pages.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Previews how man page written in Troff will look like 2title: Previews how man page written in Troff will look like
3url: preview-troff-man-pages.html 3permalink: /preview-troff-man-pages.html
4date: 2023-05-15T12:00:00+02:00 4date: 2023-05-15T12:00:00+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7tags: [troff] 8tags: [troff]
diff --git a/content/notes/2023-05-16-mass-set-permission.md b/_posts/2023-05-16-mass-set-permission.md
index 4891ba8..654d9d1 100644
--- a/content/notes/2023-05-16-mass-set-permission.md
+++ b/_posts/2023-05-16-mass-set-permission.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Change permissions of matching files recursively 2title: Change permissions of matching files recursively
3url: mass-set-permission.html 3permalink: /mass-set-permission.html
4date: 2023-05-16T12:00:00+02:00 4date: 2023-05-16T12:00:00+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7tags: [linux] 8tags: [linux]
diff --git a/content/posts/2023-05-16-rekindling-my-love-for-programming.md b/_posts/2023-05-16-rekindling-my-love-for-programming.md
index 3c2267b..dc5344f 100644
--- a/content/posts/2023-05-16-rekindling-my-love-for-programming.md
+++ b/_posts/2023-05-16-rekindling-my-love-for-programming.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Rekindling my love for programming and enjoying the act of creating 2title: Rekindling my love for programming and enjoying the act of creating
3url: rekindling-my-love-for-programming.html 3permalink: /rekindling-my-love-for-programming.html
4date: 2023-05-16T12:00:00+02:00 4date: 2023-05-16T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
diff --git a/content/notes/2023-05-22-non-blocking-shell-exec-csharp.md b/_posts/2023-05-22-non-blocking-shell-exec-csharp.md
index ffad85c..f8b9c53 100644
--- a/content/notes/2023-05-22-non-blocking-shell-exec-csharp.md
+++ b/_posts/2023-05-22-non-blocking-shell-exec-csharp.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Execute not blocking async shell command in C# 2title: Execute not blocking async shell command in C#
3url: non-blocking-shell-exec-csharp.html 3permalink: /non-blocking-shell-exec-csharp.html
4date: 2023-05-22T12:00:00+02:00 4date: 2023-05-22T12:00:00+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7tags: [csharp] 8tags: [csharp]
diff --git a/content/notes/2023-05-23-extend-lua-with-custom-c.md b/_posts/2023-05-23-extend-lua-with-custom-c.md
index 554a6a4..604d359 100644
--- a/content/notes/2023-05-23-extend-lua-with-custom-c.md
+++ b/_posts/2023-05-23-extend-lua-with-custom-c.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Extend Lua with custom C functions using Clang 2title: Extend Lua with custom C functions using Clang
3url: extend-lua-with-custom-c.html 3permalink: /extend-lua-with-custom-c.html
4date: 2023-05-23T12:00:00+02:00 4date: 2023-05-23T12:00:00+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7tags: [lua, c] 8tags: [lua, c]
@@ -24,7 +25,7 @@ Makefile will need to be modified.
24 } 25 }
25 26
26 int luaopen_nativefunc(lua_State *L) { 27 int luaopen_nativefunc(lua_State *L) {
27 static const struct luaL_Reg nativeFuncLib[] = {{"mult50", l_mult50}, {NULL, NULL}}; 28 static const struct luaL_Reg nativeFuncLib[] = { {"mult50", l_mult50}, {NULL, NULL} };
28 29
29 luaL_register(L, "nativelib", nativeFuncLib); 30 luaL_register(L, "nativelib", nativeFuncLib);
30 return 1; 31 return 1;
diff --git a/content/posts/2023-05-23-i-was-wrong-about-git-workflows.md b/_posts/2023-05-23-i-was-wrong-about-git-workflows.md
index e82f50b..57d887c 100644
--- a/content/posts/2023-05-23-i-was-wrong-about-git-workflows.md
+++ b/_posts/2023-05-23-i-was-wrong-about-git-workflows.md
@@ -1,7 +1,8 @@
1--- 1---
2title: I think I was completely wrong about Git workflows 2title: I think I was completely wrong about Git workflows
3url: i-was-wrong-about-git-workflows.html 3permalink: /i-was-wrong-about-git-workflows.html
4date: 2023-05-23T12:00:00+02:00 4date: 2023-05-23T12:00:00+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7tags: [] 8tags: []
diff --git a/content/notes/2023-05-23-parse-rss-with-lua.md b/_posts/2023-05-23-parse-rss-with-lua.md
index ecd33d5..ea8ce8c 100644
--- a/content/notes/2023-05-23-parse-rss-with-lua.md
+++ b/_posts/2023-05-23-parse-rss-with-lua.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Parse RSS feeds with Lua 2title: Parse RSS feeds with Lua
3url: parse-rss-with-lua.html 3permalink: /parse-rss-with-lua.html
4date: 2023-05-23T12:00:00+02:00 4date: 2023-05-23T12:00:00+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7tags: [lua, rss] 8tags: [lua, rss]
diff --git a/content/notes/2023-05-24-fresh-9front-desktop.md b/_posts/2023-05-24-fresh-9front-desktop.md
index 21d8d93..bdad44a 100644
--- a/content/notes/2023-05-24-fresh-9front-desktop.md
+++ b/_posts/2023-05-24-fresh-9front-desktop.md
@@ -1,7 +1,8 @@
1--- 1---
2title: My brand new Plan9/9front desktop 2title: My brand new Plan9/9front desktop
3url: fresh-9front-desktop.html 3permalink: /fresh-9front-desktop.html
4date: 2023-05-24T12:00:00+02:00 4date: 2023-05-24T12:00:00+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7tags: [plan9] 8tags: [plan9]
@@ -10,5 +11,5 @@ tags: [plan9]
10I have been experimenting with Plan9/9front for a week now. Noice! This is how 11I have been experimenting with Plan9/9front for a week now. Noice! This is how
11my desktop looks like. 12my desktop looks like.
12 13
13![9front desktop](/notes/9front-desktop.png) 14![9front desktop](/assets/notes/9front-desktop.png)
14 15
diff --git a/content/notes/2023-05-25-dcss-new-player-guide.md b/_posts/2023-05-25-dcss-new-player-guide.md
index ff8493c..76242f3 100644
--- a/content/notes/2023-05-25-dcss-new-player-guide.md
+++ b/_posts/2023-05-25-dcss-new-player-guide.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Dungeon Crawl Stone Soup - New player guide 2title: Dungeon Crawl Stone Soup - New player guide
3url: dcss-new-player-guide.html 3permalink: /dcss-new-player-guide.html
4date: 2023-05-25T22:00:00+02:00 4date: 2023-05-25T22:00:00+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7tags: [dcss] 8tags: [dcss]
@@ -10,11 +11,11 @@ tags: [dcss]
10An amazing game deserves an amazing guide. All this material can be find in some 11An amazing game deserves an amazing guide. All this material can be find in some
11form on another on [craw's](https://github.com/crawl/crawl) official repository. 12form on another on [craw's](https://github.com/crawl/crawl) official repository.
12 13
13- [DCSS Quickstart](/notes/dcss-quickstart.pdf) - Very short introduction to the 14- [DCSS Quickstart](/assets/notes/dcss-quickstart.pdf) - Very short introduction to the
14 game 15 game
15- [DCSS Manual](/notes/dcss_manual.pdf) - Extensive manual about the game 16- [DCSS Manual](/assets/notes/dcss_manual.pdf) - Extensive manual about the game
16 17
17![Dungeon Crawl Stone Soup](/notes/dcss.jpg) 18![Dungeon Crawl Stone Soup](/assets/notes/dcss.jpg)
18 19
19**Movement and Exploration** 20**Movement and Exploration**
20 21
diff --git a/content/notes/2023-05-25-show-xterm-colors.md b/_posts/2023-05-25-show-xterm-colors.md
index 1e6d526..00a3e76 100644
--- a/content/notes/2023-05-25-show-xterm-colors.md
+++ b/_posts/2023-05-25-show-xterm-colors.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Display xterm color palette 2title: Display xterm color palette
3url: xterm-color-palette.html 3permalink: /xterm-color-palette.html
4date: 2023-05-25T12:00:00+02:00 4date: 2023-05-25T12:00:00+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7tags: [linux] 8tags: [linux]
@@ -10,7 +11,7 @@ tags: [linux]
10- `bash xterm-palette.sh` - will show you number of max colors available 11- `bash xterm-palette.sh` - will show you number of max colors available
11- `bash xterm-palette.sh -v` - will create a list of all colors with codes 12- `bash xterm-palette.sh -v` - will create a list of all colors with codes
12 13
13![xterm color palette](/notes/xterm-palette.png) 14![xterm color palette](/assets/notes/xterm-palette.png)
14 15
15```sh 16```sh
16#!/usr/bin/env bash 17#!/usr/bin/env bash
diff --git a/content/notes/2023-05-25-tmux-sane-defaults.md b/_posts/2023-05-25-tmux-sane-defaults.md
index e21b62b..3d0f304 100644
--- a/content/notes/2023-05-25-tmux-sane-defaults.md
+++ b/_posts/2023-05-25-tmux-sane-defaults.md
@@ -1,7 +1,8 @@
1--- 1---
2title: Sane defaults for tmux with more visible statusbar 2title: Sane defaults for tmux with more visible statusbar
3url: tmux-sane-defaults.html 3permalink: /tmux-sane-defaults.html
4date: 2023-05-25T12:00:00+02:00 4date: 2023-05-25T12:00:00+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7tags: [tmux] 8tags: [tmux]
diff --git a/content/notes/2023-05-27-cronjobs-github-with-actions.md b/_posts/2023-05-27-cronjobs-github-with-actions.md
index b28e4a9..3fd2fdc 100644
--- a/content/notes/2023-05-27-cronjobs-github-with-actions.md
+++ b/_posts/2023-05-27-cronjobs-github-with-actions.md
@@ -1,7 +1,8 @@
1--- 1---
2title: "Cronjobs on Github with Github Actions" 2title: "Cronjobs on Github with Github Actions"
3url: cronjobs-github-with-actions.html 3permalink: /cronjobs-github-with-actions.html
4date: 2023-05-27T00:35:36+02:00 4date: 2023-05-27T00:35:36+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7tags: [github] 8tags: [github]
diff --git a/content/notes/2023-05-27-dcss-on-4k-displays.md b/_posts/2023-05-27-dcss-on-4k-displays.md
index 8dd7095..ba46099 100644
--- a/content/notes/2023-05-27-dcss-on-4k-displays.md
+++ b/_posts/2023-05-27-dcss-on-4k-displays.md
@@ -1,7 +1,8 @@
1--- 1---
2title: "Make DCSS playable on 4k displays" 2title: "Make DCSS playable on 4k displays"
3url: dcss-on-4k-display.html 3permalink: /dcss-on-4k-display.html
4date: 2023-05-27T19:35:11+02:00 4date: 2023-05-27T19:35:11+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7tags: [dcss] 8tags: [dcss]
diff --git a/content/notes/2023-05-27-drawing-pixels-in-plan9.md b/_posts/2023-05-27-drawing-pixels-in-plan9.md
index 473ccaf..c1e9335 100644
--- a/content/notes/2023-05-27-drawing-pixels-in-plan9.md
+++ b/_posts/2023-05-27-drawing-pixels-in-plan9.md
@@ -1,7 +1,8 @@
1--- 1---
2title: "Drawing Pixels in Plan9" 2title: "Drawing Pixels in Plan9"
3url: drawing-pixels-in-plan9.html 3permalink: /drawing-pixels-in-plan9.html
4date: 2023-05-27T17:41:33+02:00 4date: 2023-05-27T17:41:33+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7tags: [plan9, graphics] 8tags: [plan9, graphics]
@@ -21,7 +22,7 @@ More information:
21- [all man pages](https://9fans.github.io/plan9port/man/man3/) 22- [all man pages](https://9fans.github.io/plan9port/man/man3/)
22 can be a valuable resource for learning about the system 23 can be a valuable resource for learning about the system
23 24
24![Plan9 Howdy World!](/notes/plan9-pixels.png) 25![Plan9 Howdy World!](/assets/notes/plan9-pixels.png)
25 26
26```c 27```c
27// main.c 28// main.c
diff --git a/content/notes/2023-05-28-easy-time-took-in-bash.md b/_posts/2023-05-28-easy-time-took-in-bash.md
index 999434a..958da72 100644
--- a/content/notes/2023-05-28-easy-time-took-in-bash.md
+++ b/_posts/2023-05-28-easy-time-took-in-bash.md
@@ -1,7 +1,8 @@
1--- 1---
2title: "Easy measure time took in a bash script" 2title: "Easy measure time took in a bash script"
3url: easy-time-took-in-bash.html 3permalink: /easy-time-took-in-bash.html
4date: 2023-05-28T17:53:20+02:00 4date: 2023-05-28T17:53:20+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7tags: [bash] 8tags: [bash]
diff --git a/content/notes/2023-05-29-grep-to-less-maintain-colors.md b/_posts/2023-05-29-grep-to-less-maintain-colors.md
index 6fc40a1..49baa01 100644
--- a/content/notes/2023-05-29-grep-to-less-maintain-colors.md
+++ b/_posts/2023-05-29-grep-to-less-maintain-colors.md
@@ -1,7 +1,8 @@
1--- 1---
2title: "Grep to Less that maintain colors" 2title: "Grep to Less that maintain colors"
3url: grep-to-less-maintain-colors.html 3permalink: /grep-to-less-maintain-colors.html
4date: 2023-05-29T21:27:07+02:00 4date: 2023-05-29T21:27:07+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7tags: [bash] 8tags: [bash]
@@ -22,4 +23,4 @@ string.
22grep --color=always -rni "TODO:" | less -R 23grep --color=always -rni "TODO:" | less -R
23``` 24```
24 25
25![Less and grep](/notes/grep-less.png) 26![Less and grep](/assets/notes/grep-less.png)
diff --git a/content/notes/2023-05-31-extending-dte-editor.md b/_posts/2023-05-31-extending-dte-editor.md
index a82ab1b..e9f02a4 100644
--- a/content/notes/2023-05-31-extending-dte-editor.md
+++ b/_posts/2023-05-31-extending-dte-editor.md
@@ -1,7 +1,8 @@
1--- 1---
2title: "Extending dte editor" 2title: "Extending dte editor"
3url: extending-dte-editor.html 3permalink: /extending-dte-editor.html
4date: 2023-05-31T08:12:45+02:00 4date: 2023-05-31T08:12:45+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7tags: [dte] 8tags: [dte]
diff --git a/content/posts/2023-05-31-re-inventing-task-runner-that-i-actually-used-daily.md b/_posts/2023-05-31-re-inventing-task-runner-that-i-actually-used-daily.md
index fd44605..c595905 100644
--- a/content/posts/2023-05-31-re-inventing-task-runner-that-i-actually-used-daily.md
+++ b/_posts/2023-05-31-re-inventing-task-runner-that-i-actually-used-daily.md
@@ -1,7 +1,8 @@
1--- 1---
2title: "Re-Inventing Task Runner That I Actually Used Daily" 2title: "Re-Inventing Task Runner That I Actually Used Daily"
3url: re-inventing-task-runner-that-i-actually-used-daily.html 3permalink: /re-inventing-task-runner-that-i-actually-used-daily.html
4date: 2023-05-31T12:21:10+02:00 4date: 2023-05-31T12:21:10+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
diff --git a/content/notes/2023-06-01-ewd-manuscripts-ebook.md b/_posts/2023-06-01-ewd-manuscripts-ebook.md
index 1ce597e..a78526c 100644
--- a/content/notes/2023-06-01-ewd-manuscripts-ebook.md
+++ b/_posts/2023-06-01-ewd-manuscripts-ebook.md
@@ -1,7 +1,8 @@
1--- 1---
2title: "Edsger W. Dijkstra Manuscripts ebook" 2title: "Edsger W. Dijkstra Manuscripts ebook"
3url: ewd-manuscripts-ebook.html 3permalink: /ewd-manuscripts-ebook.html
4date: 2023-06-01T22:47:56+02:00 4date: 2023-06-01T22:47:56+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7tags: [random] 8tags: [random]
diff --git a/content/notes/2023-06-04-bulk-make-thumbnails.md b/_posts/2023-06-04-bulk-make-thumbnails.md
index 4bab661..0a502a9 100644
--- a/content/notes/2023-06-04-bulk-make-thumbnails.md
+++ b/_posts/2023-06-04-bulk-make-thumbnails.md
@@ -1,7 +1,8 @@
1--- 1---
2title: "Bulk thumbnails" 2title: "Bulk thumbnails"
3url: bulk-make-thumbnails.html 3permalink: /bulk-make-thumbnails.html
4date: 2023-06-04T20:46:56+02:00 4date: 2023-06-04T20:46:56+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7tags: [bash] 8tags: [bash]
diff --git a/content/notes/2023-06-21-presentations-with-markdown.md b/_posts/2023-06-21-presentations-with-markdown.md
index 49ea53e..9c4fa22 100644
--- a/content/notes/2023-06-21-presentations-with-markdown.md
+++ b/_posts/2023-06-21-presentations-with-markdown.md
@@ -1,7 +1,8 @@
1--- 1---
2title: "Simple presentations with Markdown" 2title: "Simple presentations with Markdown"
3url: presentations-with-markdown.html 3permalink: /presentations-with-markdown.html
4date: 2023-06-21T08:54:48+02:00 4date: 2023-06-21T08:54:48+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7tags: [random] 8tags: [random]
diff --git a/content/notes/2023-06-24-making-cgit-look-nicer.md b/_posts/2023-06-24-making-cgit-look-nicer.md
index 6eb18fa..0140a3e 100644
--- a/content/notes/2023-06-24-making-cgit-look-nicer.md
+++ b/_posts/2023-06-24-making-cgit-look-nicer.md
@@ -1,7 +1,8 @@
1--- 1---
2title: "Making cgit look nicer" 2title: "Making cgit look nicer"
3url: making-cgit-look-nicer.html 3permalink: /making-cgit-look-nicer.html
4date: 2023-06-24T13:33:58+02:00 4date: 2023-06-24T13:33:58+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7tags: [git] 8tags: [git]
diff --git a/content/notes/2023-06-25-alacritty-open-links-with-modifier.md b/_posts/2023-06-25-alacritty-open-links-with-modifier.md
index eb73c4c..a26dd14 100644
--- a/content/notes/2023-06-25-alacritty-open-links-with-modifier.md
+++ b/_posts/2023-06-25-alacritty-open-links-with-modifier.md
@@ -1,7 +1,8 @@
1--- 1---
2title: "Alacritty open links with modifier" 2title: "Alacritty open links with modifier"
3url: alacritty-open-links-with-modifier.html 3permalink: /alacritty-open-links-with-modifier.html
4date: 2023-06-25T17:17:16+02:00 4date: 2023-06-25T17:17:16+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7tags: [linux] 8tags: [linux]
diff --git a/content/notes/2023-06-25-development-environments-with-nix.md b/_posts/2023-06-25-development-environments-with-nix.md
index 6bae302..ddac7e0 100644
--- a/content/notes/2023-06-25-development-environments-with-nix.md
+++ b/_posts/2023-06-25-development-environments-with-nix.md
@@ -1,7 +1,8 @@
1--- 1---
2title: "Development environments with Nix" 2title: "Development environments with Nix"
3url: development-environments-with-nix.html 3permalink: /development-environments-with-nix.html
4date: 2023-06-25T16:38:10+02:00 4date: 2023-06-25T16:38:10+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7tags: [random] 8tags: [random]
@@ -58,7 +59,7 @@ export PS1="[\033[38;5;9m\]\u@\h\[$(tput sgr0)\]]$(is_inside_nix_shell)\[\033[33
58And this is what it looks like when you are in a Nix shell. Otherwise that part 59And this is what it looks like when you are in a Nix shell. Otherwise that part
59of prompt is omitted 60of prompt is omitted
60 61
61![PS1 Prompt](/notes/ps1-prompt.png) 62![PS1 Prompt](/assets/notes/ps1-prompt.png)
62 63
63More resources: 64More resources:
64 65
diff --git a/content/notes/2023-06-29-10gui-10-finger-multitouch-user-interface.md b/_posts/2023-06-29-10gui-10-finger-multitouch-user-interface.md
index 751d1dc..d4b8e54 100644
--- a/content/notes/2023-06-29-10gui-10-finger-multitouch-user-interface.md
+++ b/_posts/2023-06-29-10gui-10-finger-multitouch-user-interface.md
@@ -1,7 +1,8 @@
1--- 1---
2title: "10/GUI 10 Finger Multitouch User Interface" 2title: "10/GUI 10 Finger Multitouch User Interface"
3url: 10gui-10-finger-multitouch-user-interface.html 3permalink: /10gui-10-finger-multitouch-user-interface.html
4date: 2023-06-29T14:51:39+02:00 4date: 2023-06-29T14:51:39+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7tags: [graphics] 8tags: [graphics]
@@ -20,6 +21,6 @@ interaction, but have yet to find a truly viable implementation.*
20in an intuitive and powerful way.* 21in an intuitive and powerful way.*
21 22
22<video 23<video
23 poster="/notes/10gui-10-finger-multitouch-user-interface.jpg" 24 poster="/assets/notes/10gui-10-finger-multitouch-user-interface.jpg"
24 src="/notes/10gui-10-finger-multitouch-user-interface.mp4" 25 src="/assets/notes/10gui-10-finger-multitouch-user-interface.mp4"
25 controls></video> 26 controls></video>
diff --git a/content/notes/2023-06-29-60s-ibm-computers-commercial.md b/_posts/2023-06-29-60s-ibm-computers-commercial.md
index c97d747..bddca2a 100644
--- a/content/notes/2023-06-29-60s-ibm-computers-commercial.md
+++ b/_posts/2023-06-29-60s-ibm-computers-commercial.md
@@ -1,7 +1,8 @@
1--- 1---
2title: "60's IBM Computers Commercial" 2title: "60's IBM Computers Commercial"
3url: 60s-ibm-computers-commercial.html 3permalink: /60s-ibm-computers-commercial.html
4date: 2023-06-29T22:13:45+02:00 4date: 2023-06-29T22:13:45+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7tags: [random] 8tags: [random]
@@ -12,6 +13,6 @@ as this typically aired during hour-long programs. They would *not* have aired
12during a half-hour program. 13during a half-hour program.
13 14
14<video 15<video
15 poster="/notes/60s-ibm-computers-commercial.jpg" 16 poster="/assets/notes/60s-ibm-computers-commercial.jpg"
16 src="/notes/60s-ibm-computers-commercial.mp4" 17 src="/assets/notes/60s-ibm-computers-commercial.mp4"
17 controls></video> 18 controls></video>
diff --git a/content/posts/2023-07-01-bringing-all-of-my-projects-together-under-one-umbrella.md b/_posts/2023-07-01-bringing-all-of-my-projects-together-under-one-umbrella.md
index 9059b00..4bc45ce 100644
--- a/content/posts/2023-07-01-bringing-all-of-my-projects-together-under-one-umbrella.md
+++ b/_posts/2023-07-01-bringing-all-of-my-projects-together-under-one-umbrella.md
@@ -1,7 +1,8 @@
1--- 1---
2title: "Bringing all of my projects together under one umbrella" 2title: "Bringing all of my projects together under one umbrella"
3url: bringing-all-of-my-projects-together-under-one-umbrella.html 3permalink: /bringing-all-of-my-projects-together-under-one-umbrella.html
4date: 2023-07-01T18:49:07+02:00 4date: 2023-07-01T18:49:07+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
diff --git a/content/posts/2023-07-08-who-knows-what-the-world-will-look-like-tomorrow.md b/_posts/2023-07-08-who-knows-what-the-world-will-look-like-tomorrow.md
index 4743694..c7d52d5 100644
--- a/content/posts/2023-07-08-who-knows-what-the-world-will-look-like-tomorrow.md
+++ b/_posts/2023-07-08-who-knows-what-the-world-will-look-like-tomorrow.md
@@ -1,7 +1,8 @@
1--- 1---
2title: "Who knows what the world will look like tomorrow" 2title: "Who knows what the world will look like tomorrow"
3url: who-knows-what-the-world-will-look-like-tomorrow.html 3permalink: /who-knows-what-the-world-will-look-like-tomorrow.html
4date: 2023-07-08T18:49:07+02:00 4date: 2023-07-08T18:49:07+02:00
5layout: post
5type: post 6type: post
6draft: false 7draft: false
7--- 8---
diff --git a/content/posts/2023-07-10-fix-screen-tearing-on-debian-12-xorg-and-i3.md b/_posts/2023-07-10-fix-screen-tearing-on-debian-12-xorg-and-i3.md
index c7e12ae..fa88d99 100644
--- a/content/posts/2023-07-10-fix-screen-tearing-on-debian-12-xorg-and-i3.md
+++ b/_posts/2023-07-10-fix-screen-tearing-on-debian-12-xorg-and-i3.md
@@ -1,7 +1,8 @@
1--- 1---
2title: "Fix screen tearing on Debian 12 Xorg and i3" 2title: "Fix screen tearing on Debian 12 Xorg and i3"
3url: fix-screen-tearing-on-debian-12-xorg-and-i3.html 3permalink: /fix-screen-tearing-on-debian-12-xorg-and-i3.html
4date: 2023-07-10T04:21:48+02:00 4date: 2023-07-10T04:21:48+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7--- 8---
diff --git a/content/posts/2023-07-10-online-radio-streaming-with-mpv-from-terminal.md b/_posts/2023-07-10-online-radio-streaming-with-mpv-from-terminal.md
index 821a80f..60daca8 100644
--- a/content/posts/2023-07-10-online-radio-streaming-with-mpv-from-terminal.md
+++ b/_posts/2023-07-10-online-radio-streaming-with-mpv-from-terminal.md
@@ -1,7 +1,8 @@
1--- 1---
2title: "Online radio streaming with MPV from terminal" 2title: "Online radio streaming with MPV from terminal"
3url: online-radio-streaming-with-mpv-from-terminal.html 3permalink: /online-radio-streaming-with-mpv-from-terminal.html
4date: 2023-07-10T03:34:45+02:00 4date: 2023-07-10T03:34:45+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7--- 8---
diff --git a/content/notes/2023-07-14-set-color-temperature-of-displays-on-i3.md b/_posts/2023-07-14-set-color-temperature-of-displays-on-i3.md
index e213a42..4618581 100644
--- a/content/notes/2023-07-14-set-color-temperature-of-displays-on-i3.md
+++ b/_posts/2023-07-14-set-color-temperature-of-displays-on-i3.md
@@ -1,7 +1,8 @@
1--- 1---
2title: "Set color temperature of displays on i3" 2title: "Set color temperature of displays on i3"
3url: set-color-temperature-of-displays-on-i3.html 3permalink: /set-color-temperature-of-displays-on-i3.html
4date: 2023-07-14T09:19:31+02:00 4date: 2023-07-14T09:19:31+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7--- 8---
diff --git a/content/notes/2023-08-01-make-b-w-svg-charts-with-matplotlib.md b/_posts/2023-08-01-make-b-w-svg-charts-with-matplotlib.md
index 51e85ec..6e1fa14 100644
--- a/content/notes/2023-08-01-make-b-w-svg-charts-with-matplotlib.md
+++ b/_posts/2023-08-01-make-b-w-svg-charts-with-matplotlib.md
@@ -1,7 +1,8 @@
1--- 1---
2title: "Make B/W SVG charts with matplotlib" 2title: "Make B/W SVG charts with matplotlib"
3url: make-b-w-svg-charts-with-matplotlib.html 3permalink: /make-b-w-svg-charts-with-matplotlib.html
4date: 2023-08-01T17:04:10+02:00 4date: 2023-08-01T17:04:10+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7--- 8---
@@ -65,6 +66,6 @@ legend.get_frame().set_linewidth(0)
65plt.savefig("plot.svg", format="svg") 66plt.savefig("plot.svg", format="svg")
66``` 67```
67 68
68![SVG Chart](/notes/plot.svg) 69![SVG Chart](/assets/notes/plot.svg)
69 70
70The image above is SVG and you can zoom in and out and check that the image is vector. 71The image above is SVG and you can zoom in and out and check that the image is vector.
diff --git a/_posts/2023-08-05-floods-in-slovenia.md b/_posts/2023-08-05-floods-in-slovenia.md
new file mode 100644
index 0000000..5a42781
--- /dev/null
+++ b/_posts/2023-08-05-floods-in-slovenia.md
@@ -0,0 +1,20 @@
1---
2title: "Floods in Slovenia up close"
3permalink: /floods-in-slovenia.html
4date: 2023-08-05T07:06:50+02:00
5layout: post
6type: note
7draft: false
8---
9
10<video src="/assets/notes/floods/IMG_1471.mp4" controls></video>
11
12<video src="/assets/notes/floods/IMG_1474.mp4" controls></video>
13
14![](/assets/notes/floods/IMG_1469.webp)
15
16![](/assets/notes/floods/IMG_1470.webp)
17
18<video src="/assets/notes/floods/IMG_1461.mp4" controls></video>
19
20<video src="/assets/notes/floods/IMG_1466.mp4" controls></video>
diff --git a/content/notes/2023-09-18-aws-eb-pyyaml-fix.md b/_posts/2023-09-18-aws-eb-pyyaml-fix.md
index 77ae27d..b1dd0cd 100644
--- a/content/notes/2023-09-18-aws-eb-pyyaml-fix.md
+++ b/_posts/2023-09-18-aws-eb-pyyaml-fix.md
@@ -1,7 +1,8 @@
1--- 1---
2title: "AWS EB PyYAML fix" 2title: "AWS EB PyYAML fix"
3url: aws-eb-pyyaml-fix.html 3permalink: /aws-eb-pyyaml-fix.html
4date: 2023-09-18T07:27:29+02:00 4date: 2023-09-18T07:27:29+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7--- 8---
diff --git a/content/notes/2023-09-25-compile-drawterm-on-fedora-38.md b/_posts/2023-09-25-compile-drawterm-on-fedora-38.md
index ec7446b..57e1719 100644
--- a/content/notes/2023-09-25-compile-drawterm-on-fedora-38.md
+++ b/_posts/2023-09-25-compile-drawterm-on-fedora-38.md
@@ -1,7 +1,8 @@
1--- 1---
2title: "Compile drawterm on Fedora 38" 2title: "Compile drawterm on Fedora 38"
3url: compile-drawterm-on-fedora-38.html 3permalink: /compile-drawterm-on-fedora-38.html
4date: 2023-09-25T09:04:28+02:00 4date: 2023-09-25T09:04:28+02:00
5layout: post
5type: note 6type: note
6draft: false 7draft: false
7--- 8---
diff --git a/public/general/9front-cursor.png b/assets/general/9front-cursor.png
index 1448a32..1448a32 100644
--- a/public/general/9front-cursor.png
+++ b/assets/general/9front-cursor.png
Binary files differ
diff --git a/public/general/9logo.png b/assets/general/9logo.png
index b6a8f7c..b6a8f7c 100644
--- a/public/general/9logo.png
+++ b/assets/general/9logo.png
Binary files differ
diff --git a/public/general/alert-dark.svg b/assets/general/alert-dark.svg
index d453564..d453564 100755
--- a/public/general/alert-dark.svg
+++ b/assets/general/alert-dark.svg
diff --git a/public/general/alert-light.svg b/assets/general/alert-light.svg
index 86658ec..86658ec 100755
--- a/public/general/alert-light.svg
+++ b/assets/general/alert-light.svg
diff --git a/public/general/index.css b/assets/general/index.css
index d9014f7..d9014f7 100644
--- a/public/general/index.css
+++ b/assets/general/index.css
diff --git a/public/general/og-big.jpg b/assets/general/og-big.jpg
index da8273b..da8273b 100644
--- a/public/general/og-big.jpg
+++ b/assets/general/og-big.jpg
Binary files differ
diff --git a/public/general/og-big.xcf b/assets/general/og-big.xcf
index ae0b007..ae0b007 100644
--- a/public/general/og-big.xcf
+++ b/assets/general/og-big.xcf
Binary files differ
diff --git a/public/general/og.jpg b/assets/general/og.jpg
index 132f62d..132f62d 100644
--- a/public/general/og.jpg
+++ b/assets/general/og.jpg
Binary files differ
diff --git a/public/general/og.xcf b/assets/general/og.xcf
index 0572715..0572715 100644
--- a/public/general/og.xcf
+++ b/assets/general/og.xcf
Binary files differ
diff --git a/public/mitjafelicijan.pgp.pub.txt b/assets/mitjafelicijan.pgp.pub.txt
index ee10621..ee10621 100644
--- a/public/mitjafelicijan.pgp.pub.txt
+++ b/assets/mitjafelicijan.pgp.pub.txt
diff --git a/public/notes/10gui-10-finger-multitouch-user-interface.jpg b/assets/notes/10gui-10-finger-multitouch-user-interface.jpg
index 270b4ea..270b4ea 100644
--- a/public/notes/10gui-10-finger-multitouch-user-interface.jpg
+++ b/assets/notes/10gui-10-finger-multitouch-user-interface.jpg
Binary files differ
diff --git a/public/notes/10gui-10-finger-multitouch-user-interface.mp4 b/assets/notes/10gui-10-finger-multitouch-user-interface.mp4
index 8afdbf8..8afdbf8 100644
--- a/public/notes/10gui-10-finger-multitouch-user-interface.mp4
+++ b/assets/notes/10gui-10-finger-multitouch-user-interface.mp4
Binary files differ
diff --git a/public/notes/60s-ibm-computers-commercial.jpg b/assets/notes/60s-ibm-computers-commercial.jpg
index 1d49e93..1d49e93 100644
--- a/public/notes/60s-ibm-computers-commercial.jpg
+++ b/assets/notes/60s-ibm-computers-commercial.jpg
Binary files differ
diff --git a/public/notes/60s-ibm-computers-commercial.mp4 b/assets/notes/60s-ibm-computers-commercial.mp4
index 9ff1567..9ff1567 100644
--- a/public/notes/60s-ibm-computers-commercial.mp4
+++ b/assets/notes/60s-ibm-computers-commercial.mp4
Binary files differ
diff --git a/public/notes/9front-desktop.png b/assets/notes/9front-desktop.png
index 3a0964b..3a0964b 100644
--- a/public/notes/9front-desktop.png
+++ b/assets/notes/9front-desktop.png
Binary files differ
diff --git a/public/notes/dcss-quickstart.pdf b/assets/notes/dcss-quickstart.pdf
index 1b70615..1b70615 100644
--- a/public/notes/dcss-quickstart.pdf
+++ b/assets/notes/dcss-quickstart.pdf
Binary files differ
diff --git a/public/notes/dcss.jpg b/assets/notes/dcss.jpg
index ffe7c6a..ffe7c6a 100644
--- a/public/notes/dcss.jpg
+++ b/assets/notes/dcss.jpg
Binary files differ
diff --git a/public/notes/dcss_manual.pdf b/assets/notes/dcss_manual.pdf
index 03cafd2..03cafd2 100644
--- a/public/notes/dcss_manual.pdf
+++ b/assets/notes/dcss_manual.pdf
Binary files differ
diff --git a/public/notes/floods/IMG_1461.mp4 b/assets/notes/floods/IMG_1461.mp4
index 6b7f325..6b7f325 100755
--- a/public/notes/floods/IMG_1461.mp4
+++ b/assets/notes/floods/IMG_1461.mp4
Binary files differ
diff --git a/public/notes/floods/IMG_1466.mp4 b/assets/notes/floods/IMG_1466.mp4
index f15cdb9..f15cdb9 100755
--- a/public/notes/floods/IMG_1466.mp4
+++ b/assets/notes/floods/IMG_1466.mp4
Binary files differ
diff --git a/public/notes/floods/IMG_1469.webp b/assets/notes/floods/IMG_1469.webp
index b668039..b668039 100755
--- a/public/notes/floods/IMG_1469.webp
+++ b/assets/notes/floods/IMG_1469.webp
Binary files differ
diff --git a/public/notes/floods/IMG_1470.webp b/assets/notes/floods/IMG_1470.webp
index 74496ba..74496ba 100755
--- a/public/notes/floods/IMG_1470.webp
+++ b/assets/notes/floods/IMG_1470.webp
Binary files differ
diff --git a/public/notes/floods/IMG_1471.mp4 b/assets/notes/floods/IMG_1471.mp4
index ac7f8b5..ac7f8b5 100755
--- a/public/notes/floods/IMG_1471.mp4
+++ b/assets/notes/floods/IMG_1471.mp4
Binary files differ
diff --git a/public/notes/floods/IMG_1474.mp4 b/assets/notes/floods/IMG_1474.mp4
index e1018d0..e1018d0 100755
--- a/public/notes/floods/IMG_1474.mp4
+++ b/assets/notes/floods/IMG_1474.mp4
Binary files differ
diff --git a/public/notes/grep-less.png b/assets/notes/grep-less.png
index f69a935..f69a935 100644
--- a/public/notes/grep-less.png
+++ b/assets/notes/grep-less.png
Binary files differ
diff --git a/public/notes/plan9-pixels.png b/assets/notes/plan9-pixels.png
index 536dd82..536dd82 100644
--- a/public/notes/plan9-pixels.png
+++ b/assets/notes/plan9-pixels.png
Binary files differ
diff --git a/public/notes/plot.svg b/assets/notes/plot.svg
index f7cc7a4..f7cc7a4 100644
--- a/public/notes/plot.svg
+++ b/assets/notes/plot.svg
diff --git a/public/notes/ps1-prompt.png b/assets/notes/ps1-prompt.png
index e27c714..e27c714 100644
--- a/public/notes/ps1-prompt.png
+++ b/assets/notes/ps1-prompt.png
Binary files differ
diff --git a/public/notes/xterm-palette.png b/assets/notes/xterm-palette.png
index e286c5e..e286c5e 100644
--- a/public/notes/xterm-palette.png
+++ b/assets/notes/xterm-palette.png
Binary files differ
diff --git a/public/posts/algae-sava/dji-algae-0.jpg b/assets/posts/algae-sava/dji-algae-0.jpg
index d444c80..d444c80 100755
--- a/public/posts/algae-sava/dji-algae-0.jpg
+++ b/assets/posts/algae-sava/dji-algae-0.jpg
Binary files differ
diff --git a/public/posts/algae-sava/dji-algae-1.jpg b/assets/posts/algae-sava/dji-algae-1.jpg
index 26ee43c..26ee43c 100755
--- a/public/posts/algae-sava/dji-algae-1.jpg
+++ b/assets/posts/algae-sava/dji-algae-1.jpg
Binary files differ
diff --git a/public/posts/algae-sava/dji-algae-2.jpg b/assets/posts/algae-sava/dji-algae-2.jpg
index d38f8cd..d38f8cd 100755
--- a/public/posts/algae-sava/dji-algae-2.jpg
+++ b/assets/posts/algae-sava/dji-algae-2.jpg
Binary files differ
diff --git a/public/posts/algae-sava/dji-algae-3.jpg b/assets/posts/algae-sava/dji-algae-3.jpg
index 9706fa0..9706fa0 100755
--- a/public/posts/algae-sava/dji-algae-3.jpg
+++ b/assets/posts/algae-sava/dji-algae-3.jpg
Binary files differ
diff --git a/public/posts/algae-sava/dji-algae-4.jpg b/assets/posts/algae-sava/dji-algae-4.jpg
index b0db4a2..b0db4a2 100755
--- a/public/posts/algae-sava/dji-algae-4.jpg
+++ b/assets/posts/algae-sava/dji-algae-4.jpg
Binary files differ
diff --git a/public/posts/algae-sava/dji-algae-5.jpg b/assets/posts/algae-sava/dji-algae-5.jpg
index f3c1b3b..f3c1b3b 100755
--- a/public/posts/algae-sava/dji-algae-5.jpg
+++ b/assets/posts/algae-sava/dji-algae-5.jpg
Binary files differ
diff --git a/public/posts/cv/avatar.gif b/assets/posts/cv/avatar.gif
index 82e5f39..82e5f39 100755
--- a/public/posts/cv/avatar.gif
+++ b/assets/posts/cv/avatar.gif
Binary files differ
diff --git a/public/posts/dfd-rice/desktop.png b/assets/posts/dfd-rice/desktop.png
index 8dcfd51..8dcfd51 100755
--- a/public/posts/dfd-rice/desktop.png
+++ b/assets/posts/dfd-rice/desktop.png
Binary files differ
diff --git a/public/posts/dfd-rice/install-00.png b/assets/posts/dfd-rice/install-00.png
index 2660f90..2660f90 100755
--- a/public/posts/dfd-rice/install-00.png
+++ b/assets/posts/dfd-rice/install-00.png
Binary files differ
diff --git a/public/posts/dfd-rice/install-01.png b/assets/posts/dfd-rice/install-01.png
index 1281be1..1281be1 100755
--- a/public/posts/dfd-rice/install-01.png
+++ b/assets/posts/dfd-rice/install-01.png
Binary files differ
diff --git a/public/posts/dfd-rice/install-02.png b/assets/posts/dfd-rice/install-02.png
index 9cac5e3..9cac5e3 100755
--- a/public/posts/dfd-rice/install-02.png
+++ b/assets/posts/dfd-rice/install-02.png
Binary files differ
diff --git a/public/posts/dfd-rice/install-03.png b/assets/posts/dfd-rice/install-03.png
index dc7cbd1..dc7cbd1 100755
--- a/public/posts/dfd-rice/install-03.png
+++ b/assets/posts/dfd-rice/install-03.png
Binary files differ
diff --git a/public/posts/dfd-rice/install-04.png b/assets/posts/dfd-rice/install-04.png
index 675a78f..675a78f 100755
--- a/public/posts/dfd-rice/install-04.png
+++ b/assets/posts/dfd-rice/install-04.png
Binary files differ
diff --git a/public/posts/dfd-rice/install-05.png b/assets/posts/dfd-rice/install-05.png
index 8b580b9..8b580b9 100755
--- a/public/posts/dfd-rice/install-05.png
+++ b/assets/posts/dfd-rice/install-05.png
Binary files differ
diff --git a/public/posts/dfd-rice/installation.svg b/assets/posts/dfd-rice/installation.svg
index bb9560b..bb9560b 100755
--- a/public/posts/dfd-rice/installation.svg
+++ b/assets/posts/dfd-rice/installation.svg
diff --git a/public/posts/dfd-rice/layout.png b/assets/posts/dfd-rice/layout.png
index a44d2cd..a44d2cd 100755
--- a/public/posts/dfd-rice/layout.png
+++ b/assets/posts/dfd-rice/layout.png
Binary files differ
diff --git a/public/posts/dfd-rice/layout.svg b/assets/posts/dfd-rice/layout.svg
index 5a9031c..5a9031c 100755
--- a/public/posts/dfd-rice/layout.svg
+++ b/assets/posts/dfd-rice/layout.svg
diff --git a/public/posts/dfd-rice/script.png b/assets/posts/dfd-rice/script.png
index 09be37a..09be37a 100755
--- a/public/posts/dfd-rice/script.png
+++ b/assets/posts/dfd-rice/script.png
Binary files differ
diff --git a/public/posts/dna-sequence/benchmarks.csv b/assets/posts/dna-sequence/benchmarks.csv
index 8645d5e..8645d5e 100644
--- a/public/posts/dna-sequence/benchmarks.csv
+++ b/assets/posts/dna-sequence/benchmarks.csv
diff --git a/public/posts/dna-sequence/chart-size.py b/assets/posts/dna-sequence/chart-size.py
index 4fc408d..4fc408d 100644
--- a/public/posts/dna-sequence/chart-size.py
+++ b/assets/posts/dna-sequence/chart-size.py
diff --git a/public/posts/dna-sequence/chart-size.svg b/assets/posts/dna-sequence/chart-size.svg
index 1a2d127..1a2d127 100644
--- a/public/posts/dna-sequence/chart-size.svg
+++ b/assets/posts/dna-sequence/chart-size.svg
diff --git a/public/posts/dna-sequence/chart-speed.py b/assets/posts/dna-sequence/chart-speed.py
index c07b057..c07b057 100644
--- a/public/posts/dna-sequence/chart-speed.py
+++ b/assets/posts/dna-sequence/chart-speed.py
diff --git a/public/posts/dna-sequence/chart-speed.svg b/assets/posts/dna-sequence/chart-speed.svg
index 7bb0c29..7bb0c29 100644
--- a/public/posts/dna-sequence/chart-speed.svg
+++ b/assets/posts/dna-sequence/chart-speed.svg
diff --git a/public/posts/dna-sequence/dna-basics.jpg b/assets/posts/dna-sequence/dna-basics.jpg
index c2e7f52..c2e7f52 100755
--- a/public/posts/dna-sequence/dna-basics.jpg
+++ b/assets/posts/dna-sequence/dna-basics.jpg
Binary files differ
diff --git a/public/posts/dna-sequence/quote.png b/assets/posts/dna-sequence/quote.png
index 09fb01c..09fb01c 100755
--- a/public/posts/dna-sequence/quote.png
+++ b/assets/posts/dna-sequence/quote.png
Binary files differ
diff --git a/public/posts/dna-sequence/sample-binary-file.png b/assets/posts/dna-sequence/sample-binary-file.png
index 1e4622a..1e4622a 100755
--- a/public/posts/dna-sequence/sample-binary-file.png
+++ b/assets/posts/dna-sequence/sample-binary-file.png
Binary files differ
diff --git a/public/posts/dna-sequence/sample.png b/assets/posts/dna-sequence/sample.png
index 30f12da..30f12da 100755
--- a/public/posts/dna-sequence/sample.png
+++ b/assets/posts/dna-sequence/sample.png
Binary files differ
diff --git a/public/posts/dna-synthesized/bison/in.txt b/assets/posts/dna-synthesized/bison/in.txt
index fd1eea6..fd1eea6 100755
--- a/public/posts/dna-synthesized/bison/in.txt
+++ b/assets/posts/dna-synthesized/bison/in.txt
diff --git a/public/posts/dna-synthesized/bison/out.mp3 b/assets/posts/dna-synthesized/bison/out.mp3
index d6408ca..d6408ca 100755
--- a/public/posts/dna-synthesized/bison/out.mp3
+++ b/assets/posts/dna-synthesized/bison/out.mp3
Binary files differ
diff --git a/public/posts/dna-synthesized/bison/spectogram.png b/assets/posts/dna-synthesized/bison/spectogram.png
index 959902b..959902b 100755
--- a/public/posts/dna-synthesized/bison/spectogram.png
+++ b/assets/posts/dna-synthesized/bison/spectogram.png
Binary files differ
diff --git a/public/posts/dna-synthesized/elektron/IMG_0619.jpg b/assets/posts/dna-synthesized/elektron/IMG_0619.jpg
index ebf60b0..ebf60b0 100755
--- a/public/posts/dna-synthesized/elektron/IMG_0619.jpg
+++ b/assets/posts/dna-synthesized/elektron/IMG_0619.jpg
Binary files differ
diff --git a/public/posts/dna-synthesized/elektron/IMG_0620.jpg b/assets/posts/dna-synthesized/elektron/IMG_0620.jpg
index c9aa398..c9aa398 100755
--- a/public/posts/dna-synthesized/elektron/IMG_0620.jpg
+++ b/assets/posts/dna-synthesized/elektron/IMG_0620.jpg
Binary files differ
diff --git a/public/posts/dna-synthesized/elektron/IMG_0622.jpg b/assets/posts/dna-synthesized/elektron/IMG_0622.jpg
index 98acee4..98acee4 100755
--- a/public/posts/dna-synthesized/elektron/IMG_0622.jpg
+++ b/assets/posts/dna-synthesized/elektron/IMG_0622.jpg
Binary files differ
diff --git a/public/posts/dna-synthesized/elektron/elektron.mp4 b/assets/posts/dna-synthesized/elektron/elektron.mp4
index f8e39b9..f8e39b9 100755
--- a/public/posts/dna-synthesized/elektron/elektron.mp4
+++ b/assets/posts/dna-synthesized/elektron/elektron.mp4
Binary files differ
diff --git a/public/posts/dna-synthesized/elektron/midi-studio.jpg b/assets/posts/dna-synthesized/elektron/midi-studio.jpg
index 59075cd..59075cd 100755
--- a/public/posts/dna-synthesized/elektron/midi-studio.jpg
+++ b/assets/posts/dna-synthesized/elektron/midi-studio.jpg
Binary files differ
diff --git a/public/posts/dna-synthesized/mouse/in.txt b/assets/posts/dna-synthesized/mouse/in.txt
index abd34a2..abd34a2 100755
--- a/public/posts/dna-synthesized/mouse/in.txt
+++ b/assets/posts/dna-synthesized/mouse/in.txt
diff --git a/public/posts/dna-synthesized/mouse/out.mp3 b/assets/posts/dna-synthesized/mouse/out.mp3
index e66e87b..e66e87b 100755
--- a/public/posts/dna-synthesized/mouse/out.mp3
+++ b/assets/posts/dna-synthesized/mouse/out.mp3
Binary files differ
diff --git a/public/posts/dna-synthesized/mouse/spectogram.png b/assets/posts/dna-synthesized/mouse/spectogram.png
index 8b7f63f..8b7f63f 100755
--- a/public/posts/dna-synthesized/mouse/spectogram.png
+++ b/assets/posts/dna-synthesized/mouse/spectogram.png
Binary files differ
diff --git a/public/posts/dna-synthesized/quote/in.txt b/assets/posts/dna-synthesized/quote/in.txt
index 81e8eb9..81e8eb9 100755
--- a/public/posts/dna-synthesized/quote/in.txt
+++ b/assets/posts/dna-synthesized/quote/in.txt
diff --git a/public/posts/dna-synthesized/quote/out.mp3 b/assets/posts/dna-synthesized/quote/out.mp3
index 985871d..985871d 100755
--- a/public/posts/dna-synthesized/quote/out.mp3
+++ b/assets/posts/dna-synthesized/quote/out.mp3
Binary files differ
diff --git a/public/posts/dna-synthesized/quote/spectogram.png b/assets/posts/dna-synthesized/quote/spectogram.png
index c460ffd..c460ffd 100755
--- a/public/posts/dna-synthesized/quote/spectogram.png
+++ b/assets/posts/dna-synthesized/quote/spectogram.png
Binary files differ
diff --git a/public/posts/dna-synthesized/symphony-no6-1st-movement.mp3 b/assets/posts/dna-synthesized/symphony-no6-1st-movement.mp3
index 8c5a609..8c5a609 100755
--- a/public/posts/dna-synthesized/symphony-no6-1st-movement.mp3
+++ b/assets/posts/dna-synthesized/symphony-no6-1st-movement.mp3
Binary files differ
diff --git a/public/posts/dna-synthesized/symphony-no6-1st-movement.png b/assets/posts/dna-synthesized/symphony-no6-1st-movement.png
index 8269f08..8269f08 100755
--- a/public/posts/dna-synthesized/symphony-no6-1st-movement.png
+++ b/assets/posts/dna-synthesized/symphony-no6-1st-movement.png
Binary files differ
diff --git a/public/posts/dna-synthesized/taurus/in.txt b/assets/posts/dna-synthesized/taurus/in.txt
index 8c5bddb..8c5bddb 100755
--- a/public/posts/dna-synthesized/taurus/in.txt
+++ b/assets/posts/dna-synthesized/taurus/in.txt
diff --git a/public/posts/dna-synthesized/taurus/out.mp3 b/assets/posts/dna-synthesized/taurus/out.mp3
index ea7ae1a..ea7ae1a 100755
--- a/public/posts/dna-synthesized/taurus/out.mp3
+++ b/assets/posts/dna-synthesized/taurus/out.mp3
Binary files differ
diff --git a/public/posts/dna-synthesized/taurus/spectogram.png b/assets/posts/dna-synthesized/taurus/spectogram.png
index 3be9b58..3be9b58 100755
--- a/public/posts/dna-synthesized/taurus/spectogram.png
+++ b/assets/posts/dna-synthesized/taurus/spectogram.png
Binary files differ
diff --git a/public/posts/do-fuse/copy-benchmarks.tsv b/assets/posts/do-fuse/copy-benchmarks.tsv
index c7a7af4..c7a7af4 100755
--- a/public/posts/do-fuse/copy-benchmarks.tsv
+++ b/assets/posts/do-fuse/copy-benchmarks.tsv
diff --git a/public/posts/do-fuse/fuse-droplets.png b/assets/posts/do-fuse/fuse-droplets.png
index d7ce243..d7ce243 100755
--- a/public/posts/do-fuse/fuse-droplets.png
+++ b/assets/posts/do-fuse/fuse-droplets.png
Binary files differ
diff --git a/public/posts/do-fuse/fuse-spaces.png b/assets/posts/do-fuse/fuse-spaces.png
index 4dcc1c5..4dcc1c5 100755
--- a/public/posts/do-fuse/fuse-spaces.png
+++ b/assets/posts/do-fuse/fuse-spaces.png
Binary files differ
diff --git a/public/posts/do-fuse/sqlite-benchmarks.tsv b/assets/posts/do-fuse/sqlite-benchmarks.tsv
index daa2c21..daa2c21 100755
--- a/public/posts/do-fuse/sqlite-benchmarks.tsv
+++ b/assets/posts/do-fuse/sqlite-benchmarks.tsv
diff --git a/public/posts/dropbox-sync/dropbox-spaces.png b/assets/posts/dropbox-sync/dropbox-spaces.png
index c90f99f..c90f99f 100755
--- a/public/posts/dropbox-sync/dropbox-spaces.png
+++ b/assets/posts/dropbox-sync/dropbox-spaces.png
Binary files differ
diff --git a/public/posts/esp8366-micropython/boards.jpg b/assets/posts/esp8366-micropython/boards.jpg
index 89e2b30..89e2b30 100755
--- a/public/posts/esp8366-micropython/boards.jpg
+++ b/assets/posts/esp8366-micropython/boards.jpg
Binary files differ
diff --git a/public/posts/go-profiling/golang-profiling-cpu.pdf b/assets/posts/go-profiling/golang-profiling-cpu.pdf
index 15241cb..15241cb 100755
--- a/public/posts/go-profiling/golang-profiling-cpu.pdf
+++ b/assets/posts/go-profiling/golang-profiling-cpu.pdf
Binary files differ
diff --git a/public/posts/go-profiling/golang-profiling-mem.pdf b/assets/posts/go-profiling/golang-profiling-mem.pdf
index 822e445..822e445 100755
--- a/public/posts/go-profiling/golang-profiling-mem.pdf
+++ b/assets/posts/go-profiling/golang-profiling-mem.pdf
Binary files differ
diff --git a/public/posts/goaccess/goaccess-dash-html.png b/assets/posts/goaccess/goaccess-dash-html.png
index 917d959..917d959 100755
--- a/public/posts/goaccess/goaccess-dash-html.png
+++ b/assets/posts/goaccess/goaccess-dash-html.png
Binary files differ
diff --git a/public/posts/goaccess/goaccess-dash-term.png b/assets/posts/goaccess/goaccess-dash-term.png
index e3f6357..e3f6357 100755
--- a/public/posts/goaccess/goaccess-dash-term.png
+++ b/assets/posts/goaccess/goaccess-dash-term.png
Binary files differ
diff --git a/public/posts/godot-dynamic-tile-loading/2d-player-movement.webm b/assets/posts/godot-dynamic-tile-loading/2d-player-movement.webm
index 579f2f3..579f2f3 100644
--- a/public/posts/godot-dynamic-tile-loading/2d-player-movement.webm
+++ b/assets/posts/godot-dynamic-tile-loading/2d-player-movement.webm
Binary files differ
diff --git a/public/posts/godot-dynamic-tile-loading/cellular-automata.png b/assets/posts/godot-dynamic-tile-loading/cellular-automata.png
index 1b28242..1b28242 100644
--- a/public/posts/godot-dynamic-tile-loading/cellular-automata.png
+++ b/assets/posts/godot-dynamic-tile-loading/cellular-automata.png
Binary files differ
diff --git a/public/posts/godot-dynamic-tile-loading/example1/index.apple-touch-icon.png b/assets/posts/godot-dynamic-tile-loading/example1/index.apple-touch-icon.png
index 880ae2d..880ae2d 100644
--- a/public/posts/godot-dynamic-tile-loading/example1/index.apple-touch-icon.png
+++ b/assets/posts/godot-dynamic-tile-loading/example1/index.apple-touch-icon.png
Binary files differ
diff --git a/public/posts/godot-dynamic-tile-loading/example1/index.audio.worklet.js b/assets/posts/godot-dynamic-tile-loading/example1/index.audio.worklet.js
index ea4d8cb..ea4d8cb 100644
--- a/public/posts/godot-dynamic-tile-loading/example1/index.audio.worklet.js
+++ b/assets/posts/godot-dynamic-tile-loading/example1/index.audio.worklet.js
diff --git a/public/posts/godot-dynamic-tile-loading/example1/index.html b/assets/posts/godot-dynamic-tile-loading/example1/index.html
index e96af24..e96af24 100644
--- a/public/posts/godot-dynamic-tile-loading/example1/index.html
+++ b/assets/posts/godot-dynamic-tile-loading/example1/index.html
diff --git a/public/posts/godot-dynamic-tile-loading/example1/index.icon.png b/assets/posts/godot-dynamic-tile-loading/example1/index.icon.png
index c98fbb6..c98fbb6 100644
--- a/public/posts/godot-dynamic-tile-loading/example1/index.icon.png
+++ b/assets/posts/godot-dynamic-tile-loading/example1/index.icon.png
Binary files differ
diff --git a/public/posts/godot-dynamic-tile-loading/example1/index.js b/assets/posts/godot-dynamic-tile-loading/example1/index.js
index 1c18e52..1c18e52 100644
--- a/public/posts/godot-dynamic-tile-loading/example1/index.js
+++ b/assets/posts/godot-dynamic-tile-loading/example1/index.js
diff --git a/public/posts/godot-dynamic-tile-loading/example1/index.pck b/assets/posts/godot-dynamic-tile-loading/example1/index.pck
index 07ac55c..07ac55c 100644
--- a/public/posts/godot-dynamic-tile-loading/example1/index.pck
+++ b/assets/posts/godot-dynamic-tile-loading/example1/index.pck
Binary files differ
diff --git a/public/posts/godot-dynamic-tile-loading/example1/index.png b/assets/posts/godot-dynamic-tile-loading/example1/index.png
index 766b0b6..766b0b6 100644
--- a/public/posts/godot-dynamic-tile-loading/example1/index.png
+++ b/assets/posts/godot-dynamic-tile-loading/example1/index.png
Binary files differ
diff --git a/public/posts/godot-dynamic-tile-loading/example1/index.wasm b/assets/posts/godot-dynamic-tile-loading/example1/index.wasm
index 5151d56..5151d56 100644
--- a/public/posts/godot-dynamic-tile-loading/example1/index.wasm
+++ b/assets/posts/godot-dynamic-tile-loading/example1/index.wasm
Binary files differ
diff --git a/public/posts/godot-dynamic-tile-loading/village-creator.png b/assets/posts/godot-dynamic-tile-loading/village-creator.png
index bb5b468..bb5b468 100644
--- a/public/posts/godot-dynamic-tile-loading/village-creator.png
+++ b/assets/posts/godot-dynamic-tile-loading/village-creator.png
Binary files differ
diff --git a/public/posts/helix-editor/editor.png b/assets/posts/helix-editor/editor.png
index 2648364..2648364 100755
--- a/public/posts/helix-editor/editor.png
+++ b/assets/posts/helix-editor/editor.png
Binary files differ
diff --git a/public/posts/iot-application/iot-app-output.png b/assets/posts/iot-application/iot-app-output.png
index 1c80589..1c80589 100755
--- a/public/posts/iot-application/iot-app-output.png
+++ b/assets/posts/iot-application/iot-app-output.png
Binary files differ
diff --git a/public/posts/iot-application/iot-rest-example.png b/assets/posts/iot-application/iot-rest-example.png
index 3ed86aa..3ed86aa 100755
--- a/public/posts/iot-application/iot-rest-example.png
+++ b/assets/posts/iot-application/iot-rest-example.png
Binary files differ
diff --git a/public/posts/iot-application/iot-sqlite-db.png b/assets/posts/iot-application/iot-sqlite-db.png
index 82e1e29..82e1e29 100755
--- a/public/posts/iot-application/iot-sqlite-db.png
+++ b/assets/posts/iot-application/iot-sqlite-db.png
Binary files differ
diff --git a/public/posts/iot-application/kcachegrind.png b/assets/posts/iot-application/kcachegrind.png
index 0dc48ab..0dc48ab 100755
--- a/public/posts/iot-application/kcachegrind.png
+++ b/assets/posts/iot-application/kcachegrind.png
Binary files differ
diff --git a/public/posts/iot-application/profiling-viewer.png b/assets/posts/iot-application/profiling-viewer.png
index a450513..a450513 100755
--- a/public/posts/iot-application/profiling-viewer.png
+++ b/assets/posts/iot-application/profiling-viewer.png
Binary files differ
diff --git a/public/posts/iot-application/simple-iot-application-overview.svg b/assets/posts/iot-application/simple-iot-application-overview.svg
index 817666d..817666d 100755
--- a/public/posts/iot-application/simple-iot-application-overview.svg
+++ b/assets/posts/iot-application/simple-iot-application-overview.svg
diff --git a/public/posts/iot-application/simple-iot-application.zip b/assets/posts/iot-application/simple-iot-application.zip
index 46d3205..46d3205 100755
--- a/public/posts/iot-application/simple-iot-application.zip
+++ b/assets/posts/iot-application/simple-iot-application.zip
Binary files differ
diff --git a/public/posts/iot-application/snakeviz.png b/assets/posts/iot-application/snakeviz.png
index 5bab395..5bab395 100755
--- a/public/posts/iot-application/snakeviz.png
+++ b/assets/posts/iot-application/snakeviz.png
Binary files differ
diff --git a/public/posts/microsoundtrack/cow.m4v b/assets/posts/microsoundtrack/cow.m4v
index 1b2461b..1b2461b 100644
--- a/public/posts/microsoundtrack/cow.m4v
+++ b/assets/posts/microsoundtrack/cow.m4v
Binary files differ
diff --git a/public/posts/pid1/boxes.mp4 b/assets/posts/pid1/boxes.mp4
index eb647ff..eb647ff 100755
--- a/public/posts/pid1/boxes.mp4
+++ b/assets/posts/pid1/boxes.mp4
Binary files differ
diff --git a/public/posts/pid1/qemu.log b/assets/posts/pid1/qemu.log
index 11be312..11be312 100755
--- a/public/posts/pid1/qemu.log
+++ b/assets/posts/pid1/qemu.log
diff --git a/public/posts/pid1/unikernels.png b/assets/posts/pid1/unikernels.png
index 4396d02..4396d02 100644
--- a/public/posts/pid1/unikernels.png
+++ b/assets/posts/pid1/unikernels.png
Binary files differ
diff --git a/public/posts/pid1/unikernels.svg b/assets/posts/pid1/unikernels.svg
index 47ad8f0..47ad8f0 100755
--- a/public/posts/pid1/unikernels.svg
+++ b/assets/posts/pid1/unikernels.svg
diff --git a/public/posts/pid1/unikernels.webp b/assets/posts/pid1/unikernels.webp
index c823d00..c823d00 100644
--- a/public/posts/pid1/unikernels.webp
+++ b/assets/posts/pid1/unikernels.webp
Binary files differ
diff --git a/public/posts/profile-bind-error/error.jpg b/assets/posts/profile-bind-error/error.jpg
index c2e4e8f..c2e4e8f 100755
--- a/public/posts/profile-bind-error/error.jpg
+++ b/assets/posts/profile-bind-error/error.jpg
Binary files differ
diff --git a/public/posts/python-profiling/kcachegrind.png b/assets/posts/python-profiling/kcachegrind.png
index 0dc48ab..0dc48ab 100755
--- a/public/posts/python-profiling/kcachegrind.png
+++ b/assets/posts/python-profiling/kcachegrind.png
Binary files differ
diff --git a/public/posts/python-profiling/profiling-viewer.png b/assets/posts/python-profiling/profiling-viewer.png
index a450513..a450513 100755
--- a/public/posts/python-profiling/profiling-viewer.png
+++ b/assets/posts/python-profiling/profiling-viewer.png
Binary files differ
diff --git a/public/posts/python-profiling/snakeviz.png b/assets/posts/python-profiling/snakeviz.png
index 5bab395..5bab395 100755
--- a/public/posts/python-profiling/snakeviz.png
+++ b/assets/posts/python-profiling/snakeviz.png
Binary files differ
diff --git a/public/posts/sentiment-analysis/.ipynb_checkpoints/TF Test-checkpoint.ipynb b/assets/posts/sentiment-analysis/.ipynb_checkpoints/TF Test-checkpoint.ipynb
index e2a85c4..e2a85c4 100755
--- a/public/posts/sentiment-analysis/.ipynb_checkpoints/TF Test-checkpoint.ipynb
+++ b/assets/posts/sentiment-analysis/.ipynb_checkpoints/TF Test-checkpoint.ipynb
diff --git a/public/posts/sentiment-analysis/.ipynb_checkpoints/sentiment-analysis-checkpoint.ipynb b/assets/posts/sentiment-analysis/.ipynb_checkpoints/sentiment-analysis-checkpoint.ipynb
index 2c0934c..2c0934c 100755
--- a/public/posts/sentiment-analysis/.ipynb_checkpoints/sentiment-analysis-checkpoint.ipynb
+++ b/assets/posts/sentiment-analysis/.ipynb_checkpoints/sentiment-analysis-checkpoint.ipynb
diff --git a/public/posts/sentiment-analysis/guardian-sa-title-desc-relationship.png b/assets/posts/sentiment-analysis/guardian-sa-title-desc-relationship.png
index 7195bbf..7195bbf 100755
--- a/public/posts/sentiment-analysis/guardian-sa-title-desc-relationship.png
+++ b/assets/posts/sentiment-analysis/guardian-sa-title-desc-relationship.png
Binary files differ
diff --git a/public/posts/sentiment-analysis/sentiment-analysis.ipynb b/assets/posts/sentiment-analysis/sentiment-analysis.ipynb
index 2c0934c..2c0934c 100755
--- a/public/posts/sentiment-analysis/sentiment-analysis.ipynb
+++ b/assets/posts/sentiment-analysis/sentiment-analysis.ipynb
diff --git a/public/posts/simple-pubsub-server/caniuse.png b/assets/posts/simple-pubsub-server/caniuse.png
index 90f7883..90f7883 100755
--- a/public/posts/simple-pubsub-server/caniuse.png
+++ b/assets/posts/simple-pubsub-server/caniuse.png
Binary files differ
diff --git a/public/posts/simple-pubsub-server/chrome-debugging.png b/assets/posts/simple-pubsub-server/chrome-debugging.png
index 1bdc448..1bdc448 100755
--- a/public/posts/simple-pubsub-server/chrome-debugging.png
+++ b/assets/posts/simple-pubsub-server/chrome-debugging.png
Binary files differ
diff --git a/public/posts/simple-pubsub-server/clients.m4v b/assets/posts/simple-pubsub-server/clients.m4v
index 1342bc6..1342bc6 100755
--- a/public/posts/simple-pubsub-server/clients.m4v
+++ b/assets/posts/simple-pubsub-server/clients.m4v
Binary files differ
diff --git a/public/posts/simple-pubsub-server/pubsub-overview.png b/assets/posts/simple-pubsub-server/pubsub-overview.png
index 0279ec3..0279ec3 100755
--- a/public/posts/simple-pubsub-server/pubsub-overview.png
+++ b/assets/posts/simple-pubsub-server/pubsub-overview.png
Binary files differ
diff --git a/public/posts/simple-pubsub-server/sse-pubsub-server.zip b/assets/posts/simple-pubsub-server/sse-pubsub-server.zip
index 898b290..898b290 100755
--- a/public/posts/simple-pubsub-server/sse-pubsub-server.zip
+++ b/assets/posts/simple-pubsub-server/sse-pubsub-server.zip
Binary files differ
diff --git a/public/posts/state-of-web/2008-vs-2020.png b/assets/posts/state-of-web/2008-vs-2020.png
index 6cf94e5..6cf94e5 100755
--- a/public/posts/state-of-web/2008-vs-2020.png
+++ b/assets/posts/state-of-web/2008-vs-2020.png
Binary files differ
diff --git a/public/posts/state-of-web/compiling-vs-transpiling.png b/assets/posts/state-of-web/compiling-vs-transpiling.png
index afd5000..afd5000 100755
--- a/public/posts/state-of-web/compiling-vs-transpiling.png
+++ b/assets/posts/state-of-web/compiling-vs-transpiling.png
Binary files differ
diff --git a/public/posts/wap/emulator.mp4 b/assets/posts/wap/emulator.mp4
index e4f59aa..e4f59aa 100755
--- a/public/posts/wap/emulator.mp4
+++ b/assets/posts/wap/emulator.mp4
Binary files differ
diff --git a/public/posts/wap/phones.gif b/assets/posts/wap/phones.gif
index 15f99e2..15f99e2 100755
--- a/public/posts/wap/phones.gif
+++ b/assets/posts/wap/phones.gif
Binary files differ
diff --git a/public/posts/world-clock/enclosure.stl b/assets/posts/world-clock/enclosure.stl
index 99f3d1a..99f3d1a 100755
--- a/public/posts/world-clock/enclosure.stl
+++ b/assets/posts/world-clock/enclosure.stl
Binary files differ
diff --git a/public/posts/world-clock/hardware.jpg b/assets/posts/world-clock/hardware.jpg
index 315a04d..315a04d 100755
--- a/public/posts/world-clock/hardware.jpg
+++ b/assets/posts/world-clock/hardware.jpg
Binary files differ
diff --git a/public/posts/world-clock/world-clock.jpg b/assets/posts/world-clock/world-clock.jpg
index afdb6e2..afdb6e2 100755
--- a/public/posts/world-clock/world-clock.jpg
+++ b/assets/posts/world-clock/world-clock.jpg
Binary files differ
diff --git a/public/posts/yapyap/hello.png b/assets/posts/yapyap/hello.png
index d141cd3..d141cd3 100755
--- a/public/posts/yapyap/hello.png
+++ b/assets/posts/yapyap/hello.png
Binary files differ
diff --git a/public/posts/yapyap/pid1.jpg b/assets/posts/yapyap/pid1.jpg
index 99bc1d8..99bc1d8 100755
--- a/public/posts/yapyap/pid1.jpg
+++ b/assets/posts/yapyap/pid1.jpg
Binary files differ
diff --git a/public/posts/zed/zed-1.png b/assets/posts/zed/zed-1.png
index c4da2f6..c4da2f6 100755
--- a/public/posts/zed/zed-1.png
+++ b/assets/posts/zed/zed-1.png
Binary files differ
diff --git a/public/posts/zed/zed-2.png b/assets/posts/zed/zed-2.png
index 38ce72d..38ce72d 100755
--- a/public/posts/zed/zed-2.png
+++ b/assets/posts/zed/zed-2.png
Binary files differ
diff --git a/bin/webring.rb b/bin/webring.rb
new file mode 100644
index 0000000..86737be
--- /dev/null
+++ b/bin/webring.rb
@@ -0,0 +1,82 @@
1require "erb"
2require "htmlentities"
3require "open-uri"
4require "simple-rss"
5
6summary_max_length = 360
7
8feeds = [
9 "https://landley.net/rss.xml",
10 "https://drewdevault.com/feed.xml",
11 "https://offbeatpursuit.com/blog/index.rss",
12 "https://mirzapandzo.com/rss.xml",
13 "https://journal.valeriansaliou.name/rss/",
14 "https://neil.computer/rss/",
15 "https://michael.stapelberg.ch/feed.xml",
16 "https://utcc.utoronto.ca/~cks/space/blog/?atom",
17 "https://szymonkaliski.com/feed.xml"
18]
19
20out_html = ""
21decoder = HTMLEntities.new
22
23feeds.each do |feed_url|
24 begin
25 rss_content = URI.open(feed_url).read
26 rss = SimpleRSS.parse(rss_content)
27
28 first = rss.items.first
29 author = rss.channel.title
30 website = rss.channel.link
31 title = first.title
32 link = first.link
33
34 description = first.description
35 summary = description
36 content = first.content
37
38 if not summary
39 summary = content
40 end
41
42 summary.force_encoding("UTF-8")
43 summary = decoder.decode(summary)
44 .gsub(%r{</?[^>]+?>}, '')
45 .gsub(/\s{2,}/, ' ')
46 .gsub("\n", ' ')
47
48 if summary.length > summary_max_length
49 summary = "#{summary[0...summary_max_length]}..."
50 end
51
52 template = ERB.new <<-EOF
53 <li>
54 <a href="<%= link %>" target="_blank" rel="noopener"><%= title %></a>
55
56 <a href="<%= website %>" target="_blank" rel="noopener"><%= author %></a>
57 <div><%= summary %></div>
58 </li>
59 EOF
60
61 partial = template.result(binding)
62 out_html.concat(partial)
63
64 puts "Feed: #{author}"
65 puts "Title: #{title}"
66 puts "Link: #{link}"
67 puts "Summary: #{summary}"
68 puts
69 rescue OpenURI::HTTPError => e
70 puts "Failed to fetch #{url}: #{e.message}"
71 rescue SimpleRSSError => e
72 puts "Failed to parse #{url}: #{e.message}"
73 end
74end
75
76
77template = ERB.new <<-EOF
78 <h2>Posts from blogs I follow around the net</h2>
79 <ul><%= out_html %></ul>
80EOF
81out_html = template.result(binding)
82File.write("_includes/webring.html", out_html)
diff --git a/config.yaml b/config.yaml
deleted file mode 100644
index 16f8ffd..0000000
--- a/config.yaml
+++ /dev/null
@@ -1,24 +0,0 @@
1title: "Mitja Felicijan"
2baseurl: "https://mitjafelicijan.com"
3description: "You do not learn by relaxing. You learn by violently assaulting your problem until it surrenders its mysteries to you."
4language: "en-us"
5
6# Code highlighting.
7# https://swapoff.org/chroma/playground/
8# highlighting: "pygments"
9highlighting: "vs"
10
11# Minifies output HTML (including inline CSS, JS).
12minify: true
13
14extras:
15 - template: index.xml
16 url: index.xml
17 - template: notes.xml
18 url: notes.xml
19 - template: robots.txt
20 url: robots.txt
21 - template: sitemap.xml
22 url: sitemap.xml
23 - template: radio.pls
24 url: radio.pls
diff --git a/content/notes/2023-08-05-floods-in-slovenia.md b/content/notes/2023-08-05-floods-in-slovenia.md
deleted file mode 100644
index d0ebc18..0000000
--- a/content/notes/2023-08-05-floods-in-slovenia.md
+++ /dev/null
@@ -1,19 +0,0 @@
1---
2title: "Floods in Slovenia up close"
3url: floods-in-slovenia.html
4date: 2023-08-05T07:06:50+02:00
5type: note
6draft: false
7---
8
9<video src="/notes/floods/IMG_1471.mp4" controls></video>
10
11<video src="/notes/floods/IMG_1474.mp4" controls></video>
12
13![](/notes/floods/IMG_1469.webp)
14
15![](/notes/floods/IMG_1470.webp)
16
17<video src="/notes/floods/IMG_1461.mp4" controls></video>
18
19<video src="/notes/floods/IMG_1466.mp4" controls></video>
diff --git a/content/pages/vault.md b/content/pages/vault.md
deleted file mode 100644
index d25c9d2..0000000
--- a/content/pages/vault.md
+++ /dev/null
@@ -1,405 +0,0 @@
1---
2title: Personal vault
3date: 2022-08-27T12:00:00+02:00
4url: vault.html
5type: page
6draft: false
7---
8
9**Hi traveler!**
10
11This is a repository of interesting things I have gathered over time and it also
12stores binaries etc of my personal projects.
13
14Be kind, this server is bandwidth limited.
15
16*Good luck!*
17
18---
19
20- audiobooks
21 - [h-g-wells-the-time-machine.ogg](<https://mitjafelicijan.fra1.digitaloceanspaces.com/audiobooks/h-g-wells-the-time-machine.ogg>)
22 - [philip-francis-nowlan-armageddon-2419-a-d.mp3](<https://mitjafelicijan.fra1.digitaloceanspaces.com/audiobooks/philip-francis-nowlan-armageddon-2419-a-d.mp3>)
23 - [philip-francis-nowlan-the-airlords-of-han.mp3](<https://mitjafelicijan.fra1.digitaloceanspaces.com/audiobooks/philip-francis-nowlan-the-airlords-of-han.mp3>)
24- books
25 - [Civilized to Death.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/books/Civilized to Death.pdf>)
26 - [Common Sense.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/books/Common Sense.pdf>)
27 - [History of UNIX programs, sycalls, etc.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/books/History of UNIX programs, sycalls, etc.pdf>)
28 - [The Maiden Who Travels The Planet.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/books/The Maiden Who Travels The Planet.pdf>)
29 - [The UNIX-HATERS Handbook.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/books/The UNIX-HATERS Handbook.pdf>)
30- essays
31 - [Bumbleton.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/essays/Bumbleton.pdf>)
32 - [Bumbleton.tex](<https://mitjafelicijan.fra1.digitaloceanspaces.com/essays/Bumbleton.tex>)
33 - [Lorna the geologist.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/essays/Lorna the geologist.pdf>)
34 - [Lorna the geologist.tex](<https://mitjafelicijan.fra1.digitaloceanspaces.com/essays/Lorna the geologist.tex>)
35- haphazard
36 - [acme.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/acme.pdf>)
37 - [antfarm.jpg](<https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/antfarm.jpg>)
38 - [ape.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/ape.pdf>)
39 - [asciitable.txt](<https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/asciitable.txt>)
40 - [bakingonagrill.jpg](<https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/bakingonagrill.jpg>)
41 - [carules.png](<https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/carules.png>)
42 - [ccompiler.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/ccompiler.pdf>)
43 - [cellularintro.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/cellularintro.pdf>)
44 - [changeresolution.txt](<https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/changeresolution.txt>)
45 - [cord.h](<https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/cord.h>)
46 - [dunescrescent.mp4](<https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/dunescrescent.mp4>)
47 - [elisp.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/elisp.pdf>)
48 - [ewd-manuscripts.epub](<https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/ewd-manuscripts.epub>)
49 - [ewd-manuscripts.mobi](<https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/ewd-manuscripts.mobi>)
50 - [ewd831.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/ewd831.pdf>)
51 - [graphca.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/graphca.pdf>)
52 - [inspectorclay.jpg](<https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/inspectorclay.jpg>)
53 - [kaczynski2.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/kaczynski2.pdf>)
54 - [marionette.gif](<https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/marionette.gif>)
55 - [mk.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/mk.pdf>)
56 - [ncc-1701-a-engine-noise.ogg](<https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/ncc-1701-a-engine-noise.ogg>)
57 - [ownership-check-for-c.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/ownership-check-for-c.pdf>)
58 - [p9assembler.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/p9assembler.pdf>)
59 - [p9fileserver.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/p9fileserver.pdf>)
60 - [p9mkfiles.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/p9mkfiles.pdf>)
61 - [p9whub.go](<https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/p9whub.go>)
62 - [plan9.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/plan9.pdf>)
63 - [plantsystems.jpg](<https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/plantsystems.jpg>)
64 - [rcshell.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/rcshell.pdf>)
65 - [rule126.png](<https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/rule126.png>)
66 - [runonqemu.txt](<https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/runonqemu.txt>)
67 - [shred.go](<https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/shred.go>)
68 - [simulator.go](<https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/simulator.go>)
69 - [standard-ml.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/standard-ml.pdf>)
70 - [staticserver.txt](<https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/staticserver.txt>)
71- papers
72 - affective-computing
73 - [Theories-Methods-and-Current-Research-on-Emotions.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/affective-computing/Theories-Methods-and-Current-Research-on-Emotions.pdf>)
74 - [affective-computing.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/affective-computing/affective-computing.pdf>)
75 - api_design
76 - [api-design.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/api_design/api-design.pdf>)
77 - artificial-intelligence
78 - [3-bayesian-network-inference-algorithm.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/artificial-intelligence/3-bayesian-network-inference-algorithm.pdf>)
79 - [efficient-selectivity-and-backup-operators-in-monte-carlo-tree-search.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/artificial-intelligence/efficient-selectivity-and-backup-operators-in-monte-carlo-tree-search.pdf>)
80 - audio-comp-sci
81 - [an-ethnographic-and-technological-study-of-breakbeats.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/audio-comp-sci/an-ethnographic-and-technological-study-of-breakbeats.pdf>)
82 - [essentia.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/audio-comp-sci/essentia.pdf>)
83 - [marsyas.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/audio-comp-sci/marsyas.pdf>)
84 - [real-time-chord-detection.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/audio-comp-sci/real-time-chord-detection.pdf>)
85 - [shazam-audio-search-algorithm.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/audio-comp-sci/shazam-audio-search-algorithm.pdf>)
86 - caching
87 - [2q-a-low-overhead-high-performance-buffer-management-replacement-algorithm.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/caching/2q-a-low-overhead-high-performance-buffer-management-replacement-algorithm.pdf>)
88 - [a-constant-algorithm-for-implementing-the-lfu-cache-eviction-scheme.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/caching/a-constant-algorithm-for-implementing-the-lfu-cache-eviction-scheme.pdf>)
89 - [a-program-optimization-for-automatic-database-result-caching.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/caching/a-program-optimization-for-automatic-database-result-caching.pdf>)
90 - comp-sci-fundamentals-and-history
91 - [axiomatic-basis-computer-programming.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/comp-sci-fundamentals-and-history/axiomatic-basis-computer-programming.pdf>)
92 - [early-lisp-history-1956-1959-herbert-stoyan-html-rendering.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/comp-sci-fundamentals-and-history/early-lisp-history-1956-1959-herbert-stoyan-html-rendering.pdf>)
93 - [hints-for-computer-system-design.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/comp-sci-fundamentals-and-history/hints-for-computer-system-design.pdf>)
94 - [recursive-functions-of-symbolic-expressions-and-their-computation-by-machine-parti.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/comp-sci-fundamentals-and-history/recursive-functions-of-symbolic-expressions-and-their-computation-by-machine-parti.pdf>)
95 - [story-of-squeak-a-practical-smalltalk-written-in-itself.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/comp-sci-fundamentals-and-history/story-of-squeak-a-practical-smalltalk-written-in-itself.pdf>)
96 - computational-creativity
97 - [mexica-a-computer-model-of-a-cognitive-account-of-creativing-writing.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/computational-creativity/mexica-a-computer-model-of-a-cognitive-account-of-creativing-writing.pdf>)
98 - computer-education
99 - [framework-for-automated-generation-of-questions-across-formal-domains.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/computer-education/framework-for-automated-generation-of-questions-across-formal-domains.pdf>)
100 - computer-graphics
101 - [digital_video_stabilization_and_rolling_shutter_correction_using_gyroscopes.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/computer-graphics/digital_video_stabilization_and_rolling_shutter_correction_using_gyroscopes.pdf>)
102 - [imaging_vector_fields_using_line_integral_convolution.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/computer-graphics/imaging_vector_fields_using_line_integral_convolution.pdf>)
103 - [pushpull++.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/computer-graphics/pushpull++.pdf>)
104 - cryptography
105 - [communication-theory-of-secrecy-systems.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/cryptography/communication-theory-of-secrecy-systems.pdf>)
106 - [ntru-prime.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/cryptography/ntru-prime.pdf>)
107 - data-compression
108 - [Error-Controlled_Lossy_Compression_Optimized_for_High_Compression_Ratios_of_Scientific_Datasets.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/data-compression/Error-Controlled_Lossy_Compression_Optimized_for_High_Compression_Ratios_of_Scientific_Datasets.pdf>)
109 - [Significantly_Improving_Lossy_Compression_for_Scientific_Data_Sets_Based_on_Multidimensional_Prediction_and_Error-Controlled_Quantization.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/data-compression/Significantly_Improving_Lossy_Compression_for_Scientific_Data_Sets_Based_on_Multidimensional_Prediction_and_Error-Controlled_Quantization.pdf>)
110 - [data-compression.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/data-compression/data-compression.pdf>)
111 - [fast_error_bounded_Lossy_hpc_data_compression_with_sz.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/data-compression/fast_error_bounded_Lossy_hpc_data_compression_with_sz.pdf>)
112 - [fixed-rate_compressed_floating_point_arrays.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/data-compression/fixed-rate_compressed_floating_point_arrays.pdf>)
113 - [fpc_a_high_speed_compressor_for_double_precision_floating_point_data.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/data-compression/fpc_a_high_speed_compressor_for_double_precision_floating_point_data.pdf>)
114 - data-fusion
115 - [a-new-approach-to-linear-filtering-and-prediction-problems.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/data-fusion/a-new-approach-to-linear-filtering-and-prediction-problems.pdf>)
116 - data-replication
117 - [a-comprehensive-study-of-convergent-and-communative-replicated-data-types.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/data-replication/a-comprehensive-study-of-convergent-and-communative-replicated-data-types.pdf>)
118 - data-science
119 - [tidy_data.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/data-science/tidy_data.pdf>)
120 - data-structures
121 - [b-trees-write-optimization.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/data-structures/b-trees-write-optimization.pdf>)
122 - [epidemic-broadcast-trees.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/data-structures/epidemic-broadcast-trees.pdf>)
123 - [ideal-hash-trees.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/data-structures/ideal-hash-trees.pdf>)
124 - [lca-revisited.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/data-structures/lca-revisited.pdf>)
125 - [level-ancestor-simplified.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/data-structures/level-ancestor-simplified.pdf>)
126 - datastores
127 - [bigtable-a-distributed-storage-system-for-structured-data.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/datastores/bigtable-a-distributed-storage-system-for-structured-data.pdf>)
128 - [database-metatheory--asking-the-big-queries.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/datastores/database-metatheory--asking-the-big-queries.pdf>)
129 - [dynamo-amazons-highly-available-key-value-store.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/datastores/dynamo-amazons-highly-available-key-value-store.pdf>)
130 - [elle-inferring-isolation-anomalies-from-experimental-observations.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/datastores/elle-inferring-isolation-anomalies-from-experimental-observations.pdf>)
131 - [flat-datacenter-storage.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/datastores/flat-datacenter-storage.pdf>)
132 - [freenet-a-distributed-anonymous-information-and-retrieval-system.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/datastores/freenet-a-distributed-anonymous-information-and-retrieval-system.pdf>)
133 - [megastore-providing-scalable-highly-available-storage-for-interactive-services.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/datastores/megastore-providing-scalable-highly-available-storage-for-interactive-services.pdf>)
134 - [network-challenges-of-data-recovery-in-erasure-coded-distributed-storage-systems.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/datastores/network-challenges-of-data-recovery-in-erasure-coded-distributed-storage-systems.pdf>)
135 - [rados-a-scalable-reliable-storage-service-for-petabyte-scale-storage-clusters.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/datastores/rados-a-scalable-reliable-storage-service-for-petabyte-scale-storage-clusters.pdf>)
136 - [spanner-google's-globally-distributed-database.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/datastores/spanner-google's-globally-distributed-database.pdf>)
137 - [spartan-a-distributed-array-framework-with-smart-tiling.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/datastores/spartan-a-distributed-array-framework-with-smart-tiling.pdf>)
138 - [stasis-flexible-transactional-storage.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/datastores/stasis-flexible-transactional-storage.pdf>)
139 - [tao-facebook-distributed-datastore.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/datastores/tao-facebook-distributed-datastore.pdf>)
140 - [the-google-file-system.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/datastores/the-google-file-system.pdf>)
141 - [transactional-storage-for-geo-replicated-systems.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/datastores/transactional-storage-for-geo-replicated-systems.pdf>)
142 - [warp-multi-key-transactions-for-key-value-stores.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/datastores/warp-multi-key-transactions-for-key-value-stores.pdf>)
143 - design
144 - [out-of-the-tar-pit.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/design/out-of-the-tar-pit.pdf>)
145 - digital-currency
146 - [bitcoin.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/digital-currency/bitcoin.pdf>)
147 - [peercoin.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/digital-currency/peercoin.pdf>)
148 - [primecoin.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/digital-currency/primecoin.pdf>)
149 - distributed-systems
150 - [a-history-of-the-virtual-synchrony-replication-model.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/a-history-of-the-virtual-synchrony-replication-model.pdf>)
151 - [a-hundred-impossibility-proofs-for-distributed-computing.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/a-hundred-impossibility-proofs-for-distributed-computing.pdf>)
152 - [a-note-on-distributed-computing.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/a-note-on-distributed-computing.pdf>)
153 - [a-response-to-cheriton-and-skeens-criticism-of-causal-and-totally-ordered-communication.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/a-response-to-cheriton-and-skeens-criticism-of-causal-and-totally-ordered-communication.pdf>)
154 - [a-universal-modular-actor-formalism-for-artificial-intelligence.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/a-universal-modular-actor-formalism-for-artificial-intelligence.pdf>)
155 - [a-versatile-scheme-for-routing-highly-variable-traffic-in-service-overlays-and-ip.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/a-versatile-scheme-for-routing-highly-variable-traffic-in-service-overlays-and-ip.pdf>)
156 - [beehive-lookup-performance-for-power-law-query-distributions-in-peer-to-peer-overlays.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/beehive-lookup-performance-for-power-law-query-distributions-in-peer-to-peer-overlays.pdf>)
157 - [brewers-conjecture.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/brewers-conjecture.pdf>)
158 - [byzantine-chain-replication.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/byzantine-chain-replication.pdf>)
159 - [byzantine-fault-tolerant-distributed-commit-protocol.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/byzantine-fault-tolerant-distributed-commit-protocol.pdf>)
160 - [chain-replication-for-supporting-high-throughput-and-availability.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/chain-replication-for-supporting-high-throughput-and-availability.pdf>)
161 - [commodifying-replicated-state-machines-with-openreplica.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/commodifying-replicated-state-machines-with-openreplica.pdf>)
162 - [consensus-in-presence-of-partial-synchrony.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/consensus-in-presence-of-partial-synchrony.pdf>)
163 - [consistent-global-states-of-distributed-systems-fundamental-concepts-and-mechanisms.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/consistent-global-states-of-distributed-systems-fundamental-concepts-and-mechanisms.pdf>)
164 - [consistent-hashing-and-random-trees.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/consistent-hashing-and-random-trees.pdf>)
165 - [copysets-reducing-the-frequency-of-data-loss-in-cloud-storage.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/copysets-reducing-the-frequency-of-data-loss-in-cloud-storage.pdf>)
166 - [dapper-a-large-scale-distributed-tracing-infrastructure.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/dapper-a-large-scale-distributed-tracing-infrastructure.pdf>)
167 - [distributed-snapshots-determining-global-states-of-distributed-systems.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/distributed-snapshots-determining-global-states-of-distributed-systems.pdf>)
168 - [eluding-carnivores-file-sharing-with-strong-anonymity.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/eluding-carnivores-file-sharing-with-strong-anonymity.pdf>)
169 - [end-to-end-arguments-in-system-design.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/end-to-end-arguments-in-system-design.pdf>)
170 - [epidemic-algorithms-for-replicated-database-maintenance.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/epidemic-algorithms-for-replicated-database-maintenance.pdf>)
171 - [harvest-yield-and-scalable-tolerant-systems.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/harvest-yield-and-scalable-tolerant-systems.pdf>)
172 - [herbivore-a-scalable-and-efficient-protocol-for-anonymous.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/herbivore-a-scalable-and-efficient-protocol-for-anonymous.pdf>)
173 - [high-level-specifications--lessons-from-industry.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/high-level-specifications--lessons-from-industry.pdf>)
174 - [how-the-hidden-hand-shapes-the-market-for-software-reliability.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/how-the-hidden-hand-shapes-the-market-for-software-reliability.pdf>)
175 - [implementing-the-omega-failure-detector-in-crash-recovery-failure-model.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/implementing-the-omega-failure-detector-in-crash-recovery-failure-model.pdf>)
176 - [impossibility-of-consensus-with-one-faulty-process.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/impossibility-of-consensus-with-one-faulty-process.pdf>)
177 - [in-search-of-an-understandable-consensus-algorithm.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/in-search-of-an-understandable-consensus-algorithm.pdf>)
178 - [ironFleet-proving-practical-distributed-systems-correct.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/ironFleet-proving-practical-distributed-systems-correct.pdf>)
179 - [join-calculus.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/join-calculus.pdf>)
180 - [kelips-building-an-efficient-and-stable-p2p-dht-through-increased-memory-and-background-overhead.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/kelips-building-an-efficient-and-stable-p2p-dht-through-increased-memory-and-background-overhead.pdf>)
181 - [large-scale-incremental-processing-using-distributed-transactions-and-notifications.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/large-scale-incremental-processing-using-distributed-transactions-and-notifications.pdf>)
182 - [life-beyond-distributed-transactions-an-apostates-opinion.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/life-beyond-distributed-transactions-an-apostates-opinion.pdf>)
183 - [mapreduce-simplified-data-processing-on-large-clusters.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/mapreduce-simplified-data-processing-on-large-clusters.pdf>)
184 - [mesos-a-platform-for-fine-grained-resource-sharing-in-the-data-center.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/mesos-a-platform-for-fine-grained-resource-sharing-in-the-data-center.pdf>)
185 - [oblivious-routing-of-highly-variable-traffic-in-service-overlays-and-ip-backbones.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/oblivious-routing-of-highly-variable-traffic-in-service-overlays-and-ip-backbones.pdf>)
186 - [on-proof-and-progress-in-mathematics.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/on-proof-and-progress-in-mathematics.pdf>)
187 - [p5-a-protocal-for-scalable-anonymous-communication.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/p5-a-protocal-for-scalable-anonymous-communication.pdf>)
188 - [pastry-scalable-decentralized-object-location-and-routing-for-large-scale-peer-to-peer-systems.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/pastry-scalable-decentralized-object-location-and-routing-for-large-scale-peer-to-peer-systems.pdf>)
189 - [paxos-made-moderately-complex.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/paxos-made-moderately-complex.pdf>)
190 - [paxos-made-simple.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/paxos-made-simple.pdf>)
191 - [self-stabilizing-systems-in-spite-of-distributed-control.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/self-stabilizing-systems-in-spite-of-distributed-control.pdf>)
192 - [sift-design-and-analysis-of-a-fault-tolerant-computer-for-aircraft-contro.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/sift-design-and-analysis-of-a-fault-tolerant-computer-for-aircraft-contro.pdf>)
193 - [signal-&-collect-graph-algorithms-for-the-(semantic)-web.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/signal-&-collect-graph-algorithms-for-the-(semantic)-web.pdf>)
194 - [simple-testing-can-prevent-most-critical-failures.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/simple-testing-can-prevent-most-critical-failures.pdf>)
195 - [solution-of-a-problem-in-concurrent-programming-control.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/solution-of-a-problem-in-concurrent-programming-control.pdf>)
196 - [sparse-partitions.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/sparse-partitions.pdf>)
197 - [stronger-semantics-for-low-latency-geo-replicated-storage.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/stronger-semantics-for-low-latency-geo-replicated-storage.pdf>)
198 - [the-akamai-network.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/the-akamai-network.pdf>)
199 - [the-chubby-lock-service-for-loosely-coupled-distributed-systems.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/the-chubby-lock-service-for-loosely-coupled-distributed-systems.pdf>)
200 - [the-dining-cryptographers-problem.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/the-dining-cryptographers-problem.pdf>)
201 - [tiered-replication-a-cost-effective-alternative-to-full-cluster-geo-replication.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/tiered-replication-a-cost-effective-alternative-to-full-cluster-geo-replication.pdf>)
202 - [tor-the-second-generation-onion-router.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/tor-the-second-generation-onion-router.pdf>)
203 - [towards-a-cloud-computing-research-agenda.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/towards-a-cloud-computing-research-agenda.pdf>)
204 - [understanding-the-limitations-of-causally-and-totally-ordered-communication.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/understanding-the-limitations-of-causally-and-totally-ordered-communication.pdf>)
205 - [viewing-control-structures-as-patterns-of-passing-messages.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/viewing-control-structures-as-patterns-of-passing-messages.pdf>)
206 - [zab-high-performance-broadcast-for-primary-backup-systems.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/zab-high-performance-broadcast-for-primary-backup-systems.pdf>)
207 - [zookeeper-wait-free-coordination-for-internet-scale-systems.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/zookeeper-wait-free-coordination-for-internet-scale-systems.pdf>)
208 - economics
209 - [online-ad-auctions.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/economics/online-ad-auctions.pdf>)
210 - experimental-algorithmics
211 - [a-theoreticians-guide-to-the-experimental-analysis-of-algorithms.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/experimental-algorithmics/a-theoreticians-guide-to-the-experimental-analysis-of-algorithms.pdf>)
212 - faults-and-verification
213 - [epitaxis-a-system-for-syntactic-and-semantic-software-queries.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/faults-and-verification/epitaxis-a-system-for-syntactic-and-semantic-software-queries.pdf>)
214 - gamification
215 - [gamification-in-education-what-how-why-bother.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/gamification/gamification-in-education-what-how-why-bother.pdf>)
216 - [why-students-engage-in-gaming-the-system-behavior-in-interactive-learning-environments.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/gamification/why-students-engage-in-gaming-the-system-behavior-in-interactive-learning-environments.pdf>)
217 - garbage-collection
218 - [incremental_mature_garbage_collection_using_the_train_algorithm.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/garbage-collection/incremental_mature_garbage_collection_using_the_train_algorithm.pdf>)
219 - [parallel_generational_copying_garbage_collection_with_a_block_structured_heap.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/garbage-collection/parallel_generational_copying_garbage_collection_with_a_block_structured_heap.pdf>)
220 - [the_lisp_ii_garbage_collector.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/garbage-collection/the_lisp_ii_garbage_collector.pdf>)
221 - information-retrieval
222 - [authoritative-sources-in-a-hyperlinked-environment.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/information-retrieval/authoritative-sources-in-a-hyperlinked-environment.pdf>)
223 - [graph_of_word_and_tw_idf.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/information-retrieval/graph_of_word_and_tw_idf.pdf>)
224 - [okapi-at-trec3.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/information-retrieval/okapi-at-trec3.pdf>)
225 - [the-pagerank-citation-ranking-bringing-order-to-the-web.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/information-retrieval/the-pagerank-citation-ranking-bringing-order-to-the-web.pdf>)
226 - information-theory
227 - [a-mathematical-theory-of-communication-1948.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/information-theory/a-mathematical-theory-of-communication-1948.pdf>)
228 - languages-paradigms
229 - functional_programming
230 - [concatenative-programming-an-overlooked-paradigm.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-paradigms/functional_programming/concatenative-programming-an-overlooked-paradigm.pdf>)
231 - [equal-rights-for-functional-objects.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-paradigms/functional_programming/equal-rights-for-functional-objects.pdf>)
232 - [functional-programming-with-bananas-lenses-envelops-and-barbed-wire.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-paradigms/functional_programming/functional-programming-with-bananas-lenses-envelops-and-barbed-wire.pdf>)
233 - [optimal-purely-functional-priority-queues.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-paradigms/functional_programming/optimal-purely-functional-priority-queues.pdf>)
234 - [organizing-programs-without-classes.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-paradigms/functional_programming/organizing-programs-without-classes.pdf>)
235 - [purely-functional-data-structures.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-paradigms/functional_programming/purely-functional-data-structures.pdf>)
236 - [why-functional-programming-matters.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-paradigms/functional_programming/why-functional-programming-matters.pdf>)
237 - functional_reactive_programming
238 - [a-survey-of-functional-reactive-programming.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-paradigms/functional_reactive_programming/a-survey-of-functional-reactive-programming.pdf>)
239 - [deprecating-the observer-pattern.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-paradigms/functional_reactive_programming/deprecating-the observer-pattern.pdf>)
240 - [frp-in-plt-scheme.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-paradigms/functional_reactive_programming/frp-in-plt-scheme.pdf>)
241 - [functional-reactive-animation.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-paradigms/functional_reactive_programming/functional-reactive-animation.pdf>)
242 - [ray-integrating-rx-and-async-for-direct-style-reactive-streams.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-paradigms/functional_reactive_programming/ray-integrating-rx-and-async-for-direct-style-reactive-streams.pdf>)
243 - new_paradigms
244 - [cognitive-computing-programming-paradigm-corelet-language.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-paradigms/new_paradigms/cognitive-computing-programming-paradigm-corelet-language.pdf>)
245 - languages-theory
246 - [composable-and-compilable-macros-you-want-it-when.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-theory/composable-and-compilable-macros-you-want-it-when.pdf>)
247 - [fundamental-concepts-in-programming-languages.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-theory/fundamental-concepts-in-programming-languages.pdf>)
248 - [on-understanding-types-data-abstraction-polymorphism.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-theory/on-understanding-types-data-abstraction-polymorphism.pdf>)
249 - [predicate-dispatching.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-theory/predicate-dispatching.pdf>)
250 - [principal-type-schemes-for-functional-programs.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-theory/principal-type-schemes-for-functional-programs.pdf>)
251 - [programming-languages-application-and-interpretation.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-theory/programming-languages-application-and-interpretation.pdf>)
252 - [propositions-as-types.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-theory/propositions-as-types.pdf>)
253 - [the-derivative-of-a-regular-type-one-hole-contexts.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-theory/the-derivative-of-a-regular-type-one-hole-contexts.pdf>)
254 - [theory-in-programming-practice.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-theory/theory-in-programming-practice.pdf>)
255 - languages
256 - clojure
257 - [a-practical-optional-type-system-for-clojure.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages/clojure/a-practical-optional-type-system-for-clojure.pdf>)
258 - haskell
259 - [a-poor-mans-concurrency-monad.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages/haskell/a-poor-mans-concurrency-monad.pdf>)
260 - [making-a-fast-curry-push-enter-versus-eval-apply-for-higher-order-languages.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages/haskell/making-a-fast-curry-push-enter-versus-eval-apply-for-higher-order-languages.pdf>)
261 - [tackling-the-awkward-squad-monadic-input-output-concurrency-exceptions-and-foreign-language-calls-in-haskell.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages/haskell/tackling-the-awkward-squad-monadic-input-output-concurrency-exceptions-and-foreign-language-calls-in-haskell.pdf>)
262 - [scp91-felleisen.ps.gz](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages/scp91-felleisen.ps.gz>)
263 - smalltalk
264 - [Design-Principles-Behind-Smalltalk.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages/smalltalk/Design-Principles-Behind-Smalltalk.pdf>)
265 - [The-Early-History-Of-Smalltalk.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages/smalltalk/The-Early-History-Of-Smalltalk.pdf>)
266 - logic-and-programming
267 - [event-calculus.txt](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/logic-and-programming/event-calculus.txt>)
268 - [on-the-meanings-of-the-logical-constants.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/logic-and-programming/on-the-meanings-of-the-logical-constants.pdf>)
269 - [representing-game-dialogue-as-expressions-in-first-order-logic.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/logic-and-programming/representing-game-dialogue-as-expressions-in-first-order-logic.pdf>)
270 - machine-learning
271 - [General-self-similarity--an-overview.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/machine-learning/General-self-similarity--an-overview.pdf>)
272 - [Understanding-Deep-Convolutional-Networks.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/machine-learning/Understanding-Deep-Convolutional-Networks.pdf>)
273 - dimensionality_reduction
274 - [a-sparse-johnson-lindenstrauss-transform.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/machine-learning/dimensionality_reduction/a-sparse-johnson-lindenstrauss-transform.pdf>)
275 - [toward-a-unified-theory-of-sparse-dimensionality-reduction-in-euclidean-space.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/machine-learning/dimensionality_reduction/toward-a-unified-theory-of-sparse-dimensionality-reduction-in-euclidean-space.pdf>)
276 - mathematics
277 - [from-dominoes-to-hexagons.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/mathematics/from-dominoes-to-hexagons.pdf>)
278 - [graph-isomorphism-and-representation-theory.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/mathematics/graph-isomorphism-and-representation-theory.pdf>)
279 - [intro-to-tropical-algebraic-geometry.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/mathematics/intro-to-tropical-algebraic-geometry.pdf>)
280 - [tilings.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/mathematics/tilings.pdf>)
281 - [transcendence-of-pi.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/mathematics/transcendence-of-pi.pdf>)
282 - memory-management
283 - [making-lockless-synchronization-fast.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/memory-management/making-lockless-synchronization-fast.pdf>)
284 - [scatteralloc-massively-parallel-dynamic-memory-allocation-for-the-gpu.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/memory-management/scatteralloc-massively-parallel-dynamic-memory-allocation-for-the-gpu.pdf>)
285 - non-blocking-algorithms
286 - [a-wait-free-queue-as-fast-as-fetch-and-add.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/non-blocking-algorithms/a-wait-free-queue-as-fast-as-fetch-and-add.pdf>)
287 - [a-wait-free-stack.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/non-blocking-algorithms/a-wait-free-stack.pdf>)
288 - [efficient-lock-free-b+trees.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/non-blocking-algorithms/efficient-lock-free-b+trees.pdf>)
289 - operating-systems
290 - [jails-confining-the-omnipotent-root..pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/operating-systems/jails-confining-the-omnipotent-root..pdf>)
291 - [solaris-zones-operating-system-support-for-consolidating-commercial-workloads.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/operating-systems/solaris-zones-operating-system-support-for-consolidating-commercial-workloads.pdf>)
292 - [therac.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/operating-systems/therac.pdf>)
293 - [unix-time-sharing-system.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/operating-systems/unix-time-sharing-system.pdf>)
294 - pattern-matching
295 - [aho-corasick-string-matching.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/pattern-matching/aho-corasick-string-matching.pdf>)
296 - [compiling-pattern-matching-to-good-decision-trees.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/pattern-matching/compiling-pattern-matching-to-good-decision-trees.pdf>)
297 - [extensible-pattern-matching-extensible-language.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/pattern-matching/extensible-pattern-matching-extensible-language.pdf>)
298 - [warnings-for-pattern-matching.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/pattern-matching/warnings-for-pattern-matching.pdf>)
299 - physics
300 - [buridans-principle.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/physics/buridans-principle.pdf>)
301 - [on-the-attraction-of-two-perfectly-conducting-plates.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/physics/on-the-attraction-of-two-perfectly-conducting-plates.pdf>)
302 - [on-the-electrodynamics-of-moving-bodies.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/physics/on-the-electrodynamics-of-moving-bodies.pdf>)
303 - processes
304 - [communicating-sequential-processes-paper.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/processes/communicating-sequential-processes-paper.pdf>)
305 - [communicating-sequential-processes.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/processes/communicating-sequential-processes.pdf>)
306 - quantum-computing
307 - [advance_in_quantum_machine_learning.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/quantum-computing/advance_in_quantum_machine_learning.pdf>)
308 - [grovers_algorithm.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/quantum-computing/grovers_algorithm.pdf>)
309 - [shors_algorithm.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/quantum-computing/shors_algorithm.pdf>)
310 - security
311 - [ids-evasion-ptacek-newsham.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/security/ids-evasion-ptacek-newsham.pdf>)
312 - [macaroons-cookies-with-contextual-caveats.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/security/macaroons-cookies-with-contextual-caveats.pdf>)
313 - [sok-eternal-war-in-memory.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/security/sok-eternal-war-in-memory.pdf>)
314 - software-engineering-orgs
315 - [common-ground-and-coordination-in-joint-activity.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/software-engineering-orgs/common-ground-and-coordination-in-joint-activity.pdf>)
316 - sports-analytics
317 - [2014-ssac-pointwise-predicting-points-and-valuing-decisions-in-real-time.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/sports-analytics/2014-ssac-pointwise-predicting-points-and-valuing-decisions-in-real-time.pdf>)
318 - sublinear-algorithms
319 - [1985-Flajolet-Probabilistic-counting.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/sublinear-algorithms/1985-Flajolet-Probabilistic-counting.pdf>)
320 - [An-Elementary-Proof-of-a-Theorem-of-Johnson-and-Lindenstrauss.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/sublinear-algorithms/An-Elementary-Proof-of-a-Theorem-of-Johnson-and-Lindenstrauss.pdf>)
321 - systematic-review
322 - [systematic-review-in-software-engineering.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/systematic-review/systematic-review-in-software-engineering.pdf>)
323 - time-series
324 - [operators-on-inhomogeneous-time-series.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/time-series/operators-on-inhomogeneous-time-series.pdf>)
325 - [ts-asap.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/time-series/ts-asap.pdf>)
326 - virtual-machines
327 - [kvm-linux-virtual-machines-monitor.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/virtual-machines/kvm-linux-virtual-machines-monitor.pdf>)
328 - [live-migration-of-virtual-machines.pdf](<https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/virtual-machines/live-migration-of-virtual-machines.pdf>)
329- public-projects
330 - alternator
331 - [alternator-1.0.0-linux-amd64.md](<https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/alternator/alternator-1.0.0-linux-amd64.md>)
332 - [alternator-1.0.0-linux-amd64.tar.gz](<https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/alternator/alternator-1.0.0-linux-amd64.tar.gz>)
333 - [alternator-1.0.0-linux-arm64.md](<https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/alternator/alternator-1.0.0-linux-arm64.md>)
334 - [alternator-1.0.0-linux-arm64.tar.gz](<https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/alternator/alternator-1.0.0-linux-arm64.tar.gz>)
335 - errand
336 - [errand-0.1.0-darwin-arm64.md5](<https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/errand/errand-0.1.0-darwin-arm64.md5>)
337 - [errand-0.1.0-darwin-arm64.tar.gz](<https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/errand/errand-0.1.0-darwin-arm64.tar.gz>)
338 - [errand-0.1.0-linux-amd64.md5](<https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/errand/errand-0.1.0-linux-amd64.md5>)
339 - [errand-0.1.0-linux-amd64.tar.gz](<https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/errand/errand-0.1.0-linux-amd64.tar.gz>)
340 - [errand-0.1.0-linux-arm64.md5](<https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/errand/errand-0.1.0-linux-arm64.md5>)
341 - [errand-0.1.0-linux-arm64.tar.gz](<https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/errand/errand-0.1.0-linux-arm64.tar.gz>)
342 - jbmafp
343 - [jbmafp-v0.1.tar.xz](<https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/jbmafp/jbmafp-v0.1.tar.xz>)
344 - [jbmafp-v0.1.zip](<https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/jbmafp/jbmafp-v0.1.zip>)
345 - simpleapi
346 - [sapi-0.1.0-darwin-amd64.md5](<https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/simpleapi/sapi-0.1.0-darwin-amd64.md5>)
347 - [sapi-0.1.0-darwin-amd64.tar.gz](<https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/simpleapi/sapi-0.1.0-darwin-amd64.tar.gz>)
348 - [sapi-0.1.0-darwin-arm64.md5](<https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/simpleapi/sapi-0.1.0-darwin-arm64.md5>)
349 - [sapi-0.1.0-darwin-arm64.tar.gz](<https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/simpleapi/sapi-0.1.0-darwin-arm64.tar.gz>)
350 - [sapi-0.1.0-linux-amd64.md5](<https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/simpleapi/sapi-0.1.0-linux-amd64.md5>)
351 - [sapi-0.1.0-linux-amd64.tar.gz](<https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/simpleapi/sapi-0.1.0-linux-amd64.tar.gz>)
352 - [sapi-0.1.0-linux-arm64.md5](<https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/simpleapi/sapi-0.1.0-linux-arm64.md5>)
353 - [sapi-0.1.0-linux-arm64.tar.gz](<https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/simpleapi/sapi-0.1.0-linux-arm64.tar.gz>)
354- video
355 - [Building the Simplest Possible Linux System - Rob Landley.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/Building the Simplest Possible Linux System - Rob Landley.webm>)
356 - [Go webserver, HTMX Integration, Template Fragments.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/Go webserver, HTMX Integration, Template Fragments.webm>)
357 - [Toybox vs BusyBox - Rob Landley, hobbyist.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/Toybox vs BusyBox - Rob Landley, hobbyist.webm>)
358 - plan9-videos
359 - [9Front Basic Install.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/9Front Basic Install.webm>)
360 - [9Front on the Desktop; IRC, web, and video in plan9 terminals.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/9Front on the Desktop; IRC, web, and video in plan9 terminals.webm>)
361 - [A Quick Intro to C Programming, for Plan 9 and 9 Front.mp4](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/A Quick Intro to C Programming, for Plan 9 and 9 Front.mp4>)
362 - [Adding to the Grid; Listening to CO2 Levels and Speaking to Light Bulbs with Plan9.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Adding to the Grid; Listening to CO2 Levels and Speaking to Light Bulbs with Plan9.webm>)
363 - [Alternative 9Front Partition Schemes.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Alternative 9Front Partition Schemes.webm>)
364 - [Auth & File Server Setup, using 9Front.mp4](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Auth & File Server Setup, using 9Front.mp4>)
365 - [Bonus Pipe Video; funny things you can do locally with named pipes in 9Front.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Bonus Pipe Video; funny things you can do locally with named pipes in 9Front.webm>)
366 - [Booting a Terminal off a USB drive, New User set up, and Disaster recover, for Plan9 using 9Front.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Booting a Terminal off a USB drive, New User set up, and Disaster recover, for Plan9 using 9Front.webm>)
367 - [Building a Better Grid with 9Front.mp4](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Building a Better Grid with 9Front.mp4>)
368 - [Consorting With Daemons! Running 9Front in bhyve on FreeBSD.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Consorting With Daemons! Running 9Front in bhyve on FreeBSD.webm>)
369 - [Doing Custom Work. Basic Configuration Files in Plan9 ⧸ 9Front.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Doing Custom Work. Basic Configuration Files in Plan9 ⧸ 9Front.webm>)
370 - [Drivers Part 2; Doing some initial reads and writes to a USB device in 9Front.mp4](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Drivers Part 2; Doing some initial reads and writes to a USB device in 9Front.mp4>)
371 - [Getting 9 Front to run on an Arm SBC, featuring the Pine A64 LTS.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Getting 9 Front to run on an Arm SBC, featuring the Pine A64 LTS.webm>)
372 - [Getting Plan9 and Linux to play (audio) together & Bonus Rant!.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Getting Plan9 and Linux to play (audio) together & Bonus Rant!.webm>)
373 - [Grave Robbing my way out of The Global Chip Shortage, feat; 9Front.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Grave Robbing my way out of The Global Chip Shortage, feat; 9Front.webm>)
374 - [Hot Time with 9Front on Arm.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Hot Time with 9Front on Arm.webm>)
375 - [Intro to USB drivers for Plan9 and 9Front.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Intro to USB drivers for Plan9 and 9Front.webm>)
376 - [Introduction to Grids; or, what can I do with all these Plan9 machines?.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Introduction to Grids; or, what can I do with all these Plan9 machines?.webm>)
377 - [Introduction to getting around. The User Interface of Plan9 ⧸ 9Front.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Introduction to getting around. The User Interface of Plan9 ⧸ 9Front.webm>)
378 - [MIPS Rides Again; my presentation for the International Workshop on Plan 9.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/MIPS Rides Again; my presentation for the International Workshop on Plan 9.webm>)
379 - [Making New Namespaces in Plan9 with auth⧸newns.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Making New Namespaces in Plan9 with auth⧸newns.webm>)
380 - [Making Your Server Do More; Hosting services on your Plan9 server.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Making Your Server Do More; Hosting services on your Plan9 server.webm>)
381 - [Making a sythetic filesystem: making fake files for fun and profit on Plan9 and 9Front.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Making a sythetic filesystem: making fake files for fun and profit on Plan9 and 9Front.webm>)
382 - [Meanwhile, In the Laboratory; finishing house chores and starting computer projects.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Meanwhile, In the Laboratory; finishing house chores and starting computer projects.webm>)
383 - [PXE Boot 9Front.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/PXE Boot 9Front.webm>)
384 - [Plan9 File Server, pt. 1; Installing 9Front.mp4](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Plan9 File Server, pt. 1; Installing 9Front.mp4>)
385 - [Plan9's rio, and how to modify it.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Plan9's rio, and how to modify it.webm>)
386 - [Plan9, gpsfs & Raspberry Pi; Using 9Front to get the most out of Soviet Technology.mp4](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Plan9, gpsfs & Raspberry Pi; Using 9Front to get the most out of Soviet Technology.mp4>)
387 - [Planning a Plan9 Ethernet switch filesystem, feat: a stream of consciousness.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Planning a Plan9 Ethernet switch filesystem, feat: a stream of consciousness.webm>)
388 - [Raspberry Pi Plan9 Server; Using a Pi and 9Front to serve up sensor data.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Raspberry Pi Plan9 Server; Using a Pi and 9Front to serve up sensor data.webm>)
389 - [Raspberry Pi on your Plan9 Network, featuring 9Front on a Pi 3B.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Raspberry Pi on your Plan9 Network, featuring 9Front on a Pi 3B.webm>)
390 - [Reading from a USB Device with 9Front.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Reading from a USB Device with 9Front.webm>)
391 - [Show and Tell; some stuff to throw 9Front at.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Show and Tell; some stuff to throw 9Front at.webm>)
392 - [Some Useful Tools in Plan9. Mouse Chording, VT, and Acme.mp4](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Some Useful Tools in Plan9. Mouse Chording, VT, and Acme.mp4>)
393 - [Still poking around a USB Device with 9Front.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Still poking around a USB Device with 9Front.webm>)
394 - [Using Bridges and Network Aliasing in Plan9 & 9Front.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Using Bridges and Network Aliasing in Plan9 & 9Front.webm>)
395 - [Using Drawterm to access your Plan9 server.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Using Drawterm to access your Plan9 server.webm>)
396 - [Using Listen1 on Plan9 to Debug Networking Code.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Using Listen1 on Plan9 to Debug Networking Code.webm>)
397 - [Using vmx; Running Linux Mint in a virtual machine on 9Front.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Using vmx; Running Linux Mint in a virtual machine on 9Front.webm>)
398 - [When Tech Bubbles Burst & Other Strange Tales.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/When Tech Bubbles Burst & Other Strange Tales.webm>)
399 - [Where to Find Kernel Code in 9front and Plan9.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Where to Find Kernel Code in 9front and Plan9.webm>)
400 - [Why is Plan9 like this? An intermediate guide to namespaces with rio.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Why is Plan9 like this? An intermediate guide to namespaces with rio.webm>)
401 - [Why is Plan9 like this? An introduction to Namespaces.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Why is Plan9 like this? An introduction to Namespaces.webm>)
402 - [Working with Kernels; Modifying and Installing a Kernel in 9Front.mp4](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Working with Kernels; Modifying and Installing a Kernel in 9Front.mp4>)
403 - [Writing Plan9 Kernels; 9Front on the MT7688.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Writing Plan9 Kernels; 9Front on the MT7688.webm>)
404 - [wizfs: A 9Front file server for Wiz light bulbs.webm](<https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/wizfs: A 9Front file server for Wiz light bulbs.webm>)
405
diff --git a/content/pages/curriculum-vitae.md b/curriculum-vitae.md
index f768d58..2235bcf 100644
--- a/content/pages/curriculum-vitae.md
+++ b/curriculum-vitae.md
@@ -1,29 +1,13 @@
1--- 1---
2title: Curriculum Vitae 2title: Curriculum Vitae
3date: 2022-08-27T12:00:00+02:00 3date: 2022-08-27T12:00:00+02:00
4url: curriculum-vitae.html 4permalink: /curriculum-vitae.html
5layout: page
5type: page 6type: page
6draft: false
7--- 7---
8 8
9<style>
10 img {
11 width: auto !important;
12 left: initial !important;
13 margin: initial !important;
14 border: 0 !important;
15 }
16</style>
17
18<div class="cv-picture">
19
20![](/posts/cv/avatar.gif)
21
22</div>
23
24<script> 9<script>
25 window.addEventListener('load', async () => { 10 window.addEventListener('load', async () => {
26 // flip CV image on mouse over
27 const cvImage = document.querySelector('.cv-picture img'); 11 const cvImage = document.querySelector('.cv-picture img');
28 if (cvImage) { 12 if (cvImage) {
29 setInterval(() => { 13 setInterval(() => {
@@ -97,3 +81,4 @@ Email me at *[m@mitjafelicijan.com](mailto:m@mitjafelicijan.com?subject=Website+
97- Development and maintenance of the project. 81- Development and maintenance of the project.
98- Code revision, testing and output. 82- Code revision, testing and output.
99- Work on the enhancement suggested by the customers and fixes the bugs reported. 83- Work on the enhancement suggested by the customers and fixes the bugs reported.
84
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..3f7732c
--- /dev/null
+++ b/index.html
@@ -0,0 +1,30 @@
1---
2layout: index
3---
4
5<p>You do not learn by relaxing. You learn by violently assaulting your problem
6until it surrenders its mysteries to you.</p>
7
8<h2>Articles, notes, ramblings etc</h2>
9
10<ul itemscope itemtype="https://schema.org/SiteNavigationElement" role="list" aria-label="Articles" class="list">
11 <meta itemprop="name" content="Article list">
12 {% for post in site.posts %}
13 <li>
14 <a href="{{ post.url }}">{{ post.title }}</a>
15 </li>
16 {% endfor %}
17</ul>
18
19<h2>Side projects I work/worked on</h2>
20
21<ul itemscope itemtype="https://schema.org/SiteNavigationElement" role="list" aria-label="Side projects" class="list">
22 <meta itemprop="name" content="Side projects">
23 <li role="listitem"><a href="https://git.mitjafelicijan.com/cord.h.git/" target="_blank">cord.h</a> — Small C library for handling strings</li>
24 <li role="listitem"><a href="https://git.mitjafelicijan.com/mprogress.git/" target="_blank">mprogress</a> — Tiny utility that displays progress bar in terminal</li>
25 <li role="listitem"><a href="https://git.mitjafelicijan.com/journalctl-proxy.git/" target="_blank">journalctl-proxy</a> — Exposes your systemd logs to web via web interface</li>
26 <li role="listitem"><a href="https://git.mitjafelicijan.com/redis-marshal.git/" target="_blank">redis-marshal</a> — Lightweight Redis data exploration tool</li>
27 <li role="listitem"><a href="https://git.mitjafelicijan.com/vertex.git/" target="_blank">vertex</a> — Create mock API's and add basic logic to simplify prototyping</li>
28 <li role="listitem"><a href="https://git.mitjafelicijan.com/dna-encoding.git/" target="_blank">dna-encoding</a> — Tools for encoding files to DNA sequence</li>
29 <li role="listitem"><a href="https://git.mitjafelicijan.com/scarecrow.git/" target="_blank">scarecrow</a> — Minimal configuration reverse proxy</li>
30</ul>
diff --git a/public/10gui-10-finger-multitouch-user-interface.html b/public/10gui-10-finger-multitouch-user-interface.html
deleted file mode 100755
index a683c09..0000000
--- a/public/10gui-10-finger-multitouch-user-interface.html
+++ /dev/null
@@ -1,48 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>10/GUI 10 Finger Multitouch User Interface</title><meta name=description content="Message from 10/GUI team (page 10gui."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>10/GUI 10 Finger Multitouch User Interface</h1><p><cap>note</cap>, Jun 29, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>Message from 10/GUI team (page 10gui.com does not exist anymore):<p><em>Over a quarter-century ago, Xerox introduced the modern graphical user
10interface paradigm we today take for granted.</em><p><em>That it has endured is a testament to the genius of its design. But the
11industry is now at a crossroads: New technologies promise higher-bandwidth
12interaction, but have yet to find a truly viable implementation.</em><p><em>10/GUI aims to bridge this gap by rethinking the desktop to leverage technology
13in an intuitive and powerful way.</em><p><video poster=/notes/10gui-10-finger-multitouch-user-interface.jpg src=/notes/10gui-10-finger-multitouch-user-interface.mp4 controls></video></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
14a lock on a Linux NFS server, which turned
15out to be specific to NFS v3 (which I really should have seen coming,
16since it involved NLM and lockd). Finding the NFS v4 client that
17owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
18and Bradley Kuhn, are interacting on the OSI's license-discuss
19list where the're doing
20bad computer history and insisting that a guy Larry Rosen
21coincidentally interviewed for a book years ago is clearly the origin of
22somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
23i2c, plan9
24Another month, another file system.
25Well, if you can’t fix it in software, fix it in hardware (looking at
26you, bme680, we’re not
27done yet). The show must go on, as they say, and I would like my
28experiments to go on.
29So a “new” addition to the environmental sensor family connected to
30the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
31this mortal coil, we are endowed with self-awareness, agency, and free will.
32Each of the 8 billion members of this human race represents a unique person, a
33unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
34My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
351.0 has been released:
36wifi_da-1.0.sit
37(StuffIt 3 archive)
38SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
39This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
40classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
41In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
42Design Goals
43I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
44at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
45catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
46specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
47 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
48 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/60s-ibm-computers-commercial.html b/public/60s-ibm-computers-commercial.html
deleted file mode 100755
index 14594c3..0000000
--- a/public/60s-ibm-computers-commercial.html
+++ /dev/null
@@ -1,46 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>60's IBM Computers Commercial</title><meta name=description content="Likely aired during an hour-long program during the 1960s, long commercials suchas this typically aired during hour-long programs."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>60's IBM Computers Commercial</h1><p><cap>note</cap>, Jun 29, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>Likely aired during an hour-long program during the 1960s, long commercials such
10as this typically aired during hour-long programs. They would <em>not</em> have aired
11during a half-hour program.<p><video poster=/notes/60s-ibm-computers-commercial.jpg src=/notes/60s-ibm-computers-commercial.mp4 controls></video></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
12a lock on a Linux NFS server, which turned
13out to be specific to NFS v3 (which I really should have seen coming,
14since it involved NLM and lockd). Finding the NFS v4 client that
15owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
16and Bradley Kuhn, are interacting on the OSI's license-discuss
17list where the're doing
18bad computer history and insisting that a guy Larry Rosen
19coincidentally interviewed for a book years ago is clearly the origin of
20somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
21i2c, plan9
22Another month, another file system.
23Well, if you can’t fix it in software, fix it in hardware (looking at
24you, bme680, we’re not
25done yet). The show must go on, as they say, and I would like my
26experiments to go on.
27So a “new” addition to the environmental sensor family connected to
28the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
29this mortal coil, we are endowed with self-awareness, agency, and free will.
30Each of the 8 billion members of this human race represents a unique person, a
31unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
32My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
331.0 has been released:
34wifi_da-1.0.sit
35(StuffIt 3 archive)
36SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
37This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
38classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
39In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
40Design Goals
41I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
42at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
43catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
44specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
45 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
46 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/aerial-photography-of-algae-spotted-on-river-sava.html b/public/aerial-photography-of-algae-spotted-on-river-sava.html
deleted file mode 100755
index 4e29313..0000000
--- a/public/aerial-photography-of-algae-spotted-on-river-sava.html
+++ /dev/null
@@ -1,49 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Aerial photography of algae spotted on river Sava</title><meta name=description content="This is a bit of a different post than I usually write, but quite interestingone to me."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Aerial photography of algae spotted on river Sava</h1><p><cap>post</cap>, Aug 13, 2022 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>This is a bit of a different post than I usually write, but quite interesting
10one to me. River Sava has plenty of hydropower plants located down the stream.
11This makes regulating the strength of a current easier than normally. Because of
12lower stream strength and high temperatures, algae has formed on the river.
13This is the first time I've seen something like this in my whole life.<p>Below are some photographs taken from a DJI drone capturing the event.<figure><img src=/posts/algae-sava/dji-algae-0.jpg alt="Algae on Sava"></figure><figure><img src=/posts/algae-sava/dji-algae-1.jpg alt="Algae on Sava"></figure><figure><img src=/posts/algae-sava/dji-algae-2.jpg alt="Algae on Sava"></figure><figure><img src=/posts/algae-sava/dji-algae-3.jpg alt="Algae on Sava"></figure><figure><img src=/posts/algae-sava/dji-algae-4.jpg alt="Algae on Sava"></figure><figure><img src=/posts/algae-sava/dji-algae-5.jpg alt="Algae on Sava"></figure><p>I will try to get more photos of this in the future days and if something
14intriguing shows up will post it again on the blog.</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
15a lock on a Linux NFS server, which turned
16out to be specific to NFS v3 (which I really should have seen coming,
17since it involved NLM and lockd). Finding the NFS v4 client that
18owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
19and Bradley Kuhn, are interacting on the OSI's license-discuss
20list where the're doing
21bad computer history and insisting that a guy Larry Rosen
22coincidentally interviewed for a book years ago is clearly the origin of
23somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
24i2c, plan9
25Another month, another file system.
26Well, if you can’t fix it in software, fix it in hardware (looking at
27you, bme680, we’re not
28done yet). The show must go on, as they say, and I would like my
29experiments to go on.
30So a “new” addition to the environmental sensor family connected to
31the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
32this mortal coil, we are endowed with self-awareness, agency, and free will.
33Each of the 8 billion members of this human race represents a unique person, a
34unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
35My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
361.0 has been released:
37wifi_da-1.0.sit
38(StuffIt 3 archive)
39SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
40This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
41classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
42In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
43Design Goals
44I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
45at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
46catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
47specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
48 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
49 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/alacritty-open-links-with-modifier.html b/public/alacritty-open-links-with-modifier.html
deleted file mode 100755
index 5ca3da9..0000000
--- a/public/alacritty-open-links-with-modifier.html
+++ /dev/null
@@ -1,58 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Alacritty open links with modifier</title><meta name=description content="Alacritty by default makes all links in the terminal output clickable and thisgets annoying rather quickly."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Alacritty open links with modifier</h1><p><cap>note</cap>, Jun 25, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>Alacritty by default makes all links in the terminal output clickable and this
10gets annoying rather quickly. I liked the default behavior of Gnome terminal
11where you needed to hold Control key and then you could click and open links.<p>To achieve this in Alacritty you need to provide a <code>hint</code> in the configuration
12file. Config file is located at <code>~/.config/alacritty/alacritty.yml</code>.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>hints:
13</span></span><span style=display:flex><span> enabled:
14</span></span><span style=display:flex><span> - regex: <span style=color:#a31515>&#34;(mailto:|gemini:|gopher:|https:|http:|news:|file:|git:|ssh:|ftp:)\
15</span></span></span><span style=display:flex><span><span style=color:#a31515> [^\u0000-\u001F\u007F-\u009F&lt;&gt;\&#34;\\s{-}\\^⟨⟩`]+&#34;</span>
16</span></span><span style=display:flex><span> command: xdg-open
17</span></span><span style=display:flex><span> post_processing: <span style=color:#00f>true</span>
18</span></span><span style=display:flex><span> mouse:
19</span></span><span style=display:flex><span> enabled: <span style=color:#00f>true</span>
20</span></span><span style=display:flex><span> mods: Control
21</span></span></code></pre><p>The following should work under any Linux system. For macOS, you will need to
22change <code>command: xdg-open</code> to something else.<p>Now the links will be visible and clickable only when Control key is being
23pressed.<p>Source: <a href=https://github.com/alacritty/alacritty/issues/5246>https://github.com/alacritty/alacritty/issues/5246</a></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
24a lock on a Linux NFS server, which turned
25out to be specific to NFS v3 (which I really should have seen coming,
26since it involved NLM and lockd). Finding the NFS v4 client that
27owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
28and Bradley Kuhn, are interacting on the OSI's license-discuss
29list where the're doing
30bad computer history and insisting that a guy Larry Rosen
31coincidentally interviewed for a book years ago is clearly the origin of
32somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
33i2c, plan9
34Another month, another file system.
35Well, if you can’t fix it in software, fix it in hardware (looking at
36you, bme680, we’re not
37done yet). The show must go on, as they say, and I would like my
38experiments to go on.
39So a “new” addition to the environmental sensor family connected to
40the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
41this mortal coil, we are endowed with self-awareness, agency, and free will.
42Each of the 8 billion members of this human race represents a unique person, a
43unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
44My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
451.0 has been released:
46wifi_da-1.0.sit
47(StuffIt 3 archive)
48SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
49This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
50classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
51In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
52Design Goals
53I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
54at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
55catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
56specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
57 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
58 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/aws-eb-pyyaml-fix.html b/public/aws-eb-pyyaml-fix.html
deleted file mode 100755
index 9de3323..0000000
--- a/public/aws-eb-pyyaml-fix.html
+++ /dev/null
@@ -1,56 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>AWS EB PyYAML fix</title><meta name=description content="Recent update of my system completely borked EB CLIon my machine."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>AWS EB PyYAML fix</h1><p><cap>note</cap>, Sep 18, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>Recent update of my system completely borked <a href=https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/eb-cli3-install-advanced.html>EB CLI</a>
10on my machine.<p>I tried installing it with <code>pip install awsebcli --upgrade --user</code> and it failed.<p>The error was the following.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>Collecting PyYAML&lt;6.1,&gt;=5.3.1 (from awsebcli)
11</span></span><span style=display:flex><span> Using cached PyYAML-5.4.1.tar.gz (175 kB)
12</span></span><span style=display:flex><span> Installing build dependencies ... done
13</span></span><span style=display:flex><span> Getting requirements to build wheel ... error
14</span></span><span style=display:flex><span> error: subprocess-exited-with-error
15</span></span><span style=display:flex><span>
16</span></span><span style=display:flex><span> × Getting requirements to build wheel did not run successfully.
17</span></span><span style=display:flex><span> │ exit code: 1
18</span></span><span style=display:flex><span> ╰─&gt; [68 lines of output]
19</span></span></code></pre><p>To fix this issue with PyYAML you must install PyYAML separately.<p>Do the following and try installing <code>eb</code> again after.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>echo <span style=color:#a31515>&#39;Cython &lt; 3.0&#39;</span> &gt; /tmp/constraint.txt
20</span></span><span style=display:flex><span>PIP_CONSTRAINT=/tmp/constraint.txt pip install <span style=color:#a31515>&#39;PyYAML==5.4.1&#39;</span>
21</span></span></code></pre></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
22a lock on a Linux NFS server, which turned
23out to be specific to NFS v3 (which I really should have seen coming,
24since it involved NLM and lockd). Finding the NFS v4 client that
25owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
26and Bradley Kuhn, are interacting on the OSI's license-discuss
27list where the're doing
28bad computer history and insisting that a guy Larry Rosen
29coincidentally interviewed for a book years ago is clearly the origin of
30somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
31i2c, plan9
32Another month, another file system.
33Well, if you can’t fix it in software, fix it in hardware (looking at
34you, bme680, we’re not
35done yet). The show must go on, as they say, and I would like my
36experiments to go on.
37So a “new” addition to the environmental sensor family connected to
38the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
39this mortal coil, we are endowed with self-awareness, agency, and free will.
40Each of the 8 billion members of this human race represents a unique person, a
41unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
42My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
431.0 has been released:
44wifi_da-1.0.sit
45(StuffIt 3 archive)
46SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
47This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
48classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
49In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
50Design Goals
51I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
52at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
53catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
54specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
55 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
56 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/bind-warning-on-login-in-ubuntu.html b/public/bind-warning-on-login-in-ubuntu.html
deleted file mode 100755
index 584735a..0000000
--- a/public/bind-warning-on-login-in-ubuntu.html
+++ /dev/null
@@ -1,69 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Fix bind warning in .profile on login in Ubuntu</title><meta name=description content="Recently I moved back to bash as mydefault shell."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Fix bind warning in .profile on login in Ubuntu</h1><p><cap>post</cap>, Sep 8, 2020 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>Recently I moved back to <a href=https://www.gnu.org/software/bash/>bash</a> as my
10default shell. I was previously using <a href=https://fishshell.com/>fish</a> and got
11used to the cool features it has. But, regardless of that, I wanted to move to a
12more standard shell because I was hopping back and forth with exporting
13variables and stuff like that which got pretty annoying.<p>So I embarked on a mission to make <a href=https://www.gnu.org/software/bash/>bash</a>
14more like <a href=https://fishshell.com/>fish</a> and in the process found that I really
15missed autosuggest with TAB on changing directories.<p>I found a nice alternative that emulates <a href=http://zsh.sourceforge.net/>zsh</a> like
16autosuggestion and autocomplete so I added the following to my <code>.bashrc</code> file.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>bind <span style=color:#a31515>&#34;TAB:menu-complete&#34;</span>
17</span></span><span style=display:flex><span>bind <span style=color:#a31515>&#34;set show-all-if-ambiguous on&#34;</span>
18</span></span><span style=display:flex><span>bind <span style=color:#a31515>&#34;set completion-ignore-case on&#34;</span>
19</span></span><span style=display:flex><span>bind <span style=color:#a31515>&#34;set menu-complete-display-prefix on&#34;</span>
20</span></span><span style=display:flex><span>bind <span style=color:#a31515>&#39;&#34;\e[Z&#34;:menu-complete-backward&#39;</span>
21</span></span></code></pre><p>I haven't noticed anything wrong with this and all was working fine until I
22restarted my machine and then I got this error.<figure><img src=/posts/profile-bind-error/error.jpg alt="Profile bind error"></figure><p>When I pressed OK, I got into the <a href=https://wiki.gnome.org/Projects/GnomeShell>Gnome
23shell</a> and all was working fine, but
24the error was still bugging me. I started looking for the reason why this is
25happening and found a solution to this error on <a href=https://superuser.com/a/892682>Remote SSH Commands - bash bind
26warning: line editing not enabled</a>.<p>So I added a simple <code>if [ -t 1 ]</code> around <code>bind</code> statements to avoid running
27commands that presume the session is interactive when it isn't.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>if</span> [ -t 1 ]; <span style=color:#00f>then</span>
28</span></span><span style=display:flex><span> bind <span style=color:#a31515>&#34;TAB:menu-complete&#34;</span>
29</span></span><span style=display:flex><span> bind <span style=color:#a31515>&#34;set show-all-if-ambiguous on&#34;</span>
30</span></span><span style=display:flex><span> bind <span style=color:#a31515>&#34;set completion-ignore-case on&#34;</span>
31</span></span><span style=display:flex><span> bind <span style=color:#a31515>&#34;set menu-complete-display-prefix on&#34;</span>
32</span></span><span style=display:flex><span> bind <span style=color:#a31515>&#39;&#34;\e[Z&#34;:menu-complete-backward&#39;</span>
33</span></span><span style=display:flex><span><span style=color:#00f>fi</span>
34</span></span></code></pre><p>After logging out and back in the problem was gone.</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
35a lock on a Linux NFS server, which turned
36out to be specific to NFS v3 (which I really should have seen coming,
37since it involved NLM and lockd). Finding the NFS v4 client that
38owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
39and Bradley Kuhn, are interacting on the OSI's license-discuss
40list where the're doing
41bad computer history and insisting that a guy Larry Rosen
42coincidentally interviewed for a book years ago is clearly the origin of
43somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
44i2c, plan9
45Another month, another file system.
46Well, if you can’t fix it in software, fix it in hardware (looking at
47you, bme680, we’re not
48done yet). The show must go on, as they say, and I would like my
49experiments to go on.
50So a “new” addition to the environmental sensor family connected to
51the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
52this mortal coil, we are endowed with self-awareness, agency, and free will.
53Each of the 8 billion members of this human race represents a unique person, a
54unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
55My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
561.0 has been released:
57wifi_da-1.0.sit
58(StuffIt 3 archive)
59SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
60This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
61classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
62In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
63Design Goals
64I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
65at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
66catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
67specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
68 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
69 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/bringing-all-of-my-projects-together-under-one-umbrella.html b/public/bringing-all-of-my-projects-together-under-one-umbrella.html
deleted file mode 100755
index ed45cb6..0000000
--- a/public/bringing-all-of-my-projects-together-under-one-umbrella.html
+++ /dev/null
@@ -1,197 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Bringing all of my projects together under one umbrella</title><meta name=description content="What is the issue anyway?"><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Bringing all of my projects together under one umbrella</h1><p><cap>post</cap>, Jul 1, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><h2 id=what-is-the-issue-anyway>What is the issue anyway?</h2><p>Over the years, I have accumulated a bunch of virtual servers on my
10<a href=https://www.digitalocean.com/>DigitalOcean</a> account for small experimental
11projects I dabble in. And this has resulted in quite a bill. I mean, I wouldn't
12care if these projects were actually being used. But there were just being there
13unused and wasting resources. Which makes this an unnecessary burden for me.<p>Most of them are just small HTML pages that have an endpoint or two to read data
14from or to, and for that reason I wrote servers left and right. To be honest,
15all of those things could have been done with <a href=https://en.wikipedia.org/wiki/Common_Gateway_Interface>CGI
16scripts</a> and that would
17have been more than enough.<p>Recently, I decided to stop language hopping and focus on a simpler stack which
18includes C, Go and Lua. And I can accomplish all the things I am interested in.<h2 id=finding-a-web-server-replacement>Finding a web server replacement</h2><p>Usually I had <a href=https://nginx.org/en/>Nginx</a> in front of these small web servers
19and I had to manage SSL certificates and all that jazz. I am bored with these
20things. I don't want to manage any of this bullshit anymore.<p>So the logical move forward was to find a solid alternative for this. I have
21ended up on <a href=https://caddyserver.com/>Caddy server</a>. I've used it in the past
22but kind of forgotten about it. What I really like about it is an ease of use
23and a bunch of out of the box functionalities that come with it.<p>These are the <em>pitch</em> points from their website:<ul><li><strong>Secure by Default</strong>: Caddy is the only web server that uses HTTPS by
24default. A hardened TLS stack with modern protocols preserves privacy and
25exposes MITM attacks.<li><strong>Config API</strong>: As its primary mode of configuration, Caddy's REST API makes
26it easy to automate and integrate with your apps.<li><strong>No Dependencies</strong>: Because Caddy is written in Go, its binaries are entirely
27self-contained and run on every platform, including containers without libc.<li><strong>Modular Stack</strong>: Take back control over your compute edge. Caddy can be
28extended with everything you need using plugins.</ul><p>I had just a few requirements:<ul><li>Automatic SSL<li>Static file server<li>Basic authentication<li>CGI script support</ul><p>And the vanilla version does all of it, but CGI scripts. But that can easily be
29fixed with their modular approach. You can do this on their website and build a
30custom version of the server, or do it with Docker.<p>This is a <code>Dockerfile</code> I used to build a custom server.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>FROM</span><span style=color:#a31515> caddy:builder AS builder</span><span>
31</span></span></span><span style=display:flex><span><span>
32</span></span></span><span style=display:flex><span><span></span><span style=color:#00f>RUN</span> xcaddy build <span style=color:#a31515>\
33</span></span></span><span style=display:flex><span><span style=color:#a31515></span> --with github.com/aksdb/caddy-cgi<span>
34</span></span></span><span style=display:flex><span><span>
35</span></span></span><span style=display:flex><span><span></span><span style=color:#00f>FROM</span><span style=color:#a31515> caddy:latest</span><span>
36</span></span></span><span style=display:flex><span><span></span><span style=color:#00f>RUN</span> apk add --no-cache nano<span>
37</span></span></span><span style=display:flex><span><span>
38</span></span></span><span style=display:flex><span><span></span><span style=color:#00f>COPY</span> --from=builder /usr/bin/caddy /usr/bin/caddy<span>
39</span></span></span></code></pre><h2 id=getting-rid-of-all-the-unnecessary-virtual-machines>Getting rid of all the unnecessary virtual machines</h2><p>The next step was to get a handle on the number of virtual servers I have all
40over the place.<p>I decided to move all the projects and services into two main VMs:<ul><li>personal server (still Nginx)<ul><li>git server<li>static file server<li>personal blog</ul><li>projects server (Caddy server)<ul><li>personal experiments<li>other projects</ul></ul><p>I will focus on projects' server in this post since it's more interesting.<h2 id=testing-cgi-scripts>Testing CGI scripts</h2><p>The first thing I tested was how CGI scripts work under Caddy. This is
41particularly import to me because almost all of my experiments and mini projects
42need this to work.<p>To configure Caddy server, you must provide the server with a configuration
43file. By default, it's called <code>Caaddyfile</code>.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>{
44</span></span><span style=display:flex><span> <span style=color:#00f>order</span> <span style=color:#a31515>cgi</span> before <span style=color:#a31515>respond</span>
45</span></span><span style=display:flex><span>}
46</span></span><span style=display:flex><span>
47</span></span><span style=display:flex><span><span style=font-weight:700>examples.mitjafelicijan.com</span> {
48</span></span><span style=display:flex><span> <span style=color:#00f>cgi</span> /bash-test <span style=color:#a31515>/opt/projects/examples/bash-test.sh</span>
49</span></span><span style=display:flex><span> <span style=color:#00f>cgi</span> /tcl-test <span style=color:#a31515>/opt/projects/examples/tcl-test.tcl</span>
50</span></span><span style=display:flex><span> <span style=color:#00f>cgi</span> /lua-test <span style=color:#a31515>/opt/projects/examples/lua-test.lua</span>
51</span></span><span style=display:flex><span> <span style=color:#00f>cgi</span> /python-test <span style=color:#a31515>/opt/projects/examples/python-test.py</span>
52</span></span><span style=display:flex><span>
53</span></span><span style=display:flex><span> <span style=color:#00f>root</span> * <span style=color:#a31515>/opt/projects/examples</span>
54</span></span><span style=display:flex><span> <span style=color:#00f>file_server</span>
55</span></span><span style=display:flex><span>}
56</span></span></code></pre><ul><li>The order is very important. Make sure that <code>order cgi before respond</code> is at
57the top of the configuration file.<li>Also, when you run with Caddy v2, make sure you provide <code>adapter</code> argument
58like this <code>/usr/bin/caddy run --watch --environ --config /etc/caddy/Caddyfile --adapter caddyfile</code>. Otherwise, Caddy will try to use a different format for
59config file.</ul><p>I did a small batch of tests with <a href=https://www.gnu.org/software/bash/>Bash</a>,
60<a href=https://www.tcl-lang.org/>Tcl</a>, <a href=https://www.lua.org/>Lua</a> and
61<a href=https://www.python.org/>Python</a>. Here is a cheat sheet if you need it.<p>Let's get Bash out of the way first.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>#!/usr/bin/bash
62</span></span></span><span style=display:flex><span><span style=color:#00f></span>
63</span></span><span style=display:flex><span>printf <span style=color:#a31515>&#34;Content-type: text/plain\n\n&#34;</span>
64</span></span><span style=display:flex><span>
65</span></span><span style=display:flex><span>printf <span style=color:#a31515>&#34;Hello from Bash\n\n&#34;</span>
66</span></span><span style=display:flex><span>printf <span style=color:#a31515>&#34;PATH_INFO [%s]\n&#34;</span> $PATH_INFO
67</span></span><span style=display:flex><span>printf <span style=color:#a31515>&#34;QUERY_STRING [%s]\n&#34;</span> $QUERY_STRING
68</span></span><span style=display:flex><span>printf <span style=color:#a31515>&#34;\n&#34;</span>
69</span></span><span style=display:flex><span>
70</span></span><span style=display:flex><span><span style=color:#00f>for</span> i in {0..9..1}; <span style=color:#00f>do</span>
71</span></span><span style=display:flex><span> printf <span style=color:#a31515>&#34;&gt; %s\n&#34;</span> $i
72</span></span><span style=display:flex><span><span style=color:#00f>done</span>
73</span></span><span style=display:flex><span>
74</span></span><span style=display:flex><span>exit 0
75</span></span></code></pre><p>This one is for Tcl script.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green>#!/usr/bin/tclsh
76</span></span></span><span style=display:flex><span><span style=color:green>
77</span></span></span><span style=display:flex><span><span style=color:green></span>puts <span style=color:#a31515>&#34;Content-type: text/plain\n&#34;</span>
78</span></span><span style=display:flex><span>
79</span></span><span style=display:flex><span>puts <span style=color:#a31515>&#34;Hello from Tcl\n&#34;</span>
80</span></span><span style=display:flex><span>puts <span style=color:#a31515>&#34;PATH_INFO \[$env(PATH_INFO)\]&#34;</span>
81</span></span><span style=display:flex><span>puts <span style=color:#a31515>&#34;QUERY_STRING \[$env(QUERY_STRING)\]&#34;</span>
82</span></span><span style=display:flex><span>puts <span style=color:#a31515>&#34;&#34;</span>
83</span></span><span style=display:flex><span>
84</span></span><span style=display:flex><span><span style=color:#00f>for</span> <span style=color:#00f>{set</span> i 0<span style=color:#00f>}</span> <span style=color:#00f>{</span>$i &lt; 10<span style=color:#00f>}</span> <span style=color:#00f>{</span>incr i<span style=color:#00f>}</span> <span style=color:#00f>{</span>
85</span></span><span style=display:flex><span> puts <span style=color:#a31515>&#34;&gt; $i&#34;</span>
86</span></span><span style=display:flex><span><span style=color:#00f>}</span>
87</span></span></code></pre><p>And for all you Python enjoyers.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green>#!/usr/bin/python3</span>
88</span></span><span style=display:flex><span>
89</span></span><span style=display:flex><span><span style=color:#00f>import</span> os
90</span></span><span style=display:flex><span>
91</span></span><span style=display:flex><span>print(<span style=color:#a31515>&#34;Content-type: text/plain</span><span style=color:#a31515>\n</span><span style=color:#a31515>&#34;</span>)
92</span></span><span style=display:flex><span>
93</span></span><span style=display:flex><span>print(<span style=color:#a31515>&#34;Hello from Python</span><span style=color:#a31515>\n</span><span style=color:#a31515>&#34;</span>)
94</span></span><span style=display:flex><span>print(<span style=color:#a31515>&#34;PATH_INFO [</span><span style=color:#a31515>{}</span><span style=color:#a31515>]&#34;</span>.format(os.environ[<span style=color:#a31515>&#39;PATH_INFO&#39;</span>]))
95</span></span><span style=display:flex><span>print(<span style=color:#a31515>&#34;QUERY_STRING [</span><span style=color:#a31515>{}</span><span style=color:#a31515>]&#34;</span>.format(os.environ[<span style=color:#a31515>&#39;QUERY_STRING&#39;</span>]))
96</span></span><span style=display:flex><span>print(<span style=color:#a31515>&#34;&#34;</span>)
97</span></span><span style=display:flex><span>
98</span></span><span style=display:flex><span><span style=color:#00f>for</span> i <span style=color:#00f>in</span> range(10):
99</span></span><span style=display:flex><span> print(<span style=color:#a31515>&#34;&gt; </span><span style=color:#a31515>{}</span><span style=color:#a31515>&#34;</span>.format(i))
100</span></span></code></pre><p>And for the final example, Lua.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>#!/usr/bin/lua</span>
101</span></span><span style=display:flex><span>
102</span></span><span style=display:flex><span>print(<span style=color:#a31515>&#34;Content-type: text/plain</span><span style=color:#a31515>\n</span><span style=color:#a31515>&#34;</span>)
103</span></span><span style=display:flex><span>
104</span></span><span style=display:flex><span>print(<span style=color:#a31515>&#34;Hello from Lua</span><span style=color:#a31515>\n</span><span style=color:#a31515>&#34;</span>)
105</span></span><span style=display:flex><span>print(string.format(<span style=color:#a31515>&#34;PATH_INFO [%s]&#34;</span>, os.getenv(<span style=color:#a31515>&#34;PATH_INFO&#34;</span>)))
106</span></span><span style=display:flex><span>print(string.format(<span style=color:#a31515>&#34;QUERY_STRING [%s]&#34;</span>, os.getenv(<span style=color:#a31515>&#34;QUERY_STRING&#34;</span>)))
107</span></span><span style=display:flex><span>print()
108</span></span><span style=display:flex><span>
109</span></span><span style=display:flex><span><span style=color:#00f>for</span> i = 0, 9 <span style=color:#00f>do</span>
110</span></span><span style=display:flex><span> print(string.format(<span style=color:#a31515>&#34;&gt; %d&#34;</span>, i))
111</span></span><span style=display:flex><span><span style=color:#00f>end</span>
112</span></span></code></pre><h2 id=basic-authentication>Basic authentication</h2><p>One thing was also to have an option for some sort of authentication, and
113something like <a href=https://en.wikipedia.org/wiki/Basic_access_authentication>Basic access
114authentication</a> would
115be more than enough.<p>Thankfully, Caddy supports this out of the box already. Below is an updated
116example.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>{
117</span></span><span style=display:flex><span> <span style=color:#00f>order</span> <span style=color:#a31515>cgi</span> before <span style=color:#a31515>respond</span>
118</span></span><span style=display:flex><span>}
119</span></span><span style=display:flex><span>
120</span></span><span style=display:flex><span><span style=font-weight:700>examples.mitjafelicijan.com</span> {
121</span></span><span style=display:flex><span> <span style=color:#00f>cgi</span> /bash-test <span style=color:#a31515>/opt/projects/examples/bash-test.sh</span>
122</span></span><span style=display:flex><span> <span style=color:#00f>cgi</span> /tcl-test <span style=color:#a31515>/opt/projects/examples/tcl-test.tcl</span>
123</span></span><span style=display:flex><span> <span style=color:#00f>cgi</span> /lua-test <span style=color:#a31515>/opt/projects/examples/lua-test.lua</span>
124</span></span><span style=display:flex><span> <span style=color:#00f>cgi</span> /python-test <span style=color:#a31515>/opt/projects/examples/python-test.py</span>
125</span></span><span style=display:flex><span>
126</span></span><span style=display:flex><span> <span style=color:#00f>root</span> * <span style=color:#a31515>/opt/projects/examples</span>
127</span></span><span style=display:flex><span> <span style=color:#00f>file_server</span>
128</span></span><span style=display:flex><span>
129</span></span><span style=display:flex><span> <span style=color:#00f>basicauth</span> * {
130</span></span><span style=display:flex><span> <span style=color:#00f>bob</span> <span>$</span><span style=color:#a31515>2a</span><span>$</span>14<span>$</span><span style=color:#a31515>/wCgaf9oMnmQa20txB76u.nI1AldGMBT/1J7fXCfgOiRShwz/JOkK</span>
131</span></span><span style=display:flex><span> }
132</span></span><span style=display:flex><span>}
133</span></span></code></pre><p><code>basicauth *</code> matches everything under this domain/sub-domain and protects it
134with Basic Authentication.<ul><li><code>bob</code> is the username<li><code>hash</code> is the password</ul><p>To generate these passwords, execute <code>caddy hash-password</code> and this will prompt
135you to insert a password twice and spit out a hashed password that you can put
136in your configuration file.<p>Restart the server and you are ready to go.<h2 id=making-caddy-a-service-with-systemd>Making Caddy a service with systemd</h2><p>After the tests were successful, I copied <code>caddy</code> to <code>/usr/bin/caddy</code> and copied
137<code>Caddyfile</code> to <code>/etc/caddy/Caddyfile</code>.<p>Now off to the systemd. Each systemd service requires you to create a service
138file.<ul><li>I created a <code>/etc/systemd/system/caddy.service</code> and put the following content
139in the file.</ul><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>[Unit]</span>
140</span></span><span style=display:flex><span>Description=<span style=color:#a31515>Caddy</span>
141</span></span><span style=display:flex><span>Documentation=<span style=color:#a31515>https://caddyserver.com/docs/</span>
142</span></span><span style=display:flex><span>After=<span style=color:#a31515>network.target network-online.target</span>
143</span></span><span style=display:flex><span>Requires=<span style=color:#a31515>network-online.target</span>
144</span></span><span style=display:flex><span>
145</span></span><span style=display:flex><span><span style=color:#00f>[Service]</span>
146</span></span><span style=display:flex><span>Type=<span style=color:#a31515>notify</span>
147</span></span><span style=display:flex><span>User=<span style=color:#a31515>root</span>
148</span></span><span style=display:flex><span>Group=<span style=color:#a31515>root</span>
149</span></span><span style=display:flex><span>ExecStart=<span style=color:#a31515>/usr/bin/caddy run --environ --config /etc/caddy/Caddyfile --adapter caddyfile</span>
150</span></span><span style=display:flex><span>ExecReload=<span style=color:#a31515>/usr/bin/caddy reload --config /etc/caddy/Caddyfile --force --adapter caddyfile</span>
151</span></span><span style=display:flex><span>TimeoutStopSec=<span style=color:#a31515>5s</span>
152</span></span><span style=display:flex><span>LimitNOFILE=<span style=color:#a31515>1048576</span>
153</span></span><span style=display:flex><span>LimitNPROC=<span style=color:#a31515>512</span>
154</span></span><span style=display:flex><span>PrivateTmp=<span style=color:#a31515>true</span>
155</span></span><span style=display:flex><span>ProtectSystem=<span style=color:#a31515>full</span>
156</span></span><span style=display:flex><span>AmbientCapabilities=<span style=color:#a31515>CAP_NET_ADMIN CAP_NET_BIND_SERVICE</span>
157</span></span><span style=display:flex><span>
158</span></span><span style=display:flex><span><span style=color:#00f>[Install]</span>
159</span></span><span style=display:flex><span>WantedBy=<span style=color:#a31515>multi-user.target</span>
160</span></span></code></pre><ul><li>You might need to reload systemd with <code>systemctl daemon-reload</code>.<li>Then I enabled the service with <code>systemctl enable caddy.service</code>.<li>And then I started the service with <code>systemctl start caddy.service</code>.</ul><p>This was about all that I needed to do to get it running. Now I can easily add
161new subdomains and domains to the main configuration file and be done with
162it. No manual Let's Encrypt shenanigans needed.</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
163a lock on a Linux NFS server, which turned
164out to be specific to NFS v3 (which I really should have seen coming,
165since it involved NLM and lockd). Finding the NFS v4 client that
166owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
167and Bradley Kuhn, are interacting on the OSI's license-discuss
168list where the're doing
169bad computer history and insisting that a guy Larry Rosen
170coincidentally interviewed for a book years ago is clearly the origin of
171somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
172i2c, plan9
173Another month, another file system.
174Well, if you can’t fix it in software, fix it in hardware (looking at
175you, bme680, we’re not
176done yet). The show must go on, as they say, and I would like my
177experiments to go on.
178So a “new” addition to the environmental sensor family connected to
179the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
180this mortal coil, we are endowed with self-awareness, agency, and free will.
181Each of the 8 billion members of this human race represents a unique person, a
182unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
183My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
1841.0 has been released:
185wifi_da-1.0.sit
186(StuffIt 3 archive)
187SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
188This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
189classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
190In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
191Design Goals
192I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
193at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
194catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
195specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
196 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
197 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/bulk-make-thumbnails.html b/public/bulk-make-thumbnails.html
deleted file mode 100755
index 4d94983..0000000
--- a/public/bulk-make-thumbnails.html
+++ /dev/null
@@ -1,52 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Bulk thumbnails</title><meta name=description content="Make bulk thumbnails of JPGs with ImageMagick."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Bulk thumbnails</h1><p><cap>note</cap>, Jun 4, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>Make bulk thumbnails of JPGs with ImageMagick.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>#!/bin/bash
10</span></span></span><span style=display:flex><span><span style=color:#00f></span>
11</span></span><span style=display:flex><span>directory=<span style=color:#a31515>&#34;./images/&#34;</span>
12</span></span><span style=display:flex><span>dimensions=<span style=color:#a31515>&#34;360x360&#34;</span>
13</span></span><span style=display:flex><span>
14</span></span><span style=display:flex><span><span style=color:#00f>for</span> file in <span style=color:#a31515>&#34;</span>$directory<span style=color:#a31515>&#34;</span>*.jpg; <span style=color:#00f>do</span>
15</span></span><span style=display:flex><span> convert <span style=color:#a31515>&#34;</span>$file<span style=color:#a31515>&#34;</span> -resize $dimensions <span style=color:#a31515>&#34;</span>$file<span style=color:#a31515>&#34;</span> <span style=color:#a31515>&#34;</span><span style=color:#a31515>${</span>file%.*<span style=color:#a31515>}</span><span style=color:#a31515>-thumbnail.jpg&#34;</span>
16</span></span><span style=display:flex><span><span style=color:#00f>done</span>
17</span></span></code></pre></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
18a lock on a Linux NFS server, which turned
19out to be specific to NFS v3 (which I really should have seen coming,
20since it involved NLM and lockd). Finding the NFS v4 client that
21owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
22and Bradley Kuhn, are interacting on the OSI's license-discuss
23list where the're doing
24bad computer history and insisting that a guy Larry Rosen
25coincidentally interviewed for a book years ago is clearly the origin of
26somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
27i2c, plan9
28Another month, another file system.
29Well, if you can’t fix it in software, fix it in hardware (looking at
30you, bme680, we’re not
31done yet). The show must go on, as they say, and I would like my
32experiments to go on.
33So a “new” addition to the environmental sensor family connected to
34the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
35this mortal coil, we are endowed with self-awareness, agency, and free will.
36Each of the 8 billion members of this human race represents a unique person, a
37unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
38My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
391.0 has been released:
40wifi_da-1.0.sit
41(StuffIt 3 archive)
42SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
43This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
44classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
45In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
46Design Goals
47I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
48at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
49catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
50specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
51 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
52 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/cachebusting-in-hugo.html b/public/cachebusting-in-hugo.html
deleted file mode 100755
index 7e2956f..0000000
--- a/public/cachebusting-in-hugo.html
+++ /dev/null
@@ -1,48 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Cache busting in Hugo</title><meta name=description content="{{ $cachebuster := delimit (shuffle (split (md5 &amp;#34;6fab11c6669976d759d2992eff1dd5be&amp;#34;) &amp;#34;&amp;#34; )) &amp;#34;&amp;#34; }}&amp;lt;link rel=&amp;#34;stylesheet&amp;#34; href=&amp;#34;/style."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Cache busting in Hugo</h1><p><cap>note</cap>, May 1, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>{{ $cachebuster := delimit (shuffle (split (md5 &#34;6fab11c6669976d759d2992eff1dd5be&#34;) &#34;&#34; )) &#34;&#34; }}
10</span></span><span style=display:flex><span>
11</span></span><span style=display:flex><span>&lt;link rel=<span style=color:#a31515>&#34;stylesheet&#34;</span> href=<span style=color:#a31515>&#34;/style.css?v={{ $cachebuster }}&#34;</span>&gt;
12</span></span></code></pre><p>This <code>6fab11c6669976d759d2992eff1dd5be</code> can be random string you generate use.
13You can use whatever you want.</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
14a lock on a Linux NFS server, which turned
15out to be specific to NFS v3 (which I really should have seen coming,
16since it involved NLM and lockd). Finding the NFS v4 client that
17owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
18and Bradley Kuhn, are interacting on the OSI's license-discuss
19list where the're doing
20bad computer history and insisting that a guy Larry Rosen
21coincidentally interviewed for a book years ago is clearly the origin of
22somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
23i2c, plan9
24Another month, another file system.
25Well, if you can’t fix it in software, fix it in hardware (looking at
26you, bme680, we’re not
27done yet). The show must go on, as they say, and I would like my
28experiments to go on.
29So a “new” addition to the environmental sensor family connected to
30the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
31this mortal coil, we are endowed with self-awareness, agency, and free will.
32Each of the 8 billion members of this human race represents a unique person, a
33unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
34My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
351.0 has been released:
36wifi_da-1.0.sit
37(StuffIt 3 archive)
38SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
39This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
40classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
41In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
42Design Goals
43I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
44at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
45catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
46specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
47 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
48 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/catv-weechat-config.html b/public/catv-weechat-config.html
deleted file mode 100755
index 95ec19e..0000000
--- a/public/catv-weechat-config.html
+++ /dev/null
@@ -1,51 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>#cat-v on weechat configuration</title><meta name=description content="Set up weechat to connect to #cat-v on oftc."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>#cat-v on weechat configuration</h1><p><cap>note</cap>, May 9, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>Set up weechat to connect to #cat-v on oftc. This applies to
10<a href=https://weechat.org/>weechat</a> but should be similar for other irc clients.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># Install weechat and launch it and execute the following commands.</span>
11</span></span><span style=display:flex><span>
12</span></span><span style=display:flex><span>/server add oftc irc.oftc.net -tls
13</span></span><span style=display:flex><span>/set irc.server.oftc.autoconnect on
14</span></span><span style=display:flex><span>/set irc.server.oftc.autojoin <span style=color:#a31515>&#34;#cat-v&#34;</span>
15</span></span><span style=display:flex><span>/set irc.server.oftc.nicks <span style=color:#a31515>&#34;nick1,nick2,nick3&#34;</span>
16</span></span></code></pre></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
17a lock on a Linux NFS server, which turned
18out to be specific to NFS v3 (which I really should have seen coming,
19since it involved NLM and lockd). Finding the NFS v4 client that
20owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
21and Bradley Kuhn, are interacting on the OSI's license-discuss
22list where the're doing
23bad computer history and insisting that a guy Larry Rosen
24coincidentally interviewed for a book years ago is clearly the origin of
25somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
26i2c, plan9
27Another month, another file system.
28Well, if you can’t fix it in software, fix it in hardware (looking at
29you, bme680, we’re not
30done yet). The show must go on, as they say, and I would like my
31experiments to go on.
32So a “new” addition to the environmental sensor family connected to
33the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
34this mortal coil, we are endowed with self-awareness, agency, and free will.
35Each of the 8 billion members of this human race represents a unique person, a
36unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
37My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
381.0 has been released:
39wifi_da-1.0.sit
40(StuffIt 3 archive)
41SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
42This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
43classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
44In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
45Design Goals
46I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
47at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
48catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
49specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
50 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
51 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/compile-drawterm-on-fedora-38.html b/public/compile-drawterm-on-fedora-38.html
deleted file mode 100755
index c14d3f9..0000000
--- a/public/compile-drawterm-on-fedora-38.html
+++ /dev/null
@@ -1,48 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Compile drawterm on Fedora 38</title><meta name=description content="First install two dependencies:sudo dnf install libX11-devel libXt-develClone the repo and compile it:git clone git://git."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Compile drawterm on Fedora 38</h1><p><cap>note</cap>, Sep 25, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>First install two dependencies:<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>sudo dnf install libX11-devel libXt-devel
10</span></span></code></pre><p>Clone the repo and compile it:<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>git clone git://git.9front.org/plan9front/drawterm
11</span></span><span style=display:flex><span>cd drawterm
12</span></span><span style=display:flex><span>CONF=unix make
13</span></span></code></pre><p>That should produce <code>drawterm</code> binary.</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
14a lock on a Linux NFS server, which turned
15out to be specific to NFS v3 (which I really should have seen coming,
16since it involved NLM and lockd). Finding the NFS v4 client that
17owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
18and Bradley Kuhn, are interacting on the OSI's license-discuss
19list where the're doing
20bad computer history and insisting that a guy Larry Rosen
21coincidentally interviewed for a book years ago is clearly the origin of
22somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
23i2c, plan9
24Another month, another file system.
25Well, if you can’t fix it in software, fix it in hardware (looking at
26you, bme680, we’re not
27done yet). The show must go on, as they say, and I would like my
28experiments to go on.
29So a “new” addition to the environmental sensor family connected to
30the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
31this mortal coil, we are endowed with self-awareness, agency, and free will.
32Each of the 8 billion members of this human race represents a unique person, a
33unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
34My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
351.0 has been released:
36wifi_da-1.0.sit
37(StuffIt 3 archive)
38SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
39This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
40classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
41In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
42Design Goals
43I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
44at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
45catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
46specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
47 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
48 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/convert-mkv.html b/public/convert-mkv.html
deleted file mode 100755
index d18252e..0000000
--- a/public/convert-mkv.html
+++ /dev/null
@@ -1,49 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Convert all MKV files into other formats</title><meta name=description content="You will need ffmpeg installed on your system."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Convert all MKV files into other formats</h1><p><cap>note</cap>, May 14, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>You will need <code>ffmpeg</code> installed on your system. This will convert all MKV files
10into WebM format.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># Convert all MKV files into WebM format.</span>
11</span></span><span style=display:flex><span>find ./ -name <span style=color:#a31515>&#39;*.mkv&#39;</span> -exec bash -c <span style=color:#a31515>&#39;ffmpeg -i &#34;$0&#34; -vcodec libvpx -acodec libvorbis -cpu-used 5 -threads 8 &#34;${0%%.mp4}.webm&#34;&#39;</span> {} <span style=color:#a31515>\;</span>
12</span></span></code></pre><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># Convert all MKV files into MP4 format.</span>
13</span></span><span style=display:flex><span>find ./ -name <span style=color:#a31515>&#39;*.mkv&#39;</span> -exec bash -c <span style=color:#a31515>&#39;ffmpeg -i &#34;$0&#34; c:a copy -c:v copy -cpu-used 5 -threads 8 &#34;${0%%.mp4}.mp4&#34;&#39;</span> {} <span style=color:#a31515>\;</span>
14</span></span></code></pre></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
15a lock on a Linux NFS server, which turned
16out to be specific to NFS v3 (which I really should have seen coming,
17since it involved NLM and lockd). Finding the NFS v4 client that
18owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
19and Bradley Kuhn, are interacting on the OSI's license-discuss
20list where the're doing
21bad computer history and insisting that a guy Larry Rosen
22coincidentally interviewed for a book years ago is clearly the origin of
23somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
24i2c, plan9
25Another month, another file system.
26Well, if you can’t fix it in software, fix it in hardware (looking at
27you, bme680, we’re not
28done yet). The show must go on, as they say, and I would like my
29experiments to go on.
30So a “new” addition to the environmental sensor family connected to
31the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
32this mortal coil, we are endowed with self-awareness, agency, and free will.
33Each of the 8 billion members of this human race represents a unique person, a
34unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
35My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
361.0 has been released:
37wifi_da-1.0.sit
38(StuffIt 3 archive)
39SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
40This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
41classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
42In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
43Design Goals
44I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
45at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
46catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
47specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
48 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
49 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/crafting-stories-in-zed-editor.html b/public/crafting-stories-in-zed-editor.html
deleted file mode 100755
index d7de10c..0000000
--- a/public/crafting-stories-in-zed-editor.html
+++ /dev/null
@@ -1,57 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>From General Zod to Superman - Crafting Stories in Zed Editor</title><meta name=description content="Pretentious title!"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>body{padding:1rem;max-width:700px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px;margin:0 auto}hr{margin-block-start:1.5rem}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}table{max-width:100%;border-collapse:separate;border-spacing:2px;border:1px solid #000;border-left:1px solid #999;border-top:1px solid #999}blockquote{font-style:italic}table thead{background:#eee}ul.list li{padding:.2em 0}ul{line-height:1.4em}td,th{border:1px solid #000;padding:4px;border-right:1px solid #999;border-bottom:1px solid #999;text-align:left}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;background:#fffaf0}code{background:#fffaf0;padding:0 3px;font-size:14px}pre code{line-height:1.3em;background:initial}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{text-align:center}figcaption p{margin:.3em 0 0}img,video,audio{max-width:100%}header{display:flex;flex-direction:row;gap:3rem}nav{display:flex;gap:.75rem}nav.main{flex-grow:1}.pstatus-orange{background:gold}.pstatus-green{background:#9acd32}.pstatus-red{background:#cd5c5c}@media only screen and (max-width:600px){body{padding:15px}header{flex-direction:column;gap:1rem}a{word-wrap:break-word}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=toolbar><a href=/>Home</a>
2<a href=https://git.mitjafelicijan.com/ target=_blank>Git</a>
3<a href=https://files.mitjafelicijan.com/ target=_blank>Files</a>
4<a href=/radio.pls target=_blank>Radio</a>
5<a href=/mitjafelicijan.pgp.pub.txt target=_blank>PGP</a>
6<a href=/curriculum-vitae.html>CV</a>
7<a href=/index.xml target=_blank>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>From General Zod to Superman - Crafting Stories in Zed Editor</h1><p><cap>post</cap>, May 22, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>Pretentious title! Good start! I have nothing to add to this discussion. I just
8like this editor and wanted to write something here that will remind me to use
9it again in a while when/if it becomes available for Linux.<p><strong>TLDR:</strong> I think this code editor is very cool and has a massive potential. I
10hope they don’t mess up with adding a plugin ecosystem to it!<p>Out of morbid curiosity, I started using the <a href=https://zed.dev/>Zed editor</a> on
11my Mac. Zed is a high-performance, multiplayer code editor developed by the
12creators of Atom and Tree-sitter. Written in Rust so it has to be blazingly
13fast! 😊 It's a joke, calm down.<p>Over the past year, I have switched between <a href=https://helix-editor.com/>Helix
14editor</a> and <a href=https://code.visualstudio.com/>VS
15Code</a>, but for the last couple of months, I have
16been using Helix exclusively.<p>I've been genuinely impressed by Zed. When you open a file, it automatically
17detects its type and downloads the corresponding <a href=https://en.wikipedia.org/wiki/Language_Server_Protocol>LSP (language
18server)</a>. The list of
19supported languages is not extensive, but it's still impressive. It's a great
20example of how to create a product that stays out of your way.<figure><img loading="lazy" loading="lazy" loading="lazy" loading="lazy" loading="lazy" loading="lazy" loading="lazy" loading="lazy" src="/posts/zed/zed-1.png?style=bigimg" alt="Zed editor"><figcaption><p>C code on a light theme.</figcaption></figure><p>For C development it downloaded <a href=https://clangd.llvm.org/>clangd</a> and setting
21up missing dependencies in code was rather easy. For this project I use
22<a href=https://www.libsdl.org/>SDL2</a> for rendering terminal emulator. It’s a hobby
23project, don’t worry about it.<p>If you are going to give this a try and you are using C, I suggest checking two
24files in the root of your project folder. If you don't have them, create them.<p><strong>compile_flags.txt</strong><pre><code>-I/opt/homebrew/include
25-I/opt/homebrew/include/SDL2
26</code></pre><p>Easy way of checking what the appropriate includes for a specific library is to
27use <code>pkg-config</code> and in my case <code>pkg-config SDL2 --cflags-only-I</code>. But this is
28nothing new to C/C++ devs. Just a noter for people who are using Visual Studio.<p><strong>.clang-format</strong><pre><code>ColumnLimit: 220
29BasedOnStyle: Mozilla
30</code></pre><p>I prefer Mozilla coding style for C so you can set that up.<p>They really have something special here. Although there is no version available
31for Linux yet, I will stick to Helix. This impressive piece of engineering is,
32above all, an amazing example of craftsmanship.<p>They have a bunch of amazing integrated functionalities like live desktop
33sharing, code sharing in a live coding session. There is a lot of pretentious
34marketing speak there but the product is still amazing!<p>For me the speed and the simplicity of the product was the most impressive
35thing. You get that: it just works feeling. A rare thing in 2023.<figure><img loading="lazy" loading="lazy" loading="lazy" loading="lazy" loading="lazy" loading="lazy" loading="lazy" loading="lazy" src="/posts/zed/zed-2.png?style=bigimg" alt="Zed editor"></figure><p>They also managed to add <a href=https://github.com/features/copilot>Github Copilot</a>
36in a non obtrusive way. To me, everything feels very intentional and
37specifically selected. It's minimal yet maximally effective.<p><video src=https://zed.dev/img/post/copilot/copilot-demo.webm autoplay loop></video><p>It is a perfect balance between VS Code, Jetbrains IDE’s and something like VIM
38or Helix.<p>I just hope they <strong>DON’T</strong> add plugin support and keep it like it is. They as a
39vendor should add stuff to it with great deliberation and thought. And this way
40the product will stay fast and focused. That’s my two cents.<p>Amazing job!</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://chotrin.org/writing/2023-09-20.html target=_blank rel=noopener>fun with dithering.</a><div>I wrote about dithering my images using the NES palette. — <a href=https://chotrin.org>chötrin's wiki.</a><li><a href=https://drewdevault.com/2023/09/17/Hyprland-toxicity.html target=_blank rel=noopener>Hyprland is a toxic community</a><div>Hyprland is an open source Wayland compositor based on wlroots, a
41project I started back in 2017 to make it easier to build good Wayland
42compositors. It’s a project w… — <a href=https://drewdevault.com>Drew DeVault's blog</a><li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. Ther… — <a href=https://neil.computer/>Neil Panchal</a><li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up … — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><li><a href=https://solar.lowtechmagazine.com/2023/08/direct-solar-power-off-grid-without-batteries/ target=_blank rel=noopener>Direct Solar Power: Off-Grid Without Batteries</a><div>Image: a laptop running on direct solar power. Photo: Marie Verdeil.
43Conventional solar installations do not question our dependence on fossil fuels and the energy… — <a href=https://solar.lowtechmagazine.com/posts/>LOW←TECH MAGAZINE English</a><li><a href=https://mirzapandzo.com/control-what-openais-gptbot-and-other-ai-bots-crawl-on-your-website-via-robots-txt-file target=_blank rel=noopener>Control what OpenAI's GPTBot and other AI bots crawl on your website via robots.txt file</a><div>You can control what OpenAI's GPTBot and other AI bots crawls on your website via the site's robots.txt file — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><li><a href=https://jcs.org/2023/09/20/vcfmw target=_blank rel=noopener>Video: C Programming on System 6 - VCF Midwest, Wi-Fi DA</a><div>I attended the
44Vintage Computer Festival Midwest 18
45and made some things.
46Your browser doesn't seem to support HTML video.
47You can download the video in
48… — <a href=https://jcs.org/>joshua stein</a><li><a href="http://offbeatpursuit.com:80/blog/?id=24" target=_blank rel=noopener>Printf debugging</a><div>tags:
49plan9
50There’s no shame in that. Yes, there is documentation, code to be
51read, and debuggers to be used. But sometimes you just need to “see”
52what is happening.
53So… — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a></ul><p><a href=https://git.sr.ht/~sircmpwn/openring>Generated with openring.</a></section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
54at <a href=mailto:m@mitjafelicijan.com>m@mitjafelicijan.com</a> or
55catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under
56the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless specified
57otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer> \ No newline at end of file
diff --git a/public/create-placeholder-images-with-sharp.html b/public/create-placeholder-images-with-sharp.html
deleted file mode 100755
index b30ee51..0000000
--- a/public/create-placeholder-images-with-sharp.html
+++ /dev/null
@@ -1,111 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Create placeholder images with sharp Node.js image processing library</title><meta name=description content="I have been searching for a solution to pre-generate some placeholder images forimage server I needed to develop that resizes images on S3."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Create placeholder images with sharp Node.js image processing library</h1><p><cap>post</cap>, Mar 27, 2020 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>I have been searching for a solution to pre-generate some placeholder images for
10image server I needed to develop that resizes images on S3. I though this would
11be a 15min job and quickly found out how very mistaken I was.<p>Even though Node.js is not really the best way to do this kind of things (surely
12something written in C or Rust or even Golang would be the correct way to do
13this but we didn't need the speed in our case) I found an excellent library
14<a href=https://github.com/lovell/sharp>sharp - High performance Node.js image
15processing</a>.<p>Getting things running was a breeze.<h2 id=fetch-image-from-s3-and-save-resized>Fetch image from S3 and save resized</h2><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>const</span> sharp = require(<span style=color:#a31515>&#39;sharp&#39;</span>);
16</span></span><span style=display:flex><span><span style=color:#00f>const</span> aws = require(<span style=color:#a31515>&#39;aws-sdk&#39;</span>);
17</span></span><span style=display:flex><span>
18</span></span><span style=display:flex><span><span style=color:#00f>const</span> x,y = 100;
19</span></span><span style=display:flex><span><span style=color:#00f>const</span> s3 = <span style=color:#00f>new</span> aws.S3({});
20</span></span><span style=display:flex><span>
21</span></span><span style=display:flex><span>aws.config.update({
22</span></span><span style=display:flex><span> secretAccessKey: <span style=color:#a31515>&#39;secretAccessKey&#39;</span>,
23</span></span><span style=display:flex><span> accessKeyId: <span style=color:#a31515>&#39;accessKeyId&#39;</span>,
24</span></span><span style=display:flex><span> region: <span style=color:#a31515>&#39;region&#39;</span>
25</span></span><span style=display:flex><span>});
26</span></span><span style=display:flex><span>
27</span></span><span style=display:flex><span><span style=color:#00f>const</span> originalImage = <span style=color:#00f>await</span> s3.getObject({
28</span></span><span style=display:flex><span> Bucket: <span style=color:#a31515>&#39;some-bucket-name&#39;</span>,
29</span></span><span style=display:flex><span> Key: <span style=color:#a31515>&#39;image.jpg&#39;</span>,
30</span></span><span style=display:flex><span>}).promise();
31</span></span><span style=display:flex><span>
32</span></span><span style=display:flex><span><span style=color:#00f>const</span> resizedImage = <span style=color:#00f>await</span> sharp(originalImage.Body)
33</span></span><span style=display:flex><span> .resize(x, y)
34</span></span><span style=display:flex><span> .jpeg({ progressive: <span style=color:#00f>true</span> })
35</span></span><span style=display:flex><span> .toBuffer();
36</span></span><span style=display:flex><span>
37</span></span><span style=display:flex><span>s3.putObject({
38</span></span><span style=display:flex><span> Bucket: <span style=color:#a31515>&#39;some-bucket-name&#39;</span>,
39</span></span><span style=display:flex><span> Key: <span style=color:#a31515>`optimized/</span><span style=color:#a31515>${</span>x<span style=color:#a31515>}</span><span style=color:#a31515>x</span><span style=color:#a31515>${</span>y<span style=color:#a31515>}</span><span style=color:#a31515>/image.jpg`</span>,
40</span></span><span style=display:flex><span> Body: resizedImage,
41</span></span><span style=display:flex><span> ContentType: <span style=color:#a31515>&#39;image/jpeg&#39;</span>,
42</span></span><span style=display:flex><span> ACL: <span style=color:#a31515>&#39;public-read&#39;</span>
43</span></span><span style=display:flex><span>}).promise();
44</span></span></code></pre><p>All this code was wrapped inside a web service with some additional security
45checks and defensive coding to detect if key is missing on S3.<p>And at that point I needed to return placeholder images as a response in case
46key is missing or x,y are not allowed by the server etc. I could have created
47PNG in Gimp and just serve them but I wanted to respect aspect ratio and I
48didn't want to return some mangled images.<blockquote><p>Main problem with finding a clean solution I could copy and paste and change a
49bit was a task. API is changing constantly and there weren't clear examples or
50I was unable to find them.</blockquote><h2 id=generating-placeholder-images-using-svg>Generating placeholder images using SVG</h2><p>What I ended up was using SVG to generate text and created image with sharp and
51used composition to combine both layers. Response returned by this function is a
52buffer you can use to either upload to S3 or save to local file.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>const</span> generatePlaceholderImageWithText = <span style=color:#00f>async</span> (width, height, message) =&gt; {
53</span></span><span style=display:flex><span> <span style=color:#00f>const</span> overlay = <span style=color:#a31515>`&lt;svg width=&#34;</span><span style=color:#a31515>${</span>width - 20<span style=color:#a31515>}</span><span style=color:#a31515>&#34; height=&#34;</span><span style=color:#a31515>${</span>height - 20<span style=color:#a31515>}</span><span style=color:#a31515>&#34;&gt;
54</span></span></span><span style=display:flex><span><span style=color:#a31515> &lt;text x=&#34;50%&#34; y=&#34;50%&#34; font-family=&#34;sans-serif&#34; font-size=&#34;16&#34; text-anchor=&#34;middle&#34;&gt;</span><span style=color:#a31515>${</span>message<span style=color:#a31515>}</span><span style=color:#a31515>&lt;/text&gt;
55</span></span></span><span style=display:flex><span><span style=color:#a31515> &lt;/svg&gt;`</span>;
56</span></span><span style=display:flex><span>
57</span></span><span style=display:flex><span> <span style=color:#00f>return</span> <span style=color:#00f>await</span> sharp({
58</span></span><span style=display:flex><span> create: {
59</span></span><span style=display:flex><span> width: width,
60</span></span><span style=display:flex><span> height: height,
61</span></span><span style=display:flex><span> channels: 4,
62</span></span><span style=display:flex><span> background: { r: 230, g: 230, b: 230, alpha: 1 }
63</span></span><span style=display:flex><span> }
64</span></span><span style=display:flex><span> })
65</span></span><span style=display:flex><span> .composite([{
66</span></span><span style=display:flex><span> input: Buffer.from(overlay),
67</span></span><span style=display:flex><span> gravity: <span style=color:#a31515>&#39;center&#39;</span>,
68</span></span><span style=display:flex><span> }])
69</span></span><span style=display:flex><span> .jpeg()
70</span></span><span style=display:flex><span> .toBuffer();
71</span></span><span style=display:flex><span>}
72</span></span></code></pre><p>That is about it. Nothing more to it. You can change the color of the image by
73changing <code>background</code> and if you want to change text styling you can adapt SVG
74to your needs.<blockquote><p>Also be careful about the length of the text. This function positions text at
75the center and adds <code>20px</code> padding on all sides. If text is longer than the
76image it will get cut.</blockquote></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
77a lock on a Linux NFS server, which turned
78out to be specific to NFS v3 (which I really should have seen coming,
79since it involved NLM and lockd). Finding the NFS v4 client that
80owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
81and Bradley Kuhn, are interacting on the OSI's license-discuss
82list where the're doing
83bad computer history and insisting that a guy Larry Rosen
84coincidentally interviewed for a book years ago is clearly the origin of
85somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
86i2c, plan9
87Another month, another file system.
88Well, if you can’t fix it in software, fix it in hardware (looking at
89you, bme680, we’re not
90done yet). The show must go on, as they say, and I would like my
91experiments to go on.
92So a “new” addition to the environmental sensor family connected to
93the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
94this mortal coil, we are endowed with self-awareness, agency, and free will.
95Each of the 8 billion members of this human race represents a unique person, a
96unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
97My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
981.0 has been released:
99wifi_da-1.0.sit
100(StuffIt 3 archive)
101SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
102This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
103classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
104In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
105Design Goals
106I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
107at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
108catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
109specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
110 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
111 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/cronjobs-github-with-actions.html b/public/cronjobs-github-with-actions.html
deleted file mode 100755
index acd0a52..0000000
--- a/public/cronjobs-github-with-actions.html
+++ /dev/null
@@ -1,60 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Cronjobs on Github with Github Actions</title><meta name=description content="In the root of your repository create a folder ."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Cronjobs on Github with Github Actions</h1><p><cap>note</cap>, May 27, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>In the root of your repository create a folder <code>.github/workflows</code> and in that
10folder create a file a file <code>cron.yaml</code>. This file can be named whatever you
11wish. But it has to be a <code>yaml</code> file.<p>File below (<code>.github/workflows/cron.yaml</code>) describes an action that will trigger
12every six hours and it will curl example.com.<p>However. Be sure that you have enough credits. Free account is not that generous
13with the minutes they give you for free. Check more about GitHub Actions usage
14on their website <a href=https://docs.github.com/en/actions>https://docs.github.com/en/actions</a>.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># .github/workflows/cron.yaml</span>
15</span></span><span style=display:flex><span>name: Do a curl every 6 hours
16</span></span><span style=display:flex><span>on:
17</span></span><span style=display:flex><span> schedule:
18</span></span><span style=display:flex><span> - cron: <span style=color:#a31515>&#39;0 */6 * * *&#39;</span>
19</span></span><span style=display:flex><span>jobs:
20</span></span><span style=display:flex><span> cron:
21</span></span><span style=display:flex><span> runs-on: ubuntu-latest
22</span></span><span style=display:flex><span> steps:
23</span></span><span style=display:flex><span> - name: Call some url
24</span></span><span style=display:flex><span> run: curl &#39;https://example.com&#39;
25</span></span></code></pre></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
26a lock on a Linux NFS server, which turned
27out to be specific to NFS v3 (which I really should have seen coming,
28since it involved NLM and lockd). Finding the NFS v4 client that
29owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
30and Bradley Kuhn, are interacting on the OSI's license-discuss
31list where the're doing
32bad computer history and insisting that a guy Larry Rosen
33coincidentally interviewed for a book years ago is clearly the origin of
34somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
35i2c, plan9
36Another month, another file system.
37Well, if you can’t fix it in software, fix it in hardware (looking at
38you, bme680, we’re not
39done yet). The show must go on, as they say, and I would like my
40experiments to go on.
41So a “new” addition to the environmental sensor family connected to
42the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
43this mortal coil, we are endowed with self-awareness, agency, and free will.
44Each of the 8 billion members of this human race represents a unique person, a
45unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
46My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
471.0 has been released:
48wifi_da-1.0.sit
49(StuffIt 3 archive)
50SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
51This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
52classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
53In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
54Design Goals
55I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
56at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
57catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
58specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
59 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
60 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/curriculum-vitae.html b/public/curriculum-vitae.html
deleted file mode 100755
index d035515..0000000
--- a/public/curriculum-vitae.html
+++ /dev/null
@@ -1,54 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Curriculum Vitae</title><meta name=description content="Mitja FelicijanEmail me at m@mitjafelicijan."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><div><h1>Curriculum Vitae</h1><div><style>img{width:auto!important;left:initial!important;margin:initial!important;border:0!important}</style><div class=cv-picture><figure><img src=/posts/cv/avatar.gif alt></figure></div><script>
10 window.addEventListener('load', async () => {
11 // flip CV image on mouse over
12 const cvImage = document.querySelector('.cv-picture img');
13 if (cvImage) {
14 setInterval(() => {
15 cvImage.style.transform = cvImage.style.transform === 'scaleX(1)' ? 'scaleX(-1)' : 'scaleX(1)';
16 }, 1000);
17 }
18 });
19</script><p><strong>Mitja Felicijan</strong><p>Email me at <em><a href="mailto:m@mitjafelicijan.com?subject=Website+CV+Contact">m@mitjafelicijan.com</a></em><h2 id=technical-experience>Technical experience</h2><ul><li><strong>Key languages:</strong> C, Golang, Lua, Python, Bash.<li><strong>Platforms:</strong> GNU/Linux, macOS.<li><strong>Interests:</strong> Zigbee, KNX, Modbus, Machine to Machine, Embedded systems, Operating systems, Distributed systems, IOT, RDBMS, Algorithms, Database engine design, SQL, NoSQL, NewSQL, Big data analytics, Machine learning, Prediction algorithms, Realtime analytics, Systems automation, Natural language processing, Bioinformatics, Game development.</ul><h2 id=major-projects>Major projects</h2><ul><li>SMS marketing system (2007)<li>Yacht management software (2008)<li>Smart Home Gateway (2009)<li>Moxa UPort 1130 USB to RS485 Universal Linux driver (2009)<li>Remote management of electricity meter (2009)<li>Remote management of blood pressure monitor (2010)<li>Infomat automation system (2010)<li>GPS Tourist - GIS Software (2011)<li>Minimal GNU/Linux distribution for embedded platforms (2011)<li>Digital Jukebox system (2012)<li>NanoCloudLogger - Machine to Machine (2012)<li>Street Lightning System (2012)<li>Smart cabins with hardware sensor management (2013)<li>Contextual advertising server (2015)<li>Network accessible database engine for caching and in-memory storage (2016)<li>Tick database engine specifically designed for storing and processing large amount of sensor data with high write throughput (2016)<li>Wireless industrial lighting management system - hardware and software (2016)<li>Minimal configuration reverse proxy (2017)<li>Industrial IOT platform for deployment on on-premise (2018)<li>Custom Platform as a service based on Docker Swarm (2018)<li>Toolkit for encoding binary data into DNA sequence (2019)<li>Minimal configuration reverse proxy with load balancing and rate limiting (2019)<li>E-ink conference room occupancy display, hardware and software solution (2019)<li>Caching module for Apache web server (2022)<li>Task runner for the command line (2022)<li>World of Warcraft Tweaks and Enhancements Addon (2023)</ul><h2 id=employment-history>Employment history</h2><ul><li>Freelancer (2001 – Present)<li>Software developer at Mobinia (2005 – 2007)<li>Senior Software Engineer at Milk (2007 – 2009)<li>Co-Founder of UTS (2009 – 2015)<li>Senior Software Engineer at TSmedia (2015 - 2017)<li>Senior Software Engineer at Renderspace (2017 - 2019)<li>Senior Software Engineer at Digg (2019 - Present)</ul><h2 id=awards>Awards</h2><ul><li>Regional Award for Innovation by Chamber of Commerce and Industry of Slovenia for project Intelligent system management and regulation of Street Lighting, 2010<li>National Award for Innovation by Chamber of Commerce and Industry of Slovenia for project Intelligent system management and regulation of Street Lighting, 2010</ul><h2 id=key-responsibilities>Key responsibilities</h2><ul><li>Embedded platform development.<li>Hardware design and driver development.<li>Designing, developing and testing systems.<li>Implementation of the systems.<li>Writing and maintaining user and technical documents.<li>Development and maintenance of the project.<li>Code revision, testing and output.<li>Work on the enhancement suggested by the customers and fixes the bugs reported.</ul></div></div></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
20a lock on a Linux NFS server, which turned
21out to be specific to NFS v3 (which I really should have seen coming,
22since it involved NLM and lockd). Finding the NFS v4 client that
23owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
24and Bradley Kuhn, are interacting on the OSI's license-discuss
25list where the're doing
26bad computer history and insisting that a guy Larry Rosen
27coincidentally interviewed for a book years ago is clearly the origin of
28somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
29i2c, plan9
30Another month, another file system.
31Well, if you can’t fix it in software, fix it in hardware (looking at
32you, bme680, we’re not
33done yet). The show must go on, as they say, and I would like my
34experiments to go on.
35So a “new” addition to the environmental sensor family connected to
36the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
37this mortal coil, we are endowed with self-awareness, agency, and free will.
38Each of the 8 billion members of this human race represents a unique person, a
39unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
40My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
411.0 has been released:
42wifi_da-1.0.sit
43(StuffIt 3 archive)
44SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
45This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
46classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
47In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
48Design Goals
49I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
50at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
51catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
52specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
53 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
54 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/dcss-new-player-guide.html b/public/dcss-new-player-guide.html
deleted file mode 100755
index 2d640cb..0000000
--- a/public/dcss-new-player-guide.html
+++ /dev/null
@@ -1,76 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Dungeon Crawl Stone Soup - New player guide</title><meta name=description content="An amazing game deserves an amazing guide."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Dungeon Crawl Stone Soup - New player guide</h1><p><cap>note</cap>, May 25, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>An amazing game deserves an amazing guide. All this material can be find in some
10form on another on <a href=https://github.com/crawl/crawl>craw's</a> official repository.<ul><li><a href=/notes/dcss-quickstart.pdf>DCSS Quickstart</a> - Very short introduction to the
11game<li><a href=/notes/dcss_manual.pdf>DCSS Manual</a> - Extensive manual about the game</ul><figure><img src=/notes/dcss.jpg alt="Dungeon Crawl Stone Soup"></figure><p><strong>Movement and Exploration</strong><ul><li>You can move around with the numpad (try numlock on and off), vi-keys, or
12clicking with the mouse. Arrow keys work, though you can't move diagonally
13with them. Pressing Shift and a direction will move until you see/hit
14something.<li>Pressing <code>></code> will take you down a staircase, and <code>&lt;</code> to go up a staircase.<li>You can open doors by walking into them, and close them with <code>C</code>.<li>You can autoexplore by pressing <code>o</code>.<li>You can re-view recent messages with <code>Ctrl-p</code>.</ul><p><strong>Monsters and Combat</strong><ul><li>You can pick up items with <code>,</code> or <code>g</code>.<li>Wield weapons with <code>w</code>. Weapons have different stats.<ul><li>(You may also engage in Unarmed Combat, though it isn't very effective when
15untrained).</ul><li>Attack monsters in melee by walking in their direction (or with
16Ctrl-direction).<li>You can wait with <code>.</code> or <code>s</code>, passing your turn - such as to get monsters into
17a corridor with you.<li>You can rest with <code>5</code>, waiting until you are fully healed, or something
18noteworthy happens.<li>Either mouseover and rightclick, or use <code>x</code> then <code>v</code> on the monster to examine
19monsters. Monsters with a red border are 'dangerous' relative to your current
20XP level (XL).<li>Quiver (often ranged) actions for further use with <code>Q</code>.<li>You can fire ranged weapons manually with <code>f</code>, or auto-target your quiver with
21<code>p</code> or <code>Shift-Tab</code>. Throwing weapons can be thrown immediately, while
22launchers (like bows) need to be wielded first.</ul><p><strong>Items and Inventory</strong><ul><li>View your inventory by pressing <code>i</code>. Most item related commands can also be
23done with this menu.<li>You can wear amour with <code>W;</code> amour gives <code>AC</code>, while heavier body armour
24reduces <code>EV</code>.<li>Autoexplore will automatically pick up useful items, such as potions and
25scrolls, if you aren't in danger.<li>You can read scrolls with <code>r</code> and drink ("quaff") potions with <code>q</code>.<li>Equipment items may have brands, with special properties. Branded equipment is
26blue when unidentified.<li>Equipment items may be artifacts, often with unique properties, and are
27unmodifiable. They are written in white.<li>You can evoke wands with <code>V</code>.<li>You can put on jewelry with <code>P</code>, and remove it with <code>R</code>.<li>Gold is used in shops, which can be interacted with by either <code>></code> or <code>&lt;</code>.</ul><p><strong>Magic and Spellcasting</strong><ul><li>Once you find a spellbook, you can memorize spells with <code>M</code>.<li>You need to be the same XL as the spell's spell level in order to learn it, in
28addition to training magical skill (to lower failure rate).<li>Cast spells by pressing <code>z</code>, then the letter assigned to the spell. You may
29also Quiver a spell and then use it like a ranged weapon (with Shift-Tab).<li>You can view your memorized spells by pressing <code>I</code> (capital-i) or <code>z</code>.<li>Like HP, you can recover MP by resting (with 5).<li>Many spells can be positioned more effectively, or combined with other spells,
30in order to get (more effective) use out of them.<li>Heavier body amour and shields hamper spellcasting.</ul><p><strong>Gods and Divine Abilities</strong><ul><li>You may look at a god's overview by praying at their altar (with <code>></code> or <code>&lt;</code>).
31After praying, you can worship the god by pressing Enter afterwards.<li>Gods all have unique features about them. Trog, the god of the tutorial, is
32also the god of rage and bloodshed, and so despises spellcasting.<li>Gods like and dislike different things. Most gods either like killing things
33(like Trog) or exploring new areas (like Elyvilon), rewarding you piety
34(divine favor) for doing so.<li>You should learn to use and even rely on divine abilities often, as they are
35usually very strong. Trog's Berserk gives you 1.5x health, 1.5x speed (to all
36valid actions), and a big damage boost. Note that Berserk prevents most
37actions other than move and melee attack, and runs out very quickly if you
38aren't attacking. And after berserk ends, you are slowed down and can't
39berserk again for a short time.<li>In addition, the vast majority of abilities consume piety in the process.
40Regardless, this ability is very cheap, and the benefits are incredible, so
41don't hold back!<li>Pressing <code>^</code> will let you view your current god, abilities, and piety.</ul></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
42a lock on a Linux NFS server, which turned
43out to be specific to NFS v3 (which I really should have seen coming,
44since it involved NLM and lockd). Finding the NFS v4 client that
45owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
46and Bradley Kuhn, are interacting on the OSI's license-discuss
47list where the're doing
48bad computer history and insisting that a guy Larry Rosen
49coincidentally interviewed for a book years ago is clearly the origin of
50somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
51i2c, plan9
52Another month, another file system.
53Well, if you can’t fix it in software, fix it in hardware (looking at
54you, bme680, we’re not
55done yet). The show must go on, as they say, and I would like my
56experiments to go on.
57So a “new” addition to the environmental sensor family connected to
58the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
59this mortal coil, we are endowed with self-awareness, agency, and free will.
60Each of the 8 billion members of this human race represents a unique person, a
61unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
62My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
631.0 has been released:
64wifi_da-1.0.sit
65(StuffIt 3 archive)
66SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
67This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
68classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
69In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
70Design Goals
71I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
72at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
73catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
74specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
75 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
76 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/dcss-on-4k-display.html b/public/dcss-on-4k-display.html
deleted file mode 100755
index 06aa80b..0000000
--- a/public/dcss-on-4k-display.html
+++ /dev/null
@@ -1,55 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Make DCSS playable on 4k displays</title><meta name=description content="Dungeon Crawl Stone Soup has a a very small font by default."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Make DCSS playable on 4k displays</h1><p><cap>note</cap>, May 27, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>Dungeon Crawl Stone Soup has a a very small font by default. On a 4k display, it
10is barely readable. This is how I made it playable.<p>Make a file <code>~/.crawlrc</code> with the following content:<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># Adjust the sizes to your liking.</span>
11</span></span><span style=display:flex><span>
12</span></span><span style=display:flex><span>tile_font_crt_size = <span style=color:#a31515>32</span>
13</span></span><span style=display:flex><span>tile_font_stat_size = <span style=color:#a31515>32</span>
14</span></span><span style=display:flex><span>tile_font_msg_size = <span style=color:#a31515>32</span>
15</span></span><span style=display:flex><span>tile_font_tip_size = <span style=color:#a31515>32</span>
16</span></span><span style=display:flex><span>tile_font_lbl_size = <span style=color:#a31515>32</span>
17</span></span><span style=display:flex><span>tile_sidebar_pixels = <span style=color:#a31515>64</span>
18</span></span></code></pre><p>To zoom in and out in viewport, press <code>Ctrl+</code> and <code>Ctrl-</code> respectively.<p>All the possible options are documented in the <a href=https://github.com/crawl/crawl/blob/master/crawl-ref/docs/options_guide.txt>Dungeon Crawl Stone Soup Options
19Guide</a>
20file.</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
21a lock on a Linux NFS server, which turned
22out to be specific to NFS v3 (which I really should have seen coming,
23since it involved NLM and lockd). Finding the NFS v4 client that
24owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
25and Bradley Kuhn, are interacting on the OSI's license-discuss
26list where the're doing
27bad computer history and insisting that a guy Larry Rosen
28coincidentally interviewed for a book years ago is clearly the origin of
29somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
30i2c, plan9
31Another month, another file system.
32Well, if you can’t fix it in software, fix it in hardware (looking at
33you, bme680, we’re not
34done yet). The show must go on, as they say, and I would like my
35experiments to go on.
36So a “new” addition to the environmental sensor family connected to
37the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
38this mortal coil, we are endowed with self-awareness, agency, and free will.
39Each of the 8 billion members of this human race represents a unique person, a
40unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
41My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
421.0 has been released:
43wifi_da-1.0.sit
44(StuffIt 3 archive)
45SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
46This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
47classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
48In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
49Design Goals
50I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
51at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
52catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
53specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
54 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
55 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/debian-based-riced-up-distribution-for-developers-and-devops-folks.html b/public/debian-based-riced-up-distribution-for-developers-and-devops-folks.html
deleted file mode 100755
index 1fd3064..0000000
--- a/public/debian-based-riced-up-distribution-for-developers-and-devops-folks.html
+++ /dev/null
@@ -1,158 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Debian based riced up distribution for Developers and DevOps folks</title><meta name=description content="IntroductionI have been using Ubuntu for quite a longtime now."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Debian based riced up distribution for Developers and DevOps folks</h1><p><cap>post</cap>, Dec 3, 2021 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><h2 id=introduction>Introduction</h2><p>I have been using <a href=https://ubuntu.com/>Ubuntu</a> for quite a longtime now. I have
10used <a href=https://www.debian.org/>Debian</a> in the past and
11<a href=https://manjaro.org/>Manjaro</a>. Also had <a href=https://archlinux.org/>Arch</a> for
12some time and even ran <a href=https://www.gentoo.org/>Gentoo</a> way back.<p>What I learned from all this is that I prefer running a bit older versions and
13having them be stable than run bleeding edge rolling release. For that reason, I
14stuck with Ubuntu for a couple of years now. I am also at a point in my life
15where I just don't care what is cool or hip anymore. I just want a stable system
16that doesn't get in my way.<p>During all this, I noticed that these distributions were getting very bloated
17and a lot of software got included that I usually uninstall on fresh
18installation. Maybe this is my OCD speaking, but why do I have to give fresh
19installation min 1 GB of ram out of the box just to have a blank screen in front
20of me? I get it, there are many things included in the distro to make my life
21easier. I understand. But at this point I have a feeling that modern Linux
22distributions are becoming similar to <a href=https://devhumor.com/content/uploads/images/August2017/node-modules.jpg>Node.js project with
23node_modules</a>.
24Just a crazy number of packages serving very little or no purpose, just
25supporting other software.<p>I felt I needed a fresh start. To start over with something minimal and clean.
26Something that would put a little more joy into using a computer again.<p>For the first version, I wanted to target the following machines I have at home
27that I want this thing to work on.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># My main stationary work machine</span>
28</span></span><span style=display:flex><span>Resolution: 3840x1080 (Super Ultrawide Monitor 32:9)
29</span></span><span style=display:flex><span>CPU: Intel i7-8700 (12) @ 4.600GHz
30</span></span><span style=display:flex><span>GPU: AMD ATI Radeon RX 470/480/570/570X/580/580X/590
31</span></span><span style=display:flex><span>Memory: 32020MiB
32</span></span></code></pre><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># Thinkpad x220 for testing things and goofing around</span>
33</span></span><span style=display:flex><span>Resolution: 1366x768
34</span></span><span style=display:flex><span>CPU: Intel i5-2520M (4) @ 3.200GHz
35</span></span><span style=display:flex><span>GPU: Intel 2nd Generation Core Processor Family
36</span></span><span style=display:flex><span>Memory: 15891MiB
37</span></span></code></pre><h2 id=how-should-i-approach-this>How should I approach this?</h2><p>I knew I wanted to use <a href=https://www.debian.org/CD/netinst/>minimal Debian netinst</a> for the base to give myself a head
38start. No reason to go through changing the installer and also testing all that
39behemoth of a thing. So, some sort of ricing was the only logical option to get
40this thing of the grounds somewhat quickly.<blockquote><p><strong>What is ricing anyway?</strong>
41The term “RICE” stands for Race Inspired Cosmetic Enhancement. A group of
42people (could be one, idk) decided to see if they could tweak their own
43distros like they/others did their cars. This gave rise to a community of
44Linux/Unix enthusiasts trying to make their distros look cooler and better
45than others... For more information, read this article
46<a href=https://pesos.github.io/2020/07/14/what-is-ricing.html>What in the world is ricing!?</a>.</blockquote><p>I didn't want this to just be a set of config files for theming purpose. I
47wanted this to include a set of pre-installed tools and services that are being
48used all the time by a modern developer. Theming is just a tiny part of it.
49Fonts being applied across the distro and things like that.<p>First, I choose terminal installer and left it to load additional components.
50Avoid using graphical installer in this case.<figure><img src=/posts/dfd-rice/install-00.png alt></figure><p>After that I selected hostname and created a normal user and set password for
51that user and root user and choose guided mode for disk partitioning.<figure><img src=/posts/dfd-rice/install-01.png alt></figure><p>I left it run to install all the things required for the base system and opted
52out of scanning additional media for use by the package manager. Those will be
53downloaded from the internet during installation.<figure><img src=/posts/dfd-rice/install-02.png alt></figure><p>I opted out of the popularity contest, and <strong>now comes the important part</strong>.
54Uncheck all the boxes in Software selection and only leave 'standard system
55utilities'. I also left an SSH server, so I was able to log in to the machine
56from my main PC.<figure><img src=/posts/dfd-rice/install-03.png alt></figure><p>At this point, I installed GRUB bootloader on the disk where I installed the
57system.<figure><img src=/posts/dfd-rice/install-04.png alt></figure><p>That concluded the installation of base Debian and after restarting the computer
58I was prompted with the login screen.<figure><img src=/posts/dfd-rice/install-05.png alt></figure><p>Now that I had the base installation, it was time to choose what software do I
59want to include in this so-called distribution. I wanted out of the box
60developer experience, so I had plenty to choose.<p>Let's not waste time and go through the list.<h2 id=desktop-environments>Desktop environments</h2><p>I have been using <a href=https://www.gnome.org/>Gnome</a> for my whole Linux life. From
61version 2 forward. It's been quite a ride. I hated version 3 when it came out
62and replaced version 2. But I got used to it. And now with version 40+ they also
63made couple of changes which I found both frustrating and presently surprised.<p>The amount of vertical space you loose because of the beefy title bars on
64windows is ridiculous. And then in case of
65<a href=https://gnunn1.github.io/tilix-web/>Tilix</a> you also have tabs, and you are
66100px deep. Vertical space is one of the most important things for a
67developer. The more real estate you have, the more code you can have in a
68viewport.<p>But on the other hand, I still love how Gnome feels and looks. I gotta give them
69that. They really are trying to make Gnome feel unified and modern.<p>Regardless of all the nice things Gnome has, I was looking at the tiling window
70managers for some time, but never had the nerve to actually go with it. But now
71was the ideal time to give it a go. No guts, no glory kind of a thing.<p>One of the requirements for me was easy custom layouts because I use a really
72strange monitor with aspect ratio of 32:9. So relying on included layouts most
73of them have is a non-starter.<p>What I was doing in Gnome was having windows in a layout like the diagram
74below. This is my common practice. And if you look at it you can clearly see I
75was replicating tiling window manager setup in Gnome.<figure><img src=/posts/dfd-rice/layout.png alt></figure><p>That made me look into a bunch of tiling window managers and then tested them
76out. Candidates I was looking at were:<ul><li><a href=https://i3wm.org/>i3</a><li><a href=https://github.com/baskerville/bspwm>bspwm</a><li><a href=https://awesomewm.org/index.html>awesome</a><li><a href=https://xmonad.org/>XMonad</a><li><a href=https://swaywm.org/>sway</a><li><a href=http://www.qtile.org/>Qtile</a><li><a href=https://dwm.suckless.org/>dwm</a></ul><p>You can also check article <a href=https://www.tecmint.com/best-tiling-window-managers-for-linux/>13 Best Tiling Window Managers for
77Linux</a> I was
78referencing while testing them out.<p>While all of them provided what I needed, I liked i3 the most. What particular
79caught my eye was the ease to use and tree based layouts which allows flexible
80layouts. I know others can be set up also to have custom layouts other than<br>spiral, dwindle etc. I think i3 is a good entry-level window manager for
81somebody like me.<h2 id=batteries-included>Batteries included</h2><p>The source for the whole thing is located on Github
82<a href=https://github.com/mitjafelicijan/dfd-rice>https://github.com/mitjafelicijan/dfd-rice</a>.<p>Currenly included:<ul><li><code>non-free</code> (enables non-free packages in apt)<li><code>sudo</code> (adds sudo and adds user to sudo group)<li><code>essentials</code> (gcc, htop, zip, curl, etc...)<li><code>wifi</code> (network manager nmtui)<li><code>desktop</code> (i3, dmenu, fonts, configurations)<li><code>pulseaudio</code> (pulseaudio with pavucontrol)<li><code>code-editors</code> (vim, micro, vscode)<li><code>ohmybash</code> (make bash pretty)<li><code>file-managers</code> (mc)<li><code>git-ui</code> (terminal git gui)<li><code>meld</code> (diff tool)<li><code>profiling</code> (kcachegrind, valgrind, strace, ltrace)<li><code>browsers</code> (brave, firefox, chromium)<li>programming languages:<ul><li><code>python</code><li><code>golang</code><li><code>nodejs</code><li><code>rust</code><li><code>nim</code><li><code>php</code><li><code>ruby</code></ul><li><code>docker</code> (with docker-compose)<li><code>ansible</code></ul><p>Install script also allows you to install only specific packages (example for:
83essentials ohmybash docker rust).<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>su - root <span style=color:#a31515>\
84</span></span></span><span style=display:flex><span><span style=color:#a31515></span> bash -c <span style=color:#a31515>&#34;</span><span style=color:#00f>$(</span>wget -q https://raw.github.com/mitjafelicijan/dfd-rice/master/tools/install.sh -O -<span style=color:#00f>)</span><span style=color:#a31515>&#34;</span> -- <span style=color:#a31515>\
85</span></span></span><span style=display:flex><span><span style=color:#a31515></span> essentials ohmybash docker rust
86</span></span></code></pre><p>Currently, most of these recipes use what Debian and this is totally fine with
87me since I never use bleeding edge features of a package. But if something major
88would come to light, I will replace it with a possible compilation script or
89something similar.<p>This is some of the output from the installation script.<figure><img src=/posts/dfd-rice/script.png alt></figure><p>Let's take a look at some examples in the installation script.<h3 id=docker-recipe>Docker recipe</h3><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># docker</span>
90</span></span><span style=display:flex><span>print_header <span style=color:#a31515>&#34;Installing Docker&#34;</span>
91</span></span><span style=display:flex><span>curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --yes --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
92</span></span><span style=display:flex><span>echo <span style=color:#a31515>&#34;deb [arch=</span><span style=color:#00f>$(</span>dpkg --print-architecture<span style=color:#00f>)</span><span style=color:#a31515> signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian </span><span style=color:#00f>$(</span>lsb_release -cs<span style=color:#00f>)</span><span style=color:#a31515> stable&#34;</span> | tee /etc/apt/sources.list.d/docker.list &gt; /dev/null
93</span></span><span style=display:flex><span>apt update
94</span></span><span style=display:flex><span>apt -y install docker-ce docker-ce-cli containerd.io docker-compose
95</span></span><span style=display:flex><span>
96</span></span><span style=display:flex><span>systemctl start docker
97</span></span><span style=display:flex><span>systemctl enable docker
98</span></span><span style=display:flex><span>systemctl status docker --no-pager
99</span></span><span style=display:flex><span>
100</span></span><span style=display:flex><span>/sbin/usermod -aG docker $USERNAME
101</span></span></code></pre><h3 id=making-bash-pretty>Making bash pretty</h3><p>I really like <a href=https://ohmyz.sh/>Oh My Zsh</a>, but I don't like zsh shell. When
102I used it, I constantly needed to be aware of it and running bash scripts was a
103pain. So, I was really delighted when I found out that a version for bash
104existed called <a href=https://ohmybash.nntoan.com/>Oh My Bash</a>. Let's take a look at
105the recipe for installing it.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># ohmybash</span>
106</span></span><span style=display:flex><span>print_header <span style=color:#a31515>&#34;Enabling OhMyBash&#34;</span>
107</span></span><span style=display:flex><span>sudo -u $USERNAME sh -c <span style=color:#a31515>&#34;</span><span style=color:#00f>$(</span>curl -fsSL https://raw.github.com/ohmybash/oh-my-bash/master/tools/install.sh<span style=color:#00f>)</span><span style=color:#a31515>&#34;</span> &amp;
108</span></span><span style=display:flex><span>T1=<span style=color:#a31515>${</span>!<span style=color:#a31515>}</span>
109</span></span><span style=display:flex><span>wait <span style=color:#a31515>${</span>T1<span style=color:#a31515>}</span>
110</span></span></code></pre><p>Because OhMyBash does <code>exec bash</code> at the end, this traps our script inside
111another shell and our script cannot continue. For that reason, I executed this
112in background. But that presents a new problem. Because this is executed in
113background, we lose track of progress naturally. And that strange trick with
114<code>T1=${!}</code> and <code>wait ${T1}</code> waits for the background process to finish before
115continuing to another task in bash script.<p>Check <a href=https://www.cloudsavvyit.com/12277/how-to-use-multi-threaded-processing-in-bash-scripts/>Multi-Threaded Processing in Bash Scripts</a>
116for more details.<h2 id=conclusion>Conclusion</h2><p>Take a look at
117<a href=https://github.com/mitjafelicijan/dfd-rice/blob/develop/tools/install.sh>https://github.com/mitjafelicijan/dfd-rice/blob/develop/tools/install.sh</a> script
118to get familiar with it. This is just a first iteration and I will continue to
119update it because I need this in my life.<p>The current version boots in 4s to the login prompt, and after you log in, the
120desktop environment loads in 2s. So, its fast, very fast. And on clean boot, I
121measured ~230 MB of RAM usage.<p>And this is how it looks with two terminals side by side. I really like the
122simplicity and clean interface. I will polish the colors and stuff like that,
123but I really do like the results.<figure><img src=/posts/dfd-rice/desktop.png alt></figure></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
124a lock on a Linux NFS server, which turned
125out to be specific to NFS v3 (which I really should have seen coming,
126since it involved NLM and lockd). Finding the NFS v4 client that
127owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
128and Bradley Kuhn, are interacting on the OSI's license-discuss
129list where the're doing
130bad computer history and insisting that a guy Larry Rosen
131coincidentally interviewed for a book years ago is clearly the origin of
132somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
133i2c, plan9
134Another month, another file system.
135Well, if you can’t fix it in software, fix it in hardware (looking at
136you, bme680, we’re not
137done yet). The show must go on, as they say, and I would like my
138experiments to go on.
139So a “new” addition to the environmental sensor family connected to
140the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
141this mortal coil, we are endowed with self-awareness, agency, and free will.
142Each of the 8 billion members of this human race represents a unique person, a
143unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
144My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
1451.0 has been released:
146wifi_da-1.0.sit
147(StuffIt 3 archive)
148SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
149This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
150classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
151In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
152Design Goals
153I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
154at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
155catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
156specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
157 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
158 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/development-environments-with-nix.html b/public/development-environments-with-nix.html
deleted file mode 100755
index 9aa9920..0000000
--- a/public/development-environments-with-nix.html
+++ /dev/null
@@ -1,74 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Development environments with Nix</title><meta name=description content="Nix is amazing for making reproducible cross OS development environment."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Development environments with Nix</h1><p><cap>note</cap>, Jun 25, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>Nix is amazing for making reproducible cross OS development environment.<p>First you need to <a href=https://nixos.org/download.html>install Nix package
10manager</a>.<ul><li>Create a file <code>shell.nix</code> in your project folder.<li>In the section that has <code>python3</code> etc add programs you want to use. These can
11be CLI or GUI applications. It doesn't matter to Nix.</ul><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>{ pkgs ? <span style=color:#00f>import</span> <span style=color:#a31515>&lt;nixpkgs&gt;</span> {} }:
12</span></span><span style=display:flex><span> pkgs.mkShell {
13</span></span><span style=display:flex><span> nativeBuildInputs = <span style=color:#00f>with</span> pkgs.buildPackages; [
14</span></span><span style=display:flex><span> python3
15</span></span><span style=display:flex><span> tinycc
16</span></span><span style=display:flex><span> ];
17</span></span><span style=display:flex><span>}
18</span></span></code></pre><p>And then run it <code>nix-shell</code>. By default it will look for <code>shell.nix</code> file. If
19you want to specify a different file use <code>nix-shell file.nix</code>. That is about it.<p>When the shell is spawned it could happen that your <code>PS1</code> prompt will be
20overwritten and your prompt will look differently. In that case you need to
21either do <code>NIX_SHELL_PRESERVE_PROMPT=1 nix shell</code> or add
22<code>NIX_SHELL_PRESERVE_PROMPT</code> variable to your <code>bashrc</code> or <code>zshrc</code> file and set it
23to <code>1</code>.<p>I also have a modified <code>PS1</code> prompt for Bash that I use and it also catches the
24usage of Nix shell.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>NIX_SHELL_PRESERVE_PROMPT=1
25</span></span><span style=display:flex><span>
26</span></span><span style=display:flex><span>parse_git_branch() {
27</span></span><span style=display:flex><span> git branch 2&gt; /dev/null | sed -e <span style=color:#a31515>&#39;/^[^*]/d&#39;</span> -e <span style=color:#a31515>&#39;s/* \(.*\)/ (\1)/&#39;</span>
28</span></span><span style=display:flex><span>}
29</span></span><span style=display:flex><span>
30</span></span><span style=display:flex><span>is_inside_nix_shell() {
31</span></span><span style=display:flex><span> nix_shell_name=<span style=color:#a31515>&#34;</span><span style=color:#00f>$(</span>basename <span style=color:#a31515>&#34;</span>$IN_NIX_SHELL<span style=color:#a31515>&#34;</span> 2&gt;/dev/null<span style=color:#00f>)</span><span style=color:#a31515>&#34;</span>
32</span></span><span style=display:flex><span> <span style=color:#00f>if</span> [[ -n <span style=color:#a31515>&#34;</span>$nix_shell_name<span style=color:#a31515>&#34;</span> ]]; <span style=color:#00f>then</span>
33</span></span><span style=display:flex><span> echo <span style=color:#a31515>&#34; \e[0;36m(nix-shell)\e[0m&#34;</span>
34</span></span><span style=display:flex><span> <span style=color:#00f>fi</span>
35</span></span><span style=display:flex><span>}
36</span></span><span style=display:flex><span>
37</span></span><span style=display:flex><span>export PS1=<span style=color:#a31515>&#34;[\033[38;5;9m\]\u@\h\[</span><span style=color:#00f>$(</span>tput sgr0<span style=color:#00f>)</span><span style=color:#a31515>\]]</span><span style=color:#00f>$(</span>is_inside_nix_shell<span style=color:#00f>)</span><span style=color:#a31515>\[\033[33m\]\$(parse_git_branch)\[\033[00m\] \w\[</span><span style=color:#00f>$(</span>tput sgr0<span style=color:#00f>)</span><span style=color:#a31515>\] \n</span>$<span style=color:#a31515> &#34;</span>
38</span></span></code></pre><p>And this is what it looks like when you are in a Nix shell. Otherwise that part
39of prompt is omitted<figure><img src=/notes/ps1-prompt.png alt="PS1 Prompt"></figure><p>More resources:<ul><li><a href=https://nixos.wiki/wiki/Development_environment_with_nix-shell>https://nixos.wiki/wiki/Development_environment_with_nix-shell</a><li><a href=https://nixos.wiki/wiki/Main_Page>https://nixos.wiki/wiki/Main_Page</a><li><a href=https://itsfoss.com/why-use-nixos/>https://itsfoss.com/why-use-nixos/</a><li><a href=https://mynixos.com/>https://mynixos.com/</a></ul></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
40a lock on a Linux NFS server, which turned
41out to be specific to NFS v3 (which I really should have seen coming,
42since it involved NLM and lockd). Finding the NFS v4 client that
43owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
44and Bradley Kuhn, are interacting on the OSI's license-discuss
45list where the're doing
46bad computer history and insisting that a guy Larry Rosen
47coincidentally interviewed for a book years ago is clearly the origin of
48somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
49i2c, plan9
50Another month, another file system.
51Well, if you can’t fix it in software, fix it in hardware (looking at
52you, bme680, we’re not
53done yet). The show must go on, as they say, and I would like my
54experiments to go on.
55So a “new” addition to the environmental sensor family connected to
56the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
57this mortal coil, we are endowed with self-awareness, agency, and free will.
58Each of the 8 billion members of this human race represents a unique person, a
59unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
60My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
611.0 has been released:
62wifi_da-1.0.sit
63(StuffIt 3 archive)
64SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
65This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
66classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
67In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
68Design Goals
69I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
70at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
71catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
72specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
73 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
74 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/digitalocean-spaces-to-sync-between-computers.html b/public/digitalocean-spaces-to-sync-between-computers.html
deleted file mode 100755
index 33ce9da..0000000
--- a/public/digitalocean-spaces-to-sync-between-computers.html
+++ /dev/null
@@ -1,98 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Using Digitalocean Spaces to sync between computers</title><meta name=description content="I&amp;#39;ve been using Dropbox for probably 10+ yearsnow and I-ve became so used to it that it runs in the background that I don&amp;#39;teven imagine a world without it."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Using Digitalocean Spaces to sync between computers</h1><p><cap>post</cap>, Sep 9, 2020 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>I've been using <a href=https://www.dropbox.com/>Dropbox</a> for probably <strong>10+ years</strong>
10now and I-ve became so used to it that it runs in the background that I don't
11even imagine a world without it. But it's not without problems.<p>At first I had problems with <code>.venv</code> environments for Python and the only
12solution for excluding synchronization for this folder was to manually exclude a
13specific folder which is not really scalable. FYI, my whole project folder is
14synced on <a href=https://www.dropbox.com/>Dropbox</a>. This of course introduced a lot
15of syncing of files and folders that are not needed or even break things on
16other machines. In the case of <strong>Python</strong>, I couldn't use that on my second
17machine. I needed to delete <code>.venv</code> folder and pip it again which synced files
18again to the main machine. This was very frustrating. <strong>Nodejs</strong> handles this
19much nicer and I can just run the scripts without deleting <code>node_modules</code> again
20and reinstalling. However, <code>node_modules</code> is a beast of its own. It creates so
21many files that OS has a problem counting them when you check the folder
22contents for size.<p>I wanted something similar to Dropbox. I could without the instant syncing but
23it would need to be fast and had the option for me to exclude folders like
24<code>node_modules, .venv, .git</code> and folders like that.<p>I went on a hunt for an alternative to <a href=https://www.dropbox.com/>Dropbox</a>
25and found:<ul><li><a href=https://tresorit.com/>Tresorit</a><li><a href=https://sync.com>Sync.com</a><li><a href=https://www.box.com/>Box</a></ul><p>You know, the usual list of suspects. I didn't include <a href=https://drive.google.com>Google
26drive</a> or <a href=https://onedrive.live.com/>One drive</a>
27since they are even more draconian than Dropbox.<blockquote><p>All this does not stem from me being paranoid but recently these companies
28have became more and more aggressive and they keep violating our privacy when
29they share our data with 3rd party services. It is getting out of control.</blockquote><p>So, my main problem was still there. No way of excluding a specific folder from
30syncing. And before we go into "<em>But you have git, isn't that enough?</em>", I must
31say, that many of the files (PDFs, spreadsheets, etc) I have in a <code>git</code> repo
32don't get pushed upstream to Git and I still want to have them synced across my
33computers.<p>I initially wanted to use <a href=https://linux.die.net/man/1/rsync>rsync</a> but I would
34need to then have a remote VPS or transfer between my computers directly. I
35wanted a solution where all my files could be accessible to me without my
36machine.<blockquote><p><strong>WARNING: This solution will cost you money!</strong> DigitalOcean Spaces are $5 per
37month and there are some bandwidth limitations and if you go beyond that you get
38billed additionally.</blockquote><p>Then I remembered that I could use something like
39<a href=https://en.wikipedia.org/wiki/Amazon_S3>S3</a> since it has versioning and is
40fully managed. I didn't want to go down the AWS rabbit hole with this so I
41choose <a href=https://www.digitalocean.com/products/spaces/>DigitalOcean Spaces</a>.<p>Then I needed a command-line tool to sync between source and target. I found
42this nice tool <a href=https://s3tools.org/s3cmd>s3cmd</a> and it is in the Ubuntu
43repositories.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>sudo apt install s3cmd
44</span></span></code></pre><p>After installation will I create a new Space bucket on DigitalOcean. Remember
45the zone you will choose because you will need it when you will configure
46<code>s3cmd</code>.<p>Then I visited <a href=https://cloud.digitalocean.com/account/api/tokens>Digitalocean Applications &
47API</a> and generated <strong>Spaces
48access keys</strong>. Save both key and secret somewhere safe because when you will
49leave the page secret will not be available anymore to you and you will need to
50re-generate it.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># enter your key and secret and correct endpoint</span>
51</span></span><span style=display:flex><span><span style=color:green># my endpoint is ams3.digitaloceanspaces.com because</span>
52</span></span><span style=display:flex><span><span style=color:green># I created my bucket in Amsterdam regiin</span>
53</span></span><span style=display:flex><span>s3cmd --configure
54</span></span></code></pre><p>After that I played around with options for <code>s3cmd</code> and got to the following
55command.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># I executed this command from my projects folder</span>
56</span></span><span style=display:flex><span>cd projects
57</span></span><span style=display:flex><span>s3cmd sync --delete-removed --exclude <span style=color:#a31515>&#39;node_modules/*&#39;</span> --exclude <span style=color:#a31515>&#39;.git/*&#39;</span> --exclude <span style=color:#a31515>&#39;.venv/*&#39;</span> ./ s3://my-bucket-name/projects/
58</span></span></code></pre><p>When syncing int he other direction you will need to change the order of the
59<code>SOURCE</code> and <code>TARGET</code> to <code>s3://my-bucket-name/projects/</code> and <code>./</code>.<blockquote><p>Be sure that all the paths have trailing slash so that sync knows that this
60are directories.</blockquote><p>I am planning to implement some sort of a <code>.ignore</code> file that will enable me to
61have a project-specific exclude options.<p>I am currently running this every hour as a cronjob which is perfectly fine for
62now when I am testing how this whole thing works and how it all will turn out.<p>I have also created a small Gnome extension which is still very unstable, but
63when/if this whole experiment pays of I will share on Github.</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
64a lock on a Linux NFS server, which turned
65out to be specific to NFS v3 (which I really should have seen coming,
66since it involved NLM and lockd). Finding the NFS v4 client that
67owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
68and Bradley Kuhn, are interacting on the OSI's license-discuss
69list where the're doing
70bad computer history and insisting that a guy Larry Rosen
71coincidentally interviewed for a book years ago is clearly the origin of
72somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
73i2c, plan9
74Another month, another file system.
75Well, if you can’t fix it in software, fix it in hardware (looking at
76you, bme680, we’re not
77done yet). The show must go on, as they say, and I would like my
78experiments to go on.
79So a “new” addition to the environmental sensor family connected to
80the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
81this mortal coil, we are endowed with self-awareness, agency, and free will.
82Each of the 8 billion members of this human race represents a unique person, a
83unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
84My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
851.0 has been released:
86wifi_da-1.0.sit
87(StuffIt 3 archive)
88SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
89This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
90classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
91In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
92Design Goals
93I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
94at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
95catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
96specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
97 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
98 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/disable-mouse-wake-from-suspend-with-systemd-service.html b/public/disable-mouse-wake-from-suspend-with-systemd-service.html
deleted file mode 100755
index 8018d4b..0000000
--- a/public/disable-mouse-wake-from-suspend-with-systemd-service.html
+++ /dev/null
@@ -1,84 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Disable mouse wake from suspend with systemd service</title><meta name=description content="I recently bought ThinkPadX220 just as ajoke on eBay to test Linux distributions and play around with things and notdestroy my main machine."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Disable mouse wake from suspend with systemd service</h1><p><cap>post</cap>, Aug 15, 2020 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>I recently bought <a href=https://www.laptopmag.com/reviews/laptops/lenovo-thinkpad-x220>ThinkPad
10X220</a> just as a
11joke on eBay to test Linux distributions and play around with things and not
12destroy my main machine. Little to my knowledge I felt in love with it. Man,
13they really made awesome machines back then.<p>After changing disk that came with it to SSD and installing Ubuntu to test if 
14everything works I noticed that even after a single touch of my external mouse
15the system would wake up from sleep even though the lid was shut down.<p>I wouldn't even noticed it if laptop didn't have <a href="https://support.lenovo.com/lk/en/solutions/~/media/Images/ContentImages/p/pd025386_x1_status_03.ashx?w=426&amp;h=262">LED
16sleep indicator</a>.
17I already had a bad experience with Linux and it's power management. I had a
18<a href=https://www.pcmag.com/reviews/dell-inspiron-15-7537>Dell Inspiron 7537</a> laptop
19with a touchscreen and while traveling it decided to wake up and started cooking
20in my backpack to the point that the digitizer responsible for touch actually
21glue off and the whole screen got wrecked. So, I am a bit touchy about this.<p>I went on solution hunting and to my surprise there is no easy way to disable
22specific devices to perform wake up. Why is this not under the power management 
23tab in setting is really strange.<p>After googling for a solution I found <a href=https://codetrips.com/2020/03/18/ubuntu-disable-mouse-wake-from-suspend/>this nice article describing the
24solution</a>
25that worked for me. The only problem with this solution was that he added his
26solution to <code>.bashrc</code> and this triggers <code>sudo</code> that asks for a password each
27time new terminal is opened, which get annoying quickly since I open a lot of
28terminals all the time.<p>I followed his instructions and got to solution <code>sudo sh -c "echo 'disabled' > /sys/bus/usb/devices/2-1.1/power/wakeup"</code>.<p>I created a system service file <code>sudo nano /etc/systemd/system/disable-mouse-wakeup.service</code> and removed <code>sudo</code> and
29replaced <code>sh</code> with <code>/usr/bin/sh</code> and pasted all that in <code>ExecStart</code>.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>[Unit]</span>
30</span></span><span style=display:flex><span>Description=<span style=color:#a31515>Disables wakeup on mouse event</span>
31</span></span><span style=display:flex><span>After=<span style=color:#a31515>network.target</span>
32</span></span><span style=display:flex><span>StartLimitIntervalSec=<span style=color:#a31515>0</span>
33</span></span><span style=display:flex><span>
34</span></span><span style=display:flex><span><span style=color:#00f>[Service]</span>
35</span></span><span style=display:flex><span>Type=<span style=color:#a31515>simple</span>
36</span></span><span style=display:flex><span>Restart=<span style=color:#a31515>always</span>
37</span></span><span style=display:flex><span>RestartSec=<span style=color:#a31515>1</span>
38</span></span><span style=display:flex><span>User=<span style=color:#a31515>root</span>
39</span></span><span style=display:flex><span>ExecStart=<span style=color:#a31515>/usr/bin/sh -c &#34;echo &#39;disabled&#39; &gt; /sys/bus/usb/devices/2-1.1/power/wakeup&#34;</span>
40</span></span><span style=display:flex><span>
41</span></span><span style=display:flex><span><span style=color:#00f>[Install]</span>
42</span></span><span style=display:flex><span>WantedBy=<span style=color:#a31515>multi-user.target</span>
43</span></span></code></pre><p>After that I enabled, started and checked status of service.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>sudo systemctl enable disable-mouse-wakeup.service
44</span></span><span style=display:flex><span>sudo systemctl start disable-mouse-wakeup.service
45</span></span><span style=display:flex><span>sudo systemctl status disable-mouse-wakeup.service
46</span></span></code></pre><p>This will permanently disable that device from wakeing up you computer on boot.
47If you have many devices you would like to surpress from waking up your machine
48I would create a shell script and call that instead of direclty doing it in
49service file.</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
50a lock on a Linux NFS server, which turned
51out to be specific to NFS v3 (which I really should have seen coming,
52since it involved NLM and lockd). Finding the NFS v4 client that
53owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
54and Bradley Kuhn, are interacting on the OSI's license-discuss
55list where the're doing
56bad computer history and insisting that a guy Larry Rosen
57coincidentally interviewed for a book years ago is clearly the origin of
58somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
59i2c, plan9
60Another month, another file system.
61Well, if you can’t fix it in software, fix it in hardware (looking at
62you, bme680, we’re not
63done yet). The show must go on, as they say, and I would like my
64experiments to go on.
65So a “new” addition to the environmental sensor family connected to
66the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
67this mortal coil, we are endowed with self-awareness, agency, and free will.
68Each of the 8 billion members of this human race represents a unique person, a
69unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
70My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
711.0 has been released:
72wifi_da-1.0.sit
73(StuffIt 3 archive)
74SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
75This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
76classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
77In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
78Design Goals
79I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
80at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
81catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
82specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
83 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
84 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/download-youtube-videos.html b/public/download-youtube-videos.html
deleted file mode 100755
index f952394..0000000
--- a/public/download-youtube-videos.html
+++ /dev/null
@@ -1,50 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Download list of YouTube files</title><meta name=description content="If you need to download a list of YouTube videos and don&amp;#39;t want to download theactual YouTube list (which yt-dlp supports), you can use the following method."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Download list of YouTube files</h1><p><cap>note</cap>, May 13, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>If you need to download a list of YouTube videos and don't want to download the
10actual YouTube list (which <code>yt-dlp</code> supports), you can use the following method.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green>// Used to get list of raw URL&#39;s from YouTube&#39;s video tab&#39;.
11</span></span></span><span style=display:flex><span><span style=color:green>// Copy them into videos.txt.
12</span></span></span><span style=display:flex><span><span style=color:green></span>document.querySelectorAll(<span style=color:#a31515>&#39;#contents a.ytd-thumbnail.style-scope.ytd-thumbnail&#39;</span>).forEach(el =&gt; console.log(el.href))
13</span></span></code></pre><p>Download and install <a href=https://github.com/yt-dlp/yt-dlp>https://github.com/yt-dlp/yt-dlp</a>.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># This will download all videos in videos.txt.</span>
14</span></span><span style=display:flex><span>yt-dlp --batch-file videos.txt -N <span style=color:#a31515>`</span>nproc<span style=color:#a31515>`</span> -f webm
15</span></span></code></pre></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
16a lock on a Linux NFS server, which turned
17out to be specific to NFS v3 (which I really should have seen coming,
18since it involved NLM and lockd). Finding the NFS v4 client that
19owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
20and Bradley Kuhn, are interacting on the OSI's license-discuss
21list where the're doing
22bad computer history and insisting that a guy Larry Rosen
23coincidentally interviewed for a book years ago is clearly the origin of
24somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
25i2c, plan9
26Another month, another file system.
27Well, if you can’t fix it in software, fix it in hardware (looking at
28you, bme680, we’re not
29done yet). The show must go on, as they say, and I would like my
30experiments to go on.
31So a “new” addition to the environmental sensor family connected to
32the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
33this mortal coil, we are endowed with self-awareness, agency, and free will.
34Each of the 8 billion members of this human race represents a unique person, a
35unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
36My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
371.0 has been released:
38wifi_da-1.0.sit
39(StuffIt 3 archive)
40SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
41This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
42classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
43In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
44Design Goals
45I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
46at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
47catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
48specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
49 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
50 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/drawing-pixels-in-plan9.html b/public/drawing-pixels-in-plan9.html
deleted file mode 100755
index c0e7a0c..0000000
--- a/public/drawing-pixels-in-plan9.html
+++ /dev/null
@@ -1,96 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Drawing Pixels in Plan9</title><meta name=description content="I have started exploring Plan9&amp;#39;s graphics capabilities."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Drawing Pixels in Plan9</h1><p><cap>note</cap>, May 27, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>I have started exploring Plan9's graphics capabilities. This is a hello world
10alternative for drawing that draws a yellow square on a blue background.<p>More information:<ul><li><a href=https://github.com/0intro/plan9/blob/main/sys/include/draw.h>draw.h header file</a>
11contains all the drawing functions<li><a href=https://9fans.github.io/plan9port/man/man3/draw.html>draw man page</a>
12has a bit more digestable descriptions of the draw functions<li><a href=https://9fans.github.io/plan9port/man/man3/graphics.html>graphics man page</a>
13has a bit more digestable descriptions of the graphics functions<li><a href=https://9fans.github.io/plan9port/man/man3/>all man pages</a>
14can be a valuable resource for learning about the system</ul><figure><img src=/notes/plan9-pixels.png alt="Plan9 Howdy World!"></figure><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green>// main.c
15</span></span></span><span style=display:flex><span><span style=color:green></span><span style=color:#00f>#include</span> <span style=color:#00f>&lt;u.h&gt;</span><span style=color:#00f>
16</span></span></span><span style=display:flex><span><span style=color:#00f>#include</span> <span style=color:#00f>&lt;libc.h&gt;</span><span style=color:#00f>
17</span></span></span><span style=display:flex><span><span style=color:#00f>#include</span> <span style=color:#00f>&lt;draw.h&gt;</span><span style=color:#00f>
18</span></span></span><span style=display:flex><span><span style=color:#00f>#include</span> <span style=color:#00f>&lt;cursor.h&gt;</span><span style=color:#00f>
19</span></span></span><span style=display:flex><span><span style=color:#00f></span>
20</span></span><span style=display:flex><span><span style=color:#2b91af>void</span>
21</span></span><span style=display:flex><span>main()
22</span></span><span style=display:flex><span>{
23</span></span><span style=display:flex><span> ulong co;
24</span></span><span style=display:flex><span> Image *im, *bg;
25</span></span><span style=display:flex><span> co = 0x0000FFFF;
26</span></span><span style=display:flex><span>
27</span></span><span style=display:flex><span> <span style=color:#00f>if</span> (initdraw(nil, nil, argv0) &lt; 0)
28</span></span><span style=display:flex><span> {
29</span></span><span style=display:flex><span> sysfatal(<span style=color:#a31515>&#34;%s: %r&#34;</span>, argv0);
30</span></span><span style=display:flex><span> }
31</span></span><span style=display:flex><span>
32</span></span><span style=display:flex><span> im = allocimage(display, Rect(0, 0, 300, 300), RGB24, 0, DYellow);
33</span></span><span style=display:flex><span> bg = allocimage(display, Rect(0, 0, 1, 1), RGB24, 1, co);
34</span></span><span style=display:flex><span>
35</span></span><span style=display:flex><span> <span style=color:#00f>if</span> (im == nil || bg == nil)
36</span></span><span style=display:flex><span> {
37</span></span><span style=display:flex><span> sysfatal(<span style=color:#a31515>&#34;not enough memory&#34;</span>);
38</span></span><span style=display:flex><span> }
39</span></span><span style=display:flex><span>
40</span></span><span style=display:flex><span> draw(screen, screen-&gt;r, bg, nil, ZP);
41</span></span><span style=display:flex><span> draw(screen, screen-&gt;r, im, nil, Pt(-40, -40));
42</span></span><span style=display:flex><span>
43</span></span><span style=display:flex><span> flushimage(display, Refnone);
44</span></span><span style=display:flex><span>
45</span></span><span style=display:flex><span> <span style=color:green>// Wait 10 seconds before exiting.
46</span></span></span><span style=display:flex><span><span style=color:green></span> sleep(10000);
47</span></span><span style=display:flex><span>
48</span></span><span style=display:flex><span> exits(nil);
49</span></span><span style=display:flex><span>}
50</span></span></code></pre><p>And then compile with <code>mk</code> (mkfile below):<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># mkfile
51</span></span></span><span style=display:flex><span><span style=color:green></span><span>&lt;/$objtype/mkfile</span>
52</span></span><span style=display:flex><span>
53</span></span><span style=display:flex><span>RC=/rc/bin
54</span></span><span style=display:flex><span>BIN=/$objtype/bin
55</span></span><span style=display:flex><span>MAN=/sys/man
56</span></span><span style=display:flex><span>
57</span></span><span style=display:flex><span>main:
58</span></span><span style=display:flex><span> $CC $CFLAGS main.c
59</span></span><span style=display:flex><span> $LD $LDFLAGS -o main main.$O
60</span></span></code></pre><p>And run with <code>./main</code>. To exit the program, press <code>Delete key</code> (strange but this
61is the alternative for Ctrl+C).<p><em>This is <strong>very cool</strong> indeed!</em></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
62a lock on a Linux NFS server, which turned
63out to be specific to NFS v3 (which I really should have seen coming,
64since it involved NLM and lockd). Finding the NFS v4 client that
65owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
66and Bradley Kuhn, are interacting on the OSI's license-discuss
67list where the're doing
68bad computer history and insisting that a guy Larry Rosen
69coincidentally interviewed for a book years ago is clearly the origin of
70somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
71i2c, plan9
72Another month, another file system.
73Well, if you can’t fix it in software, fix it in hardware (looking at
74you, bme680, we’re not
75done yet). The show must go on, as they say, and I would like my
76experiments to go on.
77So a “new” addition to the environmental sensor family connected to
78the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
79this mortal coil, we are endowed with self-awareness, agency, and free will.
80Each of the 8 billion members of this human race represents a unique person, a
81unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
82My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
831.0 has been released:
84wifi_da-1.0.sit
85(StuffIt 3 archive)
86SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
87This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
88classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
89In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
90Design Goals
91I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
92at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
93catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
94specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
95 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
96 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/easy-time-took-in-bash.html b/public/easy-time-took-in-bash.html
deleted file mode 100755
index 45b60c7..0000000
--- a/public/easy-time-took-in-bash.html
+++ /dev/null
@@ -1,56 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Easy measure time took in a bash script</title><meta name=description content="In Bash, the $SECONDS variable is a special variable that automatically keepstrack of the number of seconds since the current shell or script startedexecuting."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Easy measure time took in a bash script</h1><p><cap>note</cap>, May 28, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>In Bash, the <code>$SECONDS</code> variable is a special variable that automatically keeps
10track of the number of seconds since the current shell or script started
11executing. It starts counting from the moment the script begins running.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>#!/bin/bash
12</span></span></span><span style=display:flex><span><span style=color:#00f></span>
13</span></span><span style=display:flex><span><span style=color:green># Reset the timer to zero.</span>
14</span></span><span style=display:flex><span>SECONDS=0
15</span></span><span style=display:flex><span>
16</span></span><span style=display:flex><span><span style=color:green># Do something.</span>
17</span></span><span style=display:flex><span>sleep 5
18</span></span><span style=display:flex><span>
19</span></span><span style=display:flex><span><span style=color:green># Print the time elapsed.</span>
20</span></span><span style=display:flex><span>echo <span style=color:#a31515>&#34;Time taken: </span>$SECONDS<span style=color:#a31515> seconds&#34;</span>
21</span></span></code></pre></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
22a lock on a Linux NFS server, which turned
23out to be specific to NFS v3 (which I really should have seen coming,
24since it involved NLM and lockd). Finding the NFS v4 client that
25owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
26and Bradley Kuhn, are interacting on the OSI's license-discuss
27list where the're doing
28bad computer history and insisting that a guy Larry Rosen
29coincidentally interviewed for a book years ago is clearly the origin of
30somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
31i2c, plan9
32Another month, another file system.
33Well, if you can’t fix it in software, fix it in hardware (looking at
34you, bme680, we’re not
35done yet). The show must go on, as they say, and I would like my
36experiments to go on.
37So a “new” addition to the environmental sensor family connected to
38the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
39this mortal coil, we are endowed with self-awareness, agency, and free will.
40Each of the 8 billion members of this human race represents a unique person, a
41unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
42My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
431.0 has been released:
44wifi_da-1.0.sit
45(StuffIt 3 archive)
46SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
47This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
48classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
49In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
50Design Goals
51I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
52at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
53catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
54specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
55 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
56 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/encoding-binary-data-into-dna-sequence.html b/public/encoding-binary-data-into-dna-sequence.html
deleted file mode 100755
index f1b37c8..0000000
--- a/public/encoding-binary-data-into-dna-sequence.html
+++ /dev/null
@@ -1,219 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Encoding binary data into DNA sequence</title><meta name=description content="Initial thoughtsImagine a world where you could go outside and take a leaf from a tree and putit through your personal DNA sequencer and get data like music, videos orcomputer programs from it."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Encoding binary data into DNA sequence</h1><p><cap>post</cap>, Jan 3, 2019 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><h2 id=initial-thoughts>Initial thoughts</h2><p>Imagine a world where you could go outside and take a leaf from a tree and put
10it through your personal DNA sequencer and get data like music, videos or
11computer programs from it. Well, this is all possible now. It was not done on a
12large scale because it is quite expensive to create DNA strands but it's
13possible.<p>Encoding data into DNA sequence is relatively simple process once you understand
14the relationship between binary data and nucleotides and scientists have been
15making large leaps in this field in order to provide viable long-term storage
16solution for our data that would potentially survive our specie if case of
17global disaster. We could imprint all the world's knowledge into plants and
18ensure the survival of our knowledge.<p>More optimistic usage for this technology would be easier storage of ever
19growing data we produce every day. Once machines for sequencing DNA become fast
20enough and cheaper this could mean the next evolution of storing data and
21abandoning classical hard and solid state drives in data warehouses.<p>As we currently stand this is still not viable but it is quite an amazing and
22cool technology.<p>My interests in this field are purely in encoding processes and experimental
23testing mainly because I don't have the access to this expensive machines. My
24initial goal was to create a toolkit that can be used by everybody to encode
25their data into a proper DNA sequence.<h2 id=glossary>Glossary</h2><p><strong>deoxyribose</strong> A five-carbon sugar molecule with a hydrogen atom rather than a
26hydroxyl group in the 2′ position; the sugar component of DNA nucleotides.<p><strong>double helix</strong> The molecular shape of DNA in which two strands of nucleotides
27wind around each other in a spiral shape.<p><strong>nitrogenous base</strong> A nitrogen-containing molecule that acts as a base; often
28referring to one of the purine or pyrimidine components of nucleic acids.<p><strong>phosphate group</strong> A molecular group consisting of a central phosphorus atom
29bound to four oxygen atoms.<p><strong>RGB</strong> The RGB color model is an additive color model in which red, green and
30blue light are added together in various ways to reproduce a broad array of
31colors.<p><strong>GCC</strong> The GNU Compiler Collection is a compiler system produced by the GNU
32Project supporting various programming languages.<h2 id=data-encoding>Data encoding</h2><p><strong>TL;DR:</strong> Encoding involves the use of a code to change original data into a
33form that can be used by an external process.<p>Encoding is the process of converting data into a format required for a number
34of information processing needs, including:<ul><li>Program compiling and execution<li>Data transmission, storage and compression/decompression<li>Application data processing, such as file conversion</ul><p>Encoding can have two meanings:<ul><li>In computer technology, encoding is the process of applying a specific code,
35such as letters, symbols and numbers, to data for conversion into an
36equivalent cipher.<li>In electronics, encoding refers to analog to digital conversion.</ul><h2 id=quick-history-of-dna>Quick history of DNA</h2><ul><li><strong>1869</strong> - Friedrich Miescher identifies "nuclein".<li><strong>1900s</strong> - The Eugenics Movement.<li><strong>1900</strong> – Mendel's theories are rediscovered by researchers.<li><strong>1944</strong> - Oswald Avery identifies DNA as the 'transforming principle'.<li><strong>1952</strong> - Rosalind Franklin photographs crystallized DNA fibres.<li><strong>1953</strong> - James Watson and Francis Crick discover the double helix structure of DNA.<li><strong>1965</strong> - Marshall Nirenberg is the first person to sequence the bases in each codon.<li><strong>1983</strong> - Huntington's disease is the first mapped genetic disease.<li><strong>1990</strong> - The Human Genome Project begins.<li><strong>1995</strong> - Haemophilus Influenzae is the first bacterium genome sequenced.<li><strong>1996</strong> - Dolly the sheep is cloned.<li><strong>1999</strong> - First human chromosome is decoded.<li><strong>2000</strong> – Genetic code of the fruit fly is decoded.<li><strong>2002</strong> – Mouse is the first mammal to have its genome decoded.<li><strong>2003</strong> – The Human Genome Project is completed.<li><strong>2013</strong> – DNA Worldwide and Eurofins Forensic discover identical twins have differences in their genetic makeup.</ul><h2 id=what-is-dna>What is DNA?</h2><p>Deoxyribonucleic acid, a self-replicating material which is <strong>present in nearly
37all living organisms</strong> as the main constituent of chromosomes. It is the
38<strong>carrier of genetic information</strong>.<blockquote><p>The nitrogen in our DNA, the calcium in our teeth, the iron in our blood,
39the carbon in our apple pies were made in the interiors of collapsing stars.
40We are made of starstuff.
41<strong>-- Carl Sagan, Cosmos</strong></blockquote><p>The nucleotide in DNA consists of a sugar (deoxyribose), one of four bases
42(cytosine (C), thymine (T), adenine (A), guanine (G)), and a phosphate.
43Cytosine and thymine are pyrimidine bases, while adenine and guanine are purine
44bases. The sugar and the base together are called a nucleoside.<figure><img src=/posts/dna-sequence/dna-basics.jpg alt=DNA><figcaption><p><em>DNA (a) forms a double stranded helix, and (b) adenine pairs with thymine and
45cytosine pairs with guanine. (credit a: modification of work by Jerome Walker,
46Dennis Myts)</em></figcaption></figure><h2 id=encode-binary-data-into-dna-sequence>Encode binary data into DNA sequence</h2><p>As an input file you can use any file you want:<ul><li>ASCII files,<li>Compiled programs,<li>Multimedia files (MP3, MP4, MVK, etc),<li>Images,<li>Database files,<li>etc.</ul><p>Note: If you would copy all the bytes from RAM to file or pipe data to file you
47could encode also this data as long as you provide file pointer to the encoder.<h3 id=basic-encoding>Basic Encoding</h3><p>As already mentioned, the Basic Encoding is based on a simple mapping. Since DNA
48is composed of 4 nucleotides (Adenine, Cytosine, Guanine, Thymine; usually
49referred using the first letter). Using this technique we can encode<p><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 -907.9672135000189 11313.37788460873 1185.0382429179317" style="width: 26.259ex; height: 2.721ex; vertical-align: -0.68ex; margin: 1px 0px;"><g stroke="black" fill="black" stroke-width="0" transform="matrix(1 0 0 -1 0 0)"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-6C"/><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-6F" x="303" y="0"/><g transform="translate(793,0)"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-67"/><use transform="scale(0.7071067811865476)" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMAIN-32" x="681" y="-213"/></g><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMAIN-28" x="1732" y="0"/><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMAIN-34" x="2126" y="0"/><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMAIN-29" x="2631" y="0"/><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMAIN-3D" x="3302" y="0"/><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-6C" x="4363" y="0"/><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-6F" x="4666" y="0"/><g transform="translate(5156,0)"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-67"/><use transform="scale(0.7071067811865476)" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMAIN-32" x="681" y="-213"/></g><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMAIN-28" x="6095" y="0"/><g transform="translate(6489,0)"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMAIN-32"/><use transform="scale(0.7071067811865476)" xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMAIN-32" x="714" y="583"/></g><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMAIN-29" x="7451" y="0"/><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMAIN-3D" x="8123" y="0"/><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMAIN-32" x="9184" y="0"/><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-62" x="9689" y="0"/><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-69" x="10123" y="0"/><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-74" x="10473" y="0"/><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#MJMATHI-73" x="10839" y="0"/></g><defs id="MathJax_SVG_glyphs"><path id="MJSZ2-2211" stroke-width="10" d="M60 948Q63 950 665 950H1267L1325 815Q1384 677 1388 669H1348L1341 683Q1320 724 1285 761Q1235 809 1174 838T1033 881T882 898T699 902H574H543H251L259 891Q722 258 724 252Q725 250 724 246Q721 243 460 -56L196 -356Q196 -357 407 -357Q459 -357 548 -357T676 -358Q812 -358 896 -353T1063 -332T1204 -283T1307 -196Q1328 -170 1348 -124H1388Q1388 -125 1381 -145T1356 -210T1325 -294L1267 -449L666 -450Q64 -450 61 -448Q55 -446 55 -439Q55 -437 57 -433L590 177Q590 178 557 222T452 366T322 544L56 909L55 924Q55 945 60 948Z"/><path id="MJMATHI-69" stroke-width="10" d="M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z"/><path id="MJMAIN-3D" stroke-width="10" d="M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z"/><path id="MJMAIN-30" stroke-width="10" d="M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z"/><path id="MJMATHI-6E" stroke-width="10" d="M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z"/><path id="MJMAIN-28" stroke-width="10" d="M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z"/><path id="MJMAIN-2B" stroke-width="10" d="M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z"/><path id="MJMAIN-31" stroke-width="10" d="M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z"/><path id="MJMAIN-29" stroke-width="10" d="M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z"/><path id="MJMAIN-32" stroke-width="10" d="M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z"/><path id="MJMATHI-6C" stroke-width="10" d="M117 59Q117 26 142 26Q179 26 205 131Q211 151 215 152Q217 153 225 153H229Q238 153 241 153T246 151T248 144Q247 138 245 128T234 90T214 43T183 6T137 -11Q101 -11 70 11T38 85Q38 97 39 102L104 360Q167 615 167 623Q167 626 166 628T162 632T157 634T149 635T141 636T132 637T122 637Q112 637 109 637T101 638T95 641T94 647Q94 649 96 661Q101 680 107 682T179 688Q194 689 213 690T243 693T254 694Q266 694 266 686Q266 675 193 386T118 83Q118 81 118 75T117 65V59Z"/><path id="MJMATHI-6F" stroke-width="10" d="M201 -11Q126 -11 80 38T34 156Q34 221 64 279T146 380Q222 441 301 441Q333 441 341 440Q354 437 367 433T402 417T438 387T464 338T476 268Q476 161 390 75T201 -11ZM121 120Q121 70 147 48T206 26Q250 26 289 58T351 142Q360 163 374 216T388 308Q388 352 370 375Q346 405 306 405Q243 405 195 347Q158 303 140 230T121 120Z"/><path id="MJMATHI-67" stroke-width="10" d="M311 43Q296 30 267 15T206 0Q143 0 105 45T66 160Q66 265 143 353T314 442Q361 442 401 394L404 398Q406 401 409 404T418 412T431 419T447 422Q461 422 470 413T480 394Q480 379 423 152T363 -80Q345 -134 286 -169T151 -205Q10 -205 10 -137Q10 -111 28 -91T74 -71Q89 -71 102 -80T116 -111Q116 -121 114 -130T107 -144T99 -154T92 -162L90 -164H91Q101 -167 151 -167Q189 -167 211 -155Q234 -144 254 -122T282 -75Q288 -56 298 -13Q311 35 311 43ZM384 328L380 339Q377 350 375 354T369 368T359 382T346 393T328 402T306 405Q262 405 221 352Q191 313 171 233T151 117Q151 38 213 38Q269 38 323 108L331 118L384 328Z"/><path id="MJMAIN-34" stroke-width="10" d="M462 0Q444 3 333 3Q217 3 199 0H190V46H221Q241 46 248 46T265 48T279 53T286 61Q287 63 287 115V165H28V211L179 442Q332 674 334 675Q336 677 355 677H373L379 671V211H471V165H379V114Q379 73 379 66T385 54Q393 47 442 46H471V0H462ZM293 211V545L74 212L183 211H293Z"/><path id="MJMATHI-62" stroke-width="10" d="M73 647Q73 657 77 670T89 683Q90 683 161 688T234 694Q246 694 246 685T212 542Q204 508 195 472T180 418L176 399Q176 396 182 402Q231 442 283 442Q345 442 383 396T422 280Q422 169 343 79T173 -11Q123 -11 82 27T40 150V159Q40 180 48 217T97 414Q147 611 147 623T109 637Q104 637 101 637H96Q86 637 83 637T76 640T73 647ZM336 325V331Q336 405 275 405Q258 405 240 397T207 376T181 352T163 330L157 322L136 236Q114 150 114 114Q114 66 138 42Q154 26 178 26Q211 26 245 58Q270 81 285 114T318 219Q336 291 336 325Z"/><path id="MJMATHI-74" stroke-width="10" d="M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z"/><path id="MJMATHI-73" stroke-width="10" d="M131 289Q131 321 147 354T203 415T300 442Q362 442 390 415T419 355Q419 323 402 308T364 292Q351 292 340 300T328 326Q328 342 337 354T354 372T367 378Q368 378 368 379Q368 382 361 388T336 399T297 405Q249 405 227 379T204 326Q204 301 223 291T278 274T330 259Q396 230 396 163Q396 135 385 107T352 51T289 7T195 -10Q118 -10 86 19T53 87Q53 126 74 143T118 160Q133 160 146 151T160 120Q160 94 142 76T111 58Q109 57 108 57T107 55Q108 52 115 47T146 34T201 27Q237 27 263 38T301 66T318 97T323 122Q323 150 302 164T254 181T195 196T148 231Q131 256 131 289Z"/></defs></svg><p>using a single nucleotide. In this way, we are able to use the 4 bases that
50compose the DNA strand to encode each byte of data.<table><thead><tr><th>Two bits<th>Nucleotides<tbody><tr><td>00<td><strong>A</strong> (Adenine)<tr><td>10<td><strong>G</strong> (Guanine)<tr><td>01<td><strong>C</strong> (Cytosine)<tr><td>11<td><strong>T</strong> (Thymine)</table><p>With this in mind we can simply encode any data by using two-bit to Nucleotides
51conversion.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>{ Algorithm 1: Naive byte array to DNA encode }
52</span></span><span style=display:flex><span>procedure EncodeToDNASequence(f) string
53</span></span><span style=display:flex><span>begin
54</span></span><span style=display:flex><span> enc string
55</span></span><span style=display:flex><span> <span style=color:#00f>while</span> <span style=color:#00f>not</span> eof(f) do
56</span></span><span style=display:flex><span> c byte := buffer[0] { Read 1 byte <span style=color:#00f>from</span> buffer }
57</span></span><span style=display:flex><span> bin integer := sprintf(<span style=color:#a31515>&#39;08b&#39;</span>, c) { Convert to string binary }
58</span></span><span style=display:flex><span> <span style=color:#00f>for</span> e <span style=color:#00f>in</span> range[0, 2, 4, 6] do
59</span></span><span style=display:flex><span> <span style=color:#00f>if</span> e[0] == 48 <span style=color:#00f>and</span> e[1] == 48 then { 0x00 - A (Adenine) }
60</span></span><span style=display:flex><span> enc += <span style=color:#a31515>&#39;A&#39;</span>
61</span></span><span style=display:flex><span> <span style=color:#00f>else</span> <span style=color:#00f>if</span> e[0] == 48 <span style=color:#00f>and</span> e[1] == 49 then { 0x01 - G (Guanine) }
62</span></span><span style=display:flex><span> enc += <span style=color:#a31515>&#39;G&#39;</span>
63</span></span><span style=display:flex><span> <span style=color:#00f>else</span> <span style=color:#00f>if</span> e[0] == 49 <span style=color:#00f>and</span> e[1] == 48 then { 0x10 - C (Cytosine) }
64</span></span><span style=display:flex><span> enc += <span style=color:#a31515>&#39;C&#39;</span>
65</span></span><span style=display:flex><span> <span style=color:#00f>else</span> <span style=color:#00f>if</span> e[0] == 49 <span style=color:#00f>and</span> e[1] == 49 then { 0x11 - T (Thymine) }
66</span></span><span style=display:flex><span> enc += <span style=color:#a31515>&#39;T&#39;</span>
67</span></span><span style=display:flex><span> <span style=color:#00f>return</span> enc { Return DNA sequence }
68</span></span><span style=display:flex><span>end
69</span></span></code></pre><p>Another encoding would be <strong>Goldman encoding</strong>. Using this encoding helps with
70Nonsense mutation (amino acids replaced by a stop codon) that occurs and is the
71most problematic during translation because it leads to truncated amino acid
72sequences, which in turn results in truncated proteins.<p><a href="https://www.youtube.com/watch?v=a4PiGWNsIEU">Where to store big data? In DNA: Nick Goldman at TEDxPrague</a><h3 id=fasta-file-format>FASTA file format</h3><p>In bioinformatics, FASTA format is a text-based format for representing either
73nucleotide sequences or peptide sequences, in which nucleotides or amino acids
74are represented using single-letter codes. The format also allows for sequence
75names and comments to precede the sequences. The format originates from the
76FASTA software package, but has now become a standard in the field of
77bioinformatics.<p>The first line in a FASTA file started either with a ">" (greater-than) symbol
78or, less frequently, a ";" (semicolon) was taken as a comment. Subsequent lines
79starting with a semicolon would be ignored by software. Since the only comment
80used was the first, it quickly became used to hold a summary description of the
81sequence, often starting with a unique library accession number, and with time
82it has become commonplace to always use ">" for the first line and to not use
83";" comments (which would otherwise be ignored).<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>;LCBO - Prolactin precursor - Bovine
84</span></span><span style=display:flex><span>; a sample sequence in FASTA format
85</span></span><span style=display:flex><span>MDSKGSSQKGSRLLLLLVVSNLLLCQGVVSTPVCPNGPGNCQVSLRDLFDRAVMVSHYIHDLSS
86</span></span><span style=display:flex><span>EMFNEFDKRYAQGKGFITMALNSCHTSSLPTPEDKEQAQQTHHEVLMSLILGLLRSWNDPLYHL
87</span></span><span style=display:flex><span>VTEVRGMKGAPDAILSRAIEIEEENKRLLEGMEMIFGQVIPGAKETEPYPVWSGLPSLQTKDED
88</span></span><span style=display:flex><span>ARYSAFYNLLHCLRRDSSKIDTYLKLLNCRIIYNNNC*
89</span></span><span style=display:flex><span>
90</span></span><span style=display:flex><span>&gt;MCHU - Calmodulin - Human, rabbit, bovine, rat, and chicken
91</span></span><span style=display:flex><span>ADQLTEEQIAEFKEAFSLFDKDGDGTITTKELGTVMRSLGQNPTEAELQDMINEVDADGNGTID
92</span></span><span style=display:flex><span>FPEFLTMMARKMKDTDSEEEIREAFRVFDKDGNGYISAAELRHVMTNLGEKLTDEEVDEMIREA
93</span></span><span style=display:flex><span>DIDGDGQVNYEEFVQMMTAK*
94</span></span><span style=display:flex><span>
95</span></span><span style=display:flex><span>&gt;gi|5524211|gb|AAD44166.1| cytochrome b [Elephas maximus maximus]
96</span></span><span style=display:flex><span>LCLYTHIGRNIYYGSYLYSETWNTGIMLLLITMATAFMGYVLPWGQMSFWGATVITNLFSAIPYIGTNLV
97</span></span><span style=display:flex><span>EWIWGGFSVDKATLNRFFAFHFILPFTMVALAGVHLTFLHETGSNNPLGLTSDSDKIPFHPYYTIKDFLG
98</span></span><span style=display:flex><span>LLILILLLLLLALLSPDMLGDPDNHMPADPLNTPLHIKPEWYFLFAYAILRSVPNKLGGVLALFLSIVIL
99</span></span><span style=display:flex><span>GLMPFLHTSKHRSMMLRPLSQALFWTLTMDLLTLTWIGSQPVEYPYTIIGQMASILYFSIILAFLPIAGX
100</span></span><span style=display:flex><span>IENY
101</span></span></code></pre><p>FASTA format was extended by <a href=https://en.wikipedia.org/wiki/FASTQ_format>FASTQ</a>
102format from the <a href=https://www.sanger.ac.uk/>Sanger Centre</a> in Cambridge.<h3 id=png-encoded-dna-sequence>PNG encoded DNA sequence</h3><table><thead><tr><th>Nucleotides<th>RGB<th>Color name<tbody><tr><td>A ➞ Adenine<td>(0,0,255)<td>Blue<tr><td>G ➞ Guanine<td>(0,100,0)<td>Green<tr><td>C ➞ Cytosine<td>(255,0,0)<td>Red<tr><td>T ➞ Thymine<td>(255,255,0)<td>Yellow</table><p>With this in mind we can create a simple algorithm to create PNG representation
103of a DNA sequence.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>{ Algorithm 2: Naive DNA to PNG encode <span style=color:#00f>from</span> FASTA file }
104</span></span><span style=display:flex><span>procedure EncodeDNASequenceToPNG(f)
105</span></span><span style=display:flex><span>begin
106</span></span><span style=display:flex><span> i image
107</span></span><span style=display:flex><span> <span style=color:#00f>while</span> <span style=color:#00f>not</span> eof(f) do
108</span></span><span style=display:flex><span> c char := buffer[0] { Read 1 char <span style=color:#00f>from</span> buffer }
109</span></span><span style=display:flex><span> case c of
110</span></span><span style=display:flex><span> <span style=color:#a31515>&#39;A&#39;</span>: color := RGB(0, 0, 255) { Blue }
111</span></span><span style=display:flex><span> <span style=color:#a31515>&#39;G&#39;</span>: color := RGB(0, 100, 0) { Green }
112</span></span><span style=display:flex><span> <span style=color:#a31515>&#39;C&#39;</span>: color := RGB(255, 0, 0) { Red }
113</span></span><span style=display:flex><span> <span style=color:#a31515>&#39;T&#39;</span>: color := RGB(255, 255, 0) { Yellow }
114</span></span><span style=display:flex><span> drawRect(i, [x, y], color)
115</span></span><span style=display:flex><span> save(i) { Save PNG image }
116</span></span><span style=display:flex><span>end
117</span></span></code></pre><h2 id=encoding-text-file-in-practice>Encoding text file in practice</h2><p>In this example we will take a simple text file as our input stream for
118encoding. This file will have a quote from Niels Bohr and saved as txt file.<blockquote><p>How wonderful that we have met with a paradox. Now we have some hope of
119making progress.
120― Niels Bohr</blockquote><p>First we encode text file into FASTA file.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>./dnae-encode -i quote.txt -o quote.fa
121</span></span><span style=display:flex><span>2019/01/10 00:38:29 Gathering input file stats
122</span></span><span style=display:flex><span>2019/01/10 00:38:29 Starting encoding ...
123</span></span><span style=display:flex><span> 106 B / 106 B [==================================] 100.00% 0s
124</span></span><span style=display:flex><span>2019/01/10 00:38:29 Saving to FASTA file ...
125</span></span><span style=display:flex><span>2019/01/10 00:38:29 Output FASTA file length is 438 B
126</span></span><span style=display:flex><span>2019/01/10 00:38:29 Process took 987.263µs
127</span></span><span style=display:flex><span>2019/01/10 00:38:29 Done ...
128</span></span></code></pre><p>Output of <code>quote.fa</code> file contains the encoded DNA sequence in ASCII format.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>&gt;SEQ1
129</span></span><span style=display:flex><span>GACAGCTTGTGTACAAGTGTGCTTGCTCGCGAGCGGGTACGCGCGTGGGCTAACAAGTGA
130</span></span><span style=display:flex><span>GCCAGCAGGTGAACAAGTGTGCGGACAAGCCAGCAGGTGCGCGGACAAGCTGGCGGGTGA
131</span></span><span style=display:flex><span>ACAAGTGTGCCGGTGAGCCAACAAGCAGACAAGTAAGCAGGTACGCAGGCGAGCTTGTCA
132</span></span><span style=display:flex><span>ACTCACAAGATCGCTTGTGTACAAGTGTGCGGACAAGCCAGCAGGTGCGCGGACAAGTAT
133</span></span><span style=display:flex><span>GCTTGCTGGCGGACAAGCCAGCTTGTAAGCGGACAAGCTTGCGCACAAGCTGGCAGGCCT
134</span></span><span style=display:flex><span>GCCGGCTCGCGTACAAATTCACAAGTAAGTACGCTTGCGTGTACGCGGGTATGTATACTC
135</span></span><span style=display:flex><span>AACCTCACCAAACGGGACAAGATCGCCGGCGGGCTAGTATACAAGAACGCTTGCCAGTAC
136</span></span><span style=display:flex><span>AACC
137</span></span></code></pre><p>Then we encode FASTA file from previous operation to encode this data into PNG.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>./dnae-png -i quote.fa -o quote.png
138</span></span><span style=display:flex><span>2019/01/10 00:40:09 Gathering input file stats ...
139</span></span><span style=display:flex><span>2019/01/10 00:40:09 Deconstructing FASTA file ...
140</span></span><span style=display:flex><span>2019/01/10 00:40:09 Compositing image file ...
141</span></span><span style=display:flex><span> 424 / 424 [==================================] 100.00% 0s
142</span></span><span style=display:flex><span>2019/01/10 00:40:09 Saving output file ...
143</span></span><span style=display:flex><span>2019/01/10 00:40:09 Output image file length is 1.1 kB
144</span></span><span style=display:flex><span>2019/01/10 00:40:09 Process took 19.036117ms
145</span></span><span style=display:flex><span>2019/01/10 00:40:09 Done ...
146</span></span></code></pre><p>After encoding into PNG format this file looks like this.<figure><img src=/posts/dna-sequence/quote.png alt="Encoded Quote in PNG format"><figcaption><p>The larger the input stream is the larger the PNG file would be.</figcaption></figure><p>Compiled basic Hello World C program with
147<a href=https://www.gnu.org/software/gcc/>GCC</a> would <a href=/posts/dna-sequence/sample.png>look
148like</a>.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green>// gcc -O3 -o sample sample.c
149</span></span></span><span style=display:flex><span><span style=color:green></span><span style=color:#00f>#include</span> <span style=color:#00f>&lt;stdio.h&gt;</span><span style=color:#00f>
150</span></span></span><span style=display:flex><span><span style=color:#00f></span>
151</span></span><span style=display:flex><span>main() {
152</span></span><span style=display:flex><span> printf(<span style=color:#a31515>&#34;Hello, world!</span><span style=color:#a31515>\n</span><span style=color:#a31515>&#34;</span>);
153</span></span><span style=display:flex><span> <span style=color:#00f>return</span> 0;
154</span></span><span style=display:flex><span>}
155</span></span></code></pre><h2 id=toolkit-for-encoding-data>Toolkit for encoding data</h2><p>I have created a toolkit with two main programs:<ul><li>dnae-encode (encodes file into FASTA file)<li>dnae-png (encodes FASTA file into PNG)</ul><p>Toolkit with full source code is available on
156<a href=https://github.com/mitjafelicijan/dna-encoding>github.com/mitjafelicijan/dna-encoding</a>.<h3 id=dnae-encode>dnae-encode</h3><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>&gt; ./dnae-encode --help
157</span></span><span style=display:flex><span>usage: dnae-encode --input=INPUT [&lt;flags&gt;]
158</span></span><span style=display:flex><span>
159</span></span><span style=display:flex><span>A command-line application that encodes file into DNA sequence.
160</span></span><span style=display:flex><span>
161</span></span><span style=display:flex><span>Flags:
162</span></span><span style=display:flex><span> --help Show context-sensitive help (also try --help-long and --help-man).
163</span></span><span style=display:flex><span> -i, --input=INPUT Input file (ASCII or binary) which will be encoded into DNA sequence.
164</span></span><span style=display:flex><span> -o, --output=<span style=color:#a31515>&#34;out.fa&#34;</span> Output file which stores DNA sequence in FASTA format.
165</span></span><span style=display:flex><span> -s, --sequence=SEQ1 The description line (defline) or header/identifier line, gives a name and/or a unique identifier <span style=color:#00f>for</span> the sequence.
166</span></span><span style=display:flex><span> -c, --columns=60 Row characters length (no more than 120 characters). Devices preallocate fixed line sizes in software.
167</span></span><span style=display:flex><span> --version Show application version.
168</span></span></code></pre><h3 id=dnae-png>dnae-png</h3><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>&gt; ./dnae-png --help
169</span></span><span style=display:flex><span>usage: dnae-png --input=INPUT [&lt;flags&gt;]
170</span></span><span style=display:flex><span>
171</span></span><span style=display:flex><span>A command-line application that encodes FASTA file into PNG image.
172</span></span><span style=display:flex><span>
173</span></span><span style=display:flex><span>Flags:
174</span></span><span style=display:flex><span> --help Show context-sensitive help (also try --help-long and --help-man).
175</span></span><span style=display:flex><span> -i, --input=INPUT Input FASTA file which will be encoded into PNG image.
176</span></span><span style=display:flex><span> -o, --output=<span style=color:#a31515>&#34;out.png&#34;</span> Output file in PNG format that represents DNA sequence in graphical way.
177</span></span><span style=display:flex><span> -s, --size=10 Size of pairings of DNA bases on image in pixels (lower resolution lower file size).
178</span></span><span style=display:flex><span> --version Show application version.
179</span></span></code></pre><h2 id=benchmarks>Benchmarks</h2><p>First we generate some binary sample data with dd.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>dd <span style=color:#00f>if</span>=&lt;(openssl enc -aes-256-ctr -pass pass:<span style=color:#a31515>&#34;</span><span style=color:#00f>$(</span>dd <span style=color:#00f>if</span>=/dev/urandom bs=128 count=1 2&gt;/dev/null | base64<span style=color:#00f>)</span><span style=color:#a31515>&#34;</span> -nosalt &lt; /dev/zero) of=1KB.bin bs=1KB count=1 iflag=fullblock
180</span></span></code></pre><figure><img src=/posts/dna-sequence/sample-binary-file.png alt="Sample binary file 1KB"><figcaption><p>Our freshly generated 1KB file looks something like this (its full of
181garbage data as intended).</figcaption></figure><p>We create following binary files:<ul><li>1KB.bin<li>10KB.bin<li>100KB.bin<li>1MB.bin<li>10MB.bin<li>100MB.bin</ul><p>After this we create FASTA files for all the binary files by encoding them
182into DNA sequence.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>./dnae-encode -i 100MB.bin -o 100MB.fa
183</span></span></code></pre><p>Then we GZIP all the FASTA files to see how much the can be compressed.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>gzip -9 &lt; 10MB.fa &gt; 10MB.fa.gz
184</span></span></code></pre><figure><img src=/posts/dna-sequence/chart-speed.svg alt="Encode to FASTA"><figcaption><p>The speed increase that occurs when encoding to FASTA format.</figcaption></figure><figure><img src=/posts/dna-sequence/chart-size.svg alt="File sizes"><figcaption><p>Size of the out file after encoding.</figcaption></figure><p><a href=/posts/dna-sequence/benchmarks.csv>Download CSV file with benchmarks</a>.<h2 id=references>References</h2><ul><li><a href=https://www.techopedia.com/definition/948/encoding>https://www.techopedia.com/definition/948/encoding</a><li><a href=https://www.dna-worldwide.com/resource/160/history-dna-timeline>https://www.dna-worldwide.com/resource/160/history-dna-timeline</a><li><a href=https://opentextbc.ca/biology/chapter/9-1-the-structure-of-dna/>https://opentextbc.ca/biology/chapter/9-1-the-structure-of-dna/</a><li><a href=https://arxiv.org/abs/1801.04774>https://arxiv.org/abs/1801.04774</a><li><a href=https://en.wikipedia.org/wiki/FASTA_format>https://en.wikipedia.org/wiki/FASTA_format</a></ul></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
185a lock on a Linux NFS server, which turned
186out to be specific to NFS v3 (which I really should have seen coming,
187since it involved NLM and lockd). Finding the NFS v4 client that
188owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
189and Bradley Kuhn, are interacting on the OSI's license-discuss
190list where the're doing
191bad computer history and insisting that a guy Larry Rosen
192coincidentally interviewed for a book years ago is clearly the origin of
193somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
194i2c, plan9
195Another month, another file system.
196Well, if you can’t fix it in software, fix it in hardware (looking at
197you, bme680, we’re not
198done yet). The show must go on, as they say, and I would like my
199experiments to go on.
200So a “new” addition to the environmental sensor family connected to
201the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
202this mortal coil, we are endowed with self-awareness, agency, and free will.
203Each of the 8 billion members of this human race represents a unique person, a
204unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
205My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
2061.0 has been released:
207wifi_da-1.0.sit
208(StuffIt 3 archive)
209SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
210This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
211classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
212In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
213Design Goals
214I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
215at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
216catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
217specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
218 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
219 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/esp8266-and-micropython-guide.html b/public/esp8266-and-micropython-guide.html
deleted file mode 100755
index 0bfb2dc..0000000
--- a/public/esp8266-and-micropython-guide.html
+++ /dev/null
@@ -1,128 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Getting started with MicroPython and ESP8266</title><meta name=description content="IntroductionA while ago I bought someESP8266 andESP32 dev boards to playaround with and I finally found a project to try it out."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Getting started with MicroPython and ESP8266</h1><p><cap>post</cap>, Sep 6, 2020 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><h2 id=introduction>Introduction</h2><p>A while ago I bought some
10<a href=https://www.espressif.com/en/products/socs/esp8266>ESP8266</a> and
11<a href=https://www.espressif.com/en/products/socs/esp32>ESP32</a> dev boards to play
12around with and I finally found a project to try it out.<p>For my project, I used <a href=https://www.espressif.com/en/products/socs/esp32>ESP32</a>
13but I could easily choose
14<a href=https://www.espressif.com/en/products/socs/esp8266>ESP8266</a>. This guide
15contains which tools I use and how I prepared my workspace to code for
16<a href=https://www.espressif.com/en/products/socs/esp8266>ESP8266</a>.<figure><img src=/posts/esp8366-micropython/boards.jpg alt="ESP8266 and ESP32 boards"></figure><p>This guide covers:<ul><li>flashing SOC<li>install proper tooling<li>deploying a simple script</ul><blockquote><p>Make sure that you are using <strong>a good USB cable</strong>. I had some problems with
17mine and once I replaced it everything started to work.</blockquote><h2 id=flashing-the-soc>Flashing the SOC</h2><p>Plug your ESP8266 to USB port and check if the device was recognized with
18executing <code>dmesg | grep ch341-uart</code>.<p>Then check if the device is available under <code>/dev/</code> by running <code>ls /dev/ttyUSB*</code>.<blockquote><p><strong>Linux users</strong>: if a device is not available be sure you are in <code>dialout</code>
19group. You can check this by executing <code>groups $USER</code>. You can add a user to
20<code>dialout</code> group with <code>sudo adduser $USER dialout</code>.</blockquote><p>After these conditions are meet go to the navigate to
21<a href=https://micropython.org/download/esp8266/>https://micropython.org/download/esp8266/</a>
22and download <code>esp8266-20200902-v1.13.bin</code>.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>mkdir esp8266-test
23</span></span><span style=display:flex><span>cd esp8266-test
24</span></span><span style=display:flex><span>
25</span></span><span style=display:flex><span>wget https://micropython.org/resources/firmware/esp8266-20200902-v1.13.bin
26</span></span></code></pre><p>After obtaining firmware we will need some tooling to flash the firmware to the
27board.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>sudo pip3 install esptool
28</span></span></code></pre><p>You can read more about <code>esptool</code> at
29<a href=https://github.com/espressif/esptool/>https://github.com/espressif/esptool/</a>.<p>Before flashing the firmware we need to erase the flash on device. Substitute
30<code>USB0</code> with the device listed in output of <code>ls /dev/ttyUSB*</code>.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>esptool.py --port /dev/ttyUSB0 erase_flash
31</span></span></code></pre><p>If flash was successfully erased it is now time to flash the new firmware to it.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=detect 0 esp8266-20200902-v1.13.bin
32</span></span></code></pre><p>If everything went ok you can try accessing MicroPython REPL with <code>screen /dev/ttyUSB0 115200</code> or <code>picocom /dev/ttyUSB0 -b115200</code>.<blockquote><p>Sometimes you will need to press <code>ENTER</code> in <code>screen</code> or <code>picocom</code> to access
33REPL.</blockquote><p>When you are in REPL you can test if all is working properly following steps.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>&gt; <span style=color:#00f>import</span> machine
34</span></span><span style=display:flex><span>&gt; machine.freq()
35</span></span></code></pre><p>This should output a number representing a frequency of the CPU (mine was
36<code>80000000</code>).<p>When you are in <code>screen</code> or <code>picocom</code> these can help you a bit.<table><thead><tr><th>Key<th>Command<tbody><tr><td>CTRL+d<td>preforms soft reboot<tr><td>CTRL+a x<td>exits picocom<tr><td>CTRL+a \<td>exits screen</table><h2 id=install-better-tooling>Install better tooling</h2><p>Now, to make our lives a little bit easier there are couple of additional tools
37that will make this whole experience a little more bearable.<p>There are twq cool ways of uploading local files to SOC flash.<ul><li>ampy → <a href=https://github.com/scientifichackers/ampy>https://github.com/scientifichackers/ampy</a><li>rshell → <a href=https://github.com/dhylands/rshell>https://github.com/dhylands/rshell</a></ul><h3 id=ampy>ampy</h3><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># installing ampy</span>
38</span></span><span style=display:flex><span>sudo pip3 install adafruit-ampy
39</span></span></code></pre><p>Listed below are some common commands I used.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># uploads file to flash</span>
40</span></span><span style=display:flex><span>ampy --delay 2 --port /dev/ttyUSB0 put boot.py
41</span></span><span style=display:flex><span>
42</span></span><span style=display:flex><span><span style=color:green># lists file on flash</span>
43</span></span><span style=display:flex><span>ampy --delay 2 --port /dev/ttyUSB0 ls
44</span></span><span style=display:flex><span>
45</span></span><span style=display:flex><span><span style=color:green># outputs contents of file on flash</span>
46</span></span><span style=display:flex><span>ampy --delay 2 --port /dev/ttyUSB0 cat boot.py
47</span></span></code></pre><blockquote><p>I added <code>delay</code> of 2 seconds because I had problems with executing commands.</blockquote><h3 id=rshell>rshell</h3><p>Even though <code>ampy</code> is a cool tool I opted with <code>rshell</code> in the end since it's
48much more polished and feature rich.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># installing ampy</span>
49</span></span><span style=display:flex><span>sudo pip3 install rshell
50</span></span></code></pre><p>Now that <code>rshell</code> is installed we can connect to the board.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>rshell --buffer-size=30 -p /dev/ttyUSB0 -a
51</span></span></code></pre><p>This will open a shell inside bash and from here you can execute multiple
52commands. You can check what is supported with <code>help</code> once you are inside of a
53shell.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>m@turing ~/Junk/esp8266-test
54</span></span><span style=display:flex><span>$ rshell --buffer-size=30 -p /dev/ttyUSB0 -a
55</span></span><span style=display:flex><span>
56</span></span><span style=display:flex><span>Using buffer-size of 30
57</span></span><span style=display:flex><span>Connecting to /dev/ttyUSB0 (buffer-size 30)...
58</span></span><span style=display:flex><span>Trying to connect to REPL connected
59</span></span><span style=display:flex><span>Testing <span style=color:#00f>if</span> ubinascii.unhexlify exists ... Y
60</span></span><span style=display:flex><span>Retrieving root directories ... /boot.py/
61</span></span><span style=display:flex><span>Setting time ... Sep 06, 2020 23:54:28
62</span></span><span style=display:flex><span>Evaluating board_name ... pyboard
63</span></span><span style=display:flex><span>Retrieving time epoch ... Jan 01, 2000
64</span></span><span style=display:flex><span>Welcome to rshell. Use Control-D (or the exit command) to exit rshell.
65</span></span><span style=display:flex><span>/home/m/Junk/esp8266-test&gt; help
66</span></span><span style=display:flex><span>
67</span></span><span style=display:flex><span>Documented commands (type help &lt;topic&gt;):
68</span></span><span style=display:flex><span>========================================
69</span></span><span style=display:flex><span>args cat connect date edit filesize help mkdir rm shell
70</span></span><span style=display:flex><span>boards cd cp echo exit filetype ls repl rsync
71</span></span><span style=display:flex><span>
72</span></span><span style=display:flex><span>Use Control-D (or the exit command) to exit rshell.
73</span></span></code></pre><blockquote><p>Inside a shell <code>ls</code> will display list of files on your machine. To get list
74of files on flash folder <code>/pyboard</code> is remapped inside the shell. To list files
75on flash you must perform <code>ls /pyboard</code>.</blockquote><h4 id=moving-files-to-flash>Moving files to flash</h4><p>To avoid copying files all the time I used <code>rsync</code> function from the inside of
76<code>rshell</code>.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>rsync . /pyboard
77</span></span></code></pre><h4 id=executing-scripts>Executing scripts</h4><p>It is a pain to continuously reboot the device to trigger <code>/pyboard/boot.py</code> and
78there is a better way of testing local scripts on remote device.<p>Lets assume we have <code>src/freq.py</code> file that displays CPU frequency of a remote
79device.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># src/freq.py</span>
80</span></span><span style=display:flex><span>
81</span></span><span style=display:flex><span><span style=color:#00f>import</span> machine
82</span></span><span style=display:flex><span>print(machine.freq())
83</span></span></code></pre><p>Now lets upload this and execute it.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># syncs files to remove device</span>
84</span></span><span style=display:flex><span>rsync ./src /pyboard
85</span></span><span style=display:flex><span>
86</span></span><span style=display:flex><span><span style=color:green># goes into REPL</span>
87</span></span><span style=display:flex><span>repl
88</span></span><span style=display:flex><span>
89</span></span><span style=display:flex><span><span style=color:green># we import file by importing it without .py extension and this will run the script</span>
90</span></span><span style=display:flex><span>&gt; import freq
91</span></span><span style=display:flex><span>
92</span></span><span style=display:flex><span><span style=color:green># CTRL+x will exit REPL</span>
93</span></span></code></pre><h2 id=additional-resources>Additional resources</h2><ul><li><a href=https://randomnerdtutorials.com/getting-started-micropython-esp32-esp8266/>https://randomnerdtutorials.com/getting-started-micropython-esp32-esp8266/</a><li><a href=http://docs.micropython.org/en/latest/esp8266/quickref.html>http://docs.micropython.org/en/latest/esp8266/quickref.html</a></ul></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
94a lock on a Linux NFS server, which turned
95out to be specific to NFS v3 (which I really should have seen coming,
96since it involved NLM and lockd). Finding the NFS v4 client that
97owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
98and Bradley Kuhn, are interacting on the OSI's license-discuss
99list where the're doing
100bad computer history and insisting that a guy Larry Rosen
101coincidentally interviewed for a book years ago is clearly the origin of
102somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
103i2c, plan9
104Another month, another file system.
105Well, if you can’t fix it in software, fix it in hardware (looking at
106you, bme680, we’re not
107done yet). The show must go on, as they say, and I would like my
108experiments to go on.
109So a “new” addition to the environmental sensor family connected to
110the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
111this mortal coil, we are endowed with self-awareness, agency, and free will.
112Each of the 8 billion members of this human race represents a unique person, a
113unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
114My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
1151.0 has been released:
116wifi_da-1.0.sit
117(StuffIt 3 archive)
118SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
119This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
120classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
121In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
122Design Goals
123I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
124at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
125catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
126specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
127 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
128 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/ewd-manuscripts-ebook.html b/public/ewd-manuscripts-ebook.html
deleted file mode 100755
index c234b37..0000000
--- a/public/ewd-manuscripts-ebook.html
+++ /dev/null
@@ -1,46 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Edsger W. Dijkstra Manuscripts ebook</title><meta name=description content="I love reading the original manuscripts of Edsger W."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Edsger W. Dijkstra Manuscripts ebook</h1><p><cap>note</cap>, Jun 1, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>I love reading the original manuscripts of Edsger W. Dijkstra. They are
10available online at the University of Texas at Austin website, but I also found
11MOBI version. I converted it into ePub as well.<p>Downloads:<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/ewd-manuscripts.mobi>MOBI version of all Manuscripts</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/ewd-manuscripts.epub>ePub version of all Manuscripts</a></ul><p>Sources and credits:<ul><li><a href=https://www.cs.utexas.edu/users/EWD/index00xx.html>Original manuscripts from University of Texas at Austin</a><li><a href=https://github.com/evmn/The-Manuscripts-of-Edsger-W.-Dijkstra>Original repository of MOBI version</a></ul></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
12a lock on a Linux NFS server, which turned
13out to be specific to NFS v3 (which I really should have seen coming,
14since it involved NLM and lockd). Finding the NFS v4 client that
15owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
16and Bradley Kuhn, are interacting on the OSI's license-discuss
17list where the're doing
18bad computer history and insisting that a guy Larry Rosen
19coincidentally interviewed for a book years ago is clearly the origin of
20somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
21i2c, plan9
22Another month, another file system.
23Well, if you can’t fix it in software, fix it in hardware (looking at
24you, bme680, we’re not
25done yet). The show must go on, as they say, and I would like my
26experiments to go on.
27So a “new” addition to the environmental sensor family connected to
28the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
29this mortal coil, we are endowed with self-awareness, agency, and free will.
30Each of the 8 billion members of this human race represents a unique person, a
31unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
32My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
331.0 has been released:
34wifi_da-1.0.sit
35(StuffIt 3 archive)
36SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
37This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
38classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
39In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
40Design Goals
41I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
42at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
43catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
44specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
45 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
46 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/extend-lua-with-custom-c.html b/public/extend-lua-with-custom-c.html
deleted file mode 100755
index cb3b0ac..0000000
--- a/public/extend-lua-with-custom-c.html
+++ /dev/null
@@ -1,72 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Extend Lua with custom C functions using Clang</title><meta name=description content="Here is a boilerplate for extending Lua with custom C functions."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Extend Lua with custom C functions using Clang</h1><p><cap>note</cap>, May 23, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>Here is a boilerplate for extending Lua with custom C functions. This requires
10Clang and Lua 5.1 to be installed. GCC can be used instead of Clang, but the
11Makefile will need to be modified.<ul><li><p>nativefunc.c<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>#include</span> <span style=color:#00f>&lt;lua.h&gt;</span><span style=color:#00f>
12</span></span></span><span style=display:flex><span><span style=color:#00f>#include</span> <span style=color:#00f>&lt;lauxlib.h&gt;</span><span style=color:#00f>
13</span></span></span><span style=display:flex><span><span style=color:#00f></span>
14</span></span><span style=display:flex><span><span style=color:#00f>static</span> <span style=color:#2b91af>int</span> l_mult50(lua_State *L) {
15</span></span><span style=display:flex><span> <span style=color:#2b91af>double</span> number = luaL_checknumber(L, 1);
16</span></span><span style=display:flex><span> lua_pushnumber(L, number * 50);
17</span></span><span style=display:flex><span> <span style=color:#00f>return</span> 1;
18</span></span><span style=display:flex><span>}
19</span></span><span style=display:flex><span>
20</span></span><span style=display:flex><span><span style=color:#2b91af>int</span> luaopen_nativefunc(lua_State *L) {
21</span></span><span style=display:flex><span> <span style=color:#00f>static</span> <span style=color:#00f>const</span> <span style=color:#00f>struct</span> luaL_Reg nativeFuncLib[] = {{<span style=color:#a31515>&#34;mult50&#34;</span>, l_mult50}, {NULL, NULL}};
22</span></span><span style=display:flex><span>
23</span></span><span style=display:flex><span> luaL_register(L, <span style=color:#a31515>&#34;nativelib&#34;</span>, nativeFuncLib);
24</span></span><span style=display:flex><span> <span style=color:#00f>return</span> 1;
25</span></span><span style=display:flex><span>}
26</span></span></code></pre><li><p>main.lua<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>require <span style=color:#a31515>&#34;nativefunc&#34;</span>
27</span></span><span style=display:flex><span>print(nativelib.mult50(50))
28</span></span></code></pre><li><p>Makefile<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>CC = clang
29</span></span><span style=display:flex><span>CFLAGS =
30</span></span><span style=display:flex><span>INCLUDES = <span style=color:#a31515>`</span>pkg-config lua5.1 --cflags-only-I<span style=color:#a31515>`</span>
31</span></span><span style=display:flex><span>
32</span></span><span style=display:flex><span>all:
33</span></span><span style=display:flex><span> <span style=color:#00f>$(</span>CC<span style=color:#00f>)</span> -shared -o nativefunc.so -fPIC nativefunc.c <span style=color:#00f>$(</span>CFLAGS<span style=color:#00f>)</span> <span style=color:#00f>$(</span>INCLUDES<span style=color:#00f>)</span>
34</span></span><span style=display:flex><span>
35</span></span><span style=display:flex><span>clean:
36</span></span><span style=display:flex><span> rm *.so
37</span></span></code></pre></ul></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
38a lock on a Linux NFS server, which turned
39out to be specific to NFS v3 (which I really should have seen coming,
40since it involved NLM and lockd). Finding the NFS v4 client that
41owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
42and Bradley Kuhn, are interacting on the OSI's license-discuss
43list where the're doing
44bad computer history and insisting that a guy Larry Rosen
45coincidentally interviewed for a book years ago is clearly the origin of
46somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
47i2c, plan9
48Another month, another file system.
49Well, if you can’t fix it in software, fix it in hardware (looking at
50you, bme680, we’re not
51done yet). The show must go on, as they say, and I would like my
52experiments to go on.
53So a “new” addition to the environmental sensor family connected to
54the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
55this mortal coil, we are endowed with self-awareness, agency, and free will.
56Each of the 8 billion members of this human race represents a unique person, a
57unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
58My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
591.0 has been released:
60wifi_da-1.0.sit
61(StuffIt 3 archive)
62SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
63This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
64classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
65In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
66Design Goals
67I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
68at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
69catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
70specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
71 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
72 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/extending-dte-editor.html b/public/extending-dte-editor.html
deleted file mode 100755
index 1e3352f..0000000
--- a/public/extending-dte-editor.html
+++ /dev/null
@@ -1,79 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Extending dte editor</title><meta name=description content="dte is an interesting editor I startedusing lately more and more."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Extending dte editor</h1><p><cap>note</cap>, May 31, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p><a href=https://craigbarnes.gitlab.io/dte/><code>dte</code></a> is an interesting editor I started
10using lately more and more. Since it is using
11<a href=https://linux.die.net/man/3/execvp><code>execvp()</code></a> it can be easily extended. I
12needed comment/uncomment feature so I created a small utility that does this for
13me. Code lives on repository <a href=https://git.mitjafelicijan.com/dte-extensions.git/about/>dte
14extensions</a> but this
15utilities can be used for whatever you want. Make sure you have version 1.11 or
16above.<p>Next one will be invoking formatter based on the type of a file.<p>My config that works for me.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>set show-line-numbers true;
17</span></span><span style=display:flex><span>set tab-width 4;
18</span></span><span style=display:flex><span>set <span style=color:#00f>case</span>-sensitive-search false;
19</span></span><span style=display:flex><span>
20</span></span><span style=display:flex><span><span style=color:green># Special aliases</span>
21</span></span><span style=display:flex><span>alias m_comment <span style=color:#a31515>&#39;exec -s -i line -o buffer -e errmsg ~/.dte/bin/comment&#39;</span>
22</span></span><span style=display:flex><span>alias m_format <span style=color:#a31515>&#39;save; exec go fmt .; reload&#39;</span>
23</span></span><span style=display:flex><span>alias m_duplicate <span style=color:#a31515>&#39;copy;paste&#39;</span>;
24</span></span><span style=display:flex><span>
25</span></span><span style=display:flex><span><span style=color:green># Useful aliases.</span>
26</span></span><span style=display:flex><span>alias m_force_close <span style=color:#a31515>&#39;quit -f&#39;</span>;
27</span></span><span style=display:flex><span>alias m_reload <span style=color:#a31515>&#39;close; open $FILE&#39;</span>
28</span></span><span style=display:flex><span>
29</span></span><span style=display:flex><span><span style=color:green># Key bindings.</span>
30</span></span><span style=display:flex><span>bind M-s save;
31</span></span><span style=display:flex><span>bind M-q m_force_close;
32</span></span><span style=display:flex><span>bind M-z refresh;
33</span></span><span style=display:flex><span>bind C-down blkdown;
34</span></span><span style=display:flex><span>bind C-up blkup;
35</span></span><span style=display:flex><span>bind C-_ m_comment;
36</span></span><span style=display:flex><span>bind M-. m_format;
37</span></span><span style=display:flex><span>bind C-d m_duplicate;
38</span></span><span style=display:flex><span>
39</span></span><span style=display:flex><span><span style=color:green># Syntax highlighting.</span>
40</span></span><span style=display:flex><span>hi preproc magenta;
41</span></span><span style=display:flex><span>hi keyword red;
42</span></span><span style=display:flex><span>hi linenumber blue;
43</span></span><span style=display:flex><span>hi comment cyan;
44</span></span></code></pre></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
45a lock on a Linux NFS server, which turned
46out to be specific to NFS v3 (which I really should have seen coming,
47since it involved NLM and lockd). Finding the NFS v4 client that
48owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
49and Bradley Kuhn, are interacting on the OSI's license-discuss
50list where the're doing
51bad computer history and insisting that a guy Larry Rosen
52coincidentally interviewed for a book years ago is clearly the origin of
53somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
54i2c, plan9
55Another month, another file system.
56Well, if you can’t fix it in software, fix it in hardware (looking at
57you, bme680, we’re not
58done yet). The show must go on, as they say, and I would like my
59experiments to go on.
60So a “new” addition to the environmental sensor family connected to
61the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
62this mortal coil, we are endowed with self-awareness, agency, and free will.
63Each of the 8 billion members of this human race represents a unique person, a
64unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
65My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
661.0 has been released:
67wifi_da-1.0.sit
68(StuffIt 3 archive)
69SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
70This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
71classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
72In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
73Design Goals
74I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
75at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
76catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
77specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
78 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
79 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/fix-plan9-bootloader.html b/public/fix-plan9-bootloader.html
deleted file mode 100755
index 3fbac5d..0000000
--- a/public/fix-plan9-bootloader.html
+++ /dev/null
@@ -1,50 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Fix bootloader not being written in Plan9</title><meta name=description content="If the bootloader is not being written to a disk when installing 9front on realharware try clearing first sector of the disk with the following command."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Fix bootloader not being written in Plan9</h1><p><cap>note</cap>, May 11, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>If the bootloader is not being written to a disk when installing 9front on real
10harware try clearing first sector of the disk with the following command.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>dd <span style=color:#00f>if</span>=/dev/zero of=/dev/sdX bs=512 count=1
11</span></span><span style=display:flex><span>
12</span></span><span style=display:flex><span><span style=color:green># If command above doesn&#39;t work try this one, wait couple of seconds and</span>
13</span></span><span style=display:flex><span><span style=color:green># press delete key to stop the command.</span>
14</span></span><span style=display:flex><span>cat &lt;/dev/zero &gt;/dev/sd*/data
15</span></span></code></pre></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
16a lock on a Linux NFS server, which turned
17out to be specific to NFS v3 (which I really should have seen coming,
18since it involved NLM and lockd). Finding the NFS v4 client that
19owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
20and Bradley Kuhn, are interacting on the OSI's license-discuss
21list where the're doing
22bad computer history and insisting that a guy Larry Rosen
23coincidentally interviewed for a book years ago is clearly the origin of
24somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
25i2c, plan9
26Another month, another file system.
27Well, if you can’t fix it in software, fix it in hardware (looking at
28you, bme680, we’re not
29done yet). The show must go on, as they say, and I would like my
30experiments to go on.
31So a “new” addition to the environmental sensor family connected to
32the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
33this mortal coil, we are endowed with self-awareness, agency, and free will.
34Each of the 8 billion members of this human race represents a unique person, a
35unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
36My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
371.0 has been released:
38wifi_da-1.0.sit
39(StuffIt 3 archive)
40SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
41This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
42classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
43In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
44Design Goals
45I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
46at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
47catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
48specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
49 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
50 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/fix-screen-tearing-on-debian-12-xorg-and-i3.html b/public/fix-screen-tearing-on-debian-12-xorg-and-i3.html
deleted file mode 100755
index db8a5e1..0000000
--- a/public/fix-screen-tearing-on-debian-12-xorg-and-i3.html
+++ /dev/null
@@ -1,52 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Fix screen tearing on Debian 12 Xorg and i3</title><meta name=description content="I have been experiencing some issues with Intel® Integrated HD Graphics 3000under Debian 12 with Xorg and i3."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Fix screen tearing on Debian 12 Xorg and i3</h1><p><cap>note</cap>, Jul 10, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>I have been experiencing some issues with Intel® Integrated HD Graphics 3000
10under Debian 12 with Xorg and i3. Using <code>picom</code> compositor didn't help. To fix
11this issue create new file <code>/etc/X11/xorg.conf.d/20-intel.conf</code> as root and put
12the following in the file.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>Section &#34;Device&#34;
13</span></span><span style=display:flex><span> Identifier &#34;Intel Graphics&#34;
14</span></span><span style=display:flex><span> Driver &#34;intel&#34;
15</span></span><span style=display:flex><span> Option &#34;TearFree&#34; &#34;true&#34;
16</span></span><span style=display:flex><span>EndSection
17</span></span></code></pre><p>Reboot the system and that should be it.</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
18a lock on a Linux NFS server, which turned
19out to be specific to NFS v3 (which I really should have seen coming,
20since it involved NLM and lockd). Finding the NFS v4 client that
21owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
22and Bradley Kuhn, are interacting on the OSI's license-discuss
23list where the're doing
24bad computer history and insisting that a guy Larry Rosen
25coincidentally interviewed for a book years ago is clearly the origin of
26somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
27i2c, plan9
28Another month, another file system.
29Well, if you can’t fix it in software, fix it in hardware (looking at
30you, bme680, we’re not
31done yet). The show must go on, as they say, and I would like my
32experiments to go on.
33So a “new” addition to the environmental sensor family connected to
34the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
35this mortal coil, we are endowed with self-awareness, agency, and free will.
36Each of the 8 billion members of this human race represents a unique person, a
37unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
38My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
391.0 has been released:
40wifi_da-1.0.sit
41(StuffIt 3 archive)
42SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
43This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
44classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
45In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
46Design Goals
47I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
48at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
49catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
50specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
51 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
52 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/floods-in-slovenia.html b/public/floods-in-slovenia.html
deleted file mode 100755
index 425a541..0000000
--- a/public/floods-in-slovenia.html
+++ /dev/null
@@ -1,44 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Floods in Slovenia up close</title><meta name=description content><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Floods in Slovenia up close</h1><p><cap>note</cap>, Aug 5, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p><video src=/notes/floods/IMG_1471.mp4 controls></video><p><video src=/notes/floods/IMG_1474.mp4 controls></video><figure><img src=/notes/floods/IMG_1469.webp alt></figure><figure><img src=/notes/floods/IMG_1470.webp alt></figure><p><video src=/notes/floods/IMG_1461.mp4 controls></video><p><video src=/notes/floods/IMG_1466.mp4 controls></video></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
10a lock on a Linux NFS server, which turned
11out to be specific to NFS v3 (which I really should have seen coming,
12since it involved NLM and lockd). Finding the NFS v4 client that
13owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
14and Bradley Kuhn, are interacting on the OSI's license-discuss
15list where the're doing
16bad computer history and insisting that a guy Larry Rosen
17coincidentally interviewed for a book years ago is clearly the origin of
18somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
19i2c, plan9
20Another month, another file system.
21Well, if you can’t fix it in software, fix it in hardware (looking at
22you, bme680, we’re not
23done yet). The show must go on, as they say, and I would like my
24experiments to go on.
25So a “new” addition to the environmental sensor family connected to
26the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
27this mortal coil, we are endowed with self-awareness, agency, and free will.
28Each of the 8 billion members of this human race represents a unique person, a
29unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
30My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
311.0 has been released:
32wifi_da-1.0.sit
33(StuffIt 3 archive)
34SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
35This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
36classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
37In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
38Design Goals
39I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
40at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
41catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
42specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
43 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
44 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/fresh-9front-desktop.html b/public/fresh-9front-desktop.html
deleted file mode 100755
index a4a6c65..0000000
--- a/public/fresh-9front-desktop.html
+++ /dev/null
@@ -1,45 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>My brand new Plan9/9front desktop</title><meta name=description content="I have been experimenting with Plan9/9front for a week now."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>My brand new Plan9/9front desktop</h1><p><cap>note</cap>, May 24, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>I have been experimenting with Plan9/9front for a week now. Noice! This is how
10my desktop looks like.<figure><img src=/notes/9front-desktop.png alt="9front desktop"></figure></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
11a lock on a Linux NFS server, which turned
12out to be specific to NFS v3 (which I really should have seen coming,
13since it involved NLM and lockd). Finding the NFS v4 client that
14owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
15and Bradley Kuhn, are interacting on the OSI's license-discuss
16list where the're doing
17bad computer history and insisting that a guy Larry Rosen
18coincidentally interviewed for a book years ago is clearly the origin of
19somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
20i2c, plan9
21Another month, another file system.
22Well, if you can’t fix it in software, fix it in hardware (looking at
23you, bme680, we’re not
24done yet). The show must go on, as they say, and I would like my
25experiments to go on.
26So a “new” addition to the environmental sensor family connected to
27the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
28this mortal coil, we are endowed with self-awareness, agency, and free will.
29Each of the 8 billion members of this human race represents a unique person, a
30unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
31My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
321.0 has been released:
33wifi_da-1.0.sit
34(StuffIt 3 archive)
35SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
36This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
37classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
38In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
39Design Goals
40I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
41at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
42catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
43specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
44 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
45 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/from-internet-consumer-to-full-hominum-again.html b/public/from-internet-consumer-to-full-hominum-again.html
deleted file mode 100755
index 5b9f577..0000000
--- a/public/from-internet-consumer-to-full-hominum-again.html
+++ /dev/null
@@ -1,112 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>My journey from being an internet über consumer to being a full hominum again</title><meta name=description content="It&amp;#39;s been almost a year since I started purging all my online accounts andgoing down this rabbit hole of being almost independent of the current internetmachine."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>My journey from being an internet über consumer to being a full hominum again</h1><p><cap>post</cap>, Jul 30, 2021 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>It's been almost a year since I started purging all my online accounts and
10going down this rabbit hole of being almost independent of the current internet
11machine. Even though I initially thought that I will have problems adapting,
12I was pleasantly surprised that the transition went so smoothly. Even better,
13it brought many benefits to my life. Such as increased focus, less stress
14about trivial things, etc.<p>It all started with me doing small changes like unsubscribing from emails that I
15have either subscribed to by accepting terms and conditions. Or even some more
16malicious emails that I was getting because I was on a shared mailing list. And
17the later ones I hate the most of all. How the hell do they keep sharing my
18email and sending me unsolicited emails and get away with it? I have a suspicion
19that these marketing people share an Excel file between them and keep
20resubscribing me when they import lists into Mailchimp or similar software.<p>It's fascinating to see how much crap you get subscribed to when you are not
21paying attention. It got so bad that my primary Gmail address is a full of junk
22and need constant monitoring and cleaning up. And because I want to have Inbox
23Zero, this presents an additional problem for me.<p>The stress that email presented for me didn't occur to me for a long time. I was
24noticing that I was unable to go through one single hour without hysterically
25refreshing email. And if somebody wrote me something, I needed to see it right
26then, even though I didn't immediately reply to it. I can only describe this
27with FOMO (fear of missing out). I have no other explanation than that. It was
28crippling, and I was constantly context switching, which I will address further
29down this post in more details.<p>This was one of the reasons why I spawned up my personal email server, and I am
30using it now as my primary and person email. I still have Gmail as my “junk”
31email that I use for throw away stuff. I log in to Gmail once a week and check
32if there are any important emails that I got, but apart from that, it's sitting
33dormant and collecting dust.<p>The more I was watching the world loose it's self with allowing anti freedom
34things to happen to it, the more I started to realize that something has to
35change. I don't have the power to change the world. And I also don't have a
36grandiose opinion of myself to even think to try it. But what I can do is to not
37subscribe to this consumer way of thinking. I will not be complicit in this. My
38moral and ethical stances won't allow it. So, this brings us to the second part
39of my journey.<p>I was using all these 3rd party services because I was either lazy or OK with
40the drawbacks of them. I watched these services and companies became more and
41privacy policies and everybody is OK with accepting them, and they pray on that
42more evil. It is evil if you sell your user's data in this manner. Nobody reads
43flaw in human nature. I really hate the hypocrisy they manage to muster. These
44companies prey on our laziness, and we are at fault here. Nobody else. And I
45truly understand the reasons why we rather accept and move on, and not object
46and have our lives a little more difficult. They have perfected this through
47years of small changes that make us a little more dependent on them. You could
48not convince a person to give away all his rights and data in one day. This was
49gradual and slow. And it caught us all in surprise. When I really stopped and
50thought about it, I felt repulsed. By really stopping and thinking about it, I
51really mean stopping and thinking about it. Thoroughly and in depth.<p>Each step I took depleted my character a bit more. Like I was trading myself bit
52by bit without understanding what it all meant. What it meant to be a full
53person, not divided by all this bought attention they want from me. They don't
54just get your data, but they also take your attention away from you. They
55scatter your and go with the divide and conquer tactic from there. And a person
56divided is a person not fully there. Not at the moment. Not alive fully.<p>I was unable to form long thoughts. Well, I thought I was. But now that I see
57what being a full person is again, I can see that I was not at my 100% back
58then.<p>A revolt was inevitable. There was no other way of continuing my story without
59it. Without taking back my attention, my thoughts, my time, and my privacy,
60regardless of how too late it maybe is.<p>This has nothing to do with conspiracy theories. Even less with changing the
61world. All I wanted was to get my life back in order and not waste the energy
62that could be spent in other, better places.<p>I started reading more. I can focus now fully on things I work on. Furthermore,
63I have the mental acuity that I never had before. My mind feels sharp. I don't
64get angry so much. I can cherish the finer things in life now without the need
65to interpret them intellectually. Not only that, but I have a feeling of
66belonging again. Sense of purpose has returned with a vengeance. And I can now
67help people without depleting myself.<p>The last step so far was to finish closing all the remaining online accounts
68that I still had. And when I was thinking what value they bring me, I wasn't
69surprised that the answer was none. I wasn't logging in them and using them. I
70stopped being afraid of FOMO. If somebody wants to get in contact me, they will
71find a way. I am one search away.<p>We are not beholden to anybody. Our lives are our own. So dare yourself to
72delete Facebook, LinkedIn. To unsubscribe. Dare yourself to take your time and
73attention back. Use that time and energy to go for a walk without thinking about
74work. Read a book instead of reading comment on social media that you will
75forget in an hour. Enrich your life instead of wasting it. It only requires a
76small step. And you will feel the benefits immediately. Lose the weight of the
77world that is crushing you without your consent.</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
78a lock on a Linux NFS server, which turned
79out to be specific to NFS v3 (which I really should have seen coming,
80since it involved NLM and lockd). Finding the NFS v4 client that
81owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
82and Bradley Kuhn, are interacting on the OSI's license-discuss
83list where the're doing
84bad computer history and insisting that a guy Larry Rosen
85coincidentally interviewed for a book years ago is clearly the origin of
86somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
87i2c, plan9
88Another month, another file system.
89Well, if you can’t fix it in software, fix it in hardware (looking at
90you, bme680, we’re not
91done yet). The show must go on, as they say, and I would like my
92experiments to go on.
93So a “new” addition to the environmental sensor family connected to
94the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
95this mortal coil, we are endowed with self-awareness, agency, and free will.
96Each of the 8 billion members of this human race represents a unique person, a
97unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
98My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
991.0 has been released:
100wifi_da-1.0.sit
101(StuffIt 3 archive)
102SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
103This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
104classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
105In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
106Design Goals
107I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
108at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
109catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
110specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
111 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
112 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/git-push-multiple-origins.html b/public/git-push-multiple-origins.html
deleted file mode 100755
index 6791454..0000000
--- a/public/git-push-multiple-origins.html
+++ /dev/null
@@ -1,47 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Push to multiple origins at once in Git</title><meta name=description content="Sometimes you want to push to multiple origins at once."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Push to multiple origins at once in Git</h1><p><cap>note</cap>, May 6, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>Sometimes you want to push to multiple origins at once. This is useful if you
10have a mirror of your repository on another server. You can do this by adding
11multiple push urls to your git config. This is a shorthand for command above.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>git config --global alias.pushall <span style=color:#a31515>&#39;!sh -c &#34;git remote | xargs -L1 git push --all&#34;&#39;</span>
12</span></span></code></pre></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
13a lock on a Linux NFS server, which turned
14out to be specific to NFS v3 (which I really should have seen coming,
15since it involved NLM and lockd). Finding the NFS v4 client that
16owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
17and Bradley Kuhn, are interacting on the OSI's license-discuss
18list where the're doing
19bad computer history and insisting that a guy Larry Rosen
20coincidentally interviewed for a book years ago is clearly the origin of
21somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
22i2c, plan9
23Another month, another file system.
24Well, if you can’t fix it in software, fix it in hardware (looking at
25you, bme680, we’re not
26done yet). The show must go on, as they say, and I would like my
27experiments to go on.
28So a “new” addition to the environmental sensor family connected to
29the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
30this mortal coil, we are endowed with self-awareness, agency, and free will.
31Each of the 8 billion members of this human race represents a unique person, a
32unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
33My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
341.0 has been released:
35wifi_da-1.0.sit
36(StuffIt 3 archive)
37SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
38This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
39classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
40In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
41Design Goals
42I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
43at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
44catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
45specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
46 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
47 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/golang-profiling-simplified.html b/public/golang-profiling-simplified.html
deleted file mode 100755
index f794aba..0000000
--- a/public/golang-profiling-simplified.html
+++ /dev/null
@@ -1,124 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Golang profiling simplified</title><meta name=description content="Many posts have been written regarding profiling in Golang and I haven’t foundproper tutorial regarding this."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Golang profiling simplified</h1><p><cap>post</cap>, Mar 7, 2017 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>Many posts have been written regarding profiling in Golang and I haven’t found
10proper tutorial regarding this. Almost all of them are missing some part of
11important information and it gets pretty frustrating when you have a deadline
12and are not finding simple distilled solution.<p>Nevertheless, after searching and experimenting I have found a solution that
13works for me and probably should also for you.<h2 id=where-are-my-pprof-files>Where are my pprof files?</h2><p>By default pprof files are generated in /tmp/ folder. You can override folder
14where this files are generated programmatically in your golang code as we will
15see below in example.<h2 id=why-is-my-cpu-profile-empty>Why is my CPU profile empty?</h2><p>I have found out that sometimes CPU profile is empty because program was not
16executing long enough. Programs, that execute too quickly don’t produce pprof
17file in my cases. Well, file is generated but only contains 4KB of information.<h2 id=profiling>Profiling</h2><p>As you can see from examples we are executing dummy_benchmark functions to
18ensure some sort of execution. Memory profiling can be done without such a
19“complex” function. But CPU profiling needs it.<p>Both memory and CPU profiling examples are almost the same. Only parameters in
20main function when calling profile.Start are different. When we set
21profile.ProfilePath(“.”) we tell profiler to store pprof files in the same
22folder as our program.<h3 id=memory-profiling>Memory profiling</h3><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>package</span> main
23</span></span><span style=display:flex><span>
24</span></span><span style=display:flex><span><span style=color:#00f>import</span> (
25</span></span><span style=display:flex><span> <span style=color:#a31515>&#34;fmt&#34;</span>
26</span></span><span style=display:flex><span> <span style=color:#a31515>&#34;time&#34;</span>
27</span></span><span style=display:flex><span> <span style=color:#a31515>&#34;github.com/pkg/profile&#34;</span>
28</span></span><span style=display:flex><span>)
29</span></span><span style=display:flex><span>
30</span></span><span style=display:flex><span><span style=color:#00f>func</span> dummy_benchmark() {
31</span></span><span style=display:flex><span>
32</span></span><span style=display:flex><span> fmt.Println(<span style=color:#a31515>&#34;first set ...&#34;</span>)
33</span></span><span style=display:flex><span> <span style=color:#00f>for</span> i := 0; i &lt; 918231333; i++ {
34</span></span><span style=display:flex><span> i *= 2
35</span></span><span style=display:flex><span> i /= 2
36</span></span><span style=display:flex><span> }
37</span></span><span style=display:flex><span>
38</span></span><span style=display:flex><span> &lt;-time.After(time.Second*3)
39</span></span><span style=display:flex><span>
40</span></span><span style=display:flex><span> fmt.Println(<span style=color:#a31515>&#34;sencond set ...&#34;</span>)
41</span></span><span style=display:flex><span> <span style=color:#00f>for</span> i := 0; i &lt; 9182312232; i++ {
42</span></span><span style=display:flex><span> i *= 2
43</span></span><span style=display:flex><span> i /= 2
44</span></span><span style=display:flex><span> }
45</span></span><span style=display:flex><span>}
46</span></span><span style=display:flex><span>
47</span></span><span style=display:flex><span><span style=color:#00f>func</span> main() {
48</span></span><span style=display:flex><span> <span style=color:#00f>defer</span> profile.Start(profile.MemProfile, profile.ProfilePath(<span style=color:#a31515>&#34;.&#34;</span>), profile.NoShutdownHook).Stop()
49</span></span><span style=display:flex><span> dummy_benchmark()
50</span></span><span style=display:flex><span>}
51</span></span></code></pre><h3 id=cpu-profiling>CPU profiling</h3><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>package</span> main
52</span></span><span style=display:flex><span>
53</span></span><span style=display:flex><span><span style=color:#00f>import</span> (
54</span></span><span style=display:flex><span> <span style=color:#a31515>&#34;fmt&#34;</span>
55</span></span><span style=display:flex><span> <span style=color:#a31515>&#34;time&#34;</span>
56</span></span><span style=display:flex><span> <span style=color:#a31515>&#34;github.com/pkg/profile&#34;</span>
57</span></span><span style=display:flex><span>)
58</span></span><span style=display:flex><span>
59</span></span><span style=display:flex><span><span style=color:#00f>func</span> dummy_benchmark() {
60</span></span><span style=display:flex><span>
61</span></span><span style=display:flex><span> fmt.Println(<span style=color:#a31515>&#34;first set ...&#34;</span>)
62</span></span><span style=display:flex><span> <span style=color:#00f>for</span> i := 0; i &lt; 918231333; i++ {
63</span></span><span style=display:flex><span> i *= 2
64</span></span><span style=display:flex><span> i /= 2
65</span></span><span style=display:flex><span> }
66</span></span><span style=display:flex><span>
67</span></span><span style=display:flex><span> &lt;-time.After(time.Second*3)
68</span></span><span style=display:flex><span>
69</span></span><span style=display:flex><span> fmt.Println(<span style=color:#a31515>&#34;sencond set ...&#34;</span>)
70</span></span><span style=display:flex><span> <span style=color:#00f>for</span> i := 0; i &lt; 9182312232; i++ {
71</span></span><span style=display:flex><span> i *= 2
72</span></span><span style=display:flex><span> i /= 2
73</span></span><span style=display:flex><span> }
74</span></span><span style=display:flex><span>}
75</span></span><span style=display:flex><span>
76</span></span><span style=display:flex><span><span style=color:#00f>func</span> main() {
77</span></span><span style=display:flex><span> <span style=color:#00f>defer</span> profile.Start(profile.CPUProfile, profile.ProfilePath(<span style=color:#a31515>&#34;.&#34;</span>), profile.NoShutdownHook).Stop()
78</span></span><span style=display:flex><span> dummy_benchmark()
79</span></span><span style=display:flex><span>}
80</span></span></code></pre><h3 id=generating-profiling-reports>Generating profiling reports</h3><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># memory profiling</span>
81</span></span><span style=display:flex><span>go build mem.go
82</span></span><span style=display:flex><span>./mem
83</span></span><span style=display:flex><span>go tool pprof -pdf ./mem mem.pprof &gt; mem.pdf
84</span></span><span style=display:flex><span>
85</span></span><span style=display:flex><span><span style=color:green># cpu profiling</span>
86</span></span><span style=display:flex><span>go build cpu.go
87</span></span><span style=display:flex><span>./cpu
88</span></span><span style=display:flex><span>go tool pprof -pdf ./cpu cpu.pprof &gt; cpu.pdf
89</span></span></code></pre><p>This will generate PDF document with visualized profile.<ul><li><a href=/posts/go-profiling/golang-profiling-mem.pdf>Memory PDF profile example</a><li><a href=/posts/go-profiling/golang-profiling-cpu.pdf>CPU PDF profile example</a></ul></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
90a lock on a Linux NFS server, which turned
91out to be specific to NFS v3 (which I really should have seen coming,
92since it involved NLM and lockd). Finding the NFS v4 client that
93owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
94and Bradley Kuhn, are interacting on the OSI's license-discuss
95list where the're doing
96bad computer history and insisting that a guy Larry Rosen
97coincidentally interviewed for a book years ago is clearly the origin of
98somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
99i2c, plan9
100Another month, another file system.
101Well, if you can’t fix it in software, fix it in hardware (looking at
102you, bme680, we’re not
103done yet). The show must go on, as they say, and I would like my
104experiments to go on.
105So a “new” addition to the environmental sensor family connected to
106the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
107this mortal coil, we are endowed with self-awareness, agency, and free will.
108Each of the 8 billion members of this human race represents a unique person, a
109unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
110My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
1111.0 has been released:
112wifi_da-1.0.sit
113(StuffIt 3 archive)
114SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
115This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
116classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
117In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
118Design Goals
119I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
120at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
121catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
122specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
123 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
124 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/grep-to-less-maintain-colors.html b/public/grep-to-less-maintain-colors.html
deleted file mode 100755
index 893904a..0000000
--- a/public/grep-to-less-maintain-colors.html
+++ /dev/null
@@ -1,49 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Grep to Less that maintain colors</title><meta name=description content="I often use grep to search for todo&amp;#39;s in my code and other people&amp;#39;s code andthen pipe them in less and I missed having colors that grep outputs in less."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Grep to Less that maintain colors</h1><p><cap>note</cap>, May 29, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>I often use <code>grep</code> to search for todo's in my code and other people's code and
10then pipe them in <code>less</code> and I missed having colors that grep outputs in <code>less</code>.<ul><li>Grep's <code>--color=always</code> use markers to highlight the matching strings.<li>Less's <code>-R</code> option outputs "raw" control characters.</ul><p>You could use <code>alias grep='grep --color=always'</code> and <code>alias less='less -R'</code> or
11create todo function in your <code>.bashrc</code> that accepts first argument as search
12string.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># This is where the magic happens.</span>
13</span></span><span style=display:flex><span>grep --color=always -rni <span style=color:#a31515>&#34;TODO:&#34;</span> | less -R
14</span></span></code></pre><figure><img src=/notes/grep-less.png alt="Less and grep"></figure></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
15a lock on a Linux NFS server, which turned
16out to be specific to NFS v3 (which I really should have seen coming,
17since it involved NLM and lockd). Finding the NFS v4 client that
18owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
19and Bradley Kuhn, are interacting on the OSI's license-discuss
20list where the're doing
21bad computer history and insisting that a guy Larry Rosen
22coincidentally interviewed for a book years ago is clearly the origin of
23somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
24i2c, plan9
25Another month, another file system.
26Well, if you can’t fix it in software, fix it in hardware (looking at
27you, bme680, we’re not
28done yet). The show must go on, as they say, and I would like my
29experiments to go on.
30So a “new” addition to the environmental sensor family connected to
31the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
32this mortal coil, we are endowed with self-awareness, agency, and free will.
33Each of the 8 billion members of this human race represents a unique person, a
34unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
35My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
361.0 has been released:
37wifi_da-1.0.sit
38(StuffIt 3 archive)
39SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
40This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
41classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
42In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
43Design Goals
44I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
45at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
46catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
47specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
48 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
49 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/i-was-wrong-about-git-workflows.html b/public/i-was-wrong-about-git-workflows.html
deleted file mode 100755
index 2be0cbd..0000000
--- a/public/i-was-wrong-about-git-workflows.html
+++ /dev/null
@@ -1,84 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>I think I was completely wrong about Git workflows</title><meta name=description content="I have been using some approximation of GitFlow for years now and never reallyquestioned it to be honest."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>I think I was completely wrong about Git workflows</h1><p><cap>post</cap>, May 23, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>I have been using some approximation of <a href=https://jeffkreeftmeijer.com/git-flow/>Git
10Flow</a> for years now and never really
11questioned it to be honest. When I create a repo I create develop branch and set
12it as default one and then merge to master from there. Seems reasonable enough.<p>One thing that I have learned is that long living branches are the devil. They
13always end up making a huge mess when they need to be merged eventually into
14master. So by that reason, what is the develop branch if not the longest living
15feature branch. And from my personal experience there was never a situation
16where I wasn’t sweating bullets when I had to merge develop back to master.<p>This realisation started to give me pause. So why the hell am I doing this, and
17is there a better way. Well the solution was always there. And it comes in a
18form of <a href=https://git-scm.com/book/en/v2/Git-Basics-Tagging>git tags</a>.<p>So what are git tags? Git tags are references to specific points in a Git
19repository's history. They are used to mark important milestones, such as
20releases or significant commits, making it easier to identify and access
21specific versions of a project.<p>Somehow we have all hijacked the meaning of the master branch that it has to be
22the most releasable version of code. And this is also where the confusing about
23versioning the software kicks in. Because master branch implicitly says that we
24are dealing with the rolling release type of a software. And by having a develop
25branch we are hacking around this confusion. With a separation of develop and
26master we lock functionalities into place and forcing a stable vs development
27version of the software.<p>But if that is true and the long living branches are the devil then why have
28develop at all. I think that most of this comes to how continuous integration is
29being done. There usually is no granular access to tags and CD software deploys
30what is present on a specific branch, may that be master for production and
31develop for staging. This is a gross simplification and by having this in place
32we have completely removed tagging as a viable option to create a fix point in
33software cycle that says, this is the production ready code.<p>One cool thing about tags are that you can checkout a specific tag. So they
34behave very similarly as branches in that regard. And you don’t have the
35overhead of having two mainstream branches.<p>So what is the solution? One approach is to use development workflow, where all
36changes are made on the smaller branches and continuously merged into
37master. Where the software is ready to be pushed to production you tag the
38master branch. This approach eliminates the need for long-lived branches and
39simplifies the development process. It also encourages developers to make small,
40incremental changes that can be tested and deployed quickly. However, this
41approach may not be suitable for all projects or teams that heavily rely on
42automated deployment based on branch names only.<p>This also requires that developers always keep production in mind. No more
43living on an island of the develop branch. All your actions and code need to be
44ready to meet production standards on a much smaller timescale.<p>I think that we have complicated the workflow in an honest attempt to make
45things more streamlined but in the process of doing this, we have inadvertently
46made our lives much more complicated.<p>In conclusion, it's important to re-evaluate our workflows from time to time to
47see if they still make sense and if there are better alternatives available.
48Long-living branches can be problematic, and using tags to mark important
49milestones can simplify the development process.</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
50a lock on a Linux NFS server, which turned
51out to be specific to NFS v3 (which I really should have seen coming,
52since it involved NLM and lockd). Finding the NFS v4 client that
53owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
54and Bradley Kuhn, are interacting on the OSI's license-discuss
55list where the're doing
56bad computer history and insisting that a guy Larry Rosen
57coincidentally interviewed for a book years ago is clearly the origin of
58somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
59i2c, plan9
60Another month, another file system.
61Well, if you can’t fix it in software, fix it in hardware (looking at
62you, bme680, we’re not
63done yet). The show must go on, as they say, and I would like my
64experiments to go on.
65So a “new” addition to the environmental sensor family connected to
66the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
67this mortal coil, we are endowed with self-awareness, agency, and free will.
68Each of the 8 billion members of this human race represents a unique person, a
69unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
70My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
711.0 has been released:
72wifi_da-1.0.sit
73(StuffIt 3 archive)
74SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
75This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
76classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
77In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
78Design Goals
79I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
80at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
81catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
82specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
83 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
84 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/index.html b/public/index.html
deleted file mode 100755
index ae9b5b0..0000000
--- a/public/index.html
+++ /dev/null
@@ -1,44 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Mitja Felicijan</title><meta name=description content="You do not learn by relaxing. You learn by violently assaulting your problem until it surrenders its mysteries to you."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><div><p>You do not learn by relaxing. You learn by violently assaulting your problem until it surrenders its mysteries to you.<h2><a name=posts></a>More long form, ramblings etc</h2><ul itemscope itemtype=https://schema.org/SiteNavigationElement role=list aria-label=Articles class=list><meta itemprop=name content="Article list"><li role=listitem><a href=/who-knows-what-the-world-will-look-like-tomorrow.html>Who knows what the world will look like tomorrow</a><li role=listitem><a href=/bringing-all-of-my-projects-together-under-one-umbrella.html>Bringing all of my projects together under one umbrella</a><li role=listitem><a href=/re-inventing-task-runner-that-i-actually-used-daily.html>Re-Inventing Task Runner That I Actually Used Daily</a><li role=listitem><a href=/i-was-wrong-about-git-workflows.html>I think I was completely wrong about Git workflows</a><li role=listitem><a href=/rekindling-my-love-for-programming.html>Rekindling my love for programming and enjoying the act of creating</a><li role=listitem><a href=/trying-to-build-a-new-kind-of-terminal-emulator.html>Trying to build a New kind of terminal emulator for the modern age</a><li role=listitem><a href=/that-sound-that-machine-makes-when-struggling.html>Microsoundtrack — That sound that machine makes when struggling</a><li role=listitem><a href=/state-of-web-technologies-and-web-development-in-year-2022.html>State of Web Technologies and Web development in year 2022</a><li role=listitem><a href=/aerial-photography-of-algae-spotted-on-river-sava.html>Aerial photography of algae spotted on river Sava</a><li role=listitem><a href=/what-would-dna-sound-if-synthesized.html>What would DNA sound if synthesized to an audio file</a><li role=listitem><a href=/tying-out-helix-code-editor.html>Trying out Helix code editor as my main editor</a><li role=listitem><a href=/wap-mobile-web-before-the-web.html>Wireless Application Protocol and the mobile web before the web</a><li role=listitem><a href=/running-golang-application-as-pid1.html>Running Golang application as PID 1 with Linux kernel</a><li role=listitem><a href=/debian-based-riced-up-distribution-for-developers-and-devops-folks.html>Debian based riced up distribution for Developers and DevOps folks</a><li role=listitem><a href=/linux-cheatsheet.html>List of essential Linux commands for server management</a><li role=listitem><a href=/from-internet-consumer-to-full-hominum-again.html>My journey from being an internet über consumer to being a full hominum again</a><li role=listitem><a href=/simple-world-clock-with-eiink-display-and-raspberry-pi-zero.html>Simple world clock with eInk display and Raspberry Pi Zero</a><li role=listitem><a href=/using-goaccess-with-nginx-to-replace-google-analytics.html>Using GoAccess with Nginx to replace Google Analytics</a><li role=listitem><a href=/replacing-dropbox-in-favor-of-digitalocean-spaces.html>Replacing Dropbox in favor of DigitalOcean spaces</a><li role=listitem><a href=/digitalocean-spaces-to-sync-between-computers.html>Using Digitalocean Spaces to sync between computers</a><li role=listitem><a href=/bind-warning-on-login-in-ubuntu.html>Fix bind warning in .profile on login in Ubuntu</a><li role=listitem><a href=/esp8266-and-micropython-guide.html>Getting started with MicroPython and ESP8266</a><li role=listitem><a href=/disable-mouse-wake-from-suspend-with-systemd-service.html>Disable mouse wake from suspend with systemd service</a><li role=listitem><a href=/remote-work.html>Remote work and how it affects the daily lives of people</a><li role=listitem><a href=/my-love-and-hate-relationship-with-nodejs.html>My love and hate relationship with Node.js</a><li role=listitem><a href=/the-strange-case-of-elasticsearch-allocation-failure.html>The strange case of Elasticsearch allocation failure</a><li role=listitem><a href=/create-placeholder-images-with-sharp.html>Create placeholder images with sharp Node.js image processing library</a><li role=listitem><a href=/simple-server-sent-events-based-pubsub-server.html>Simple Server-Sent Events based PubSub Server</a><li role=listitem><a href=/using-sentiment-analysis-for-clickbait-detection-in-rss-feeds.html>Using sentiment analysis for clickbait detection in RSS feeds</a><li role=listitem><a href=/simplifying-and-reducing-clutter.html>Simplifying and reducing clutter in my life and work</a><li role=listitem><a href=/encoding-binary-data-into-dna-sequence.html>Encoding binary data into DNA sequence</a><li role=listitem><a href=/using-digitalocean-spaces-object-storage-with-fuse.html>Using DigitalOcean Spaces Object Storage with FUSE</a><li role=listitem><a href=/simple-iot-application.html>Simple IOT application supported by real-time monitoring and data history</a><li role=listitem><a href=/profiling-python-web-applications-with-visual-tools.html>Profiling Python web applications with visual tools</a><li role=listitem><a href=/what-i-ve-learned-developing-ad-server.html>What I've learned developing ad server</a><li role=listitem><a href=/golang-profiling-simplified.html>Golang profiling simplified</a><li role=listitem><a href=/software-development-pitfalls.html>Software development and my favorite pitfalls</a><li role=listitem><a href=/wireless-sensor-networks.html>Wireless sensor networks</a><li role=listitem><a href=/led-technology-not-so-eco.html>LED technology might not be as eco-friendly as you think</a><li role=listitem><a href=/most-likely-to-succeed-in-year-of-2011.html>Most likely to succeed in the year of 2011</a></ul><h2><a name=notes></a>Notes?! Maybe useful</h2><h2></h2><ul itemscope itemtype=https://schema.org/SiteNavigationElement role=list aria-label=Notes class=list><meta itemprop=name content="Note list"><li role=listitem><a href=/compile-drawterm-on-fedora-38.html>Compile drawterm on Fedora 38</a><li role=listitem><a href=/aws-eb-pyyaml-fix.html>AWS EB PyYAML fix</a><li role=listitem><a href=/floods-in-slovenia.html>Floods in Slovenia up close</a><li role=listitem><a href=/make-b-w-svg-charts-with-matplotlib.html>Make B/W SVG charts with matplotlib</a><li role=listitem><a href=/set-color-temperature-of-displays-on-i3.html>Set color temperature of displays on i3</a><li role=listitem><a href=/fix-screen-tearing-on-debian-12-xorg-and-i3.html>Fix screen tearing on Debian 12 Xorg and i3</a><li role=listitem><a href=/online-radio-streaming-with-mpv-from-terminal.html>Online radio streaming with MPV from terminal</a><li role=listitem><a href=/60s-ibm-computers-commercial.html>60's IBM Computers Commercial</a><li role=listitem><a href=/10gui-10-finger-multitouch-user-interface.html>10/GUI 10 Finger Multitouch User Interface</a><li role=listitem><a href=/alacritty-open-links-with-modifier.html>Alacritty open links with modifier</a><li role=listitem><a href=/development-environments-with-nix.html>Development environments with Nix</a><li role=listitem><a href=/making-cgit-look-nicer.html>Making cgit look nicer</a><li role=listitem><a href=/presentations-with-markdown.html>Simple presentations with Markdown</a><li role=listitem><a href=/bulk-make-thumbnails.html>Bulk thumbnails</a><li role=listitem><a href=/ewd-manuscripts-ebook.html>Edsger W. Dijkstra Manuscripts ebook</a><li role=listitem><a href=/extending-dte-editor.html>Extending dte editor</a><li role=listitem><a href=/grep-to-less-maintain-colors.html>Grep to Less that maintain colors</a><li role=listitem><a href=/easy-time-took-in-bash.html>Easy measure time took in a bash script</a><li role=listitem><a href=/dcss-on-4k-display.html>Make DCSS playable on 4k displays</a><li role=listitem><a href=/drawing-pixels-in-plan9.html>Drawing Pixels in Plan9</a><li role=listitem><a href=/cronjobs-github-with-actions.html>Cronjobs on Github with Github Actions</a><li role=listitem><a href=/dcss-new-player-guide.html>Dungeon Crawl Stone Soup - New player guide</a><li role=listitem><a href=/xterm-color-palette.html>Display xterm color palette</a><li role=listitem><a href=/tmux-sane-defaults.html>Sane defaults for tmux with more visible statusbar</a><li role=listitem><a href=/fresh-9front-desktop.html>My brand new Plan9/9front desktop</a><li role=listitem><a href=/parse-rss-with-lua.html>Parse RSS feeds with Lua</a><li role=listitem><a href=/extend-lua-with-custom-c.html>Extend Lua with custom C functions using Clang</a><li role=listitem><a href=/non-blocking-shell-exec-csharp.html>Execute not blocking async shell command in C#</a><li role=listitem><a href=/mass-set-permission.html>Change permissions of matching files recursively</a><li role=listitem><a href=/preview-troff-man-pages.html>Previews how man page written in Troff will look like</a><li role=listitem><a href=/convert-mkv.html>Convert all MKV files into other formats</a><li role=listitem><a href=/download-youtube-videos.html>Download list of YouTube files</a><li role=listitem><a href=/install-plan9port-linux.html>Install Plan9port on Linux</a><li role=listitem><a href=/fix-plan9-bootloader.html>Fix bootloader not being written in Plan9</a><li role=listitem><a href=/plan9-screenshot.html>Take a screenshot in Plan9</a><li role=listitem><a href=/catv-weechat-config.html>#cat-v on weechat configuration</a><li role=listitem><a href=/write-iso-usb.html>Write ISO to USB Key</a><li role=listitem><a href=/mount-plan9-over-network.html>Mount Plan9 over network</a><li role=listitem><a href=/git-push-multiple-origins.html>Push to multiple origins at once in Git</a><li role=listitem><a href=/run-9front-in-qemu.html>Run 9front in Qemu</a><li role=listitem><a href=/cachebusting-in-hugo.html>Cache busting in Hugo</a></ul><h2><a name=sideprojects></a>Side projects I work/worked on</h2><ul itemscope itemtype=https://schema.org/SiteNavigationElement role=list aria-label="Side projects" class=list><meta itemprop=name content="Side projects"><li role=listitem><a href=https://git.mitjafelicijan.com/cord.h.git/ target=_blank>cord.h</a> — Small C library for handling strings<li role=listitem><a href=https://git.mitjafelicijan.com/mprogress.git/ target=_blank>mprogress</a> — Tiny utility that displays progress bar in terminal<li role=listitem><a href=https://git.mitjafelicijan.com/journalctl-proxy.git/ target=_blank>journalctl-proxy</a> — Exposes your systemd logs to web via web interface<li role=listitem><a href=https://git.mitjafelicijan.com/redis-marshal.git/ target=_blank>redis-marshal</a> — Lightweight Redis data exploration tool<li role=listitem><a href=https://git.mitjafelicijan.com/vertex.git/ target=_blank>vertex</a> — Create mock API's and add basic logic to simplify prototyping<li role=listitem><a href=https://git.mitjafelicijan.com/dna-encoding.git/ target=_blank>dna-encoding</a> — Tools for encoding files to DNA sequence<li role=listitem><a href=https://git.mitjafelicijan.com/scarecrow.git/ target=_blank>scarecrow</a> — Minimal configuration reverse proxy</ul></div></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
10a lock on a Linux NFS server, which turned
11out to be specific to NFS v3 (which I really should have seen coming,
12since it involved NLM and lockd). Finding the NFS v4 client that
13owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
14and Bradley Kuhn, are interacting on the OSI's license-discuss
15list where the're doing
16bad computer history and insisting that a guy Larry Rosen
17coincidentally interviewed for a book years ago is clearly the origin of
18somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
19i2c, plan9
20Another month, another file system.
21Well, if you can’t fix it in software, fix it in hardware (looking at
22you, bme680, we’re not
23done yet). The show must go on, as they say, and I would like my
24experiments to go on.
25So a “new” addition to the environmental sensor family connected to
26the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
27this mortal coil, we are endowed with self-awareness, agency, and free will.
28Each of the 8 billion members of this human race represents a unique person, a
29unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
30My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
311.0 has been released:
32wifi_da-1.0.sit
33(StuffIt 3 archive)
34SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
35This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
36classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
37In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
38Design Goals
39I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
40at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
41catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
42specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
43 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
44 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/index.xml b/public/index.xml
deleted file mode 100755
index 5ab7594..0000000
--- a/public/index.xml
+++ /dev/null
@@ -1,6103 +0,0 @@
1<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
2 <channel>
3 <title>Mitja Felicijan's posts</title>
4 <link>https://mitjafelicijan.com</link>
5 <description>You do not learn by relaxing. You learn by violently assaulting your problem until it surrenders its mysteries to you.</description>
6 <language>en-us</language>
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 <item>
25 <title>Who knows what the world will look like tomorrow</title>
26 <link>https://mitjafelicijan.com/who-knows-what-the-world-will-look-like-tomorrow.html</link>
27 <pubDate>Sat, 08 Jul 2023 18:49:07 &#43;0200</pubDate>
28 <guid>https://mitjafelicijan.com/who-knows-what-the-world-will-look-like-tomorrow.html</guid>
29 <description>This site has gone through a lot of changes over the years.</description>
30 <content:encoded>&lt;p&gt;This site has gone through a lot of changes over the years. From being written
31in Flask and Bottle to moving on to static site generators. I have used and
32tested probably 10s of them my now. From homebrew solutions to the biggest and
33the baddest. From Bash scripts to Node.js disasters. I&#39;ve seen some things, no
34doubt. Not all bad.&lt;/p&gt;
35&lt;p&gt;I have been closely observing the web and where the trends are going, and I
36don&#39;t like what I see. Instead of internet being this weird place where
37experimentation is happening, it all became stale and formulized. Boring,
38actually. Really boring. And sad. Where is that old, revolutionary FU spirit I
39remember? It&#39;s still there, I know. But it&#39;s being drowned by the voices of
40mediocrity and formulaic boredom.&lt;/p&gt;
41&lt;p&gt;It almost feels like that the internet stopped for 10 years and only now
42something has started happening. With all the insanity around the world. People
43hating people without actual reasons, just because it&#39;s fashionable to hate and
44crowd is saying so. Sad state of affairs.&lt;/p&gt;
45&lt;p&gt;All this is contributing to this overall negativity masked as apathy. Everybody
46walking in lockstep. Instead of being creative and bold, we are just
47re-inventing the world and making the same mistakes. Maybe, just maybe, some
48things are good enough and there is no need to try to be too smart for our own
49good. After N-attempts, maybe something should click inside our heads to maybe
50say: &amp;quot;This thing, opinion, etc. is actually really good, and even after several
51attempts it still holds.&amp;quot;&lt;/p&gt;
52&lt;p&gt;The older I get, the more careful I am of my own thoughts and why I think the
53way I think. More and more, I try to understand people with opposite
54opinions. Far from perfect, but closer to bearable. And then I see people
55hearing or reading a thing on internet and let&#39;s fucking goooooo! Strong
56opinions are a sign of a weak and uneducated mind. I am more and more sure of
57this.&lt;/p&gt;
58&lt;p&gt;It&#39;s gotten to a point where you can with great certainty deduce a person&#39;s
59personality based on one or two opinions. How boring have we become. No wonder
60people can&#39;t talk to each other. These would be very quick conversations anyway.&lt;/p&gt;
61&lt;p&gt;I just got remembered of a song, &lt;a href=&#34;https://www.youtube.com/watch?v=s_nc1IVoMxc&#34;&gt;&amp;quot;Hi
62Ren&amp;quot;&lt;/a&gt;. The ending talks about being
63stiff and not being able to dance. Such an amazing metaphor. And we as people
64have gone so far, we can&#39;t even walk or even crawl normally anymore. We have
65forgotten that the most beautiful things in life have a great deal of
66uncertainty about them. We want instant gratification. Not only that, but we
67want absolute obedience. Complete control over others, because we have zero
68control of ourselves. And all the lies we could tell ourselves will not help us
69out of this situation.&lt;/p&gt;
70&lt;p&gt;It is funny how I catch myself from time to time being a complete idiot. It&#39;s
71like having an outer body experience. I can see myself being an idiot, and
72cannot stop myself. It serves as a learning lesson to stop before speaking. To
73think before saying. And to crawl before walking.&lt;/p&gt;
74&lt;p&gt;So there is still time. We can dance once more. All we need to do is stop for a
75second. Me and you. Us two is a start. Let&#39;s not try to change the world, but
76rather nudge ourselves just a tiny bit. And if we only did that?! Just
77imagine. Each of us nudged ourselves a small, tiny bit, the world would heal. If
78we would just put down the phones and ignored Internet for a day or two. Put
79visiting websites that feed on us on hold. Listened to just one sentence and try
80to understand it from a person who we completely disagree with. I truly believe
81that this is possible.&lt;/p&gt;
82&lt;p&gt;Life is about suffering and joy. And instead of wishing suffering on others and
83excepting joy for yourselves, we should for a brief moment want suffering for
84ourselves and wish joy on others. Wouldn&#39;t that be an amazing sight to see?&lt;/p&gt;
85&lt;p&gt;I caught myself hating on Rust. And I deeply thought about it afterward. Why did
86I do it? It is obviously not for me. So why the hell was I being so negative
87towards it? I think that I know the answer. I was negative because that is
88easy. Because it&#39;s much easier to hate on things than to say to yourself: &amp;quot;Well,
89you know what? This is not for me. I will focus on creation and not
90destruction. This is who I want to be. This is what fills me with joy and
91purpose.&amp;quot; Where joy is keeping me happy and purpose scares the shit out of me
92and keeps me honest. This is who I want to be. Admit to myself when I am wrong
93and accept the faults that I have without reservation and with courage march on.&lt;/p&gt;
94&lt;p&gt;I just realized that this blog post is a sort of therapy for me. It&#39;s
95cathartic. Going thought the history of this site and remembering all the
96decisions and annoyances that came with it. When I was cursing at the tools. And
97time moved on, and the site is still here. It serves as a reminder that
98perseverance wins at the end. If we just let things go.&lt;/p&gt;
99&lt;p&gt;This came with a decision that simplifying life and removing all the unnecessary
100negativity is key. Rather than worrying about what the internet is saying, what
101the world is trying to take from you, you are the only one who can say no. And
102create instead of destroy.&lt;/p&gt;
103&lt;p&gt;I don&#39;t have an ending for this post, so I will say this. We live in the most
104amazing times in the recorded history, and we should be internally grateful for
105it. Create and study, this should be my mantra. Just create and let the world
106happen. And when you feel yourself to be too certain, stop and check how deep in the
107shit you are already. Strong opinions are a sign of a weak and uneducated
108mind. Hate and disdain is for the weak.&lt;/p&gt;
109</content:encoded>
110 </item>
111
112
113
114 <item>
115 <title>Bringing all of my projects together under one umbrella</title>
116 <link>https://mitjafelicijan.com/bringing-all-of-my-projects-together-under-one-umbrella.html</link>
117 <pubDate>Sat, 01 Jul 2023 18:49:07 &#43;0200</pubDate>
118 <guid>https://mitjafelicijan.com/bringing-all-of-my-projects-together-under-one-umbrella.html</guid>
119 <description>What is the issue anyway?</description>
120 <content:encoded>&lt;h2 id=&#34;what-is-the-issue-anyway&#34;&gt;What is the issue anyway?&lt;/h2&gt;
121&lt;p&gt;Over the years, I have accumulated a bunch of virtual servers on my
122&lt;a href=&#34;https://www.digitalocean.com/&#34;&gt;DigitalOcean&lt;/a&gt; account for small experimental
123projects I dabble in. And this has resulted in quite a bill. I mean, I wouldn&#39;t
124care if these projects were actually being used. But there were just being there
125unused and wasting resources. Which makes this an unnecessary burden for me.&lt;/p&gt;
126&lt;p&gt;Most of them are just small HTML pages that have an endpoint or two to read data
127from or to, and for that reason I wrote servers left and right. To be honest,
128all of those things could have been done with &lt;a href=&#34;https://en.wikipedia.org/wiki/Common_Gateway_Interface&#34;&gt;CGI
129scripts&lt;/a&gt; and that would
130have been more than enough.&lt;/p&gt;
131&lt;p&gt;Recently, I decided to stop language hopping and focus on a simpler stack which
132includes C, Go and Lua. And I can accomplish all the things I am interested in.&lt;/p&gt;
133&lt;h2 id=&#34;finding-a-web-server-replacement&#34;&gt;Finding a web server replacement&lt;/h2&gt;
134&lt;p&gt;Usually I had &lt;a href=&#34;https://nginx.org/en/&#34;&gt;Nginx&lt;/a&gt; in front of these small web servers
135and I had to manage SSL certificates and all that jazz. I am bored with these
136things. I don&#39;t want to manage any of this bullshit anymore.&lt;/p&gt;
137&lt;p&gt;So the logical move forward was to find a solid alternative for this. I have
138ended up on &lt;a href=&#34;https://caddyserver.com/&#34;&gt;Caddy server&lt;/a&gt;. I&#39;ve used it in the past
139but kind of forgotten about it. What I really like about it is an ease of use
140and a bunch of out of the box functionalities that come with it.&lt;/p&gt;
141&lt;p&gt;These are the &lt;em&gt;pitch&lt;/em&gt; points from their website:&lt;/p&gt;
142&lt;ul&gt;
143&lt;li&gt;&lt;strong&gt;Secure by Default&lt;/strong&gt;: Caddy is the only web server that uses HTTPS by
144default. A hardened TLS stack with modern protocols preserves privacy and
145exposes MITM attacks.&lt;/li&gt;
146&lt;li&gt;&lt;strong&gt;Config API&lt;/strong&gt;: As its primary mode of configuration, Caddy&#39;s REST API makes
147it easy to automate and integrate with your apps.&lt;/li&gt;
148&lt;li&gt;&lt;strong&gt;No Dependencies&lt;/strong&gt;: Because Caddy is written in Go, its binaries are entirely
149self-contained and run on every platform, including containers without libc.&lt;/li&gt;
150&lt;li&gt;&lt;strong&gt;Modular Stack&lt;/strong&gt;: Take back control over your compute edge. Caddy can be
151extended with everything you need using plugins.&lt;/li&gt;
152&lt;/ul&gt;
153&lt;p&gt;I had just a few requirements:&lt;/p&gt;
154&lt;ul&gt;
155&lt;li&gt;Automatic SSL&lt;/li&gt;
156&lt;li&gt;Static file server&lt;/li&gt;
157&lt;li&gt;Basic authentication&lt;/li&gt;
158&lt;li&gt;CGI script support&lt;/li&gt;
159&lt;/ul&gt;
160&lt;p&gt;And the vanilla version does all of it, but CGI scripts. But that can easily be
161fixed with their modular approach. You can do this on their website and build a
162custom version of the server, or do it with Docker.&lt;/p&gt;
163&lt;p&gt;This is a &lt;code&gt;Dockerfile&lt;/code&gt; I used to build a custom server.&lt;/p&gt;
164&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;FROM&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt; caddy:builder AS builder&lt;/span&gt;&lt;span style=&#34;&#34;&gt;
165&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;
166&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#00f&#34;&gt;RUN&lt;/span&gt; xcaddy build &lt;span style=&#34;color:#a31515&#34;&gt;\
167&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&lt;/span&gt; --with github.com/aksdb/caddy-cgi&lt;span style=&#34;&#34;&gt;
168&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;
169&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#00f&#34;&gt;FROM&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt; caddy:latest&lt;/span&gt;&lt;span style=&#34;&#34;&gt;
170&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#00f&#34;&gt;RUN&lt;/span&gt; apk add --no-cache nano&lt;span style=&#34;&#34;&gt;
171&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;
172&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#00f&#34;&gt;COPY&lt;/span&gt; --from=builder /usr/bin/caddy /usr/bin/caddy&lt;span style=&#34;&#34;&gt;
173&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;getting-rid-of-all-the-unnecessary-virtual-machines&#34;&gt;Getting rid of all the unnecessary virtual machines&lt;/h2&gt;
174&lt;p&gt;The next step was to get a handle on the number of virtual servers I have all
175over the place.&lt;/p&gt;
176&lt;p&gt;I decided to move all the projects and services into two main VMs:&lt;/p&gt;
177&lt;ul&gt;
178&lt;li&gt;personal server (still Nginx)
179&lt;ul&gt;
180&lt;li&gt;git server&lt;/li&gt;
181&lt;li&gt;static file server&lt;/li&gt;
182&lt;li&gt;personal blog&lt;/li&gt;
183&lt;/ul&gt;
184&lt;/li&gt;
185&lt;li&gt;projects server (Caddy server)
186&lt;ul&gt;
187&lt;li&gt;personal experiments&lt;/li&gt;
188&lt;li&gt;other projects&lt;/li&gt;
189&lt;/ul&gt;
190&lt;/li&gt;
191&lt;/ul&gt;
192&lt;p&gt;I will focus on projects&#39; server in this post since it&#39;s more interesting.&lt;/p&gt;
193&lt;h2 id=&#34;testing-cgi-scripts&#34;&gt;Testing CGI scripts&lt;/h2&gt;
194&lt;p&gt;The first thing I tested was how CGI scripts work under Caddy. This is
195particularly import to me because almost all of my experiments and mini projects
196need this to work.&lt;/p&gt;
197&lt;p&gt;To configure Caddy server, you must provide the server with a configuration
198file. By default, it&#39;s called &lt;code&gt;Caaddyfile&lt;/code&gt;.&lt;/p&gt;
199&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
200&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;order&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;cgi&lt;/span&gt; before &lt;span style=&#34;color:#a31515&#34;&gt;respond&lt;/span&gt;
201&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
202&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
203&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;examples.mitjafelicijan.com&lt;/span&gt; {
204&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;cgi&lt;/span&gt; /bash-test &lt;span style=&#34;color:#a31515&#34;&gt;/opt/projects/examples/bash-test.sh&lt;/span&gt;
205&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;cgi&lt;/span&gt; /tcl-test &lt;span style=&#34;color:#a31515&#34;&gt;/opt/projects/examples/tcl-test.tcl&lt;/span&gt;
206&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;cgi&lt;/span&gt; /lua-test &lt;span style=&#34;color:#a31515&#34;&gt;/opt/projects/examples/lua-test.lua&lt;/span&gt;
207&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;cgi&lt;/span&gt; /python-test &lt;span style=&#34;color:#a31515&#34;&gt;/opt/projects/examples/python-test.py&lt;/span&gt;
208&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
209&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;root&lt;/span&gt; * &lt;span style=&#34;color:#a31515&#34;&gt;/opt/projects/examples&lt;/span&gt;
210&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;file_server&lt;/span&gt;
211&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
212&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
213&lt;li&gt;The order is very important. Make sure that &lt;code&gt;order cgi before respond&lt;/code&gt; is at
214the top of the configuration file.&lt;/li&gt;
215&lt;li&gt;Also, when you run with Caddy v2, make sure you provide &lt;code&gt;adapter&lt;/code&gt; argument
216like this &lt;code&gt;/usr/bin/caddy run --watch --environ --config /etc/caddy/Caddyfile --adapter caddyfile&lt;/code&gt;. Otherwise, Caddy will try to use a different format for
217config file.&lt;/li&gt;
218&lt;/ul&gt;
219&lt;p&gt;I did a small batch of tests with &lt;a href=&#34;https://www.gnu.org/software/bash/&#34;&gt;Bash&lt;/a&gt;,
220&lt;a href=&#34;https://www.tcl-lang.org/&#34;&gt;Tcl&lt;/a&gt;, &lt;a href=&#34;https://www.lua.org/&#34;&gt;Lua&lt;/a&gt; and
221&lt;a href=&#34;https://www.python.org/&#34;&gt;Python&lt;/a&gt;. Here is a cheat sheet if you need it.&lt;/p&gt;
222&lt;p&gt;Let&#39;s get Bash out of the way first.&lt;/p&gt;
223&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;#!/usr/bin/bash
224&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;&lt;/span&gt;
225&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;printf &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Content-type: text/plain\n\n&amp;#34;&lt;/span&gt;
226&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
227&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;printf &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Hello from Bash\n\n&amp;#34;&lt;/span&gt;
228&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;printf &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;PATH_INFO [%s]\n&amp;#34;&lt;/span&gt; $PATH_INFO
229&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;printf &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;QUERY_STRING [%s]\n&amp;#34;&lt;/span&gt; $QUERY_STRING
230&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;printf &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;\n&amp;#34;&lt;/span&gt;
231&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
232&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;for&lt;/span&gt; i in {0..9..1}; &lt;span style=&#34;color:#00f&#34;&gt;do&lt;/span&gt;
233&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; printf &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&amp;gt; %s\n&amp;#34;&lt;/span&gt; $i
234&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;done&lt;/span&gt;
235&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
236&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;exit 0
237&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This one is for Tcl script.&lt;/p&gt;
238&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;#!/usr/bin/tclsh
239&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;
240&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt;puts &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Content-type: text/plain\n&amp;#34;&lt;/span&gt;
241&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
242&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;puts &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Hello from Tcl\n&amp;#34;&lt;/span&gt;
243&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;puts &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;PATH_INFO \[$env(PATH_INFO)\]&amp;#34;&lt;/span&gt;
244&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;puts &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;QUERY_STRING \[$env(QUERY_STRING)\]&amp;#34;&lt;/span&gt;
245&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;puts &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;
246&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
247&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;for&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;{set&lt;/span&gt; i 0&lt;span style=&#34;color:#00f&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;{&lt;/span&gt;$i &amp;lt; 10&lt;span style=&#34;color:#00f&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;{&lt;/span&gt;incr i&lt;span style=&#34;color:#00f&#34;&gt;}&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;{&lt;/span&gt;
248&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; puts &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&amp;gt; $i&amp;#34;&lt;/span&gt;
249&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;}&lt;/span&gt;
250&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And for all you Python enjoyers.&lt;/p&gt;
251&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;#!/usr/bin/python3&lt;/span&gt;
252&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
253&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; os
254&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
255&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Content-type: text/plain&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt;)
256&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
257&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Hello from Python&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt;)
258&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;PATH_INFO [&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;]&amp;#34;&lt;/span&gt;.format(os.environ[&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;PATH_INFO&amp;#39;&lt;/span&gt;]))
259&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;QUERY_STRING [&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;]&amp;#34;&lt;/span&gt;.format(os.environ[&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;QUERY_STRING&amp;#39;&lt;/span&gt;]))
260&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
261&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
262&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;for&lt;/span&gt; i &lt;span style=&#34;color:#00f&#34;&gt;in&lt;/span&gt; range(10):
263&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; print(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt;.format(i))
264&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And for the final example, Lua.&lt;/p&gt;
265&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;#!/usr/bin/lua&lt;/span&gt;
266&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
267&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Content-type: text/plain&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt;)
268&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
269&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Hello from Lua&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt;)
270&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(string.format(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;PATH_INFO [%s]&amp;#34;&lt;/span&gt;, os.getenv(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;PATH_INFO&amp;#34;&lt;/span&gt;)))
271&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(string.format(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;QUERY_STRING [%s]&amp;#34;&lt;/span&gt;, os.getenv(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;QUERY_STRING&amp;#34;&lt;/span&gt;)))
272&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print()
273&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
274&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;for&lt;/span&gt; i = 0, 9 &lt;span style=&#34;color:#00f&#34;&gt;do&lt;/span&gt;
275&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; print(string.format(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&amp;gt; %d&amp;#34;&lt;/span&gt;, i))
276&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;end&lt;/span&gt;
277&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;basic-authentication&#34;&gt;Basic authentication&lt;/h2&gt;
278&lt;p&gt;One thing was also to have an option for some sort of authentication, and
279something like &lt;a href=&#34;https://en.wikipedia.org/wiki/Basic_access_authentication&#34;&gt;Basic access
280authentication&lt;/a&gt; would
281be more than enough.&lt;/p&gt;
282&lt;p&gt;Thankfully, Caddy supports this out of the box already. Below is an updated
283example.&lt;/p&gt;
284&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
285&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;order&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;cgi&lt;/span&gt; before &lt;span style=&#34;color:#a31515&#34;&gt;respond&lt;/span&gt;
286&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
287&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
288&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;examples.mitjafelicijan.com&lt;/span&gt; {
289&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;cgi&lt;/span&gt; /bash-test &lt;span style=&#34;color:#a31515&#34;&gt;/opt/projects/examples/bash-test.sh&lt;/span&gt;
290&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;cgi&lt;/span&gt; /tcl-test &lt;span style=&#34;color:#a31515&#34;&gt;/opt/projects/examples/tcl-test.tcl&lt;/span&gt;
291&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;cgi&lt;/span&gt; /lua-test &lt;span style=&#34;color:#a31515&#34;&gt;/opt/projects/examples/lua-test.lua&lt;/span&gt;
292&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;cgi&lt;/span&gt; /python-test &lt;span style=&#34;color:#a31515&#34;&gt;/opt/projects/examples/python-test.py&lt;/span&gt;
293&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
294&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;root&lt;/span&gt; * &lt;span style=&#34;color:#a31515&#34;&gt;/opt/projects/examples&lt;/span&gt;
295&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;file_server&lt;/span&gt;
296&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
297&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;basicauth&lt;/span&gt; * {
298&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;bob&lt;/span&gt; &lt;span style=&#34;&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;2a&lt;/span&gt;&lt;span style=&#34;&#34;&gt;$&lt;/span&gt;14&lt;span style=&#34;&#34;&gt;$&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;/wCgaf9oMnmQa20txB76u.nI1AldGMBT/1J7fXCfgOiRShwz/JOkK&lt;/span&gt;
299&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
300&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
301&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;code&gt;basicauth *&lt;/code&gt; matches everything under this domain/sub-domain and protects it
302with Basic Authentication.&lt;/p&gt;
303&lt;ul&gt;
304&lt;li&gt;&lt;code&gt;bob&lt;/code&gt; is the username&lt;/li&gt;
305&lt;li&gt;&lt;code&gt;hash&lt;/code&gt; is the password&lt;/li&gt;
306&lt;/ul&gt;
307&lt;p&gt;To generate these passwords, execute &lt;code&gt;caddy hash-password&lt;/code&gt; and this will prompt
308you to insert a password twice and spit out a hashed password that you can put
309in your configuration file.&lt;/p&gt;
310&lt;p&gt;Restart the server and you are ready to go.&lt;/p&gt;
311&lt;h2 id=&#34;making-caddy-a-service-with-systemd&#34;&gt;Making Caddy a service with systemd&lt;/h2&gt;
312&lt;p&gt;After the tests were successful, I copied &lt;code&gt;caddy&lt;/code&gt; to &lt;code&gt;/usr/bin/caddy&lt;/code&gt; and copied
313&lt;code&gt;Caddyfile&lt;/code&gt; to &lt;code&gt;/etc/caddy/Caddyfile&lt;/code&gt;.&lt;/p&gt;
314&lt;p&gt;Now off to the systemd. Each systemd service requires you to create a service
315file.&lt;/p&gt;
316&lt;ul&gt;
317&lt;li&gt;I created a &lt;code&gt;/etc/systemd/system/caddy.service&lt;/code&gt; and put the following content
318in the file.&lt;/li&gt;
319&lt;/ul&gt;
320&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;[Unit]&lt;/span&gt;
321&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Description=&lt;span style=&#34;color:#a31515&#34;&gt;Caddy&lt;/span&gt;
322&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Documentation=&lt;span style=&#34;color:#a31515&#34;&gt;https://caddyserver.com/docs/&lt;/span&gt;
323&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;After=&lt;span style=&#34;color:#a31515&#34;&gt;network.target network-online.target&lt;/span&gt;
324&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Requires=&lt;span style=&#34;color:#a31515&#34;&gt;network-online.target&lt;/span&gt;
325&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
326&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;[Service]&lt;/span&gt;
327&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Type=&lt;span style=&#34;color:#a31515&#34;&gt;notify&lt;/span&gt;
328&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;User=&lt;span style=&#34;color:#a31515&#34;&gt;root&lt;/span&gt;
329&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Group=&lt;span style=&#34;color:#a31515&#34;&gt;root&lt;/span&gt;
330&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ExecStart=&lt;span style=&#34;color:#a31515&#34;&gt;/usr/bin/caddy run --environ --config /etc/caddy/Caddyfile --adapter caddyfile&lt;/span&gt;
331&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ExecReload=&lt;span style=&#34;color:#a31515&#34;&gt;/usr/bin/caddy reload --config /etc/caddy/Caddyfile --force --adapter caddyfile&lt;/span&gt;
332&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;TimeoutStopSec=&lt;span style=&#34;color:#a31515&#34;&gt;5s&lt;/span&gt;
333&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;LimitNOFILE=&lt;span style=&#34;color:#a31515&#34;&gt;1048576&lt;/span&gt;
334&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;LimitNPROC=&lt;span style=&#34;color:#a31515&#34;&gt;512&lt;/span&gt;
335&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PrivateTmp=&lt;span style=&#34;color:#a31515&#34;&gt;true&lt;/span&gt;
336&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ProtectSystem=&lt;span style=&#34;color:#a31515&#34;&gt;full&lt;/span&gt;
337&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;AmbientCapabilities=&lt;span style=&#34;color:#a31515&#34;&gt;CAP_NET_ADMIN CAP_NET_BIND_SERVICE&lt;/span&gt;
338&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
339&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;[Install]&lt;/span&gt;
340&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WantedBy=&lt;span style=&#34;color:#a31515&#34;&gt;multi-user.target&lt;/span&gt;
341&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;ul&gt;
342&lt;li&gt;You might need to reload systemd with &lt;code&gt;systemctl daemon-reload&lt;/code&gt;.&lt;/li&gt;
343&lt;li&gt;Then I enabled the service with &lt;code&gt;systemctl enable caddy.service&lt;/code&gt;.&lt;/li&gt;
344&lt;li&gt;And then I started the service with &lt;code&gt;systemctl start caddy.service&lt;/code&gt;.&lt;/li&gt;
345&lt;/ul&gt;
346&lt;p&gt;This was about all that I needed to do to get it running. Now I can easily add
347new subdomains and domains to the main configuration file and be done with
348it. No manual Let&#39;s Encrypt shenanigans needed.&lt;/p&gt;
349</content:encoded>
350 </item>
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370 <item>
371 <title>Re-Inventing Task Runner That I Actually Used Daily</title>
372 <link>https://mitjafelicijan.com/re-inventing-task-runner-that-i-actually-used-daily.html</link>
373 <pubDate>Wed, 31 May 2023 12:21:10 &#43;0200</pubDate>
374 <guid>https://mitjafelicijan.com/re-inventing-task-runner-that-i-actually-used-daily.html</guid>
375 <description>Couple of months ago I had this brilliant idea of re-inventing the wheel bymaking an alternative for make.</description>
376 <content:encoded>&lt;p&gt;Couple of months ago I had this brilliant idea of re-inventing the wheel by
377making an alternative for make. And so I went. Boldly into the battle. And to my
378big surprise my attempt resulted in not a completely useless piece of software.&lt;/p&gt;
379&lt;p&gt;My initial requirements were quite simple but soon grow into something more
380ambitious. And looking back I should have stuck to the simple version. My
381laziness was on my side this time though. Because I haven’t implemented some of
382the features I now realise I really didn’t need them and they would bog the
383whole program and make it be something it was never meant to be.&lt;/p&gt;
384&lt;p&gt;My basic requirements were following:&lt;/p&gt;
385&lt;ul&gt;
386&lt;li&gt;Syntax should be a tiny bit inspired by Rake and Rakefiles.&lt;/li&gt;
387&lt;li&gt;Should borrow the overall feel of a unit test experience.&lt;/li&gt;
388&lt;li&gt;Using something like Python would be a bit of an overkill.&lt;/li&gt;
389&lt;li&gt;The program must be statically compiled, so it can run on same architecture
390without libc, musl dependencies or things like that.&lt;/li&gt;
391&lt;li&gt;Install ruby for rake is a bit overkill and can not be done with certain
392really lightweight distributions like Alpine Linux. This tool would be usable
393on such lightweight systems for remote debugging.&lt;/li&gt;
394&lt;li&gt;I want to use it for more than just compiling things. I want to use it as an
395entry-point into a project, and I want this to help me indirectly document the
396project as well.&lt;/li&gt;
397&lt;li&gt;It should be an abstraction over bash shell or the default system shell.
398&lt;ul&gt;
399&lt;li&gt;Each task essentially becomes its own shell instance.&lt;/li&gt;
400&lt;/ul&gt;
401&lt;/li&gt;
402&lt;li&gt;Must work on Linux and macOS systems.&lt;/li&gt;
403&lt;li&gt;By default, running &lt;code&gt;erd&lt;/code&gt; list all the available tasks (when I use make, I
404usually put a disclaimer that you should check Makefile to see all available
405target).&lt;/li&gt;
406&lt;li&gt;Should support passing arguments when you run it from a shell.&lt;/li&gt;
407&lt;li&gt;Normal variable as the same as environmental variables. There is no
408distinction. Every variable is also essentially an environment variable and
409can be used by other programs.&lt;/li&gt;
410&lt;li&gt;State between tasks is not shared, and this makes this “pure” shell instances.&lt;/li&gt;
411&lt;li&gt;Should be single-threaded for the start and later expanded with &lt;code&gt;@spawn&lt;/code&gt;
412command.&lt;/li&gt;
413&lt;li&gt;Variables behave like macros and are preprocessed before evaluation.&lt;/li&gt;
414&lt;li&gt;Should support something like &lt;code&gt;assure&lt;/code&gt; that would check if programs like C
415compiler or Python (whatever the project requires) are installed on a machine.&lt;/li&gt;
416&lt;/ul&gt;
417&lt;p&gt;Quite a reasonable list of requirements. I do this things already in my
418Makefiles or/and Bash scripts. But I would like to avoid repeating myself every
419time I start working on something new.&lt;/p&gt;
420&lt;p&gt;So I started with the following syntax.&lt;/p&gt;
421&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@env on
422&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
423&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# Override the default shell.&lt;/span&gt;
424&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@shell &lt;span style=&#34;color:#a31515&#34;&gt;/bin/&lt;/span&gt;bash
425&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
426&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# Assure that program is installed.&lt;/span&gt;
427&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@assure docker-compose pip python3
428&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
429&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# Load local dotenv files (these are then globally available).&lt;/span&gt;
430&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@dotenv .env
431&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@dotenv .env.sample
432&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@dotenv some_other_file
433&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
434&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# This are local variables but still accessible in tasks.&lt;/span&gt;
435&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@var HI = &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;hey&amp;#34;&lt;/span&gt;
436&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@var TOKEN = &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;sometoken&amp;#34;&lt;/span&gt;
437&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@var EMAIL = &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;m@m.com&amp;#34;&lt;/span&gt;
438&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@var PASSWORD = &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;pass&amp;#34;&lt;/span&gt;
439&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@var EDITOR = &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;vim&amp;#34;&lt;/span&gt;
440&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
441&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@task dev &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Test chars .:&amp;#39;}{]!//&amp;#34;&lt;/span&gt; does
442&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; echo &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;...&amp;#34;&lt;/span&gt; $HI
443&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;end&lt;/span&gt;
444&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
445&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@task clean &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Cleans the obj files&amp;#34;&lt;/span&gt; does
446&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; rm .obj
447&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;end&lt;/span&gt;
448&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
449&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@task greet &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Greets the user&amp;#34;&lt;/span&gt; does
450&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; echo &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Hi user $TOKEN or $WINDOWID $EMAIL&amp;#34;&lt;/span&gt;
451&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;end&lt;/span&gt;
452&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
453&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@task stack &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Starts Docker stack&amp;#34;&lt;/span&gt; does
454&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; docker-compose -f stack.yml up
455&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;end&lt;/span&gt;
456&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
457&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@task todo &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Shows all todos in source files and count them&amp;#34;&lt;/span&gt; does
458&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; grep -ir &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;TODO|FIXME&amp;#34;&lt;/span&gt; . | wc -l
459&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;end&lt;/span&gt;
460&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
461&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@task test1 &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;For testing 1&amp;#34;&lt;/span&gt; does
462&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; unknown-command
463&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; echo &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;test1&amp;#34;&lt;/span&gt;
464&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ls -lha
465&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;end&lt;/span&gt;
466&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
467&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@task test2 &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;For testing 2&amp;#34;&lt;/span&gt; does
468&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; echo &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;test1&amp;#34;&lt;/span&gt;
469&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ls -lha
470&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; docker-compose -f samples/stack.yml up
471&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;end&lt;/span&gt;
472&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;One thing that I really like about Errand. Yes, this is what it is called. And
473it is available at &lt;a href=&#34;https://git.mitjafelicijan.com/errand.git/about/&#34;&gt;https://git.mitjafelicijan.com/errand.git/about/&lt;/a&gt;. Moving
474on. One thing that I really like is that a task is a persistent shell. By that I
475mean, that the whole task, even if it contains multiple command in one shell.
476In make each line in a target is that and you need to combine lines or add &lt;code&gt;\&lt;/code&gt;
477at the end of the line.&lt;/p&gt;
478&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# How you do this things in make.&lt;/span&gt;
479&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;target:
480&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; source .venv/bin/activate &lt;span style=&#34;color:#a31515&#34;&gt;\
481&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&lt;/span&gt; python script.py
482&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This solves this problem. Consider each task and what is being executed in that
483task a shell that will only close when all the tasks are completed.&lt;/p&gt;
484&lt;p&gt;By self-documenting I mean that if you are in a directory with &lt;code&gt;Errandfile&lt;/code&gt; in,
485if you only type &lt;code&gt;erd&lt;/code&gt; and press enter it should by default display all the
486possible targets. In make i was doing this by having a first target be something
487like &lt;code&gt;default&lt;/code&gt; that echos the message “Check Makefile for all available target.”
488Because all of the tasks in Errand require a message I use that to display let’s
489call it table of contents.&lt;/p&gt;
490&lt;p&gt;Because I don’t use any external dependencies this whole thing can be statically
491compiled. So that also checked one of the boxes.&lt;/p&gt;
492&lt;p&gt;It works on Linux and on a Mac so that’s also a bonus. I don’t believe this
493would work on Windows machines because of the way that I use shell instances. By
494you could use something like Windows Subsystem for Linux and run it in
495there. That is a valid option.&lt;/p&gt;
496&lt;p&gt;To finish this essay off, how was it to use it in “real life”. I have to be
497honest. Some of the missing features still bother me. &lt;code&gt;@dotenv&lt;/code&gt; directive is
498still missing and I need to implement this ASAP.&lt;/p&gt;
499&lt;p&gt;Another thing that needs to happen is support for streaming output. Currently
500commands like &lt;code&gt;docker-compose&lt;/code&gt; that runs in foreground mode is not compatible
501with Errand. So commands that stream output are an issue. I need to revisit how
502I initiate shell and how I read stdout and stderr. But that shouldn’t be a
503problem.&lt;/p&gt;
504&lt;p&gt;I have been very satisfied with this thing. I am pleasantly surprised by how
505useful it is. I really wanted to test this in the wild before I commit to it. I
506have more abandoned project than Google and it’s bringing a massive shame to my
507family at this point. So I wanted to be sure that this is even useful. And it
508actually is. Quite surprised at myself.&lt;/p&gt;
509&lt;p&gt;I really need to package this now and write proper docs. And maybe rewrite
510tokeniser. Its atrocious right now. Site to behold! But that is an issue for
511another time.&lt;/p&gt;
512</content:encoded>
513 </item>
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537 <item>
538 <title>I think I was completely wrong about Git workflows</title>
539 <link>https://mitjafelicijan.com/i-was-wrong-about-git-workflows.html</link>
540 <pubDate>Tue, 23 May 2023 12:00:00 &#43;0200</pubDate>
541 <guid>https://mitjafelicijan.com/i-was-wrong-about-git-workflows.html</guid>
542 <description>I have been using some approximation of GitFlow for years now and never reallyquestioned it to be honest.</description>
543 <content:encoded>&lt;p&gt;I have been using some approximation of &lt;a href=&#34;https://jeffkreeftmeijer.com/git-flow/&#34;&gt;Git
544Flow&lt;/a&gt; for years now and never really
545questioned it to be honest. When I create a repo I create develop branch and set
546it as default one and then merge to master from there. Seems reasonable enough.&lt;/p&gt;
547&lt;p&gt;One thing that I have learned is that long living branches are the devil. They
548always end up making a huge mess when they need to be merged eventually into
549master. So by that reason, what is the develop branch if not the longest living
550feature branch. And from my personal experience there was never a situation
551where I wasn’t sweating bullets when I had to merge develop back to master.&lt;/p&gt;
552&lt;p&gt;This realisation started to give me pause. So why the hell am I doing this, and
553is there a better way. Well the solution was always there. And it comes in a
554form of &lt;a href=&#34;https://git-scm.com/book/en/v2/Git-Basics-Tagging&#34;&gt;git tags&lt;/a&gt;.&lt;/p&gt;
555&lt;p&gt;So what are git tags? Git tags are references to specific points in a Git
556repository&#39;s history. They are used to mark important milestones, such as
557releases or significant commits, making it easier to identify and access
558specific versions of a project.&lt;/p&gt;
559&lt;p&gt;Somehow we have all hijacked the meaning of the master branch that it has to be
560the most releasable version of code. And this is also where the confusing about
561versioning the software kicks in. Because master branch implicitly says that we
562are dealing with the rolling release type of a software. And by having a develop
563branch we are hacking around this confusion. With a separation of develop and
564master we lock functionalities into place and forcing a stable vs development
565version of the software.&lt;/p&gt;
566&lt;p&gt;But if that is true and the long living branches are the devil then why have
567develop at all. I think that most of this comes to how continuous integration is
568being done. There usually is no granular access to tags and CD software deploys
569what is present on a specific branch, may that be master for production and
570develop for staging. This is a gross simplification and by having this in place
571we have completely removed tagging as a viable option to create a fix point in
572software cycle that says, this is the production ready code.&lt;/p&gt;
573&lt;p&gt;One cool thing about tags are that you can checkout a specific tag. So they
574behave very similarly as branches in that regard. And you don’t have the
575overhead of having two mainstream branches.&lt;/p&gt;
576&lt;p&gt;So what is the solution? One approach is to use development workflow, where all
577changes are made on the smaller branches and continuously merged into
578master. Where the software is ready to be pushed to production you tag the
579master branch. This approach eliminates the need for long-lived branches and
580simplifies the development process. It also encourages developers to make small,
581incremental changes that can be tested and deployed quickly. However, this
582approach may not be suitable for all projects or teams that heavily rely on
583automated deployment based on branch names only.&lt;/p&gt;
584&lt;p&gt;This also requires that developers always keep production in mind. No more
585living on an island of the develop branch. All your actions and code need to be
586ready to meet production standards on a much smaller timescale.&lt;/p&gt;
587&lt;p&gt;I think that we have complicated the workflow in an honest attempt to make
588things more streamlined but in the process of doing this, we have inadvertently
589made our lives much more complicated.&lt;/p&gt;
590&lt;p&gt;In conclusion, it&#39;s important to re-evaluate our workflows from time to time to
591see if they still make sense and if there are better alternatives available.
592Long-living branches can be problematic, and using tags to mark important
593milestones can simplify the development process.&lt;/p&gt;
594</content:encoded>
595 </item>
596
597
598
599
600
601
602
603
604
605
606
607 <item>
608 <title>Rekindling my love for programming and enjoying the act of creating</title>
609 <link>https://mitjafelicijan.com/rekindling-my-love-for-programming.html</link>
610 <pubDate>Tue, 16 May 2023 12:00:00 &#43;0200</pubDate>
611 <guid>https://mitjafelicijan.com/rekindling-my-love-for-programming.html</guid>
612 <description>Programming can be a challenging and rewarding experience, but sometimes it&amp;#39;seasy to feel burnt out or disinterested.</description>
613 <content:encoded>&lt;p&gt;Programming can be a challenging and rewarding experience, but sometimes it&#39;s
614easy to feel burnt out or disinterested. I have lost the passion for coding over
615the past couple of months and it looked like I will never enjoy the coding as
616much as I did.&lt;/p&gt;
617&lt;p&gt;I was feeling burnt out with programming. I thought taking a break from it and
618focusing on other activities that I enjoy might be helpful. This way, I could
619come back to programming with a fresh perspective and renewed energy. I also
620thought about learning a new programming language or technology to keep things
621interesting and challenging.&lt;/p&gt;
622&lt;p&gt;However, what I didn&#39;t realize was that learning a new language or technology
623wasn&#39;t going to solve the underlying issue. I needed to take a step back and
624re-evaluate why I had lost my passion for programming in the first place. This
625involved taking a deep look into what I was doing that resulted in this rut.&lt;/p&gt;
626&lt;p&gt;Sometimes, it&#39;s easy to get caught up in the hype of new technologies or
627languages, and we can feel like we&#39;re missing out if we&#39;re not constantly
628learning and experimenting. However, it&#39;s important to remember that the latest
629and greatest isn&#39;t always the best fit for our projects or our
630interests. Instead of constantly chasing the next big thing, it can be helpful
631to focus on what truly interests us and what we&#39;re passionate about. This can
632help us stay motivated and engaged with our work, rather than feeling like we&#39;re
633just going through the motions.&lt;/p&gt;
634&lt;p&gt;I expressed that I had lost my passion for coding over the past couple of
635months, and I realized that the reason behind it was my tendency to spread
636myself too thin and not focus on completing interesting projects. In order to
637regain my passion for coding, I need to focus on projects that truly interest me
638and give me a sense of purpose and motivation.&lt;/p&gt;
639&lt;p&gt;Recently, I have been playing World of Warcraft more frequently and have become
640interested in developing addons for the game.&lt;/p&gt;
641&lt;p&gt;This quickly resulted in me creating three addons that improve the quality of
642life, and I subsequently developed a more useful add-on that encapsulates all
643the others I made.&lt;/p&gt;
644&lt;p&gt;I found it interesting that this action sparked a new interest in me.
645Additionally, I discovered the Lua language, which reminded me that coding
646should be fun rather than just a struggle with a language. It should be pure,
647unadulterated fun.&lt;/p&gt;
648&lt;p&gt;I wasn&#39;t fighting the syntax, nor was I focused on finding the most optimal
649solution. I simply created things without the pressure of making them the best
650they could possibly be.&lt;/p&gt;
651&lt;p&gt;This made me realize that I actually adore simple languages that get out of the
652way and let you express what you want to do. It forced me to rethink a lot about
653what I use and what I actually enjoy.&lt;/p&gt;
654&lt;p&gt;I have decided to stick to the basics. For a scripting language, I will use
655Lua. For networking, I will use Golang. And for any special needs, I will rely
656on C. I do not require Rust, Nim, or Zig. This selection is more than sufficient
657for my needs. I have to stay true to this simplicity. There is something to the
658Occam&#39;s Razor.&lt;/p&gt;
659&lt;p&gt;I&#39;ve been struggling with a lack of creativity lately, but now I&#39;m experiencing
660a real change. I realized I needed to take a step back and stop actively trying
661to address the issue. I needed to stop worrying and overthinking it. I simply
662needed some time. Looking back, I don&#39;t think I&#39;ve taken any significant time
663off in the last 10 years.&lt;/p&gt;
664&lt;p&gt;Suddenly, I find myself with the energy and passion to complete multiple small
665projects. It doesn&#39;t feel like a chore at all. Who knew I needed WoW to
666kickstart everything. Inspiration really does come from the strangest places.&lt;/p&gt;
667</content:encoded>
668 </item>
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696 <item>
697 <title>Trying to build a New kind of terminal emulator for the modern age</title>
698 <link>https://mitjafelicijan.com/trying-to-build-a-new-kind-of-terminal-emulator.html</link>
699 <pubDate>Thu, 26 Jan 2023 12:00:00 &#43;0200</pubDate>
700 <guid>https://mitjafelicijan.com/trying-to-build-a-new-kind-of-terminal-emulator.html</guid>
701 <description>Over the past few weeks, I have been really thinking about terminal emulators,how we interact with computers, the separation of text-based programs and GUIones.</description>
702 <content:encoded>&lt;p&gt;Over the past few weeks, I have been really thinking about terminal emulators,
703how we interact with computers, the separation of text-based programs and GUI
704ones. To be perfectly honest, I got pissed off one evening when I was cleaning
705up files on my computer. Normally, I go into console and do &lt;code&gt;ncdu&lt;/code&gt; and check
706where the junk is. Then I start deleting stuff. Without any discrimination,
707usually. But when it comes to screenshots, I have learned that it&#39;s good to keep
708them somewhere near if I need to refer to something that I was doing. I am an
709avid screenshot taker. So at that point I checked Pictures folder and also did a
710basic search &lt;code&gt;find . -type f -name &amp;quot;*.jpg&amp;quot;&lt;/code&gt; for all the JPEG files in my home
711directory and immediately got pissed off. Why can’t I see thumbnails in my
712terminal? I know why, but why in the year of 2022 this is still a problem. I am
713used to traversing my disk via terminal. I am faster, and I am more comfortable
714this way. But when it comes to visualization, I then need to revert to GUI
715applications and again find the same file to see it. I know that programs like
716&lt;code&gt;feh&lt;/code&gt; and &lt;code&gt;sxiv&lt;/code&gt; are available, but I would just like to see the preview. Like
717&lt;a href=&#34;https://jupyter.org/&#34;&gt;Jupyter notebook&lt;/a&gt; or something similar. Just having it
718inline. Part of a result.&lt;/p&gt;
719&lt;p&gt;It also didn’t help that I was spending some time with the &lt;a href=&#34;https://plan9.io/plan9/&#34;&gt;Plan
7209&lt;/a&gt; Operating system. More specifically
721&lt;a href=&#34;http://9front.org/&#34;&gt;9FRONT&lt;/a&gt;. The way that &lt;a href=&#34;http://acme.cat-v.org/&#34;&gt;ACME editor&lt;/a&gt;
722handles text editing is just wonderful. Different and fresh somehow, even though
723it’s super old.&lt;/p&gt;
724&lt;p&gt;So, I went on a lookout for an interesting way of visualizing results of some
725query. I found these applications to be outstanding examples of how not to be a
726captive of a predetermined way of doing things.&lt;/p&gt;
727&lt;ul&gt;
728&lt;li&gt;&lt;a href=&#34;https://www.wolfram.com/mathematica/&#34;&gt;Wolfram Mathematica&lt;/a&gt;&lt;/li&gt;
729&lt;li&gt;&lt;a href=&#34;https://jupyter.org/&#34;&gt;Jupyter notebooks&lt;/a&gt;&lt;/li&gt;
730&lt;li&gt;&lt;a href=&#34;http://www.9front.org&#34;&gt;Plan 9 / 9FRONT&lt;/a&gt;&lt;/li&gt;
731&lt;li&gt;&lt;a href=&#34;https://templeos.org/&#34;&gt;Temple OS&lt;/a&gt;&lt;/li&gt;
732&lt;li&gt;&lt;a href=&#34;https://www.gnu.org/software/emacs/&#34;&gt;Emacs&lt;/a&gt;&lt;/li&gt;
733&lt;/ul&gt;
734&lt;p&gt;My idea is not as out there as ACME is, but it is a spin on the terminal
735emulators. I like the modes that Vi/Vim provides you with. I like the way the
736Emacs does its own &lt;code&gt;M-x&lt;/code&gt; &lt;code&gt;M-c&lt;/code&gt;. Furthermore, I really like how Mathematica and
737Jupyter present the data in a free flowing form. And I love how Temple OS is
738basically a C interpreter on some level.&lt;/p&gt;
739&lt;blockquote&gt;
740&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This is part 1 of the journey. Nowhere finished yet. I am just
741tinkering with this at the moment. This whole thing can easily spectacularly
742fail.&lt;/p&gt;
743&lt;/blockquote&gt;
744&lt;p&gt;So I started. I knew that I wanted to have the couple of modes, but I didn’t
745like the repetition of keystrokes, so the only option was to have some sort of
746toggle and indicate to the user that they are in a special mode. Like Vi does
747for Normal and Visual mode.&lt;/p&gt;
748&lt;p&gt;These modes would for the first version be:&lt;/p&gt;
749&lt;ul&gt;
750&lt;li&gt;&lt;em&gt;Preview mode&lt;/em&gt; (toggle with Ctrl &#43; P)
751&lt;ul&gt;
752&lt;li&gt;When this mode would be enabled, the &lt;code&gt;ls&lt;/code&gt; command would try to find images
753from the results and display thumbnails from them in the terminal itself.
754No ASCII art. Proper images. In a grid!&lt;/li&gt;
755&lt;/ul&gt;
756&lt;/li&gt;
757&lt;li&gt;&lt;em&gt;Detach mode&lt;/em&gt; (toggle with Ctrl &#43; D)
758&lt;ul&gt;
759&lt;li&gt;When this mode would be enabled, every command would open a new window
760and execute that command in it. This would be useful for starting &lt;code&gt;htop&lt;/code&gt;
761in a separate window.&lt;/li&gt;
762&lt;/ul&gt;
763&lt;/li&gt;
764&lt;/ul&gt;
765&lt;p&gt;The reason for having these modes togglable is to not ask for previews every
766time. You enable a mode and until you disable it, it behaves that way. Purely
767out of ergonomic reasons.&lt;/p&gt;
768&lt;p&gt;I would like to treat every terminal I open as a session mentally. When I start
769using the terminal, I start digging deeper into the issue I am trying to
770resolve. And while I am doing this, I would like to open detached windows
771etc. A lot of these things can be done easily with something like
772&lt;a href=&#34;https://i3wm.org/&#34;&gt;i3&lt;/a&gt;, but also that pull you out of the context of what you
773were doing. I would like to orchestrate everything from one single point.&lt;/p&gt;
774&lt;p&gt;In planning for this project, I knew that I would need to use a language like C
775and a library such as &lt;a href=&#34;https://www.libsdl.org/&#34;&gt;SDL2&lt;/a&gt; in order to achieve the
776desired results. I had considered other options, but ultimately determined that
777&lt;a href=&#34;https://www.libsdl.org/&#34;&gt;SDL2&lt;/a&gt; was the best fit based on its capabilities and
778reputation in the programming community.&lt;/p&gt;
779&lt;p&gt;At first, I thought the idea of a hardware accelerated terminal was a bit of a
780joke. It seemed like such a niche and unnecessary feature, especially given the
781fact that terminal emulators have been around for decades and have always relied
782on software rendering. But to be fair, &lt;a href=&#34;https://alacritty.org/&#34;&gt;Alacritty&lt;/a&gt; is
783doing the same thing. Well, they are doing a remarkable job at it.&lt;/p&gt;
784&lt;p&gt;So, I embarked on a journey. Everything has to start somewhere. For me, it
785started with creating a window! It has to start somewhere. 🙂&lt;/p&gt;
786&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;// Oh, Hi Mark!
787&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;// Create the window, obviously.
788&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt;SDL_Window *window = SDL_CreateWindow(
789&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; WINDOW_TITLE, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
790&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; WINDOW_WIDTH, WINDOW_HEIGHT,
791&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
792&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I continued like this to get some text displayed on the screen.&lt;/p&gt;
793&lt;p&gt;I noted that
794&lt;a href=&#34;https://wiki.libsdl.org/SDL_ttf/TTF_RenderText_Solid&#34;&gt;&lt;code&gt;TTF_RenderText_Solid&lt;/code&gt;&lt;/a&gt;
795rendered text really poorly. There were no antialiasing at all. In my wisdom, I
796never checked the documentation. Well, that was a fail. To uneducated like me:
797&lt;code&gt;TTF_RenderText_Solid&lt;/code&gt; renders Latin1 text at fast quality to a new 8-bit
798surface. So, that&#39;s why the texts looked like shit. No wonder.&lt;/p&gt;
799&lt;p&gt;Remarks on &lt;code&gt;TTF_RenderText_Solid&lt;/code&gt;: This function will allocate a new 8-bit,
800palettized surface. The surface&#39;s 0 pixel will be the colorkey, giving a
801transparent background. The 1 pixel will be set to the text color.&lt;/p&gt;
802&lt;p&gt;After I replaced it with
803&lt;a href=&#34;https://wiki.libsdl.org/SDL_ttf/TTF_RenderText_LCD&#34;&gt;&lt;code&gt;TTF_RenderText_LCD&lt;/code&gt;&lt;/a&gt; which
804renders Latin1 text at LCD subpixel quality to a new ARGB surface, the text
805started looking good. Really make sure you read the documentation. It’s actually
806good. As a side note, you can find all the documentation regarding &lt;a href=&#34;https://wiki.libsdl.org/&#34;&gt;SDL2 on
807their Wiki&lt;/a&gt;.&lt;/p&gt;
808&lt;p&gt;After that was done, I started working on displaying other things like &lt;code&gt;Preview&lt;/code&gt;
809and &lt;code&gt;Detach&lt;/code&gt; modes. This wasn’t really that hard. In SDL2 you can check all the
810available events with &lt;code&gt;while (SDL_PollEvent(&amp;amp;event) &amp;gt; 0)&lt;/code&gt; and have a bunch of
811switch statements to determine which key is currently being pressed. More about
812keys, &lt;a href=&#34;https://documentation.help/SDL/sdlkey.html&#34;&gt;SDLKey&lt;/a&gt; and mroe about
813pooling the events on
814&lt;a href=&#34;https://documentation.help/SDL/sdlpollevent.html&#34;&gt;SDL_PollEvent&lt;/a&gt;.&lt;/p&gt;
815&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;while&lt;/span&gt; (SDL_PollEvent(&amp;amp;event) &amp;gt; 0)
816&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
817&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;switch&lt;/span&gt; (event.type)
818&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {
819&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;case&lt;/span&gt; SDL_QUIT:
820&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; running = false;
821&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;break&lt;/span&gt;;
822&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
823&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;case&lt;/span&gt; SDL_TEXTINPUT:
824&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt; (!meta_key_pressed)
825&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {
826&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; strncat(input_prompt_text, event.text.text, 1);
827&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; update_input_prompt = true;
828&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
829&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;break&lt;/span&gt;;
830&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
831&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
832&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After that was somewhat working correctly, I started creating a struct that
833would hold all the commands and results and I call them Cells. Yes, I stole that
834naming idea from Jupyter.&lt;/p&gt;
835&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;struct&lt;/span&gt;
836&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
837&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#2b91af&#34;&gt;char&lt;/span&gt; *command;
838&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#2b91af&#34;&gt;char&lt;/span&gt; *result;
839&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; SDL_Surface *surface;
840&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; SDL_Texture *texture;
841&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; SDL_Rect rect;
842&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} Cell;
843&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I am at a place now where I am starting to implement scrolling. This will for
844sure be fun to code. Memory management in C is super easy. 😂&lt;/p&gt;
845&lt;p&gt;I have also added a simple &lt;a href=&#34;https://en.wikipedia.org/wiki/INI_file&#34;&gt;INI file like
846configuration&lt;/a&gt; support. It is done in an
847&lt;a href=&#34;https://github.com/nothings/stb/blob/master/docs/stb_howto.txt&#34;&gt;STB style of
848header&lt;/a&gt; and maps
849to specific options supported by the terminal. It is not universal, and the code
850below demonstrates how I will use it in the future.&lt;/p&gt;
851&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;#ifndef CONFIG_H
852&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;#define CONFIG_H
853&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;&lt;/span&gt;
854&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;/*
855&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# This is a comment
856&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;
857&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# This is the first configuration option
858&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;dettach=value11111
859&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;
860&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# This is the second configuration option
861&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;preview=value22222
862&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;
863&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# This is the third configuration option
864&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;debug=value33333
865&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;*/&lt;/span&gt;
866&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
867&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;// Define a struct to hold the configuration options
868&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#00f&#34;&gt;typedef&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;struct&lt;/span&gt;
869&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
870&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#2b91af&#34;&gt;char&lt;/span&gt; dettach[256];
871&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#2b91af&#34;&gt;char&lt;/span&gt; preview[256];
872&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#2b91af&#34;&gt;char&lt;/span&gt; debug[256];
873&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;} Config;
874&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
875&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;// Read the configuration file and return the options as a struct
876&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#00f&#34;&gt;extern&lt;/span&gt; Config read_config_file(&lt;span style=&#34;color:#00f&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#2b91af&#34;&gt;char&lt;/span&gt; *filename)
877&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
878&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;// Create a struct to hold the configuration options
879&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt; Config config = {0};
880&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
881&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;// Open the configuration file
882&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt; FILE *file = fopen(filename, &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;r&amp;#34;&lt;/span&gt;);
883&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
884&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;// Read each line from the file
885&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt; &lt;span style=&#34;color:#2b91af&#34;&gt;char&lt;/span&gt; line[256];
886&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;while&lt;/span&gt; (fgets(line, &lt;span style=&#34;color:#00f&#34;&gt;sizeof&lt;/span&gt;(line), file))
887&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {
888&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;// Check if this line is a comment or empty
889&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt; (line[0] == &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;#&amp;#39;&lt;/span&gt; || line[0] == &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;\n&amp;#39;&lt;/span&gt;)
890&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;continue&lt;/span&gt;;
891&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
892&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;// Parse the line to get the option and value
893&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt; &lt;span style=&#34;color:#2b91af&#34;&gt;char&lt;/span&gt; option[128], value[128];
894&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt; (sscanf(line, &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;%[^=]=%s&amp;#34;&lt;/span&gt;, option, value) != 2)
895&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;continue&lt;/span&gt;;
896&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
897&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;// Set the value of the appropriate option in the config struct
898&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt; (strcmp(option, &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;dettach&amp;#34;&lt;/span&gt;) == 0)
899&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {
900&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; strncpy(config.option1, value, &lt;span style=&#34;color:#00f&#34;&gt;sizeof&lt;/span&gt;(config.option1));
901&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
902&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt; (strcmp(option, &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;preview&amp;#34;&lt;/span&gt;) == 0)
903&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {
904&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; strncpy(config.option2, value, &lt;span style=&#34;color:#00f&#34;&gt;sizeof&lt;/span&gt;(config.option2));
905&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
906&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt; (strcmp(option, &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;debug&amp;#34;&lt;/span&gt;) == 0)
907&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {
908&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; strncpy(config.option3, value, &lt;span style=&#34;color:#00f&#34;&gt;sizeof&lt;/span&gt;(config.option3));
909&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
910&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
911&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
912&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;// Close the configuration file
913&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt; fclose(file);
914&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
915&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;// Return the configuration options
916&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;return&lt;/span&gt; config;
917&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
918&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
919&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;#endif
920&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is as far as I managed to get for now. I have a daily job and this
921prohibits me to work on these things full time. But I should probably get back
922and finish this. At least have a simple version working out, so I can start
923testing it on my machines. Fingers crossed. 🕵️‍♂️&lt;/p&gt;
924</content:encoded>
925 </item>
926
927
928
929 <item>
930 <title>Microsoundtrack — That sound that machine makes when struggling</title>
931 <link>https://mitjafelicijan.com/that-sound-that-machine-makes-when-struggling.html</link>
932 <pubDate>Sun, 16 Oct 2022 12:00:00 &#43;0200</pubDate>
933 <guid>https://mitjafelicijan.com/that-sound-that-machine-makes-when-struggling.html</guid>
934 <description>A couple of months ago, I got an idea about micro soundtracks.</description>
935 <content:encoded>&lt;p&gt;A couple of months ago, I got an idea about micro soundtracks. In this concept,
936you are the observer, director, and audience in this tiny movies.&lt;/p&gt;
937&lt;p&gt;What you do is to attempt to imagine what would be happening around you based on
938a title of the song and let the song help you fill the void in your story.&lt;/p&gt;
939&lt;p&gt;I made these songs is Logic Pro X. Every year or so I do this kind of thing and
940make a couple of songs similar to this. But this is the first time I am posting
941about it.&lt;/p&gt;
942&lt;p&gt;You can listen to the whole set on
943&lt;a href=&#34;https://www.youtube.com/watch?v=_5oXBhSmF3c&#34;&gt;Youtube&lt;/a&gt; or scroll down the page
944and there are embedded players for each song.&lt;/p&gt;
945&lt;h2 id=&#34;a-bunch-of-inter-dimensional-people-with-loud-clocks&#34;&gt;A bunch of inter-dimensional people with loud clocks&lt;/h2&gt;
946&lt;p&gt;A group of inter-dimensional people are going up and down the elevator with you
947while having loud clocks around their necks. Each clock ticks on a different
948frequency. A lot of other sounds are getting drawn into your dimension,
949resulting in a strange merging of dimensions.&lt;/p&gt;
950&lt;iframe style=&#34;border: 0; width: 100%; height: 42px;&#34; src=&#34;https://bandcamp.com/EmbeddedPlayer/album=3913808801/size=small/bgcol=ffffff/linkcol=0687f5/track=1349272965/transparent=true/&#34; seamless title=&#34;Bandcamp&#34;&gt;&lt;a href=&#34;https://mitjafelicijan.bandcamp.com/album/that-sound-that-machine-makes-when-struggling&#34;&gt;That sound that machine makes when struggling by Mitja Felicijan&lt;/a&gt;&lt;/iframe&gt;
951&lt;h2 id=&#34;two-black-holes-conversing-about-the-weather&#34;&gt;Two black holes conversing about the weather&lt;/h2&gt;
952&lt;p&gt;You are a traveler in a spaceship flying very close to two colliding black holes
953having a discussion about the weather while tearing each other apart. During all
954this your ship is getting pulled into the event horizon of both black holes,
955putting a lot of strain on your spaceship.&lt;/p&gt;
956&lt;iframe style=&#34;border: 0; width: 100%; height: 42px;&#34; src=&#34;https://bandcamp.com/EmbeddedPlayer/album=3913808801/size=small/bgcol=ffffff/linkcol=0687f5/track=1756714200/transparent=true/&#34; seamless title=&#34;Bandcamp&#34;&gt;&lt;a href=&#34;https://mitjafelicijan.bandcamp.com/album/that-sound-that-machine-makes-when-struggling&#34;&gt;That sound that machine makes when struggling by Mitja Felicijan&lt;/a&gt;&lt;/iframe&gt;
957&lt;h2 id=&#34;a-planet-where-every-organism-is-a-plant&#34;&gt;A planet where every organism is a plant&lt;/h2&gt;
958&lt;p&gt;You land on a planet where every living organism is a plant and among those
959plants some of them are highly intelligent, and you were asked to make first
960contact with the native species. Your visit takes place in a giant cave where
961you are meeting these plants, and they are talking to you.&lt;/p&gt;
962&lt;iframe style=&#34;border: 0; width: 100%; height: 42px;&#34; src=&#34;https://bandcamp.com/EmbeddedPlayer/album=3913808801/size=small/bgcol=ffffff/linkcol=0687f5/track=3710973979/transparent=true/&#34; seamless title=&#34;Bandcamp&#34;&gt;&lt;a href=&#34;https://mitjafelicijan.bandcamp.com/album/that-sound-that-machine-makes-when-struggling&#34;&gt;That sound that machine makes when struggling by Mitja Felicijan&lt;/a&gt;&lt;/iframe&gt;
963&lt;h2 id=&#34;bio-implants-having-a-fit-and-reprogramming-your-brain&#34;&gt;Bio implants having a fit and reprogramming your brain&lt;/h2&gt;
964&lt;p&gt;In a distant future where everybody has bio implants, you have just received
965your first one, which happens to be a brain implant. Something goes wrong, and
966your implant is starting to misbehave, and you are experiencing brain
967malfunctions. You are on the streets at night a couple of hours after your
968procedure. You can feel your sanity breaking down.&lt;/p&gt;
969&lt;iframe style=&#34;border: 0; width: 100%; height: 42px;&#34; src=&#34;https://bandcamp.com/EmbeddedPlayer/album=3913808801/size=small/bgcol=ffffff/linkcol=0687f5/track=1157430581/transparent=true/&#34; seamless title=&#34;Bandcamp&#34;&gt;&lt;a href=&#34;https://mitjafelicijan.bandcamp.com/album/that-sound-that-machine-makes-when-struggling&#34;&gt;That sound that machine makes when struggling by Mitja Felicijan&lt;/a&gt;&lt;/iframe&gt;
970&lt;h2 id=&#34;cow-animation&#34;&gt;Cow animation&lt;/h2&gt;
971&lt;p&gt;I also made this little cow animation. Go into full screen to see the effects in
972more details.&lt;/p&gt;
973&lt;p&gt;&lt;video src=&#34;/posts/microsoundtrack/cow.m4v&#34; controls loop&gt;&lt;/video&gt;&lt;/p&gt;
974</content:encoded>
975 </item>
976
977
978
979 <item>
980 <title>State of Web Technologies and Web development in year 2022</title>
981 <link>https://mitjafelicijan.com/state-of-web-technologies-and-web-development-in-year-2022.html</link>
982 <pubDate>Thu, 06 Oct 2022 12:00:00 &#43;0200</pubDate>
983 <guid>https://mitjafelicijan.com/state-of-web-technologies-and-web-development-in-year-2022.html</guid>
984 <description>Initial thoughtsThis post is a critique on the current state of web development.</description>
985 <content:encoded>&lt;h2 id=&#34;initial-thoughts&#34;&gt;Initial thoughts&lt;/h2&gt;
986&lt;p&gt;&lt;em&gt;This post is a critique on the current state of web development. It is an
987opinionated post! I will learn more about this in the future, and probably
988slightly change my mind about some of the things I criticize.&lt;/em&gt;&lt;/p&gt;
989&lt;p&gt;I have started working on a hobby project about two weeks ago, and I wanted to
990use that situation as a learning one. Trying new things, new technologies, new
991tools. I always considered myself to be an adventurous person when it comes to
992technology. I never shy away from trying new languages, new operating systems
993etc. Likewise, I find the whole experience satisfying, and it tickles that part
994of my brain that finds discovery the highest of the mountains to climb.&lt;/p&gt;
995&lt;p&gt;What I always wanted to make was a coding game, that you would play in a browser
996(just to eliminate building binaries for each operating system) where you would
997level up your character and go into these scriptable battles. You know, RPG
998elements.&lt;/p&gt;
999&lt;p&gt;So, the natural way to go would be some sort of SPA (single page application)
1000with basic routing and some state management. Nothing crazy.&lt;/p&gt;
1001&lt;blockquote&gt;
1002&lt;p&gt;&lt;strong&gt;Before we move on&lt;/strong&gt;, I have to be transparent. Take my views on this with
1003a grain of salt. I have only scratched the surface with these technologies,
1004and my knowledge is full of gaps. This is my experience using some of these
1005products for the first time or in a limited capacity.&lt;/p&gt;
1006&lt;/blockquote&gt;
1007&lt;p&gt;Having this out of the way, I got myself a fresh pot of coffee and down the
1008rabbit hole I went.&lt;/p&gt;
1009&lt;h2 id=&#34;giving-react-js-a-spin&#34;&gt;Giving React JS a spin&lt;/h2&gt;
1010&lt;p&gt;I first tried &lt;a href=&#34;https://reactjs.org/&#34;&gt;React JS&lt;/a&gt;. I kind of like it. Furthermore,
1011I have worked with libraries like this in the past and also wrote a couple of
1012them (nothing compared to that level), but I had the basic understanding of what
1013was going on. I rolled up a project quickly and had basic things done in a
1014matter of two hours, which was impressive.&lt;/p&gt;
1015&lt;p&gt;I prefer using &lt;a href=&#34;https://tailwindcss.com/&#34;&gt;Tailwind CSS&lt;/a&gt; for my styling
1016pleasures, and integrating that was also a painless experience. It was actually
1017nice to see that some things got better with time. In about 2 minutes I got
1018Tailwind working, and I was able to use classes at my disposal. All that
1019&lt;code&gt;postcss&lt;/code&gt; stuff was taken care of by adding a couple of things in config files
1020(all described really well in their documentation).&lt;/p&gt;
1021&lt;p&gt;It is not that different from Vue which I have had more encounters with in the
1022past People will probably call me a lunatic for saying this. But you know, it is
1023the truth. Same same, but different. I still believe that using libraries like
1024this is beneficial. I am not a JavaScript purist. They all have their quirks,
1025but at the end of the day, I truly believe it’s worth it.&lt;/p&gt;
1026&lt;h2 id=&#34;bundlers-and-transpilers&#34;&gt;Bundlers and Transpilers&lt;/h2&gt;
1027&lt;p&gt;I still reject calling &lt;a href=&#34;https://www.typescriptlang.org/&#34;&gt;Typescript&lt;/a&gt; to
1028&lt;a href=&#34;https://www.javascript.com/&#34;&gt;JavaScript&lt;/a&gt; conversion a &amp;quot;compilation process&amp;quot;. I
1029call them &lt;a href=&#34;https://devopedia.org/transpiler&#34;&gt;transpilers&lt;/a&gt;, and I don’t care! 😈&lt;/p&gt;
1030&lt;p&gt;The first one that I ever used was &lt;a href=&#34;https://webpack.js.org/&#34;&gt;webpack&lt;/a&gt;, and it
1031was an absolute horrific experience. Saying this, it is an absolutely fantastic
1032tool. I felt more like a config editor than actually a programmer. To be fair,
1033I am a huge fan of &lt;a href=&#34;https://www.gnu.org/software/make/&#34;&gt;make&lt;/a&gt;, and you can do as
1034you wish with this information. I like my build systems simple.&lt;/p&gt;
1035&lt;p&gt;Also, isn’t it interesting that we need something like
1036&lt;a href=&#34;https://babeljs.io/&#34;&gt;Babel&lt;/a&gt; to make JavaScript code work in a browser that has
1037only one client side scripting available, which is by no accident also
1038JavaScript. Why? I know why it’s needed, but seriously, why.&lt;/p&gt;
1039&lt;p&gt;I haven’t used Babel for years now. Or if I did, it was packaged together by
1040some other bundler thingy. Which does not make things better, but at least I
1041didn’t need to worry about it.&lt;/p&gt;
1042&lt;p&gt;I really don’t like complicated build systems. I really don’t like abstracting
1043code and making things appear magical. The older I get, the more I appreciate
1044clear and clean, expressive code. No one-liners, if possible.&lt;/p&gt;
1045&lt;p&gt;But I have to give props to &lt;a href=&#34;https://vitejs.dev/&#34;&gt;Vite&lt;/a&gt;! This was one of the
1046best developer experiences I have ever had. Granted, it still has magical
1047properties. And yes, it still is a bundler and abstracts things to the nth
1048degree. But at least it didn’t force me to configure 700 lines of JSON. And I
1049know that this makes me a hypocrite. You can’t have it all. Nonetheless, my
1050reasoning here is, if using bundlers is inevitable, then at least they should
1051provide an excellent developer experience.&lt;/p&gt;
1052&lt;p&gt;I also noticed that now the catch-all phrase is “blazingly fast” and “lightning
1053fast” and “next generation” and stuff like that. I mean, yeah, tools should get
1054faster with time. But saying that starting a project now takes 2 seconds instead
1055of 20 seconds is something that is a break it or make it kind of a deal is
1056ridiculous. I don’t mind waiting a couple of seconds every couple of days. I
1057also don’t create 700 projects every day, and also who does? This argument has
1058no bite. All I want is a decent reload time (~100ms is more than good enough for
1059me) and that is it.&lt;/p&gt;
1060&lt;p&gt;You don’t need to sell me benefits if I only get them when I start a fresh
1061project, and then try to convince me that this is somehow changing the fate of
1062the universe. First of all, it is not. And second, if this is your only argument
1063for your tool, I would advise you to maybe re-focus your efforts to something
1064else. Vite says that startup times are really fast. And if that would be the
1065only thing differentiating it from other tools, I would ignore it. But it has
1066some really compelling features like &lt;a href=&#34;https://www.geeksforgeeks.org/reactjs-hot-module-replacement/&#34;&gt;Hot Module
1067Replacement&lt;/a&gt; that
1068really works well. It was a joy to use.&lt;/p&gt;
1069&lt;p&gt;So, I will be definitely using Vite in the future.&lt;/p&gt;
1070&lt;h2 id=&#34;jam-stack-mach-stack-no-snack&#34;&gt;Jam Stack, Mach Stack no snack&lt;/h2&gt;
1071&lt;p&gt;Let&#39;s get a couple of the acronyms out of the way, so we all know what we are
1072talking about:&lt;/p&gt;
1073&lt;ul&gt;
1074&lt;li&gt;Jam Stack - JavaScript, API and Markup&lt;/li&gt;
1075&lt;li&gt;Mach Stack - Microservices, API-first, Cloud-Native SaaS, Headless&lt;/li&gt;
1076&lt;/ul&gt;
1077&lt;p&gt;It is so hard to follow all these new trendy things happening around you, that
1078it makes you have a massive &lt;strong&gt;FOMO&lt;/strong&gt; all the time. But on the other hand, you
1079also don’t want to be that old fart that doesn’t move with the times and still
1080writes his trusty jQuery code while listening to Blink 182 All the small things
1081on full blast. It’s a good song, don’t get me wrong, but there are other songs
1082out there.&lt;/p&gt;
1083&lt;p&gt;I have to admit. &lt;a href=&#34;https://vercel.com/&#34;&gt;Vercel&lt;/a&gt; is really cool! Love the
1084simplicity of the service. You could compare it to
1085&lt;a href=&#34;https://www.netlify.com/&#34;&gt;Netlify&lt;/a&gt;. I haven’t tried Netlify extensively, but
1086from a couple of experimental deployments I still prefer Vercel. It is much more
1087streamlined, but maybe this is bias in me. I really like Vercel’s Analytics,
1088which give you a &lt;a href=&#34;https://web.dev/vitals/&#34;&gt;Core Web Vitals report&lt;/a&gt; in their
1089admin console. Kind of cool, I’m not going to lie.&lt;/p&gt;
1090&lt;p&gt;This whole idea about frontend and backend merging into &lt;a href=&#34;https://www.debugbear.com/blog/server-side-rendering&#34;&gt;SSR (server-side
1091rendering)&lt;/a&gt; looks so good
1092on paper. It almost doesn’t come with any major flaws.&lt;/p&gt;
1093&lt;p&gt;But when it comes to the actual implementation, there is much to be desired.
1094I’m going to lump &lt;a href=&#34;https://nextjs.org/&#34;&gt;Next.js&lt;/a&gt; and
1095&lt;a href=&#34;https://nuxtjs.org/&#34;&gt;Nuxt.js&lt;/a&gt; together because they are essentially the same
1096thing, just a different library.&lt;/p&gt;
1097&lt;p&gt;Now comes the reality. Mixing backend and frontend in this manner creates this
1098weird mental model where you kind of rely on magical properties of these
1099libraries. You relinquish control over to them for better developer experience.
1100But is that really true? Initially, I was so stoked about it. However, the more
1101I used them, the more I felt uncomfortable. I felt dirty, actually. Maybe this
1102is because I come from old ways of doing things where you control every step of
1103request, and allowing something to hijack it feels like blasphemy.&lt;/p&gt;
1104&lt;p&gt;More than that, some pretty significant technical issues arose from this. How do
1105you do JWT token authentication? You put it in &lt;code&gt;api&lt;/code&gt; folder and then do some
1106fetching and storing into local state management. But doing this also requires
1107some tinkering with await/async stuff on the React/Vue side of things. And then
1108you need to write middleware for it. And the more I look at it, the more I see
1109that this whole thing was not meant to be used like this, and it all feels and
1110looks like a huge hack.&lt;/p&gt;
1111&lt;p&gt;The issue I have with this is that they over-promise and under-deliver. They
1112want to be an all-in-one replacement for everything, and they don’t deliver on
1113this promise. And how could they?! We have to be fair. It is an impossible task.&lt;/p&gt;
1114&lt;p&gt;They sell you &lt;a href=&#34;https://www.geeksforgeeks.org/overview-of-noops/&#34;&gt;NoOps&lt;/a&gt;, but
1115when you need to accomplish something a little bit more out of the scope of
1116Hello World, you have to make hacky decisions to make it work. And having a
1117deployment strategy that relies on many moving parts is never a good idea.
1118Abstracting too much is usually a sign of bad architecture.&lt;/p&gt;
1119&lt;p&gt;Lately, this has become a huge trend that will for sure bite us in the future.
1120And let’s not get it twisted. By doing this, PaaS providers like
1121&lt;a href=&#34;https://aws.amazon.com/&#34;&gt;AWS&lt;/a&gt;, &lt;a href=&#34;https://cloud.google.com/&#34;&gt;GCS&lt;/a&gt;, etc. obscure
1122their billing, and you end up paying more than you really should. And even if
1123that is not an issue, it comes down to the principle of things. AWS is known for
1124having multiple “currencies“ inside their projects like write operations, read
1125operations, etc. which add up, and it creates this impossible to track billing
1126scheme. It all behaves suspiciously like a pay-to-win game you could find on
1127mobile phones that scams you out of your money.&lt;/p&gt;
1128&lt;p&gt;And as far as I am concerned, the most important thing was me not coding the
1129functionalities for the game I want to make. I was battling libraries and cloud
1130providers. How to deploy, what settings are relevant. Bad documentation or
1131multiple versions of achieving the same thing. You are getting bombarded by all
1132this information, and you don’t really have any control over it.
1133Production-ready code becomes a joke, essentially. Especially if you tend to
1134work on that project for a prolonged period of time.&lt;/p&gt;
1135&lt;p&gt;All of these options end up creating a fatigue. What to choose, what not to
1136choose. Unnecessary worrying about if the stack will still be deemed worthy in
1137six months. There is elegance in simplicity.&lt;/p&gt;
1138&lt;blockquote&gt;
1139&lt;p&gt;JavaScript UI frameworks and libraries work in cycles. Every six months or
1140so, a new one pops up, claiming that it has revolutionized UI development.
1141Thousands of developers adopt it into their new projects, blog posts are
1142written, Stack Overflow questions are asked and answered, and then a newer
1143(and even more revolutionary) framework pops up to usurp the throne.
1144— Ian Allen&lt;/p&gt;
1145&lt;/blockquote&gt;
1146&lt;p&gt;And this jab at these libraries and cloud providers is not done out of malice.
1147It is a real concern that I have about them. In my life, I have seen
1148technologies come and go, but the basics always stick around. So surrendering
1149all the power you have to a library or a cloud provider is in my opinion a
1150stupid move.&lt;/p&gt;
1151&lt;h2 id=&#34;tailwind-css-still-rocks&#34;&gt;Tailwind CSS still rocks!&lt;/h2&gt;
1152&lt;p&gt;You know, many people say negative things about Tailwind. And after a lot of
1153deliberation, I came to the conclusion that Tailwind is good for two types of
1154developers. Tailwind is good for a complete noob or a senior developer. A
1155complete noob doesn’t really care about inner workings of CSS, and a senior
1156developer also doesn’t care about CSS. Well, at least, not anymore. And
1157developers in between usually have the biggest issues with it. Not always of
1158course, but in a lot of cases.&lt;/p&gt;
1159&lt;p&gt;I like the creature comforts of Tailwind. Being utility first would make me
1160argue that it is actually more similar to &lt;a href=&#34;https://sass-lang.com/&#34;&gt;Sass&lt;/a&gt; or
1161&lt;a href=&#34;https://lesscss.org/&#34;&gt;Less&lt;/a&gt; than something like Bootstrap. Not technically, but
1162ideologically. After I started using it, I never looked back. I use it every
1163time I need to do something web related.&lt;/p&gt;
1164&lt;p&gt;Writing CSS for general things feels like going several steps back. Instead of
1165focusing on what you are actually trying to achieve, you focus on notations like
1166&lt;a href=&#34;https://en.bem.info/methodology/css/&#34;&gt;BEM&lt;/a&gt;, code structuring, optimizing HTML
1167size. Just doing things that make 0.1% difference. You know that saying: Early
1168optimization is the root of all evil. Exactly that.&lt;/p&gt;
1169&lt;p&gt;I am also not saying that Tailwind is the cure for everything. Sometimes custom
1170CSS is necessary. But from what I found out in using it for almost two years in
1171a production environment (on a site getting quite a lot of traffic and
1172constantly being changed), I can say without any reservations that Tailwind
1173saved our asses countless times. We would be rewriting CSS all the time without
1174it. And I don’t really think writing CSS is the best way to spend my time.&lt;/p&gt;
1175&lt;p&gt;I have also noticed that people who criticize Tailwind the most never actually
1176used it in a real project that has a long lifetime with plenty of changes that
1177will happen in the future.&lt;/p&gt;
1178&lt;p&gt;But you know, whatever floats your boat!&lt;/p&gt;
1179&lt;h2 id=&#34;code-maintainability&#34;&gt;Code maintainability&lt;/h2&gt;
1180&lt;p&gt;Somehow, people also stopped talking about maintenance. If you constantly try to
1181catch the latest and greatest train, you are by that logic always trying new
1182things. Which is a good thing if you want to learn about technologies and try
1183them. But for the production environment, you have to have a stable stack that
1184doesn’t change every 6 months.&lt;/p&gt;
1185&lt;p&gt;You can lock dependencies for sure. Nevertheless, the hype train moves along
1186anyway. And the mindset this breeds goes against locking the code. This
1187bleeding-edge rolling release cycle is not helping. That is why enterprise
1188solutions usually look down on these popular stacks and only do bare minimum to
1189appear hip and cool.&lt;/p&gt;
1190&lt;p&gt;With that said, I still think that progress is good, but should be taken with a
1191grain of salt. If your project is something that should be built once and then
1192rarely updated, going with the latest stack is a possible way to go. But, if you
1193are working on a project that lasts for years, you should probably approach it
1194with some level of caution. Web development is often times too volatile.&lt;/p&gt;
1195&lt;h2 id=&#34;web-development-has-a-marketing-issue&#34;&gt;Web development has a marketing issue&lt;/h2&gt;
1196&lt;p&gt;I noticed that almost every project now has this marketing spin put on it.
1197Everything is blazingly fast now. I get it, they are competing for your
1198attention, but what happened to just being truthful and not inflating reality.&lt;/p&gt;
1199&lt;p&gt;And in order to appeal to mass market, they leave things out of their marketing
1200materials. These open-source projects are now behaving more and more like
1201companies do. Which is a scary thought on its self.&lt;/p&gt;
1202&lt;p&gt;And we are also seeing a rise in a concept of building a company in the open,
1203which is a good thing, don&#39;t get me wrong. But when it is using open-source to
1204lure people and then lock them in their ecosystem, there is where I have issues
1205with it.&lt;/p&gt;
1206&lt;p&gt;This might be because I have been using GNU/Linux for 20 years now and have been
1207so beholden for my success to open-source that I see issues when open-source is
1208being used to trick people into a false sense of security that these projects
1209are built in the spirit of open-source. Because there is a difference. They are
1210NOT! They have a really specific goal in mind. And the open-source is being used
1211as a delivery system. Which is in my opinion disgusting!&lt;/p&gt;
1212&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
1213&lt;p&gt;I will end my post with this. Web development is running now in circles. People
1214are discovering &lt;a href=&#34;https://www.tutorialspoint.com/remote-procedure-call-rpc&#34;&gt;RPC&lt;/a&gt;
1215now and this is the now the next big thing. &lt;a href=&#34;https://graphql.org/&#34;&gt;GraphQL&lt;/a&gt; is
1216so passé. And I am so tired of it all. Of blazingly fast libraries, of all these
1217new technologies that are actually just a remake of old ones. Of just the
1218general spirit of the web. I will just use what I already know. Which worked 10
1219years ago and will work 10 years after this. I will adopt a couple of little
1220tools like Vite. But I will not waste my time on this anymore.&lt;/p&gt;
1221&lt;p&gt;It was a good exercise to get in touch with what’s new now. Nothing really
1222changed that much. FOMO is now cured! Now I have to get my ass back to actually
1223code and make the project that I wanted to make in the first place.&lt;/p&gt;
1224</content:encoded>
1225 </item>
1226
1227
1228
1229
1230
1231
1232
1233 <item>
1234 <title>Aerial photography of algae spotted on river Sava</title>
1235 <link>https://mitjafelicijan.com/aerial-photography-of-algae-spotted-on-river-sava.html</link>
1236 <pubDate>Sat, 13 Aug 2022 12:00:00 &#43;0200</pubDate>
1237 <guid>https://mitjafelicijan.com/aerial-photography-of-algae-spotted-on-river-sava.html</guid>
1238 <description>This is a bit of a different post than I usually write, but quite interestingone to me.</description>
1239 <content:encoded>&lt;p&gt;This is a bit of a different post than I usually write, but quite interesting
1240one to me. River Sava has plenty of hydropower plants located down the stream.
1241This makes regulating the strength of a current easier than normally. Because of
1242lower stream strength and high temperatures, algae has formed on the river.
1243This is the first time I&#39;ve seen something like this in my whole life.&lt;/p&gt;
1244&lt;p&gt;Below are some photographs taken from a DJI drone capturing the event.&lt;/p&gt;
1245&lt;figure&gt;
1246&lt;img src=&#34;/posts/algae-sava/dji-algae-0.jpg&#34; alt=&#34;Algae on Sava&#34; /&gt;
1247&lt;/figure&gt;
1248&lt;figure&gt;
1249&lt;img src=&#34;/posts/algae-sava/dji-algae-1.jpg&#34; alt=&#34;Algae on Sava&#34; /&gt;
1250&lt;/figure&gt;
1251&lt;figure&gt;
1252&lt;img src=&#34;/posts/algae-sava/dji-algae-2.jpg&#34; alt=&#34;Algae on Sava&#34; /&gt;
1253&lt;/figure&gt;
1254&lt;figure&gt;
1255&lt;img src=&#34;/posts/algae-sava/dji-algae-3.jpg&#34; alt=&#34;Algae on Sava&#34; /&gt;
1256&lt;/figure&gt;
1257&lt;figure&gt;
1258&lt;img src=&#34;/posts/algae-sava/dji-algae-4.jpg&#34; alt=&#34;Algae on Sava&#34; /&gt;
1259&lt;/figure&gt;
1260&lt;figure&gt;
1261&lt;img src=&#34;/posts/algae-sava/dji-algae-5.jpg&#34; alt=&#34;Algae on Sava&#34; /&gt;
1262&lt;/figure&gt;
1263&lt;p&gt;I will try to get more photos of this in the future days and if something
1264intriguing shows up will post it again on the blog.&lt;/p&gt;
1265</content:encoded>
1266 </item>
1267
1268
1269
1270 <item>
1271 <title>What would DNA sound if synthesized to an audio file</title>
1272 <link>https://mitjafelicijan.com/what-would-dna-sound-if-synthesized.html</link>
1273 <pubDate>Tue, 05 Jul 2022 12:00:00 &#43;0200</pubDate>
1274 <guid>https://mitjafelicijan.com/what-would-dna-sound-if-synthesized.html</guid>
1275 <description>IntroductionLately, I have been thinking a lot about the nature of life, what are thefoundation blocks of life and things like that.</description>
1276 <content:encoded>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;
1277&lt;p&gt;Lately, I have been thinking a lot about the nature of life, what are the
1278foundation blocks of life and things like that. It&#39;s remarkable how complex and
1279on the other hand simple the creation is when you look at it. The miracle of
1280life keeps us grounded when our imagination goes wild. If the DNA are the blocks
1281of life, you could consider them to be an API nature provided us to better
1282understand all of this chaos masquerading as order.&lt;/p&gt;
1283&lt;p&gt;I have been reading a lot about superintelligence and our somehow misguided path
1284to create general artificial intelligence. What would the building blocks or our
1285creation look like? Is the compression really the ultimate storage of
1286information? Will our creation also ponder this questions when creating new
1287worlds for themselves, or will we just disappear into the vastness of
1288possibilities? It is a little offensive that we are playing God whilst being
1289completely ignorant of our own reality. Who knows! Like many other
1290breakthroughs, this one will also come at a cost not known to us when it finally
1291happens.&lt;/p&gt;
1292&lt;p&gt;To keep things a bit lighter, I decided to convert some popular DNA sequences
1293into an audio files for us to listen to. I am not the first one, nor I will be
1294the last one to do this. But it is an interesting exercise in better
1295understanding the relationship between art and science. Maybe listening to DNA
1296instead of parsing it will find a way into better understanding, or at least
1297enjoying the creation and cryptic nature of life.&lt;/p&gt;
1298&lt;h2 id=&#34;dna-encoding-and-primer-example&#34;&gt;DNA encoding and primer example&lt;/h2&gt;
1299&lt;p&gt;I have been exploring DNA in the past in my post from about 3 years ago in
1300&lt;a href=&#34;/encoding-binary-data-into-dna-sequence.html&#34;&gt;Encoding binary data into DNA
1301sequence&lt;/a&gt; where I have been
1302converting all sorts of data into DNA sequences.&lt;/p&gt;
1303&lt;p&gt;This will be a similar exercise but instead of converting to DNA, I will be
1304generating tones from Nucleotides.&lt;/p&gt;
1305&lt;table&gt;
1306&lt;thead&gt;
1307&lt;tr&gt;
1308&lt;th&gt;Nucleotides&lt;/th&gt;
1309&lt;th&gt;Note&lt;/th&gt;
1310&lt;th&gt;Frequency&lt;/th&gt;
1311&lt;/tr&gt;
1312&lt;/thead&gt;
1313&lt;tbody&gt;
1314&lt;tr&gt;
1315&lt;td&gt;&lt;strong&gt;A&lt;/strong&gt; (Adenine)&lt;/td&gt;
1316&lt;td&gt;A&lt;/td&gt;
1317&lt;td&gt;440 Hz&lt;/td&gt;
1318&lt;/tr&gt;
1319&lt;tr&gt;
1320&lt;td&gt;&lt;strong&gt;C&lt;/strong&gt; (Cytosine)&lt;/td&gt;
1321&lt;td&gt;C&lt;/td&gt;
1322&lt;td&gt;783.99 Hz&lt;/td&gt;
1323&lt;/tr&gt;
1324&lt;tr&gt;
1325&lt;td&gt;&lt;strong&gt;G&lt;/strong&gt; (Guanine)&lt;/td&gt;
1326&lt;td&gt;G&lt;/td&gt;
1327&lt;td&gt;523.25 Hz&lt;/td&gt;
1328&lt;/tr&gt;
1329&lt;tr&gt;
1330&lt;td&gt;&lt;strong&gt;T&lt;/strong&gt; (Thymine)&lt;/td&gt;
1331&lt;td&gt;D&lt;/td&gt;
1332&lt;td&gt;587.33 Hz&lt;/td&gt;
1333&lt;/tr&gt;
1334&lt;/tbody&gt;
1335&lt;/table&gt;
1336&lt;p&gt;Since we do not have T in equal-tempered scale, I choose D to represent T note.&lt;/p&gt;
1337&lt;p&gt;You can check &lt;a href=&#34;https://pages.mtu.edu/~suits/notefreqs.html&#34;&gt;Frequencies for equal-tempered scale, A4 = 440
1338Hz&lt;/a&gt;. For this tuning, we also
1339choose &lt;code&gt;Speed of Sound = 345 m/s = 1130 ft/s = 770 miles/hr&lt;/code&gt;.&lt;/p&gt;
1340&lt;p&gt;Now that we have this out of the way, we can also brush up on the DNA sequencing
1341a bit. This is a famous quote I also used for the encoding tests, and it goes
1342like this.&lt;/p&gt;
1343&lt;blockquote&gt;
1344&lt;p&gt;How wonderful that we have met with a paradox. Now we have some hope of
1345making progress.
1346― Niels Bohr&lt;/p&gt;
1347&lt;/blockquote&gt;
1348&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;SEQ1
1349&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GACAGCTTGTGTACAAGTGTGCTTGCTCGCGAGCGGGTACGCGCGTGGGCTAACAAGTGA
1350&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GCCAGCAGGTGAACAAGTGTGCGGACAAGCCAGCAGGTGCGCGGACAAGCTGGCGGGTGA
1351&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ACAAGTGTGCCGGTGAGCCAACAAGCAGACAAGTAAGCAGGTACGCAGGCGAGCTTGTCA
1352&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ACTCACAAGATCGCTTGTGTACAAGTGTGCGGACAAGCCAGCAGGTGCGCGGACAAGTAT
1353&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GCTTGCTGGCGGACAAGCCAGCTTGTAAGCGGACAAGCTTGCGCACAAGCTGGCAGGCCT
1354&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GCCGGCTCGCGTACAAATTCACAAGTAAGTACGCTTGCGTGTACGCGGGTATGTATACTC
1355&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;AACCTCACCAAACGGGACAAGATCGCCGGCGGGCTAGTATACAAGAACGCTTGCCAGTAC
1356&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;AACC
1357&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This is what we gonna work with to get things rolling forward, when creating
1358parser and waveform generator.&lt;/p&gt;
1359&lt;h2 id=&#34;parsing-dna-data&#34;&gt;Parsing DNA data&lt;/h2&gt;
1360&lt;p&gt;This step is rather simple one. All we need to do is parse input DNA sequence in
1361&lt;a href=&#34;https://en.wikipedia.org/wiki/FASTA_format&#34;&gt;FASTA format&lt;/a&gt; well known in
1362&lt;a href=&#34;https://en.wikipedia.org/wiki/Bioinformatics&#34;&gt;Bioinformatics&lt;/a&gt; to extract single
1363Nucleotides that will be converted into separate tones based on equal-tempered
1364scale explained above.&lt;/p&gt;
1365&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nucleotide_tone_map = {
1366&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;A&amp;#39;&lt;/span&gt;: 440,
1367&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;C&amp;#39;&lt;/span&gt;: 523.25,
1368&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;G&amp;#39;&lt;/span&gt;: 783.99,
1369&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;T&amp;#39;&lt;/span&gt;: 587.33, &lt;span style=&#34;color:#008000&#34;&gt;# converted to D&lt;/span&gt;
1370&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
1371&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1372&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;def&lt;/span&gt; split(word):
1373&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;return&lt;/span&gt; [char &lt;span style=&#34;color:#00f&#34;&gt;for&lt;/span&gt; char &lt;span style=&#34;color:#00f&#34;&gt;in&lt;/span&gt; word]
1374&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1375&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;def&lt;/span&gt; generate_from_dna_sequence(sequence):
1376&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;for&lt;/span&gt; nucleotide &lt;span style=&#34;color:#00f&#34;&gt;in&lt;/span&gt; split(sequence):
1377&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; print(nucleotide, nucleotide_tone_map[nucleotide])
1378&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;generating-sine-wave&#34;&gt;Generating sine wave&lt;/h2&gt;
1379&lt;p&gt;Because we are essentially creating a long stream of notes we will be appending
1380sine notes to a global array we will later use for creating a WAV file out of
1381it.&lt;/p&gt;
1382&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; math
1383&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1384&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;def&lt;/span&gt; append_sinewave(freq=440.0, duration_milliseconds=500, volume=1.0):
1385&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;global&lt;/span&gt; audio
1386&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1387&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; num_samples = duration_milliseconds * (sample_rate / 1000.0)
1388&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1389&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;for&lt;/span&gt; x &lt;span style=&#34;color:#00f&#34;&gt;in&lt;/span&gt; range(int(num_samples)):
1390&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; audio.append(volume * math.sin(2 * math.pi * freq * (x / sample_rate)))
1391&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1392&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;return&lt;/span&gt;
1393&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The sine wave generated here is the standard beep. If you want something more
1394aggressive, you could try a square or saw tooth waveform.&lt;/p&gt;
1395&lt;h2 id=&#34;generating-a-wav-file-from-accumulated-sine-waves&#34;&gt;Generating a WAV file from accumulated sine waves&lt;/h2&gt;
1396&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; wave
1397&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; struct
1398&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1399&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;def&lt;/span&gt; save_wav(file_name):
1400&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; wav_file = wave.open(file_name, &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;w&amp;#39;&lt;/span&gt;)
1401&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; nchannels = 1
1402&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; sampwidth = 2
1403&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1404&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; nframes = len(audio)
1405&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; comptype = &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;NONE&amp;#39;&lt;/span&gt;
1406&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; compname = &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;not compressed&amp;#39;&lt;/span&gt;
1407&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; wav_file.setparams((nchannels, sampwidth, sample_rate, nframes, comptype, compname))
1408&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1409&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;for&lt;/span&gt; sample &lt;span style=&#34;color:#00f&#34;&gt;in&lt;/span&gt; audio:
1410&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; wav_file.writeframes(struct.pack(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;h&amp;#39;&lt;/span&gt;, int(sample * 32767.0)))
1411&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1412&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; wav_file.close()
1413&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;44100 is the industry standard sample rate - CD quality. If you need to save on
1414file size, you can adjust it downwards. The standard for low quality is, 8000 or
14158kHz.&lt;/p&gt;
1416&lt;p&gt;WAV files here are using short, 16 bit, signed integers for the sample size.
1417So, we multiply the floating-point data we have by 32767, the maximum value for
1418a short integer.&lt;/p&gt;
1419&lt;blockquote&gt;
1420&lt;p&gt;It is theoretically possible to use the floating point -1.0 to 1.0 data
1421directly in a WAV file, but not obvious how to do that using the wave module
1422in Python.&lt;/p&gt;
1423&lt;/blockquote&gt;
1424&lt;h2 id=&#34;generating-spectograms&#34;&gt;Generating Spectograms&lt;/h2&gt;
1425&lt;p&gt;I have tried two methods of doing this and both were just fine. I however opted
1426out to use the &lt;a href=&#34;https://linux.die.net/man/1/sox&#34;&gt;SoX - Sound eXchange, the Swiss Army knife of audio
1427manipulation&lt;/a&gt; one because it didn&#39;t require
1428anything else.&lt;/p&gt;
1429&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sox output.wav -n spectrogram -o spectrogram.png
1430&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;An example spectrogram of Ludwig van Beethoven Symphony No. 6 First movement.&lt;/p&gt;
1431&lt;audio controls&gt;
1432 &lt;source src=&#34;/posts/dna-synthesized/symphony-no6-1st-movement.mp3&#34; type=&#34;audio/mpeg&#34;&gt;
1433&lt;/audio&gt;
1434&lt;figure&gt;
1435&lt;img src=&#34;/posts/dna-synthesized/symphony-no6-1st-movement.png&#34; alt=&#34;Ludwig van Beethoven Symphony No. 6 First movement&#34; /&gt;
1436&lt;/figure&gt;
1437&lt;p&gt;The other option could also be in combination with
1438&lt;a href=&#34;http://www.gnuplot.info/&#34;&gt;gnuplot&lt;/a&gt;. This would require an intermediary step,
1439however.&lt;/p&gt;
1440&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sox output.wav audio.dat
1441&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tail -n&#43;3 audio.dat &amp;gt; audio_only.dat
1442&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gnuplot audio.gpi
1443&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And input file &lt;code&gt;audio.gpi&lt;/code&gt; that would be passed to gnuplot looks something like
1444this.&lt;/p&gt;
1445&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# set output format and size
1446&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set term png size 1000,280
1447&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1448&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# set output file
1449&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set output &amp;#34;audio.png&amp;#34;
1450&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1451&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# set y range
1452&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set yr [-1:1]
1453&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1454&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# we want just the data
1455&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;unset key
1456&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;unset tics
1457&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;unset border
1458&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set lmargin 0
1459&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set rmargin 0
1460&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set tmargin 0
1461&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set bmargin 0
1462&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1463&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# draw rectangle to change background color
1464&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set obj 1 rectangle behind from screen 0,0 to screen 1,1
1465&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set obj 1 fillstyle solid 1.0 fillcolor rgbcolor &amp;#34;#ffffff&amp;#34;
1466&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1467&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;# draw data with foreground color
1468&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;plot &amp;#34;audio_only.dat&amp;#34; with lines lt rgb &amp;#39;red&amp;#39;
1469&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;pre-generated-sequences&#34;&gt;Pre-generated sequences&lt;/h2&gt;
1470&lt;p&gt;What I did was take interesting parts from an animal&#39;s genome and feed it to a
1471tone generator script. This then generated a WAV file and I converted those to
1472MP3, so they can be played in a browser. The last step was creating a
1473spectrogram based on a WAV file.&lt;/p&gt;
1474&lt;h3 id=&#34;niels-bohr-quote&#34;&gt;Niels Bohr quote&lt;/h3&gt;
1475&lt;audio controls&gt;
1476 &lt;source src=&#34;/posts/dna-synthesized/quote/out.mp3&#34; type=&#34;audio/mpeg&#34;&gt;
1477&lt;/audio&gt;
1478&lt;figure&gt;
1479&lt;img src=&#34;/posts/dna-synthesized/quote/spectogram.png&#34; alt=&#34;Spectogram&#34; /&gt;
1480&lt;/figure&gt;
1481&lt;h3 id=&#34;mouse&#34;&gt;Mouse&lt;/h3&gt;
1482&lt;p&gt;This is part of a mouse genome &lt;code&gt;Mus_musculus.GRCm39.dna.nonchromosomal&lt;/code&gt;. You
1483can get &lt;a href=&#34;http://ftp.ensembl.org/pub/release-106/fasta/mus_musculus/dna/&#34;&gt;genom data
1484here&lt;/a&gt;.&lt;/p&gt;
1485&lt;audio controls&gt;
1486 &lt;source src=&#34;/posts/dna-synthesized/mouse/out.mp3&#34; type=&#34;audio/mpeg&#34;&gt;
1487&lt;/audio&gt;
1488&lt;figure&gt;
1489&lt;img src=&#34;/posts/dna-synthesized/mouse/spectogram.png&#34; alt=&#34;Spectogram&#34; /&gt;
1490&lt;/figure&gt;
1491&lt;h3 id=&#34;bison&#34;&gt;Bison&lt;/h3&gt;
1492&lt;p&gt;This is part of a bison genome &lt;code&gt;Bison_bison_bison.Bison_UMD1.0.cdna&lt;/code&gt;. You can
1493get &lt;a href=&#34;http://ftp.ensembl.org/pub/release-106/fasta/bison_bison_bison/cdna/&#34;&gt;genom data
1494here&lt;/a&gt;.&lt;/p&gt;
1495&lt;audio controls&gt;
1496 &lt;source src=&#34;/posts/dna-synthesized/bison/out.mp3&#34; type=&#34;audio/mpeg&#34;&gt;
1497&lt;/audio&gt;
1498&lt;figure&gt;
1499&lt;img src=&#34;/posts/dna-synthesized/bison/spectogram.png&#34; alt=&#34;Spectogram&#34; /&gt;
1500&lt;/figure&gt;
1501&lt;h3 id=&#34;taurus&#34;&gt;Taurus&lt;/h3&gt;
1502&lt;p&gt;This is part of a taurus genome &lt;code&gt;Bos_taurus.ARS-UCD1.2.cdna&lt;/code&gt;. You can get
1503&lt;a href=&#34;http://ftp.ensembl.org/pub/release-106/fasta/bos_taurus/cdna/&#34;&gt;genom data
1504here&lt;/a&gt;.&lt;/p&gt;
1505&lt;audio controls&gt;
1506 &lt;source src=&#34;/posts/dna-synthesized/taurus/out.mp3&#34; type=&#34;audio/mpeg&#34;&gt;
1507&lt;/audio&gt;
1508&lt;figure&gt;
1509&lt;img src=&#34;/posts/dna-synthesized/taurus/spectogram.png&#34; alt=&#34;Spectogram&#34; /&gt;
1510&lt;/figure&gt;
1511&lt;h2 id=&#34;making-a-drummer-out-of-a-dna-sequence&#34;&gt;Making a drummer out of a DNA sequence&lt;/h2&gt;
1512&lt;p&gt;To make things even more interesting, I decided to send this data via MIDI to my
1513&lt;a href=&#34;https://www.elektron.se/en/model-samples&#34;&gt;Elektron Model:Samples&lt;/a&gt;. This is a
1514really cool piece of equipment that supports MIDI in via USB and 3.5 mm audio
1515jack.&lt;/p&gt;
1516&lt;p&gt;Elektron is connected to my MacBook via USB cable and audio out is patched to a
1517Sony Bluetooth speaker I have that supports 3.5 mm audio in. Elektron doesn&#39;t
1518have internal speakers.&lt;/p&gt;
1519&lt;figure&gt;
1520&lt;img src=&#34;/posts/dna-synthesized/elektron/IMG_0619.jpg&#34; alt=&#34;&#34; /&gt;
1521&lt;/figure&gt;
1522&lt;figure&gt;
1523&lt;img src=&#34;/posts/dna-synthesized/elektron/IMG_0620.jpg&#34; alt=&#34;&#34; /&gt;
1524&lt;/figure&gt;
1525&lt;figure&gt;
1526&lt;img src=&#34;/posts/dna-synthesized/elektron/IMG_0622.jpg&#34; alt=&#34;&#34; /&gt;
1527&lt;/figure&gt;
1528&lt;p&gt;For communicating with Elektron, I choose &lt;code&gt;pygame&lt;/code&gt; Python module that has MIDI
1529built in. With this, it was rather simple to send notes to the device. All I did
1530was map MIDI notes to the actual Nucleotides.&lt;/p&gt;
1531&lt;p&gt;Before all of this I also checked Audio MIDI Setup app under MacOS and checked
1532MIDI Studio by pressing ⌘-2.&lt;/p&gt;
1533&lt;figure&gt;
1534&lt;img src=&#34;/posts/dna-synthesized/elektron/midi-studio.jpg&#34; alt=&#34;&#34; /&gt;
1535&lt;/figure&gt;
1536&lt;p&gt;The whole script that parses and send notes to the Elektron looks like this.&lt;/p&gt;
1537&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; pygame.midi
1538&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; time
1539&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1540&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pygame.midi.init()
1541&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1542&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(pygame.midi.get_default_output_id())
1543&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(pygame.midi.get_device_info(0))
1544&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1545&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;player = pygame.midi.Output(1)
1546&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;player.set_instrument(2)
1547&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1548&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;def&lt;/span&gt; send_note(note, velocity):
1549&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;global&lt;/span&gt; player
1550&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; player.note_on(note, velocity)
1551&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; time.sleep(0.3)
1552&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; player.note_off(note, velocity)
1553&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1554&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1555&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nucleotide_midi_map = {
1556&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;A&amp;#39;&lt;/span&gt;: 60,
1557&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;C&amp;#39;&lt;/span&gt;: 90,
1558&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;G&amp;#39;&lt;/span&gt;: 160,
1559&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;T&amp;#39;&lt;/span&gt;: 180, &lt;span style=&#34;color:#008000&#34;&gt;# is D&lt;/span&gt;
1560&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
1561&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1562&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;with&lt;/span&gt; open(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;quote.fa&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#00f&#34;&gt;as&lt;/span&gt; f:
1563&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; sequence = f.read().replace(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;)
1564&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1565&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;for&lt;/span&gt; nucleotide &lt;span style=&#34;color:#00f&#34;&gt;in&lt;/span&gt; [char &lt;span style=&#34;color:#00f&#34;&gt;for&lt;/span&gt; char &lt;span style=&#34;color:#00f&#34;&gt;in&lt;/span&gt; sequence]:
1566&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; print(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Playing nucleotide &lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt; with MIDI note &lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt;.format(
1567&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; nucleotide, nucleotide_midi_map[nucleotide]))
1568&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; send_note(nucleotide_midi_map[nucleotide], 127)
1569&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1570&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;del&lt;/span&gt; player
1571&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pygame.midi.quit()
1572&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;video src=&#34;/posts/dna-synthesized/elektron/elektron.mp4&#34; controls&gt;&lt;/video&gt;&lt;/p&gt;
1573&lt;p&gt;All of this could be made much more interesting if I choose different
1574instruments for different Nucleotides, or doing more funky stuff with Elektron.
1575But for now, this should be enough. It is just a proof of concept. Something to
1576play around with.&lt;/p&gt;
1577&lt;h2 id=&#34;going-even-further&#34;&gt;Going even further&lt;/h2&gt;
1578&lt;p&gt;As you probably notice, the end results are quite similar to each other. This is
1579to be expected because we are operating only with 4 notes essentially. What
1580could make this more interesting is using something like
1581&lt;a href=&#34;https://supercollider.github.io/&#34;&gt;Supercollider&lt;/a&gt; to create more interesting
1582sounds. By transposing notes or using effects based on repeated data in a
1583sequence. Possibilities are endless.&lt;/p&gt;
1584&lt;p&gt;It is really astonishing what can be achieved with a little bit of code and an
1585idea. I could see this becoming an interesting background soundscape instrument
1586if done properly. It could replace random note generator with something more
1587intriguing, biological, natural.&lt;/p&gt;
1588&lt;p&gt;I actually find the results fascinating. I took some time and listened to this
1589music of nature. Even though it&#39;s quite the same, it&#39;s also quite different.
1590The subtle differences on repeat kind of creates music on its own. Makes you
1591wonder. It kind of puts Occam’s Razor in its place. Nature for sure loves to
1592make things as energy efficient as possible.&lt;/p&gt;
1593</content:encoded>
1594 </item>
1595
1596
1597
1598 <item>
1599 <title>Trying out Helix code editor as my main editor</title>
1600 <link>https://mitjafelicijan.com/tying-out-helix-code-editor.html</link>
1601 <pubDate>Thu, 30 Jun 2022 12:00:00 &#43;0200</pubDate>
1602 <guid>https://mitjafelicijan.com/tying-out-helix-code-editor.html</guid>
1603 <description>I have been searching for a lightweight code editor for quite some time.</description>
1604 <content:encoded>&lt;p&gt;I have been searching for a lightweight code editor for quite some time. One of
1605the main reasons was that I wanted something that doesn&#39;t burn through CPU and
1606RAM usage is not through the roof. I have been mostly using Visual Studio Code.
1607It&#39;s been an outstanding editor. I have no quarrel with it at all. It&#39;s just
1608time to spice life up with something new.&lt;/p&gt;
1609&lt;p&gt;I have been on this search for a couple of years. I have tried Vim, Neovim,
1610Emacs, Doom Emacs, Micro and couple more. Among most of them, I liked Micro and
1611Doom Emacs the most. Micro editor was a little too basic for me. And Doom Emacs
1612was a bit too hardcore. This does not reflect on any of the editors. It&#39;s just
1613my personal preference.&lt;/p&gt;
1614&lt;blockquote&gt;
1615&lt;p&gt;I tried Helix Editor about a year ago. But I didn&#39;t pay attention to it.
1616Tried it and saw it&#39;s similar to Vi and just said no. I was premature to
1617dismiss it.&lt;/p&gt;
1618&lt;/blockquote&gt;
1619&lt;p&gt;One of the things I actually miss is line wrapping for certain files. When
1620writing Markdown, line wrapping would be very helpful. Editing such a document
1621is frustrating to say the least. Some of the Markdown to HTML converters don&#39;t
1622take kindly of new lines between sentences. Not paragraphs, sentences. And I use
1623Markdown to write this blog you are reading.&lt;/p&gt;
1624&lt;p&gt;But other than this, I have been extremely satisfied by it. It&#39;s been a pleasant
1625surprise. There have been zero issues with the editor.&lt;/p&gt;
1626&lt;p&gt;One thing to do before you are able to use autocompletion and make use Language
1627Server support is to install the language server with NPM.&lt;/p&gt;
1628&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm install -g typescript typescript-language-server
1629&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I am still getting used to the keyboard shortcuts and getting better. What Helix
1630does really well is packing in sane defaults and even though because currently
1631there is no plugin support I haven&#39;t found any need for them. It has all that
1632you would need. It goes to extreme measures to show a user what is going on with
1633popups that show you what the keyboard shortcuts are.&lt;/p&gt;
1634&lt;p&gt;And it comes us packed with many
1635&lt;a href=&#34;https://github.com/helix-editor/helix/wiki/Themes&#34;&gt;really good themes&lt;/a&gt;.&lt;/p&gt;
1636&lt;figure&gt;
1637&lt;img src=&#34;/posts/helix-editor/editor.png&#34; alt=&#34;Editor&#34; /&gt;
1638&lt;/figure&gt;
1639&lt;p&gt;It&#39;s still young but has this mature feeling to it. It has sane defaults and
1640mimics Vim (works a bit differently, but the overall idea is similar).&lt;/p&gt;
1641</content:encoded>
1642 </item>
1643
1644
1645
1646 <item>
1647 <title>Wireless Application Protocol and the mobile web before the web</title>
1648 <link>https://mitjafelicijan.com/wap-mobile-web-before-the-web.html</link>
1649 <pubDate>Thu, 30 Dec 2021 12:00:00 &#43;0200</pubDate>
1650 <guid>https://mitjafelicijan.com/wap-mobile-web-before-the-web.html</guid>
1651 <description>A little stroll down the history laneAbout two weeks ago, I watched this outstanding documentary on YouTubeSpringboard: the secret history of the first realsmartphone about the history ofsmartphones and phones in general.</description>
1652 <content:encoded>&lt;h2 id=&#34;a-little-stroll-down-the-history-lane&#34;&gt;A little stroll down the history lane&lt;/h2&gt;
1653&lt;p&gt;About two weeks ago, I watched this outstanding documentary on YouTube
1654&lt;a href=&#34;https://www.youtube.com/watch?v=b9_Vh9h3Ohw&#34;&gt;Springboard: the secret history of the first real
1655smartphone&lt;/a&gt; about the history of
1656smartphones and phones in general. It brought back so many memories. I never had
1657an actual smartphone before the Android. The closest to smartphone was &lt;a href=&#34;https://www.gsmarena.com/sony_ericsson_p1-1982.php&#34;&gt;Sony
1658Ericsson P1&lt;/a&gt;. A fantastic
1659phone and I broke it in Prague after a party and that was one of those rare
1660occasions where I was actually mad at myself. But nevertheless, after that
1661phone, the next one was an Android one.&lt;/p&gt;
1662&lt;p&gt;Before that, I only owned normal phones from Nokia and Siemens etc. Nothing
1663special, actually. These are the phones we are talking about. Before 2007.
1664Apple and Android phones didn&#39;t exist yet.&lt;/p&gt;
1665&lt;p&gt;These phones were rocking:&lt;/p&gt;
1666&lt;ul&gt;
1667&lt;li&gt;No selfie cameras.&lt;/li&gt;
1668&lt;li&gt;~2 inch displays.&lt;/li&gt;
1669&lt;li&gt;~120 MHz beast CPU&#39;s.&lt;/li&gt;
1670&lt;li&gt;144p main cameras.&lt;/li&gt;
1671&lt;li&gt;But they had a headphone jack.&lt;/li&gt;
1672&lt;/ul&gt;
1673&lt;p&gt;Let&#39;s take a look at these beauties.&lt;/p&gt;
1674&lt;figure&gt;
1675&lt;img src=&#34;/posts/wap/phones.gif&#34; alt=&#34;Old phones&#34; /&gt;
1676&lt;/figure&gt;
1677&lt;h2 id=&#34;wap---wireless-application-protocol&#34;&gt;WAP - Wireless Application Protocol&lt;/h2&gt;
1678&lt;p&gt;Not that one! We are talking about Wireless Application Protocol and not Cardi
1679B&#39;s song 😃&lt;/p&gt;
1680&lt;p&gt;WAP stands for Wireless Application Protocol. It is a protocol designed for
1681micro-browsers, and it enables the access of internet in the mobile devices. It
1682uses the mark-up language WML (Wireless Markup Language and not HTML), WML is
1683defined as XML 1.0 application. Furthermore, it enables creating web
1684applications for mobile devices. In 1998, WAP Forum was founded by Ericson,
1685Motorola, Nokia and Unwired Planet whose aim was to standardize the various
1686wireless technologies via protocols.
1687&lt;a href=&#34;https://www.geeksforgeeks.org/wireless-application-protocol/&#34;&gt;(source)&lt;/a&gt;&lt;/p&gt;
1688&lt;p&gt;WAP protocol was resulted by the joint efforts of the various members of WAP
1689Forum. In 2002, WAP forum was merged with various other forums of the industry,
1690resulting in the formation of Open Mobile Alliance (OMA).
1691&lt;a href=&#34;https://www.geeksforgeeks.org/wireless-application-protocol/&#34;&gt;(source)&lt;/a&gt;&lt;/p&gt;
1692&lt;p&gt;These were some wild times. Devices had tiny screens and data transmission rates
1693were abominable. But they were capable of rendering WML (Wireless Markup
1694Language). This was very similar to HTML, actually. It is a markup language,
1695after all.&lt;/p&gt;
1696&lt;p&gt;These pages could be served by &lt;a href=&#34;https://apache.org/&#34;&gt;Apache&lt;/a&gt; and could be
1697generated by CGI scripts on the backend. The only difference was the limited
1698markup language.&lt;/p&gt;
1699&lt;h2 id=&#34;wml---wireless-markup-language&#34;&gt;WML - Wireless Markup Language&lt;/h2&gt;
1700&lt;p&gt;Just like web browsers use HTML for content structure, older mobile device
1701browsers use WML - if you need to support really old mobile phones using WML
1702browsers, you will need to know about it. WML is XML-based (an XML vocabulary
1703just like XHTML and MathML, but not HTML) and does not use the same metaphor as
1704HTML. HTML is a single document with some metadata packed away in the head, and
1705a body encapsulating the visible page. With WML, the metaphor does not envisage
1706a page, but rather a deck of cards. A WML file might have several pages or cards
1707contained within it.
1708&lt;a href=&#34;https://www.w3.org/wiki/Introduction_to_mobile_web&#34;&gt;(source)&lt;/a&gt;&lt;/p&gt;
1709&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;&amp;lt;?xml version=&amp;#34;1.0&amp;#34;?&amp;gt;&lt;/span&gt;
1710&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;&amp;lt;!DOCTYPE wml PUBLIC &amp;#34;-//WAPFORUM//DTD WML 1.1//EN&amp;#34; &amp;#34;http://www.wapforum.org/DTD/wml_1.1.xml&amp;#34;&amp;gt;&lt;/span&gt;
1711&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;wml&amp;gt;
1712&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;card id=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;home&amp;#34;&lt;/span&gt; title=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Example Homepage&amp;#34;&lt;/span&gt;&amp;gt;
1713&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;p&amp;gt;Welcome to the Example homepage&amp;lt;/p&amp;gt;
1714&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;/card&amp;gt;
1715&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/wml&amp;gt;
1716&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;There is an amazing tutorial on &lt;a href=&#34;https://www.tutorialspoint.com/wml/index.htm&#34;&gt;Tutorialpoint about
1717WML&lt;/a&gt;.&lt;/p&gt;
1718&lt;h2 id=&#34;converting-digg-to-wml&#34;&gt;Converting Digg to WML&lt;/h2&gt;
1719&lt;p&gt;This task is completely useless and not really feasible nowadays, but I had to
1720give it a try for old-time sake. Since the data is already there in a form of
1721RSS feed, I could take this feed and parse it and create a WML version of the
1722homepage.&lt;/p&gt;
1723&lt;p&gt;We will need:&lt;/p&gt;
1724&lt;ul&gt;
1725&lt;li&gt;Python3 &#43; Pip&lt;/li&gt;
1726&lt;li&gt;ImageMagick&lt;/li&gt;
1727&lt;li&gt;feedparser and mako templating&lt;/li&gt;
1728&lt;/ul&gt;
1729&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# for fedora 35&lt;/span&gt;
1730&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo dnf install ImageMagick python3-pip
1731&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1732&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# tempalting engine for python&lt;/span&gt;
1733&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pip install mako --user
1734&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1735&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# for parsing rss feeds&lt;/span&gt;
1736&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pip install feedparser --user
1737&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Project folder structure should look like the following.&lt;/p&gt;
1738&lt;pre&gt;&lt;code&gt;12:43:53 m@khan wap → tree -L 1
1739.
1740├── generate.py
1741└── template.wml
1742
1743&lt;/code&gt;&lt;/pre&gt;
1744&lt;p&gt;After that, I created a small template for the homepage.&lt;/p&gt;
1745&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;&amp;lt;?xml version=&amp;#34;1.0&amp;#34;?&amp;gt;&lt;/span&gt;
1746&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;&amp;lt;!DOCTYPE wml PUBLIC &amp;#34;-//WAPFORUM//DTD WML 1.2//EN&amp;#34; &amp;#34;http://www.wapforum.org/DTD/wml_1.2.xml&amp;#34;&amp;gt;&lt;/span&gt;
1747&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1748&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;wml&amp;gt;
1749&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1750&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;card title=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Digg - What the Internet is talking about right now&amp;#34;&lt;/span&gt;&amp;gt;
1751&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1752&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; % for item in entries:
1753&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;p&amp;gt;&amp;lt;img src=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;/images/${item.id}.jpg&amp;#34;&lt;/span&gt; width=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;175&amp;#34;&lt;/span&gt; height=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;95&amp;#34;&lt;/span&gt; alt=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;${item.title}&amp;#34;&lt;/span&gt; /&amp;gt;&amp;lt;/p&amp;gt;
1754&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;p&amp;gt;&amp;lt;small&amp;gt;${item.kicker}&amp;lt;/small&amp;gt;&amp;lt;/p&amp;gt;
1755&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;p&amp;gt;&amp;lt;big&amp;gt;&amp;lt;b&amp;gt;${item.title}&amp;lt;/b&amp;gt;&amp;lt;/big&amp;gt;&amp;lt;/p&amp;gt;
1756&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;p&amp;gt;${item.description}&amp;lt;/p&amp;gt;
1757&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; % endfor
1758&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1759&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;/card&amp;gt;
1760&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1761&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/wml&amp;gt;
1762&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And the parser that parses RSS feed looks like this.&lt;/p&gt;
1763&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; os
1764&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; feedparser
1765&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;from&lt;/span&gt; mako.template &lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; Template
1766&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1767&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;os.system(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;mkdir -p www/images&amp;#39;&lt;/span&gt;)
1768&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1769&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;template = Template(filename=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;template.wml&amp;#39;&lt;/span&gt;)
1770&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1771&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;feed = feedparser.parse(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;https://digg.com/rss/top.xml&amp;#39;&lt;/span&gt;)
1772&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1773&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;entries = feed.entries[:15]
1774&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1775&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;for&lt;/span&gt; entry &lt;span style=&#34;color:#00f&#34;&gt;in&lt;/span&gt; entries:
1776&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; print(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;Processing image with id &lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;&lt;/span&gt;.format(entry.id))
1777&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; os.system(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;wget -q -O www/images/&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;.jpg &amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&amp;#39;&lt;/span&gt;.format(entry.id, entry.links[1].href))
1778&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; os.system(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;convert www/images/&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;.jpg -type Grayscale -resize 175x -depth 3 -quality 30 www/images/&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;.jpg&amp;#39;&lt;/span&gt;.format(entry.id, entry.id))
1779&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1780&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;html = template.render(entries = entries)
1781&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1782&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;with&lt;/span&gt; open(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;www/index.wml&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;w&#43;&amp;#39;&lt;/span&gt;) &lt;span style=&#34;color:#00f&#34;&gt;as&lt;/span&gt; fp:
1783&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; fp.write(html)
1784&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This script will create a folder &lt;code&gt;www&lt;/code&gt; and in the folder &lt;code&gt;www/images&lt;/code&gt; for
1785storing resized images.&lt;/p&gt;
1786&lt;blockquote&gt;
1787&lt;p&gt;Be sure you don&#39;t use SSL and use just normal HTTP for serving the content.
1788These old phones will have problems with TLS 1.3 etc.&lt;/p&gt;
1789&lt;/blockquote&gt;
1790&lt;p&gt;If you look at the python file, I convert all the images into tiny B&amp;amp;W images.
1791They should be WBMP (Wireless BitMaP) but I choose JPEGs for this, and it seems
1792to work properly.&lt;/p&gt;
1793&lt;p&gt;Because I currently don&#39;t have a phone old enough to test it on, I used an
1794emulator. And it was really hard to find one. I found &lt;a href=&#34;http://wap-proof.sharewarejunction.com/&#34;&gt;WAP
1795Proof&lt;/a&gt; on shareware junction, and it
1796did the job well enough. I will try to find and actual device to test it on.&lt;/p&gt;
1797&lt;p&gt;&lt;video src=&#34;/posts/wap/emulator.mp4&#34; controls&gt;&lt;/video&gt;&lt;/p&gt;
1798&lt;p&gt;If you are using Nginx to serve the contents, add a directive to the hosts file
1799that will automatically server &lt;code&gt;index.wml&lt;/code&gt; file.&lt;/p&gt;
1800&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;server&lt;/span&gt; {
1801&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;index&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;index.wml&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;index.html&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;index.htm&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;index.nginx-debian.html&lt;/span&gt;;
1802&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
1803&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
1804&lt;p&gt;Well, this was pointless, but very fun! I hope you enjoyed it as much as I did.
1805I will try to find an old phone to test it on. If you have any questions, feel
1806free to ask in the comments.&lt;/p&gt;
1807</content:encoded>
1808 </item>
1809
1810
1811
1812 <item>
1813 <title>Running Golang application as PID 1 with Linux kernel</title>
1814 <link>https://mitjafelicijan.com/running-golang-application-as-pid1.html</link>
1815 <pubDate>Sat, 25 Dec 2021 12:00:00 &#43;0200</pubDate>
1816 <guid>https://mitjafelicijan.com/running-golang-application-as-pid1.html</guid>
1817 <description>Unikernels, kernels, and alikeI have been reading a lot aboutunikernernels lately and found themvery intriguing.</description>
1818 <content:encoded>&lt;h2 id=&#34;unikernels-kernels-and-alike&#34;&gt;Unikernels, kernels, and alike&lt;/h2&gt;
1819&lt;p&gt;I have been reading a lot about
1820&lt;a href=&#34;https://en.wikipedia.org/wiki/Unikernel&#34;&gt;unikernernels&lt;/a&gt; lately and found them
1821very intriguing. When you push away all the marketing speak and look at the
1822idea, it makes a lot of sense.&lt;/p&gt;
1823&lt;blockquote&gt;
1824&lt;p&gt;A unikernel is a specialized, single address space machine image constructed
1825by using library operating systems. (&lt;a href=&#34;https://en.wikipedia.org/wiki/Unikernel&#34;&gt;Wikipedia&lt;/a&gt;)&lt;/p&gt;
1826&lt;/blockquote&gt;
1827&lt;p&gt;I really like the explanation from the article
1828&lt;a href=&#34;https://queue.acm.org/detail.cfm?id=2566628&#34;&gt;Unikernels: Rise of the Virtual Library Operating System&lt;/a&gt;.
1829Really worth a read.&lt;/p&gt;
1830&lt;p&gt;If we compare a normal operating system to a unikernel side by side, they would
1831look something like this.&lt;/p&gt;
1832&lt;figure&gt;
1833&lt;img src=&#34;/posts/pid1/unikernels.webp&#34; alt=&#34;Virtual machines vs Containers vs Unikernels&#34; /&gt;
1834&lt;/figure&gt;
1835&lt;p&gt;From this image, we can see how the complexity significantly decreases with
1836the use of Unikernels. This comes with a price, of course. Unikernels are hard
1837to get running and require a lot of work since you don&#39;t have an actual proper
1838kernel running in the background providing network access and drivers etc.&lt;/p&gt;
1839&lt;p&gt;So as a half step to make the stack simpler, I started looking into using
1840Linux kernel as a base and going from there. I came across this
1841&lt;a href=&#34;https://www.youtube.com/watch?v=Sk9TatW9ino&#34;&gt;Youtube video talking about Building the Simplest Possible Linux System&lt;/a&gt;
1842by &lt;a href=&#34;https://landley.net&#34;&gt;Rob Landley&lt;/a&gt; and apart from statically compiling the
1843application to be run as PID1 there was really no other obstacles.&lt;/p&gt;
1844&lt;h2 id=&#34;what-is-pid-1&#34;&gt;What is PID 1?&lt;/h2&gt;
1845&lt;p&gt;PID 1 is the first process that Linux kernel starts after the boot process.
1846It also has a couple of unique properties that are unique to it.&lt;/p&gt;
1847&lt;ul&gt;
1848&lt;li&gt;When the process with PID 1 dies for any reason, all other processes are
1849killed with KILL signal.&lt;/li&gt;
1850&lt;li&gt;When any process having children dies for any reason, its children are
1851re-parented to process with PID 1.&lt;/li&gt;
1852&lt;li&gt;Many signals which have default action of Term do not have one for PID 1.&lt;/li&gt;
1853&lt;li&gt;When the process with PID 1 dies for any reason, kernel panics, which
1854result in system crash.&lt;/li&gt;
1855&lt;/ul&gt;
1856&lt;p&gt;PID 1 is considered as an Init application which takes care of running other
1857and handling services like:&lt;/p&gt;
1858&lt;ul&gt;
1859&lt;li&gt;sshd,&lt;/li&gt;
1860&lt;li&gt;nginx,&lt;/li&gt;
1861&lt;li&gt;pulseaudio,&lt;/li&gt;
1862&lt;li&gt;etc.&lt;/li&gt;
1863&lt;/ul&gt;
1864&lt;p&gt;If you are on a Linux machine, you can check what your process is with PID 1
1865by running the following.&lt;/p&gt;
1866&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cat /proc/1/status
1867&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Name: systemd
1868&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Umask: 0000
1869&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;State: S (sleeping)
1870&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Tgid: 1
1871&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Ngid: 0
1872&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Pid: 1
1873&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PPid: 0
1874&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
1875&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As we can see on my machine the process with id of 1 is &lt;a href=&#34;https://systemd.io/&#34;&gt;systemd&lt;/a&gt;
1876which is a software suite that provides an array of system components for Linux
1877operating systems. If you look closely you can also see that the &lt;code&gt;PPid&lt;/code&gt;
1878(process id of the parent process) is &lt;code&gt;0&lt;/code&gt; which additionally confirms that
1879this process doesn&#39;t have a parent.&lt;/p&gt;
1880&lt;h2 id=&#34;so-why-even-run-application-as-pid-1-instead-of-just-using-a-container&#34;&gt;So why even run application as PID 1 instead of just using a container?&lt;/h2&gt;
1881&lt;p&gt;Containers are wonderful, but they come with a lot of baggage. And because they
1882are in their nature layered, the images require quite a lot of space and also a
1883lot of additional software to handle them. They are not as lightweight as they
1884seem, and many popular images require 500 MB plus disk space.&lt;/p&gt;
1885&lt;p&gt;The idea of running this as PID 1 would result in a significantly smaller footprint,
1886as we will see later in the post.&lt;/p&gt;
1887&lt;blockquote&gt;
1888&lt;p&gt;You could run a simple init system inside Docker container described more
1889in this article &lt;a href=&#34;https://blog.phusion.nl/2015/01/20/docker-and-the-pid-1-zombie-reaping-problem/&#34;&gt;Docker and the PID 1 zombie reaping problem&lt;/a&gt;.&lt;/p&gt;
1890&lt;/blockquote&gt;
1891&lt;h2 id=&#34;the-master-plan&#34;&gt;The master plan&lt;/h2&gt;
1892&lt;ol&gt;
1893&lt;li&gt;Compile Linux kernel with the default definitions.&lt;/li&gt;
1894&lt;li&gt;Prepare a Hello World application in Golang that is statically compiled.&lt;/li&gt;
1895&lt;li&gt;Run it with &lt;a href=&#34;https://www.qemu.org/&#34;&gt;QEMU&lt;/a&gt; and providing Golang application
1896as init application / PID 1.&lt;/li&gt;
1897&lt;/ol&gt;
1898&lt;p&gt;For the sake of simplicity we will not be cross-compiling any of it and just
1899use the 64bit version.&lt;/p&gt;
1900&lt;h2 id=&#34;compiling-linux-kernel&#34;&gt;Compiling Linux kernel&lt;/h2&gt;
1901&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.7.tar.xz
1902&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ tar xf linux-5.15.7.tar.xz
1903&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1904&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cd linux-5.15.7
1905&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1906&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ make clean
1907&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1908&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# read more about this https://stackoverflow.com/a/41886394&lt;/span&gt;
1909&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ make defconfig
1910&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1911&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ time make -j &lt;span style=&#34;color:#a31515&#34;&gt;`&lt;/span&gt;nproc&lt;span style=&#34;color:#a31515&#34;&gt;`&lt;/span&gt;
1912&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1913&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cd ..
1914&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;At this point we have kernel image that is located in &lt;code&gt;arch/x86_64/boot/bzImage&lt;/code&gt;.
1915We will use this in QEMU later.&lt;/p&gt;
1916&lt;p&gt;To make our lives a bit easier lets move the kernel image to another place.
1917Lets create a folder &lt;code&gt;bin/&lt;/code&gt; in the root of our project with &lt;code&gt;mkdir -p bin&lt;/code&gt;.&lt;/p&gt;
1918&lt;p&gt;At this point we can copy &lt;code&gt;bzImage&lt;/code&gt; to &lt;code&gt;bin/&lt;/code&gt; folder with
1919&lt;code&gt;cp linux-5.15.7/arch/x86_64/boot/bzImage bin/bzImage&lt;/code&gt;.&lt;/p&gt;
1920&lt;p&gt;The folder structure of this experiment should look like this.&lt;/p&gt;
1921&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pid1/
1922&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; bin/
1923&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; bzImage
1924&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; linux-5.15.7/
1925&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; linux-5.15.7.tar.xz
1926&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;preparing-pid-1-application-in-golang&#34;&gt;Preparing PID 1 application in Golang&lt;/h2&gt;
1927&lt;p&gt;This step is relatively easy. The only thing we must have in mind that we will
1928need to compile the binary as a static one.&lt;/p&gt;
1929&lt;p&gt;Let&#39;s create &lt;code&gt;init.go&lt;/code&gt; file in the root of the project.&lt;/p&gt;
1930&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;package&lt;/span&gt; main
1931&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1932&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; (
1933&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;
1934&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;time&amp;#34;&lt;/span&gt;
1935&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
1936&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1937&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;func&lt;/span&gt; main() {
1938&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;for&lt;/span&gt; {
1939&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; fmt.Println(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Hello from Golang&amp;#34;&lt;/span&gt;)
1940&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; time.Sleep(1 * time.Second)
1941&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
1942&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
1943&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If you notice, we have a forever loop in the main, with a simple sleep of 1
1944second to not overwhelm the CPU. This is because PID 1 should never complete
1945and/or exit. That would result in a kernel panic. Which is BAD!&lt;/p&gt;
1946&lt;p&gt;There are two ways of compiling Golang application. Statically and dynamically.&lt;/p&gt;
1947&lt;p&gt;To statically compile the binary, use the following command.&lt;/p&gt;
1948&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ go build -ldflags=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;-extldflags=-static&amp;#34;&lt;/span&gt; init.go
1949&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We can also check if the binary is statically compiled with:&lt;/p&gt;
1950&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ file init
1951&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;init: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, Go BuildID=Ypu8Zw_4NBxm1Yxg2OYO/H5x721rQ9uTPiDVh-VqP/vZN7kXfGG1zhX_qdHMgH/9vBfmK81tFrygfOXDEOo, not stripped
1952&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1953&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ ldd init
1954&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;not a dynamic executable
1955&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;At this point, we need to create &lt;a href=&#34;https://www.linuxfromscratch.org/blfs/view/svn/postlfs/initramfs.html&#34;&gt;initramfs&lt;/a&gt;
1956(abbreviated from &amp;quot;initial RAM file system&amp;quot;, is the successor of initrd. It
1957is a cpio archive of the initial file system that gets loaded into memory
1958during the Linux startup process).&lt;/p&gt;
1959&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ echo init | cpio -o --format=newc &amp;gt; initramfs
1960&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ mv initramfs bin/initramfs
1961&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The projects at this stage should look like this.&lt;/p&gt;
1962&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pid1/
1963&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; bin/
1964&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; bzImage
1965&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; initramfs
1966&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; linux-5.15.7/
1967&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; linux-5.15.7.tar.xz
1968&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; init.go
1969&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;running-all-of-it-with-qemu&#34;&gt;Running all of it with QEMU&lt;/h2&gt;
1970&lt;p&gt;&lt;a href=&#34;https://www.qemu.org/&#34;&gt;QEMU&lt;/a&gt; is a free and open-source hypervisor. It emulates
1971the machine&#39;s processor through dynamic binary translation and provides a set
1972of different hardware and device models for the machine, enabling it to run a
1973variety of guest operating systems.&lt;/p&gt;
1974&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ qemu-system-x86_64 -serial stdio -kernel bin/bzImage -initrd bin/initramfs -append &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;console=ttyS0&amp;#34;&lt;/span&gt; -m 128
1975&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ qemu-system-x86_64 -serial stdio -kernel bin/bzImage -initrd bin/initramfs -append &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;console=ttyS0&amp;#34;&lt;/span&gt; -m 128
1976&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[ 0.000000] Linux version 5.15.7 (m@khan) (gcc (GCC) 11.2.1 20211203 (Red Hat 11.2.1-7), GNU ld version 2.37-10.fc35) &lt;span style=&#34;color:#008000&#34;&gt;#7 SMP Mon Dec 13 10:23:25 CET 2021&lt;/span&gt;
1977&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[ 0.000000] Command line: console=ttyS0
1978&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[ 0.000000] x86/fpu: x87 FPU will use FXSAVE
1979&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[ 0.000000] signal: max sigframe size: 1440
1980&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[ 0.000000] BIOS-provided physical RAM map:
1981&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[ 0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable
1982&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[ 0.000000] BIOS-e820: [mem 0x000000000009fc00-0x000000000009ffff] reserved
1983&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[ 0.000000] BIOS-e820: [mem 0x00000000000f0000-0x00000000000fffff] reserved
1984&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[ 0.000000] BIOS-e820: [mem 0x0000000000100000-0x0000000007fdffff] usable
1985&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[ 0.000000] BIOS-e820: [mem 0x0000000007fe0000-0x0000000007ffffff] reserved
1986&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[ 0.000000] BIOS-e820: [mem 0x00000000fffc0000-0x00000000ffffffff] reserved
1987&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[ 0.000000] NX (Execute Disable) protection: active
1988&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[ 0.000000] SMBIOS 2.8 present.
1989&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[ 0.000000] DMI: QEMU Standard PC (i440FX &#43; PIIX, 1996), BIOS 1.14.0-6.fc35 04/01/2014
1990&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[ 0.000000] tsc: Fast TSC calibration failed
1991&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;...
1992&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[ 2.016106] ALSA device list:
1993&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[ 2.016329] No soundcards found.
1994&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[ 2.053176] Freeing unused kernel image (initmem) memory: 1368K
1995&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[ 2.056095] Write protecting the kernel read-only data: 20480k
1996&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[ 2.058248] Freeing unused kernel image (text/rodata gap) memory: 2032K
1997&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[ 2.058811] Freeing unused kernel image (rodata/data gap) memory: 500K
1998&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[ 2.059164] Run /init as init process
1999&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Hello from Golang
2000&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[ 2.386879] tsc: Refined TSC clocksource calibration: 3192.032 MHz
2001&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[ 2.387114] clocksource: tsc: mask: 0xffffffffffffffff max_cycles: 0x2e02e31fa14, max_idle_ns: 440795264947 ns
2002&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[ 2.387380] clocksource: Switched to clocksource tsc
2003&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[ 2.587895] input: ImExPS/2 Generic Explorer Mouse as /devices/platform/i8042/serio1/input/input3
2004&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Hello from Golang
2005&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Hello from Golang
2006&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Hello from Golang
2007&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The whole &lt;a href=&#34;/posts/pid1/qemu.log&#34;&gt;log file here&lt;/a&gt;.&lt;/p&gt;
2008&lt;h2 id=&#34;size-comparison&#34;&gt;Size comparison&lt;/h2&gt;
2009&lt;p&gt;The cool thing about this approach is that the Linux kernel and the application
2010together only take around 12 MB, which is impressive as hell. And we need to
2011also know that the size of bzImage (Linux kernel) could be greatly decreased
2012by going into &lt;code&gt;make menuconfig&lt;/code&gt; and removing a ton of features from the kernel,
2013making the size even smaller. I managed to get kernel size down to 2 MB and
2014still working properly.&lt;/p&gt;
2015&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;total 12M
2016&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-rw-r--r--. 1 m m 9.3M Dec 13 10:24 bzImage
2017&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;-rw-r--r--. 1 m m 1.9M Dec 27 01:19 initramfs
2018&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;creating-iso-image-and-running-it-with-gnome-boxes&#34;&gt;Creating ISO image and running it with Gnome Boxes&lt;/h2&gt;
2019&lt;p&gt;First we need to create proper folder structure with &lt;code&gt;mkdir -p iso/boot/grub&lt;/code&gt;.&lt;/p&gt;
2020&lt;p&gt;Then we need to download the &lt;a href=&#34;https://github.com/littleosbook/littleosbook/raw/master/files/stage2_eltorito&#34;&gt;grub binary&lt;/a&gt;.
2021You can read more about this program on &lt;a href=&#34;https://github.com/littleosbook/littleosbook&#34;&gt;https://github.com/littleosbook/littleosbook&lt;/a&gt;.&lt;/p&gt;
2022&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ wget -O iso/boot/grub/stage2_eltorito https://github.com/littleosbook/littleosbook/raw/master/files/stage2_eltorito
2023&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ tree iso/boot/
2024&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;iso/boot/
2025&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── bzImage
2026&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;├── grub
2027&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│   ├── menu.lst
2028&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;│   └── stage2_eltorito
2029&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;└── initramfs
2030&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Let&#39;s copy files into proper folders.&lt;/p&gt;
2031&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cp stage2_eltorito iso/boot/grub/
2032&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cp bin/bzImage iso/boot/
2033&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cp bin/initramfs iso/boot/
2034&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Lets create a GRUB config file at &lt;code&gt;nano iso/boot/grub/menu.lst&lt;/code&gt; with contents.&lt;/p&gt;
2035&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;default=&lt;span style=&#34;color:#a31515&#34;&gt;0&lt;/span&gt;
2036&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;timeout=&lt;span style=&#34;color:#a31515&#34;&gt;5&lt;/span&gt;
2037&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2038&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;title GoAsPID1
2039&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;kernel /boot/bzImage
2040&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;initrd /boot/initramfs
2041&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Let&#39;s create iso file by using genisoimage:&lt;/p&gt;
2042&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;genisoimage -R &lt;span style=&#34;color:#a31515&#34;&gt;\
2043&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&lt;/span&gt; -b boot/grub/stage2_eltorito &lt;span style=&#34;color:#a31515&#34;&gt;\
2044&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&lt;/span&gt; -no-emul-boot &lt;span style=&#34;color:#a31515&#34;&gt;\
2045&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&lt;/span&gt; -boot-load-size 4 &lt;span style=&#34;color:#a31515&#34;&gt;\
2046&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&lt;/span&gt; -A os &lt;span style=&#34;color:#a31515&#34;&gt;\
2047&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&lt;/span&gt; -input-charset utf8 &lt;span style=&#34;color:#a31515&#34;&gt;\
2048&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&lt;/span&gt; -quiet &lt;span style=&#34;color:#a31515&#34;&gt;\
2049&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&lt;/span&gt; -boot-info-table &lt;span style=&#34;color:#a31515&#34;&gt;\
2050&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&lt;/span&gt; -o GoAsPID1.iso &lt;span style=&#34;color:#a31515&#34;&gt;\
2051&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&lt;/span&gt; iso
2052&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will produce &lt;code&gt;GoAsPID1.iso&lt;/code&gt; which you can use with &lt;a href=&#34;https://www.virtualbox.org/&#34;&gt;Virtualbox&lt;/a&gt;
2053or &lt;a href=&#34;https://apps.gnome.org/app/org.gnome.Boxes/&#34;&gt;Gnome Boxes&lt;/a&gt;.&lt;/p&gt;
2054&lt;p&gt;&lt;video src=&#34;/posts/pid1/boxes.mp4&#34; controls&gt;&lt;/video&gt;&lt;/p&gt;
2055&lt;h2 id=&#34;is-running-applications-as-pid-1-even-worth-it&#34;&gt;Is running applications as PID 1 even worth it?&lt;/h2&gt;
2056&lt;p&gt;Well, the answer to this is not as simple as one would think. Sometimes it is
2057and sometimes it&#39;s not. For embedded systems and very specialized applications
2058it is worth for sure. But in normal uses, I don&#39;t think so. It was an interesting
2059exercise in compiling kernels and looking at the guts of the Linux kernel,
2060but sticking to containers for most of the things is a better option in my
2061opinion.&lt;/p&gt;
2062&lt;p&gt;An interesting experiment would be creating an image that supports networking
2063and could be deployed to AWS as an EC2 instance and observing how it fares.
2064But in that case, we would need to write some sort of supervisor that would
2065run on a separate EC2 that would check if other EC2 instances are running
2066properly. Remember that if your application fails, kernel panics and the
2067whole machine is inoperable in this case.&lt;/p&gt;
2068</content:encoded>
2069 </item>
2070
2071
2072
2073 <item>
2074 <title>Debian based riced up distribution for Developers and DevOps folks</title>
2075 <link>https://mitjafelicijan.com/debian-based-riced-up-distribution-for-developers-and-devops-folks.html</link>
2076 <pubDate>Fri, 03 Dec 2021 12:00:00 &#43;0200</pubDate>
2077 <guid>https://mitjafelicijan.com/debian-based-riced-up-distribution-for-developers-and-devops-folks.html</guid>
2078 <description>IntroductionI have been using Ubuntu for quite a longtime now.</description>
2079 <content:encoded>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;
2080&lt;p&gt;I have been using &lt;a href=&#34;https://ubuntu.com/&#34;&gt;Ubuntu&lt;/a&gt; for quite a longtime now. I have
2081used &lt;a href=&#34;https://www.debian.org/&#34;&gt;Debian&lt;/a&gt; in the past and
2082&lt;a href=&#34;https://manjaro.org/&#34;&gt;Manjaro&lt;/a&gt;. Also had &lt;a href=&#34;https://archlinux.org/&#34;&gt;Arch&lt;/a&gt; for
2083some time and even ran &lt;a href=&#34;https://www.gentoo.org/&#34;&gt;Gentoo&lt;/a&gt; way back.&lt;/p&gt;
2084&lt;p&gt;What I learned from all this is that I prefer running a bit older versions and
2085having them be stable than run bleeding edge rolling release. For that reason, I
2086stuck with Ubuntu for a couple of years now. I am also at a point in my life
2087where I just don&#39;t care what is cool or hip anymore. I just want a stable system
2088that doesn&#39;t get in my way.&lt;/p&gt;
2089&lt;p&gt;During all this, I noticed that these distributions were getting very bloated
2090and a lot of software got included that I usually uninstall on fresh
2091installation. Maybe this is my OCD speaking, but why do I have to give fresh
2092installation min 1 GB of ram out of the box just to have a blank screen in front
2093of me? I get it, there are many things included in the distro to make my life
2094easier. I understand. But at this point I have a feeling that modern Linux
2095distributions are becoming similar to &lt;a href=&#34;https://devhumor.com/content/uploads/images/August2017/node-modules.jpg&#34;&gt;Node.js project with
2096node_modules&lt;/a&gt;.
2097Just a crazy number of packages serving very little or no purpose, just
2098supporting other software.&lt;/p&gt;
2099&lt;p&gt;I felt I needed a fresh start. To start over with something minimal and clean.
2100Something that would put a little more joy into using a computer again.&lt;/p&gt;
2101&lt;p&gt;For the first version, I wanted to target the following machines I have at home
2102that I want this thing to work on.&lt;/p&gt;
2103&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# My main stationary work machine&lt;/span&gt;
2104&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Resolution: 3840x1080 (Super Ultrawide Monitor 32:9)
2105&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CPU: Intel i7-8700 (12) @ 4.600GHz
2106&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GPU: AMD ATI Radeon RX 470/480/570/570X/580/580X/590
2107&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Memory: 32020MiB
2108&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# Thinkpad x220 for testing things and goofing around&lt;/span&gt;
2109&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Resolution: 1366x768
2110&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CPU: Intel i5-2520M (4) @ 3.200GHz
2111&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GPU: Intel 2nd Generation Core Processor Family
2112&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Memory: 15891MiB
2113&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;how-should-i-approach-this&#34;&gt;How should I approach this?&lt;/h2&gt;
2114&lt;p&gt;I knew I wanted to use &lt;a href=&#34;https://www.debian.org/CD/netinst/&#34;&gt;minimal Debian netinst
2115&lt;/a&gt; for the base to give myself a head
2116start. No reason to go through changing the installer and also testing all that
2117behemoth of a thing. So, some sort of ricing was the only logical option to get
2118this thing of the grounds somewhat quickly.&lt;/p&gt;
2119&lt;blockquote&gt;
2120&lt;p&gt;&lt;strong&gt;What is ricing anyway?&lt;/strong&gt;
2121The term “RICE” stands for Race Inspired Cosmetic Enhancement. A group of
2122people (could be one, idk) decided to see if they could tweak their own
2123distros like they/others did their cars. This gave rise to a community of
2124Linux/Unix enthusiasts trying to make their distros look cooler and better
2125than others... For more information, read this article
2126&lt;a href=&#34;https://pesos.github.io/2020/07/14/what-is-ricing.html&#34;&gt;What in the world is ricing!?&lt;/a&gt;.&lt;/p&gt;
2127&lt;/blockquote&gt;
2128&lt;p&gt;I didn&#39;t want this to just be a set of config files for theming purpose. I
2129wanted this to include a set of pre-installed tools and services that are being
2130used all the time by a modern developer. Theming is just a tiny part of it.
2131Fonts being applied across the distro and things like that.&lt;/p&gt;
2132&lt;p&gt;First, I choose terminal installer and left it to load additional components.
2133Avoid using graphical installer in this case.&lt;/p&gt;
2134&lt;figure&gt;
2135&lt;img src=&#34;/posts/dfd-rice/install-00.png&#34; alt=&#34;&#34; /&gt;
2136&lt;/figure&gt;
2137&lt;p&gt;After that I selected hostname and created a normal user and set password for
2138that user and root user and choose guided mode for disk partitioning.&lt;/p&gt;
2139&lt;figure&gt;
2140&lt;img src=&#34;/posts/dfd-rice/install-01.png&#34; alt=&#34;&#34; /&gt;
2141&lt;/figure&gt;
2142&lt;p&gt;I left it run to install all the things required for the base system and opted
2143out of scanning additional media for use by the package manager. Those will be
2144downloaded from the internet during installation.&lt;/p&gt;
2145&lt;figure&gt;
2146&lt;img src=&#34;/posts/dfd-rice/install-02.png&#34; alt=&#34;&#34; /&gt;
2147&lt;/figure&gt;
2148&lt;p&gt;I opted out of the popularity contest, and &lt;strong&gt;now comes the important part&lt;/strong&gt;.
2149Uncheck all the boxes in Software selection and only leave &#39;standard system
2150utilities&#39;. I also left an SSH server, so I was able to log in to the machine
2151from my main PC.&lt;/p&gt;
2152&lt;figure&gt;
2153&lt;img src=&#34;/posts/dfd-rice/install-03.png&#34; alt=&#34;&#34; /&gt;
2154&lt;/figure&gt;
2155&lt;p&gt;At this point, I installed GRUB bootloader on the disk where I installed the
2156system.&lt;/p&gt;
2157&lt;figure&gt;
2158&lt;img src=&#34;/posts/dfd-rice/install-04.png&#34; alt=&#34;&#34; /&gt;
2159&lt;/figure&gt;
2160&lt;p&gt;That concluded the installation of base Debian and after restarting the computer
2161I was prompted with the login screen.&lt;/p&gt;
2162&lt;figure&gt;
2163&lt;img src=&#34;/posts/dfd-rice/install-05.png&#34; alt=&#34;&#34; /&gt;
2164&lt;/figure&gt;
2165&lt;p&gt;Now that I had the base installation, it was time to choose what software do I
2166want to include in this so-called distribution. I wanted out of the box
2167developer experience, so I had plenty to choose.&lt;/p&gt;
2168&lt;p&gt;Let&#39;s not waste time and go through the list.&lt;/p&gt;
2169&lt;h2 id=&#34;desktop-environments&#34;&gt;Desktop environments&lt;/h2&gt;
2170&lt;p&gt;I have been using &lt;a href=&#34;https://www.gnome.org/&#34;&gt;Gnome&lt;/a&gt; for my whole Linux life. From
2171version 2 forward. It&#39;s been quite a ride. I hated version 3 when it came out
2172and replaced version 2. But I got used to it. And now with version 40&#43; they also
2173made couple of changes which I found both frustrating and presently surprised.&lt;/p&gt;
2174&lt;p&gt;The amount of vertical space you loose because of the beefy title bars on
2175windows is ridiculous. And then in case of
2176&lt;a href=&#34;https://gnunn1.github.io/tilix-web/&#34;&gt;Tilix&lt;/a&gt; you also have tabs, and you are
2177100px deep. Vertical space is one of the most important things for a
2178developer. The more real estate you have, the more code you can have in a
2179viewport.&lt;/p&gt;
2180&lt;p&gt;But on the other hand, I still love how Gnome feels and looks. I gotta give them
2181that. They really are trying to make Gnome feel unified and modern.&lt;/p&gt;
2182&lt;p&gt;Regardless of all the nice things Gnome has, I was looking at the tiling window
2183managers for some time, but never had the nerve to actually go with it. But now
2184was the ideal time to give it a go. No guts, no glory kind of a thing.&lt;/p&gt;
2185&lt;p&gt;One of the requirements for me was easy custom layouts because I use a really
2186strange monitor with aspect ratio of 32:9. So relying on included layouts most
2187of them have is a non-starter.&lt;/p&gt;
2188&lt;p&gt;What I was doing in Gnome was having windows in a layout like the diagram
2189below. This is my common practice. And if you look at it you can clearly see I
2190was replicating tiling window manager setup in Gnome.&lt;/p&gt;
2191&lt;figure&gt;
2192&lt;img src=&#34;/posts/dfd-rice/layout.png&#34; alt=&#34;&#34; /&gt;
2193&lt;/figure&gt;
2194&lt;p&gt;That made me look into a bunch of tiling window managers and then tested them
2195out. Candidates I was looking at were:&lt;/p&gt;
2196&lt;ul&gt;
2197&lt;li&gt;&lt;a href=&#34;https://i3wm.org/&#34;&gt;i3&lt;/a&gt;&lt;/li&gt;
2198&lt;li&gt;&lt;a href=&#34;https://github.com/baskerville/bspwm&#34;&gt;bspwm&lt;/a&gt;&lt;/li&gt;
2199&lt;li&gt;&lt;a href=&#34;https://awesomewm.org/index.html&#34;&gt;awesome&lt;/a&gt;&lt;/li&gt;
2200&lt;li&gt;&lt;a href=&#34;https://xmonad.org/&#34;&gt;XMonad&lt;/a&gt;&lt;/li&gt;
2201&lt;li&gt;&lt;a href=&#34;https://swaywm.org/&#34;&gt;sway&lt;/a&gt;&lt;/li&gt;
2202&lt;li&gt;&lt;a href=&#34;http://www.qtile.org/&#34;&gt;Qtile&lt;/a&gt;&lt;/li&gt;
2203&lt;li&gt;&lt;a href=&#34;https://dwm.suckless.org/&#34;&gt;dwm&lt;/a&gt;&lt;/li&gt;
2204&lt;/ul&gt;
2205&lt;p&gt;You can also check article &lt;a href=&#34;https://www.tecmint.com/best-tiling-window-managers-for-linux/&#34;&gt;13 Best Tiling Window Managers for
2206Linux&lt;/a&gt; I was
2207referencing while testing them out.&lt;/p&gt;
2208&lt;p&gt;While all of them provided what I needed, I liked i3 the most. What particular
2209caught my eye was the ease to use and tree based layouts which allows flexible
2210layouts. I know others can be set up also to have custom layouts other than&lt;br /&gt;
2211spiral, dwindle etc. I think i3 is a good entry-level window manager for
2212somebody like me.&lt;/p&gt;
2213&lt;h2 id=&#34;batteries-included&#34;&gt;Batteries included&lt;/h2&gt;
2214&lt;p&gt;The source for the whole thing is located on Github
2215&lt;a href=&#34;https://github.com/mitjafelicijan/dfd-rice&#34;&gt;https://github.com/mitjafelicijan/dfd-rice&lt;/a&gt;.&lt;/p&gt;
2216&lt;p&gt;Currenly included:&lt;/p&gt;
2217&lt;ul&gt;
2218&lt;li&gt;&lt;code&gt;non-free&lt;/code&gt; (enables non-free packages in apt)&lt;/li&gt;
2219&lt;li&gt;&lt;code&gt;sudo&lt;/code&gt; (adds sudo and adds user to sudo group)&lt;/li&gt;
2220&lt;li&gt;&lt;code&gt;essentials&lt;/code&gt; (gcc, htop, zip, curl, etc...)&lt;/li&gt;
2221&lt;li&gt;&lt;code&gt;wifi&lt;/code&gt; (network manager nmtui)&lt;/li&gt;
2222&lt;li&gt;&lt;code&gt;desktop&lt;/code&gt; (i3, dmenu, fonts, configurations)&lt;/li&gt;
2223&lt;li&gt;&lt;code&gt;pulseaudio&lt;/code&gt; (pulseaudio with pavucontrol)&lt;/li&gt;
2224&lt;li&gt;&lt;code&gt;code-editors&lt;/code&gt; (vim, micro, vscode)&lt;/li&gt;
2225&lt;li&gt;&lt;code&gt;ohmybash&lt;/code&gt; (make bash pretty)&lt;/li&gt;
2226&lt;li&gt;&lt;code&gt;file-managers&lt;/code&gt; (mc)&lt;/li&gt;
2227&lt;li&gt;&lt;code&gt;git-ui&lt;/code&gt; (terminal git gui)&lt;/li&gt;
2228&lt;li&gt;&lt;code&gt;meld&lt;/code&gt; (diff tool)&lt;/li&gt;
2229&lt;li&gt;&lt;code&gt;profiling&lt;/code&gt; (kcachegrind, valgrind, strace, ltrace)&lt;/li&gt;
2230&lt;li&gt;&lt;code&gt;browsers&lt;/code&gt; (brave, firefox, chromium)&lt;/li&gt;
2231&lt;li&gt;programming languages:
2232&lt;ul&gt;
2233&lt;li&gt;&lt;code&gt;python&lt;/code&gt;&lt;/li&gt;
2234&lt;li&gt;&lt;code&gt;golang&lt;/code&gt;&lt;/li&gt;
2235&lt;li&gt;&lt;code&gt;nodejs&lt;/code&gt;&lt;/li&gt;
2236&lt;li&gt;&lt;code&gt;rust&lt;/code&gt;&lt;/li&gt;
2237&lt;li&gt;&lt;code&gt;nim&lt;/code&gt;&lt;/li&gt;
2238&lt;li&gt;&lt;code&gt;php&lt;/code&gt;&lt;/li&gt;
2239&lt;li&gt;&lt;code&gt;ruby&lt;/code&gt;&lt;/li&gt;
2240&lt;/ul&gt;
2241&lt;/li&gt;
2242&lt;li&gt;&lt;code&gt;docker&lt;/code&gt; (with docker-compose)&lt;/li&gt;
2243&lt;li&gt;&lt;code&gt;ansible&lt;/code&gt;&lt;/li&gt;
2244&lt;/ul&gt;
2245&lt;p&gt;Install script also allows you to install only specific packages (example for:
2246essentials ohmybash docker rust).&lt;/p&gt;
2247&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;su - root &lt;span style=&#34;color:#a31515&#34;&gt;\
2248&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&lt;/span&gt; bash -c &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#00f&#34;&gt;$(&lt;/span&gt;wget -q https://raw.github.com/mitjafelicijan/dfd-rice/master/tools/install.sh -O -&lt;span style=&#34;color:#00f&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt; -- &lt;span style=&#34;color:#a31515&#34;&gt;\
2249&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&lt;/span&gt; essentials ohmybash docker rust
2250&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Currently, most of these recipes use what Debian and this is totally fine with
2251me since I never use bleeding edge features of a package. But if something major
2252would come to light, I will replace it with a possible compilation script or
2253something similar.&lt;/p&gt;
2254&lt;p&gt;This is some of the output from the installation script.&lt;/p&gt;
2255&lt;figure&gt;
2256&lt;img src=&#34;/posts/dfd-rice/script.png&#34; alt=&#34;&#34; /&gt;
2257&lt;/figure&gt;
2258&lt;p&gt;Let&#39;s take a look at some examples in the installation script.&lt;/p&gt;
2259&lt;h3 id=&#34;docker-recipe&#34;&gt;Docker recipe&lt;/h3&gt;
2260&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# docker&lt;/span&gt;
2261&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print_header &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Installing Docker&amp;#34;&lt;/span&gt;
2262&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -fsSL https://download.docker.com/linux/debian/gpg | gpg --yes --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
2263&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;deb [arch=&lt;/span&gt;&lt;span style=&#34;color:#00f&#34;&gt;$(&lt;/span&gt;dpkg --print-architecture&lt;span style=&#34;color:#00f&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt; signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian &lt;/span&gt;&lt;span style=&#34;color:#00f&#34;&gt;$(&lt;/span&gt;lsb_release -cs&lt;span style=&#34;color:#00f&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt; stable&amp;#34;&lt;/span&gt; | tee /etc/apt/sources.list.d/docker.list &amp;gt; /dev/null
2264&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt update
2265&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt -y install docker-ce docker-ce-cli containerd.io docker-compose
2266&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2267&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl start docker
2268&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl enable docker
2269&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;systemctl status docker --no-pager
2270&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2271&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/sbin/usermod -aG docker $USERNAME
2272&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;making-bash-pretty&#34;&gt;Making bash pretty&lt;/h3&gt;
2273&lt;p&gt;I really like &lt;a href=&#34;https://ohmyz.sh/&#34;&gt;Oh My Zsh&lt;/a&gt;, but I don&#39;t like zsh shell. When
2274I used it, I constantly needed to be aware of it and running bash scripts was a
2275pain. So, I was really delighted when I found out that a version for bash
2276existed called &lt;a href=&#34;https://ohmybash.nntoan.com/&#34;&gt;Oh My Bash&lt;/a&gt;. Let&#39;s take a look at
2277the recipe for installing it.&lt;/p&gt;
2278&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# ohmybash&lt;/span&gt;
2279&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print_header &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Enabling OhMyBash&amp;#34;&lt;/span&gt;
2280&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo -u $USERNAME sh -c &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#00f&#34;&gt;$(&lt;/span&gt;curl -fsSL https://raw.github.com/ohmybash/oh-my-bash/master/tools/install.sh&lt;span style=&#34;color:#00f&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt; &amp;amp;
2281&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;T1=&lt;span style=&#34;color:#a31515&#34;&gt;${&lt;/span&gt;!&lt;span style=&#34;color:#a31515&#34;&gt;}&lt;/span&gt;
2282&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wait &lt;span style=&#34;color:#a31515&#34;&gt;${&lt;/span&gt;T1&lt;span style=&#34;color:#a31515&#34;&gt;}&lt;/span&gt;
2283&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Because OhMyBash does &lt;code&gt;exec bash&lt;/code&gt; at the end, this traps our script inside
2284another shell and our script cannot continue. For that reason, I executed this
2285in background. But that presents a new problem. Because this is executed in
2286background, we lose track of progress naturally. And that strange trick with
2287&lt;code&gt;T1=${!}&lt;/code&gt; and &lt;code&gt;wait ${T1}&lt;/code&gt; waits for the background process to finish before
2288continuing to another task in bash script.&lt;/p&gt;
2289&lt;p&gt;Check &lt;a href=&#34;https://www.cloudsavvyit.com/12277/how-to-use-multi-threaded-processing-in-bash-scripts/&#34;&gt;Multi-Threaded Processing in Bash Scripts&lt;/a&gt;
2290for more details.&lt;/p&gt;
2291&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
2292&lt;p&gt;Take a look at
2293&lt;a href=&#34;https://github.com/mitjafelicijan/dfd-rice/blob/develop/tools/install.sh&#34;&gt;https://github.com/mitjafelicijan/dfd-rice/blob/develop/tools/install.sh&lt;/a&gt; script
2294to get familiar with it. This is just a first iteration and I will continue to
2295update it because I need this in my life.&lt;/p&gt;
2296&lt;p&gt;The current version boots in 4s to the login prompt, and after you log in, the
2297desktop environment loads in 2s. So, its fast, very fast. And on clean boot, I
2298measured ~230 MB of RAM usage.&lt;/p&gt;
2299&lt;p&gt;And this is how it looks with two terminals side by side. I really like the
2300simplicity and clean interface. I will polish the colors and stuff like that,
2301but I really do like the results.&lt;/p&gt;
2302&lt;figure&gt;
2303&lt;img src=&#34;/posts/dfd-rice/desktop.png&#34; alt=&#34;&#34; /&gt;
2304&lt;/figure&gt;
2305</content:encoded>
2306 </item>
2307
2308
2309
2310 <item>
2311 <title>List of essential Linux commands for server management</title>
2312 <link>https://mitjafelicijan.com/linux-cheatsheet.html</link>
2313 <pubDate>Sun, 01 Aug 2021 12:00:00 &#43;0200</pubDate>
2314 <guid>https://mitjafelicijan.com/linux-cheatsheet.html</guid>
2315 <description>Generate SSH keyssh-keygen -t ed25519 -C &amp;#34;your_email@example.</description>
2316 <content:encoded>&lt;p&gt;&lt;strong&gt;Generate SSH key&lt;/strong&gt;&lt;/p&gt;
2317&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ssh-keygen -t ed25519 -C &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;your_email@example.com&amp;#34;&lt;/span&gt;
2318&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2319&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# when no support for Ed25519 present&lt;/span&gt;
2320&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ssh-keygen -t rsa -b 4096 -C &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;your_email@example.com&amp;#34;&lt;/span&gt;
2321&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Note: By default SSH keys get stored to &lt;code&gt;/home/&amp;lt;username&amp;gt;/.ssh/&lt;/code&gt; folder.&lt;/p&gt;
2322&lt;p&gt;&lt;strong&gt;Login to host via SSH&lt;/strong&gt;&lt;/p&gt;
2323&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# connect to host as your local username&lt;/span&gt;
2324&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ssh host
2325&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2326&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# connect to host as user&lt;/span&gt;
2327&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ssh &amp;lt;user&amp;gt;@&amp;lt;host&amp;gt;
2328&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2329&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# connect to host using port&lt;/span&gt;
2330&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ssh -p &amp;lt;port&amp;gt; &amp;lt;user&amp;gt;@&amp;lt;host&amp;gt;
2331&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Execute command on a server through SSH&lt;/strong&gt;&lt;/p&gt;
2332&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# execute one command&lt;/span&gt;
2333&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ssh root@100.100.100.100 &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;ls /root&amp;#34;&lt;/span&gt;
2334&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2335&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# execute many commands&lt;/span&gt;
2336&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ssh root@100.100.100.100 &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;cd /root;touch file.txt&amp;#34;&lt;/span&gt;
2337&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Displays currently logged in users in the system&lt;/strong&gt;&lt;/p&gt;
2338&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;w
2339&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Displays Linux system information&lt;/strong&gt;&lt;/p&gt;
2340&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;uname
2341&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Displays kernel release information&lt;/strong&gt;&lt;/p&gt;
2342&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;uname -r
2343&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Shows the system hostname&lt;/strong&gt;&lt;/p&gt;
2344&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;hostname
2345&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Shows system reboot history&lt;/strong&gt;&lt;/p&gt;
2346&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;last reboot
2347&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Displays information about the user&lt;/strong&gt;&lt;/p&gt;
2348&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt install finger
2349&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;finger &amp;lt;username&amp;gt;
2350&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Displays IP addresses and all the network interfaces&lt;/strong&gt;&lt;/p&gt;
2351&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip addr show
2352&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Downloads a file from an online source&lt;/strong&gt;&lt;/p&gt;
2353&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget https://example.com/example.tgz
2354&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Note: If URL contains ?, &amp;amp; enclose the URL in double quotes.&lt;/p&gt;
2355&lt;p&gt;&lt;strong&gt;Compress a file with gzip&lt;/strong&gt;&lt;/p&gt;
2356&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# will not keep the original file&lt;/span&gt;
2357&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gzip file.txt
2358&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2359&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# will keep the original file&lt;/span&gt;
2360&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gzip --keep file.txt
2361&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Interactive disk usage analyzer&lt;/strong&gt;&lt;/p&gt;
2362&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt install ncdu
2363&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2364&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ncdu
2365&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ncdu &amp;lt;path/to/directory&amp;gt;
2366&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Install Node.js using the Node Version Manager&lt;/strong&gt;&lt;/p&gt;
2367&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash
2368&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;source ~/.bashrc
2369&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2370&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nvm install v13
2371&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Too long; didn&#39;t read&lt;/strong&gt;&lt;/p&gt;
2372&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm install -g tldr
2373&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2374&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tldr tar
2375&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Combine all Nginx access logs to one big log file&lt;/strong&gt;&lt;/p&gt;
2376&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;zcat -f /var/log/nginx/access.log* &amp;gt; /var/log/nginx/access-all.log
2377&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Set up Redis server&lt;/strong&gt;&lt;/p&gt;
2378&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt install redis-server redis-tools
2379&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2380&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# check if server is running&lt;/span&gt;
2381&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo service redis status
2382&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2383&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# set and get a key value&lt;/span&gt;
2384&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;redis-cli set mykey myvalue
2385&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;redis-cli get mykey
2386&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2387&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# interactive shell&lt;/span&gt;
2388&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;redis-cli
2389&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Generate statistics of your webserver&lt;/strong&gt;&lt;/p&gt;
2390&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt install goaccess
2391&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2392&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# check if installed&lt;/span&gt;
2393&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;goaccess -v
2394&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2395&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# combine logs&lt;/span&gt;
2396&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;zcat -f /var/log/nginx/access.log* &amp;gt; /var/log/nginx/access-all.log
2397&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2398&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# export to single html&lt;/span&gt;
2399&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;goaccess &lt;span style=&#34;color:#a31515&#34;&gt;\
2400&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&lt;/span&gt; --log-file=/var/log/nginx/access-all.log &lt;span style=&#34;color:#a31515&#34;&gt;\
2401&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&lt;/span&gt; --log-format=COMBINED &lt;span style=&#34;color:#a31515&#34;&gt;\
2402&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&lt;/span&gt; --exclude-ip=0.0.0.0 &lt;span style=&#34;color:#a31515&#34;&gt;\
2403&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&lt;/span&gt; --ignore-crawlers &lt;span style=&#34;color:#a31515&#34;&gt;\
2404&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&lt;/span&gt; --real-os &lt;span style=&#34;color:#a31515&#34;&gt;\
2405&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&lt;/span&gt; --output=/var/www/html/stats.html
2406&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2407&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# cleanup afterwards&lt;/span&gt;
2408&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rm /var/log/nginx/access-all.log
2409&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Search for a given pattern in files&lt;/strong&gt;&lt;/p&gt;
2410&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;grep -r ‘pattern’ files
2411&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Find proccess ID for a specific program&lt;/strong&gt;&lt;/p&gt;
2412&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pgrep nginx
2413&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Print name of current/working directory&lt;/strong&gt;&lt;/p&gt;
2414&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pwd
2415&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Creates a blank new file&lt;/strong&gt;&lt;/p&gt;
2416&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;touch newfile.txt
2417&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Displays first lines in a file&lt;/strong&gt;&lt;/p&gt;
2418&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# -n &amp;lt;x&amp;gt; presents the number of lines (10 by default)&lt;/span&gt;
2419&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;head -n 20 somefile.txt
2420&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Displays last lines in a file&lt;/strong&gt;&lt;/p&gt;
2421&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# -n &amp;lt;x&amp;gt; presents the number of lines (10 by default)&lt;/span&gt;
2422&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tail -n 20 somefile.txt
2423&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2424&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# -f follows the changes in file (doesn&amp;#39;t closes)&lt;/span&gt;
2425&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tail -f somefile.txt
2426&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Count lines in a file&lt;/strong&gt;&lt;/p&gt;
2427&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wc -l somefile.txt
2428&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Find all instances of the file&lt;/strong&gt;&lt;/p&gt;
2429&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt install mlocate
2430&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2431&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;locate somefile.txt
2432&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Find file names that begin with ‘index’ in /home folder&lt;/strong&gt;&lt;/p&gt;
2433&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;find /home/ -name &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;index&amp;#34;&lt;/span&gt;
2434&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Find files larger than 100MB in the home folder&lt;/strong&gt;&lt;/p&gt;
2435&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;find /home -size &#43;100M
2436&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Displays block devices related information&lt;/strong&gt;&lt;/p&gt;
2437&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;lsblk
2438&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Displays free space on mounted systems&lt;/strong&gt;&lt;/p&gt;
2439&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;df -h
2440&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Displays free and used memory in the system&lt;/strong&gt;&lt;/p&gt;
2441&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;free -h
2442&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Displays all active listening ports&lt;/strong&gt;&lt;/p&gt;
2443&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt install net-tools
2444&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2445&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;netstat -pnltu
2446&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Kill a process violently&lt;/strong&gt;&lt;/p&gt;
2447&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;kill -9 &amp;lt;pid&amp;gt;
2448&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;List files opened by user&lt;/strong&gt;&lt;/p&gt;
2449&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;lsof -u &amp;lt;user&amp;gt;
2450&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;&lt;strong&gt;Execute &amp;quot;df -h&amp;quot;, showing periodic updates&lt;/strong&gt;&lt;/p&gt;
2451&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# -n 1 means every second&lt;/span&gt;
2452&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;watch -n 1 df -h
2453&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded>
2454 </item>
2455
2456
2457
2458 <item>
2459 <title>My journey from being an internet über consumer to being a full hominum again</title>
2460 <link>https://mitjafelicijan.com/from-internet-consumer-to-full-hominum-again.html</link>
2461 <pubDate>Fri, 30 Jul 2021 12:00:00 &#43;0200</pubDate>
2462 <guid>https://mitjafelicijan.com/from-internet-consumer-to-full-hominum-again.html</guid>
2463 <description>It&amp;#39;s been almost a year since I started purging all my online accounts andgoing down this rabbit hole of being almost independent of the current internetmachine.</description>
2464 <content:encoded>&lt;p&gt;It&#39;s been almost a year since I started purging all my online accounts and
2465going down this rabbit hole of being almost independent of the current internet
2466machine. Even though I initially thought that I will have problems adapting,
2467I was pleasantly surprised that the transition went so smoothly. Even better,
2468it brought many benefits to my life. Such as increased focus, less stress
2469about trivial things, etc.&lt;/p&gt;
2470&lt;p&gt;It all started with me doing small changes like unsubscribing from emails that I
2471have either subscribed to by accepting terms and conditions. Or even some more
2472malicious emails that I was getting because I was on a shared mailing list. And
2473the later ones I hate the most of all. How the hell do they keep sharing my
2474email and sending me unsolicited emails and get away with it? I have a suspicion
2475that these marketing people share an Excel file between them and keep
2476resubscribing me when they import lists into Mailchimp or similar software.&lt;/p&gt;
2477&lt;p&gt;It&#39;s fascinating to see how much crap you get subscribed to when you are not
2478paying attention. It got so bad that my primary Gmail address is a full of junk
2479and need constant monitoring and cleaning up. And because I want to have Inbox
2480Zero, this presents an additional problem for me.&lt;/p&gt;
2481&lt;p&gt;The stress that email presented for me didn&#39;t occur to me for a long time. I was
2482noticing that I was unable to go through one single hour without hysterically
2483refreshing email. And if somebody wrote me something, I needed to see it right
2484then, even though I didn&#39;t immediately reply to it. I can only describe this
2485with FOMO (fear of missing out). I have no other explanation than that. It was
2486crippling, and I was constantly context switching, which I will address further
2487down this post in more details.&lt;/p&gt;
2488&lt;p&gt;This was one of the reasons why I spawned up my personal email server, and I am
2489using it now as my primary and person email. I still have Gmail as my “junk”
2490email that I use for throw away stuff. I log in to Gmail once a week and check
2491if there are any important emails that I got, but apart from that, it&#39;s sitting
2492dormant and collecting dust.&lt;/p&gt;
2493&lt;p&gt;The more I was watching the world loose it&#39;s self with allowing anti freedom
2494things to happen to it, the more I started to realize that something has to
2495change. I don&#39;t have the power to change the world. And I also don&#39;t have a
2496grandiose opinion of myself to even think to try it. But what I can do is to not
2497subscribe to this consumer way of thinking. I will not be complicit in this. My
2498moral and ethical stances won&#39;t allow it. So, this brings us to the second part
2499of my journey.&lt;/p&gt;
2500&lt;p&gt;I was using all these 3rd party services because I was either lazy or OK with
2501the drawbacks of them. I watched these services and companies became more and
2502privacy policies and everybody is OK with accepting them, and they pray on that
2503more evil. It is evil if you sell your user&#39;s data in this manner. Nobody reads
2504flaw in human nature. I really hate the hypocrisy they manage to muster. These
2505companies prey on our laziness, and we are at fault here. Nobody else. And I
2506truly understand the reasons why we rather accept and move on, and not object
2507and have our lives a little more difficult. They have perfected this through
2508years of small changes that make us a little more dependent on them. You could
2509not convince a person to give away all his rights and data in one day. This was
2510gradual and slow. And it caught us all in surprise. When I really stopped and
2511thought about it, I felt repulsed. By really stopping and thinking about it, I
2512really mean stopping and thinking about it. Thoroughly and in depth.&lt;/p&gt;
2513&lt;p&gt;Each step I took depleted my character a bit more. Like I was trading myself bit
2514by bit without understanding what it all meant. What it meant to be a full
2515person, not divided by all this bought attention they want from me. They don&#39;t
2516just get your data, but they also take your attention away from you. They
2517scatter your and go with the divide and conquer tactic from there. And a person
2518divided is a person not fully there. Not at the moment. Not alive fully.&lt;/p&gt;
2519&lt;p&gt;I was unable to form long thoughts. Well, I thought I was. But now that I see
2520what being a full person is again, I can see that I was not at my 100% back
2521then.&lt;/p&gt;
2522&lt;p&gt;A revolt was inevitable. There was no other way of continuing my story without
2523it. Without taking back my attention, my thoughts, my time, and my privacy,
2524regardless of how too late it maybe is.&lt;/p&gt;
2525&lt;p&gt;This has nothing to do with conspiracy theories. Even less with changing the
2526world. All I wanted was to get my life back in order and not waste the energy
2527that could be spent in other, better places.&lt;/p&gt;
2528&lt;p&gt;I started reading more. I can focus now fully on things I work on. Furthermore,
2529I have the mental acuity that I never had before. My mind feels sharp. I don&#39;t
2530get angry so much. I can cherish the finer things in life now without the need
2531to interpret them intellectually. Not only that, but I have a feeling of
2532belonging again. Sense of purpose has returned with a vengeance. And I can now
2533help people without depleting myself.&lt;/p&gt;
2534&lt;p&gt;The last step so far was to finish closing all the remaining online accounts
2535that I still had. And when I was thinking what value they bring me, I wasn&#39;t
2536surprised that the answer was none. I wasn&#39;t logging in them and using them. I
2537stopped being afraid of FOMO. If somebody wants to get in contact me, they will
2538find a way. I am one search away.&lt;/p&gt;
2539&lt;p&gt;We are not beholden to anybody. Our lives are our own. So dare yourself to
2540delete Facebook, LinkedIn. To unsubscribe. Dare yourself to take your time and
2541attention back. Use that time and energy to go for a walk without thinking about
2542work. Read a book instead of reading comment on social media that you will
2543forget in an hour. Enrich your life instead of wasting it. It only requires a
2544small step. And you will feel the benefits immediately. Lose the weight of the
2545world that is crushing you without your consent.&lt;/p&gt;
2546</content:encoded>
2547 </item>
2548
2549
2550
2551 <item>
2552 <title>Simple world clock with eInk display and Raspberry Pi Zero</title>
2553 <link>https://mitjafelicijan.com/simple-world-clock-with-eiink-display-and-raspberry-pi-zero.html</link>
2554 <pubDate>Sat, 26 Jun 2021 12:00:00 &#43;0200</pubDate>
2555 <guid>https://mitjafelicijan.com/simple-world-clock-with-eiink-display-and-raspberry-pi-zero.html</guid>
2556 <description>Our team is spread across the world, from the USA all the way to Australia, sohaving some sort of world clock makes sense.</description>
2557 <content:encoded>&lt;p&gt;Our team is spread across the world, from the USA all the way to Australia, so
2558having some sort of world clock makes sense.&lt;/p&gt;
2559&lt;p&gt;Currently, I am using an extension for Gnome called &lt;a href=&#34;https://extensions.gnome.org/extension/2657/timezones-extension/&#34;&gt;Timezone
2560extension&lt;/a&gt;,
2561and it serves the purpose quite well.&lt;/p&gt;
2562&lt;p&gt;But I also have a bunch of electronics that I bought through the time, and I am
2563not using any of them, and it&#39;s time to stop hording this stuff and use it in a
2564project.&lt;/p&gt;
2565&lt;p&gt;A while ago I bought a small eInk display &lt;a href=&#34;https://shop.pimoroni.com/products/inky-phat?variant=12549254217811&#34;&gt;Inky
2566pHAT&lt;/a&gt; and I
2567have a bunch of &lt;a href=&#34;https://www.raspberrypi.org/products/raspberry-pi-zero/&#34;&gt;Raspberry Pi&#39;s
2568Zero&lt;/a&gt; lying around that
2569I really need to use.&lt;/p&gt;
2570&lt;figure&gt;
2571&lt;img src=&#34;/posts/world-clock/hardware.jpg&#34; alt=&#34;Inky pHAT, Raspberry Pi Zero&#34; /&gt;
2572&lt;/figure&gt;
2573&lt;p&gt;Since the Inky &lt;a href=&#34;https://shop.pimoroni.com/products/inky-phat?variant=12549254217811&#34;&gt;Inky
2574pHAT&lt;/a&gt; is
2575essentially a HAT, it can easily be added on top of the &lt;a href=&#34;https://www.raspberrypi.org/products/raspberry-pi-zero/&#34;&gt;Raspberry Pi
2576Zero&lt;/a&gt;.&lt;/p&gt;
2577&lt;p&gt;First, I installed the necessary software on Raspberry Pi with &lt;code&gt;pip3 install inky&lt;/code&gt;.&lt;/p&gt;
2578&lt;p&gt;And then I created a file &lt;code&gt;clock.py&lt;/code&gt; in home directory &lt;code&gt;/home/pi&lt;/code&gt;.&lt;/p&gt;
2579&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;#!/usr/bin/env python&lt;/span&gt;
2580&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# -*- coding: utf-8 -*-&lt;/span&gt;
2581&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2582&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; sys
2583&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; os
2584&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;from&lt;/span&gt; inky.auto &lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; auto
2585&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;from&lt;/span&gt; PIL &lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; Image, ImageFont, ImageDraw
2586&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;from&lt;/span&gt; font_fredoka_one &lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; FredokaOne
2587&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2588&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;clocks = [
2589&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;America/New_York&amp;#39;&lt;/span&gt;,
2590&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;Europe/Ljubljana&amp;#39;&lt;/span&gt;,
2591&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;Australia/Brisbane&amp;#39;&lt;/span&gt;,
2592&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;]
2593&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2594&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;board = auto()
2595&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;board.set_border(board.WHITE)
2596&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;board.rotation = 90
2597&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2598&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;img = Image.new(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;P&amp;#39;&lt;/span&gt;, (board.WIDTH, board.HEIGHT))
2599&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;draw = ImageDraw.Draw(img)
2600&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2601&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;big_font = ImageFont.truetype(FredokaOne, 18)
2602&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;small_font = ImageFont.truetype(FredokaOne, 13)
2603&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2604&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;x = board.WIDTH / 3
2605&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;y = board.HEIGHT / 3
2606&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2607&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;idx = 1
2608&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;for&lt;/span&gt; clock &lt;span style=&#34;color:#00f&#34;&gt;in&lt;/span&gt; clocks:
2609&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ctime = os.popen(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;TZ=&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34; date &#43;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;%a&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;,%H:%M&amp;#34;&amp;#39;&lt;/span&gt;.format(clock))
2610&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ctime = ctime.read().strip().split(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;,&amp;#39;&lt;/span&gt;)
2611&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; city = clock.split(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;/&amp;#39;&lt;/span&gt;)[1].replace(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;_&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39; &amp;#39;&lt;/span&gt;)
2612&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2613&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; draw.text((15, (idx*y)-y&#43;10), city, fill=board.BLACK, font=small_font)
2614&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; draw.text((110, (idx*y)-y&#43;7), str(ctime[0]), fill=board.BLACK, font=big_font)
2615&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; draw.text((155, (idx*y)-y&#43;7), str(ctime[1]), fill=board.BLACK, font=big_font)
2616&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2617&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; idx &#43;= 1
2618&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2619&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;board.set_image(img)
2620&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;board.show()
2621&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And because eInk displays are rather slow to refresh and the clock requires
2622refreshing only once a minute, this can be done through cronjob.&lt;/p&gt;
2623&lt;p&gt;Before we add this job to cron we need to make &lt;code&gt;clock.py&lt;/code&gt; executable with &lt;code&gt;chmod &#43;x clock.py&lt;/code&gt;.&lt;/p&gt;
2624&lt;p&gt;Then we add a cronjob with &lt;code&gt;crontab -e&lt;/code&gt;.&lt;/p&gt;
2625&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;* * * * * /home/pi/clock.py
2626&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;So, we end up with a result like this.&lt;/p&gt;
2627&lt;figure&gt;
2628&lt;img src=&#34;/posts/world-clock/world-clock.jpg&#34; alt=&#34;World Clock&#34; /&gt;
2629&lt;/figure&gt;
2630&lt;p&gt;And for the enclosure that can be 3D printed, but I haven&#39;t yet something like
2631this can be used.&lt;/p&gt;
2632&lt;iframe id=&#34;vs_iframe&#34; src=&#34;https://www.viewstl.com/?embedded&amp;url=https%3A%2F%2Fmitjafelicijan.com%2Fposts%2Fworld-clock%2Fenclosure.stl&amp;color=gray&amp;bgcolor=white&amp;edges=no&amp;orientation=front&amp;noborder=no&#34; style=&#34;border:0;margin:0;width:100%;height:400px;&#34;&gt;&lt;/iframe&gt;
2633&lt;p&gt;You can download my &lt;a href=&#34;/posts/world-clock/enclosure.stl&#34;&gt;STL file for the enclosure
2634here&lt;/a&gt;, but make sure that dimensions make
2635sense and also opening for USB port should be added or just use a drill and some
2636hot glue to make it stick in the enclosure.&lt;/p&gt;
2637</content:encoded>
2638 </item>
2639
2640
2641
2642 <item>
2643 <title>Using GoAccess with Nginx to replace Google Analytics</title>
2644 <link>https://mitjafelicijan.com/using-goaccess-with-nginx-to-replace-google-analytics.html</link>
2645 <pubDate>Mon, 25 Jan 2021 12:00:00 &#43;0200</pubDate>
2646 <guid>https://mitjafelicijan.com/using-goaccess-with-nginx-to-replace-google-analytics.html</guid>
2647 <description>IntroductionI know!</description>
2648 <content:encoded>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;
2649&lt;p&gt;I know! You cannot simply replace Google Analytics with parsing access logs and
2650displaying a couple of charts. But to be honest, I actually never used Google
2651Analytics to the fullest extent and was usually interested in seeing page hits
2652and which pages were visited most often.&lt;/p&gt;
2653&lt;p&gt;I recently moved my blog from Firebase to a VPS and also decided to remove
2654Google Analytics tracking code from the site since its quite malicious and
2655tracks users across other pages also and is creating a profile of a user, and
2656I&#39;ve had it. But I also need some insight of what is happening on a server and
2657which content is being read the most etc.&lt;/p&gt;
2658&lt;p&gt;I have looked at many existing solutions like:&lt;/p&gt;
2659&lt;ul&gt;
2660&lt;li&gt;&lt;a href=&#34;https://umami.is/&#34;&gt;Umami&lt;/a&gt;&lt;/li&gt;
2661&lt;li&gt;&lt;a href=&#34;https://github.com/sheshbabu/freshlytics&#34;&gt;Freshlytics&lt;/a&gt;&lt;/li&gt;
2662&lt;li&gt;&lt;a href=&#34;https://matomo.org/&#34;&gt;Matomo&lt;/a&gt;&lt;/li&gt;
2663&lt;/ul&gt;
2664&lt;p&gt;But the more I looked at them the more I noticed that I am replacing one evil
2665with another one. Don&#39;t get me wrong. Some of these solutions are absolutely
2666fantastic but would require installation of databases and something like PHP or
2667Node. And I was not ready to put those things on my fresh server. Also having
2668Docker installed is out of the question.&lt;/p&gt;
2669&lt;h2 id=&#34;opting-for-log-parsing&#34;&gt;Opting for log parsing&lt;/h2&gt;
2670&lt;p&gt;So, I defaulted to parsing already existing logs and generating HTML reports
2671from this data.&lt;/p&gt;
2672&lt;p&gt;I found this amazing software &lt;a href=&#34;https://goaccess.io/&#34;&gt;GoAccess&lt;/a&gt; which provides
2673all the functionalities I need, and it&#39;s a single binary. Written in Go.&lt;/p&gt;
2674&lt;p&gt;GoAccess can be used in two different modes.&lt;/p&gt;
2675&lt;figure&gt;
2676&lt;img src=&#34;/posts/goaccess/goaccess-dash-term.png&#34; alt=&#34;GoAccess Terminal&#34; /&gt;
2677&lt;/figure&gt;
2678&lt;p&gt;&lt;em&gt;Running in a terminal&lt;/em&gt;&lt;/p&gt;
2679&lt;figure&gt;
2680&lt;img src=&#34;/posts/goaccess/goaccess-dash-html.png&#34; alt=&#34;GoAccess HTML&#34; /&gt;
2681&lt;/figure&gt;
2682&lt;p&gt;&lt;em&gt;Running in a browser&lt;/em&gt;&lt;/p&gt;
2683&lt;p&gt;I, however, need this to run in a browser. So, the second option is the way to
2684go. The Idea is to periodically run cronjob and export this report into a folder
2685that gets then server by Nginx behind a Basic authentication.&lt;/p&gt;
2686&lt;h2 id=&#34;getting-nginx-ready&#34;&gt;Getting Nginx ready&lt;/h2&gt;
2687&lt;p&gt;I choose Ubuntu on &lt;a href=&#34;https://www.digitalocean.com/&#34;&gt;DigitalOcean&lt;/a&gt;. First I
2688installed &lt;a href=&#34;https://nginx.org/en/&#34;&gt;Nginx&lt;/a&gt;, and
2689&lt;a href=&#34;https://letsencrypt.org/getting-started/&#34;&gt;Letsencrypt&lt;/a&gt; certbot and all the
2690necessary dependencies.&lt;/p&gt;
2691&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# log in as root user&lt;/span&gt;
2692&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo su -
2693&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2694&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# first let&amp;#39;s update the system&lt;/span&gt;
2695&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt update &amp;amp;&amp;amp; apt upgrade -y
2696&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2697&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# let&amp;#39;s install&lt;/span&gt;
2698&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install nginx certbot python3-certbot-nginx apache2-utils
2699&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After all this is installed we can create a new configuration for a statistics.
2700Stats will be available at &lt;code&gt;stats.domain.com&lt;/code&gt;.&lt;/p&gt;
2701&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# creates directory where html will be hosted&lt;/span&gt;
2702&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p /var/www/html/stats.domain.com
2703&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2704&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cp /etc/nginx/sites-available/default /etc/nginx/sites-available/stats.domain.com
2705&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nano /etc/nginx/sites-available/stats.domain.com
2706&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;server&lt;/span&gt; {
2707&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;root&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;/var/www/html/stats.domain.com&lt;/span&gt;;
2708&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;server_name&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;stats.domain.com&lt;/span&gt;;
2709&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2710&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;index&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;index.html&lt;/span&gt;;
2711&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;location&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;/&lt;/span&gt; {
2712&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;try_files&lt;/span&gt; $uri $uri/ =404;
2713&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
2714&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
2715&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now we check if the configuration is ok. We can do this with &lt;code&gt;nginx -t&lt;/code&gt;. If all
2716is ok, we can restart Nginx with &lt;code&gt;service nginx restart&lt;/code&gt;.&lt;/p&gt;
2717&lt;p&gt;After all that you should add A record for this domain that points to IP of a
2718droplet.&lt;/p&gt;
2719&lt;p&gt;Before enabling SSL you should test if DNS records have propagated with &lt;code&gt;curl stats.domain.com&lt;/code&gt;.&lt;/p&gt;
2720&lt;p&gt;Now, it&#39;s time to provision TLS certificate. To achieve this, you execute
2721command &lt;code&gt;certbot --nginx&lt;/code&gt;. Follow the wizard and when you are asked about
2722redirection always choose 2 (always redirect to HTTPS).&lt;/p&gt;
2723&lt;p&gt;When this is done you can visit &lt;a href=&#34;https://stats.domain.com&#34;&gt;https://stats.domain.com&lt;/a&gt; and you should get 404
2724not found error which is correct.&lt;/p&gt;
2725&lt;h2 id=&#34;getting-goaccess-ready&#34;&gt;Getting GoAccess ready&lt;/h2&gt;
2726&lt;p&gt;If you are using Debian like system GoAccess should be available in repository.
2727Otherwise refer to the official website.&lt;/p&gt;
2728&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install goaccess
2729&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To enable Geo location we also need one additiona thing.&lt;/p&gt;
2730&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd /var/www/html/stats.stats.com
2731&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget https://github.com/P3TERX/GeoLite.mmdb/raw/download/GeoLite2-City.mmdb
2732&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now we create a shell script that will be executed every 10 minutes.&lt;/p&gt;
2733&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;nano /var/www/html/stats.domain.com/generate-stats.sh
2734&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Contents of this file should look like this.&lt;/p&gt;
2735&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;#!/bin/sh
2736&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;&lt;/span&gt;
2737&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;zcat -f /var/log/nginx/access.log* &amp;gt; /var/log/nginx/access-all.log
2738&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2739&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;goaccess &lt;span style=&#34;color:#a31515&#34;&gt;\
2740&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&lt;/span&gt; --log-file=/var/log/nginx/access-all.log &lt;span style=&#34;color:#a31515&#34;&gt;\
2741&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&lt;/span&gt; --log-format=COMBINED &lt;span style=&#34;color:#a31515&#34;&gt;\
2742&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&lt;/span&gt; --exclude-ip=0.0.0.0 &lt;span style=&#34;color:#a31515&#34;&gt;\
2743&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&lt;/span&gt; --geoip-database=/var/www/html/stats.domain.com/GeoLite2-City.mmdb &lt;span style=&#34;color:#a31515&#34;&gt;\
2744&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&lt;/span&gt; --ignore-crawlers &lt;span style=&#34;color:#a31515&#34;&gt;\
2745&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&lt;/span&gt; --real-os &lt;span style=&#34;color:#a31515&#34;&gt;\
2746&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&lt;/span&gt; --output=/var/www/html/stats.domain.com/index.html
2747&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2748&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rm /var/log/nginx/access-all.log
2749&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Because after a while nginx creates multiple files with access logs we use
2750&lt;a href=&#34;https://linux.die.net/man/1/zcat&#34;&gt;&lt;code&gt;zcat&lt;/code&gt;&lt;/a&gt; to extract Gziped contents and create
2751a file that has all the access logs. After this file is used we delete it.&lt;/p&gt;
2752&lt;p&gt;If you want to exclude your home IP&#39;s result look at the &lt;code&gt;--exclude-ip&lt;/code&gt; option
2753in script and instead of &lt;code&gt;0.0.0.0&lt;/code&gt; add your own home IP address. You can find
2754your home IP by executing &lt;code&gt;curl ifconfig.me&lt;/code&gt; from your local machine and NOT
2755from the droplet.&lt;/p&gt;
2756&lt;p&gt;Test the script by executing &lt;code&gt;sh /var/www/html/stats.domain.com/generate-stats.sh&lt;/code&gt; and then checking
2757&lt;code&gt;https://stats.domain.com&lt;/code&gt;. If you can see stats instead of 404 than you are
2758set.&lt;/p&gt;
2759&lt;p&gt;It&#39;s time to add this script to cron with &lt;code&gt;cron -e&lt;/code&gt;.&lt;/p&gt;
2760&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;*/10 * * * * sh /&lt;span style=&#34;color:#00f&#34;&gt;var&lt;/span&gt;/www/html/stats.domain.com/generate-stats.sh
2761&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;securing-with-basic-authentication&#34;&gt;Securing with Basic authentication&lt;/h2&gt;
2762&lt;p&gt;You probably don&#39;t want stats to be publicly available, so we should create a
2763user and a password for Basic authentication.&lt;/p&gt;
2764&lt;p&gt;First we create a password for a user &lt;code&gt;stats&lt;/code&gt; with &lt;code&gt;htpasswd -c /etc/nginx/.htpasswd stats&lt;/code&gt;.&lt;/p&gt;
2765&lt;p&gt;Now we update config file with &lt;code&gt;nano /etc/nginx/sites-available/stats.domain.com&lt;/code&gt;. You probably noticed that the
2766file looks a bit different from before. This is because &lt;code&gt;certbot&lt;/code&gt; added
2767additional rules for SSL.&lt;/p&gt;
2768&lt;p&gt;Your location portion the config file should now look like. You should add
2769&lt;code&gt;auth_basic&lt;/code&gt; and &lt;code&gt;auth_basic_user_file&lt;/code&gt; lines to the file.&lt;/p&gt;
2770&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;location&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;/&lt;/span&gt; {
2771&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;try_files&lt;/span&gt; $uri $uri/ =404;
2772&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;auth_basic&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Private&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;Property&amp;#34;&lt;/span&gt;;
2773&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;auth_basic_user_file&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;/etc/nginx/.htpasswd&lt;/span&gt;;
2774&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
2775&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Test if config is still ok with &lt;code&gt;nginx -t&lt;/code&gt; and if it is you can restart Nginx
2776with &lt;code&gt;service nginx restart&lt;/code&gt;.&lt;/p&gt;
2777&lt;p&gt;If you now visit &lt;code&gt;https://stats.domain.com&lt;/code&gt; you should be prompted for username
2778and password. If not, try reopening your browser.&lt;/p&gt;
2779&lt;p&gt;That is all. You now have analytics for your server that gets refreshed every 10
2780minutes.&lt;/p&gt;
2781</content:encoded>
2782 </item>
2783
2784
2785
2786 <item>
2787 <title>Replacing Dropbox in favor of DigitalOcean spaces</title>
2788 <link>https://mitjafelicijan.com/replacing-dropbox-in-favor-of-digitalocean-spaces.html</link>
2789 <pubDate>Sun, 24 Jan 2021 12:00:00 &#43;0200</pubDate>
2790 <guid>https://mitjafelicijan.com/replacing-dropbox-in-favor-of-digitalocean-spaces.html</guid>
2791 <description>A few months ago I experimented with DigitalOcean spaces as my backup solutionthat could replace Dropboxeventually.</description>
2792 <content:encoded>&lt;p&gt;A few months ago I experimented with DigitalOcean spaces as my backup solution
2793that could &lt;a href=&#34;/digitalocean-spaces-to-sync-between-computers.html&#34;&gt;replace Dropbox
2794eventually&lt;/a&gt;. That solution
2795worked quite nicely, and I was amazed how smashing together a couple of existing
2796solutions would work this fine.&lt;/p&gt;
2797&lt;p&gt;I have been running that solution in the background for a couple of months now
2798and kind of forgot about it. But recent developments around deplatforming and
2799having us people hostages of technology and big companies speed up my goals to
2800become less dependent on
2801&lt;a href=&#34;https://edition.cnn.com/2020/12/17/tech/google-antitrust-lawsuit/index.html&#34;&gt;Google&lt;/a&gt;,
2802&lt;a href=&#34;https://www.pcworld.com/article/2048680/dropbox-takes-a-peek-at-files.html&#34;&gt;Dropbox&lt;/a&gt;
2803etc and take back some control.&lt;/p&gt;
2804&lt;p&gt;I am not a conspiracy theory nut, but to be honest, what these companies are
2805doing lately is out of control. It is a matter of principle at this point. I
2806have almost completely degoogled my life all the way from ditching Gmail,
2807YouTube and most of the services surrounding Google. And I must tell you, I feel
2808so good. I haven&#39;t felt this way for a long time.&lt;/p&gt;
2809&lt;p&gt;&lt;strong&gt;Anyways. Let&#39;s get to the meat of things.&lt;/strong&gt;&lt;/p&gt;
2810&lt;p&gt;Before you continue you should read my post about &lt;a href=&#34;/digitalocean-spaces-to-sync-between-computers.html&#34;&gt;syncing to
2811Dropbox&lt;/a&gt;.&lt;/p&gt;
2812&lt;blockquote&gt;
2813&lt;p&gt;Also to note, I am using Linux on my machine with Gnome desktop environment.
2814This should work on MacOS too. To use this on Windows I suggest using
2815&lt;a href=&#34;https://docs.microsoft.com/en-us/windows/wsl/install-win10&#34;&gt;Subsystem for Linux&lt;/a&gt;
2816or &lt;a href=&#34;https://www.cygwin.com/&#34;&gt;Cygwin&lt;/a&gt;.&lt;/p&gt;
2817&lt;/blockquote&gt;
2818&lt;h2 id=&#34;folder-structure&#34;&gt;Folder structure&lt;/h2&gt;
2819&lt;p&gt;I liked structure from Dropbox. One folder where everything is located and
2820synced. So, that&#39;s why adopted this also for my sync setup.&lt;/p&gt;
2821&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;&#34;&gt;~&lt;/span&gt;/Vault
2822&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;&#34;&gt;↳&lt;/span&gt; backup
2823&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;&#34;&gt;↳&lt;/span&gt; bin
2824&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;&#34;&gt;↳&lt;/span&gt; documents
2825&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;&#34;&gt;↳&lt;/span&gt; projects
2826&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;All of my code is located in &lt;code&gt;~/Vault/projects&lt;/code&gt; folder. And most of the projects
2827are Git repositories. I do not use this sync method for backup per see but in
2828case I reinstall my machine I can easily recreate all the important folder
2829structure with one quick command. No external drives needed that can fail etc.&lt;/p&gt;
2830&lt;h2 id=&#34;sync-script&#34;&gt;Sync script&lt;/h2&gt;
2831&lt;p&gt;My sync script is located in &lt;code&gt;~/Vault/bin/vault-backup.sh&lt;/code&gt;&lt;/p&gt;
2832&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;#!/bin/bash
2833&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;&lt;/span&gt;
2834&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# dconf load /com/gexperts/Tilix/ &amp;lt; tilix.dconf&lt;/span&gt;
2835&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# 0 2 * * * sh ~/Vault/bin/vault-backup.sh&lt;/span&gt;
2836&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2837&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd ~/Vault/backup/dotfiles
2838&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2839&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;MACHINE=&lt;span style=&#34;color:#00f&#34;&gt;$(&lt;/span&gt;whoami&lt;span style=&#34;color:#00f&#34;&gt;)&lt;/span&gt;@&lt;span style=&#34;color:#00f&#34;&gt;$(&lt;/span&gt;hostname&lt;span style=&#34;color:#00f&#34;&gt;)&lt;/span&gt;
2840&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir -p $MACHINE
2841&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd $MACHINE
2842&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2843&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cp ~/.config/VSCodium/User/settings.json settings.json
2844&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cp ~/.s3cfg s3cfg
2845&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cp ~/.bash_extended bash_extended
2846&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cp ~/.ssh ssh -rf
2847&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2848&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;codium --list-extensions &amp;gt; vscode-extension.txt
2849&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dconf dump /com/gexperts/Tilix/ &amp;gt; tilix.dconf
2850&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2851&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd ~/Vault
2852&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;s3cmd sync --delete-removed --exclude &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;node_modules/*&amp;#39;&lt;/span&gt; --exclude &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;.git/*&amp;#39;&lt;/span&gt; --exclude &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;.venv/*&amp;#39;&lt;/span&gt; ./ s3://bucket-name/backup/
2853&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2854&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#a31515&#34;&gt;`&lt;/span&gt;date &#43;&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;%D %T&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;`&lt;/span&gt; &amp;gt;&amp;gt; ~/.vault.log
2855&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
2856&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;notify-send &lt;span style=&#34;color:#a31515&#34;&gt;\
2857&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&lt;/span&gt; -u normal &lt;span style=&#34;color:#a31515&#34;&gt;\
2858&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&lt;/span&gt; -i /usr/share/icons/Adwaita/96x96/status/security-medium-symbolic.symbolic.png &lt;span style=&#34;color:#a31515&#34;&gt;\
2859&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Vault sync succeded at `date &#43;&amp;#34;&lt;/span&gt;%D %T&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;`&amp;#34;&lt;/span&gt;
2860&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This script also backups some of the dotfiles I use and sends notification to
2861Gnome notification center. It is a straightforward solution. Nothing special
2862going on.&lt;/p&gt;
2863&lt;blockquote&gt;
2864&lt;p&gt;One obvious benefit of this is that I can omit syncing Node&#39;s &lt;code&gt;node_modules&lt;/code&gt;
2865or Python&#39;s &lt;code&gt;.venv&lt;/code&gt; and &lt;code&gt;.git&lt;/code&gt; folders.&lt;/p&gt;
2866&lt;/blockquote&gt;
2867&lt;p&gt;You can use this script in a combination with &lt;a href=&#34;https://en.wikipedia.org/wiki/Cron&#34;&gt;Cron&lt;/a&gt;.&lt;/p&gt;
2868&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;0 2 * * * sh ~/Vault/bin/vault-backup.sh
2869&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;When you start syncing your local stuff with a remote server you can review your
2870items on DigitalOcean.&lt;/p&gt;
2871&lt;figure&gt;
2872&lt;img src=&#34;/posts/dropbox-sync/dropbox-spaces.png&#34; alt=&#34;Dropbox Spaces&#34; /&gt;
2873&lt;/figure&gt;
2874&lt;p&gt;I have been using this script now for quite some time, and it&#39;s working
2875flawlessly. I also uninstalled Dropbox and stopped using it completely.&lt;/p&gt;
2876&lt;p&gt;All I need to do is write a Bash script that does the reverse and downloads from
2877remote server to local folder. This could be another post.&lt;/p&gt;
2878</content:encoded>
2879 </item>
2880
2881
2882
2883 <item>
2884 <title>Using Digitalocean Spaces to sync between computers</title>
2885 <link>https://mitjafelicijan.com/digitalocean-spaces-to-sync-between-computers.html</link>
2886 <pubDate>Wed, 09 Sep 2020 12:00:00 &#43;0200</pubDate>
2887 <guid>https://mitjafelicijan.com/digitalocean-spaces-to-sync-between-computers.html</guid>
2888 <description>I&amp;#39;ve been using Dropbox for probably 10&#43; yearsnow and I-ve became so used to it that it runs in the background that I don&amp;#39;teven imagine a world without it.</description>
2889 <content:encoded>&lt;p&gt;I&#39;ve been using &lt;a href=&#34;https://www.dropbox.com/&#34;&gt;Dropbox&lt;/a&gt; for probably &lt;strong&gt;10&#43; years&lt;/strong&gt;
2890now and I-ve became so used to it that it runs in the background that I don&#39;t
2891even imagine a world without it. But it&#39;s not without problems.&lt;/p&gt;
2892&lt;p&gt;At first I had problems with &lt;code&gt;.venv&lt;/code&gt; environments for Python and the only
2893solution for excluding synchronization for this folder was to manually exclude a
2894specific folder which is not really scalable. FYI, my whole project folder is
2895synced on &lt;a href=&#34;https://www.dropbox.com/&#34;&gt;Dropbox&lt;/a&gt;. This of course introduced a lot
2896of syncing of files and folders that are not needed or even break things on
2897other machines. In the case of &lt;strong&gt;Python&lt;/strong&gt;, I couldn&#39;t use that on my second
2898machine. I needed to delete &lt;code&gt;.venv&lt;/code&gt; folder and pip it again which synced files
2899again to the main machine. This was very frustrating. &lt;strong&gt;Nodejs&lt;/strong&gt; handles this
2900much nicer and I can just run the scripts without deleting &lt;code&gt;node_modules&lt;/code&gt; again
2901and reinstalling. However, &lt;code&gt;node_modules&lt;/code&gt; is a beast of its own. It creates so
2902many files that OS has a problem counting them when you check the folder
2903contents for size.&lt;/p&gt;
2904&lt;p&gt;I wanted something similar to Dropbox. I could without the instant syncing but
2905it would need to be fast and had the option for me to exclude folders like
2906&lt;code&gt;node_modules, .venv, .git&lt;/code&gt; and folders like that.&lt;/p&gt;
2907&lt;p&gt;I went on a hunt for an alternative to &lt;a href=&#34;https://www.dropbox.com/&#34;&gt;Dropbox&lt;/a&gt;
2908and found:&lt;/p&gt;
2909&lt;ul&gt;
2910&lt;li&gt;&lt;a href=&#34;https://tresorit.com/&#34;&gt;Tresorit&lt;/a&gt;&lt;/li&gt;
2911&lt;li&gt;&lt;a href=&#34;https://sync.com&#34;&gt;Sync.com&lt;/a&gt;&lt;/li&gt;
2912&lt;li&gt;&lt;a href=&#34;https://www.box.com/&#34;&gt;Box&lt;/a&gt;&lt;/li&gt;
2913&lt;/ul&gt;
2914&lt;p&gt;You know, the usual list of suspects. I didn&#39;t include &lt;a href=&#34;https://drive.google.com&#34;&gt;Google
2915drive&lt;/a&gt; or &lt;a href=&#34;https://onedrive.live.com/&#34;&gt;One drive&lt;/a&gt;
2916since they are even more draconian than Dropbox.&lt;/p&gt;
2917&lt;blockquote&gt;
2918&lt;p&gt;All this does not stem from me being paranoid but recently these companies
2919have became more and more aggressive and they keep violating our privacy when
2920they share our data with 3rd party services. It is getting out of control.&lt;/p&gt;
2921&lt;/blockquote&gt;
2922&lt;p&gt;So, my main problem was still there. No way of excluding a specific folder from
2923syncing. And before we go into &amp;quot;&lt;em&gt;But you have git, isn&#39;t that enough?&lt;/em&gt;&amp;quot;, I must
2924say, that many of the files (PDFs, spreadsheets, etc) I have in a &lt;code&gt;git&lt;/code&gt; repo
2925don&#39;t get pushed upstream to Git and I still want to have them synced across my
2926computers.&lt;/p&gt;
2927&lt;p&gt;I initially wanted to use &lt;a href=&#34;https://linux.die.net/man/1/rsync&#34;&gt;rsync&lt;/a&gt; but I would
2928need to then have a remote VPS or transfer between my computers directly. I
2929wanted a solution where all my files could be accessible to me without my
2930machine.&lt;/p&gt;
2931&lt;blockquote&gt;
2932&lt;p&gt;&lt;strong&gt;WARNING: This solution will cost you money!&lt;/strong&gt; DigitalOcean Spaces are $5 per
2933month and there are some bandwidth limitations and if you go beyond that you get
2934billed additionally.&lt;/p&gt;
2935&lt;/blockquote&gt;
2936&lt;p&gt;Then I remembered that I could use something like
2937&lt;a href=&#34;https://en.wikipedia.org/wiki/Amazon_S3&#34;&gt;S3&lt;/a&gt; since it has versioning and is
2938fully managed. I didn&#39;t want to go down the AWS rabbit hole with this so I
2939choose &lt;a href=&#34;https://www.digitalocean.com/products/spaces/&#34;&gt;DigitalOcean Spaces&lt;/a&gt;.&lt;/p&gt;
2940&lt;p&gt;Then I needed a command-line tool to sync between source and target. I found
2941this nice tool &lt;a href=&#34;https://s3tools.org/s3cmd&#34;&gt;s3cmd&lt;/a&gt; and it is in the Ubuntu
2942repositories.&lt;/p&gt;
2943&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt install s3cmd
2944&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After installation will I create a new Space bucket on DigitalOcean. Remember
2945the zone you will choose because you will need it when you will configure
2946&lt;code&gt;s3cmd&lt;/code&gt;.&lt;/p&gt;
2947&lt;p&gt;Then I visited &lt;a href=&#34;https://cloud.digitalocean.com/account/api/tokens&#34;&gt;Digitalocean Applications &amp;amp;
2948API&lt;/a&gt; and generated &lt;strong&gt;Spaces
2949access keys&lt;/strong&gt;. Save both key and secret somewhere safe because when you will
2950leave the page secret will not be available anymore to you and you will need to
2951re-generate it.&lt;/p&gt;
2952&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# enter your key and secret and correct endpoint&lt;/span&gt;
2953&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# my endpoint is ams3.digitaloceanspaces.com because&lt;/span&gt;
2954&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# I created my bucket in Amsterdam regiin&lt;/span&gt;
2955&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;s3cmd --configure
2956&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After that I played around with options for &lt;code&gt;s3cmd&lt;/code&gt; and got to the following
2957command.&lt;/p&gt;
2958&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# I executed this command from my projects folder&lt;/span&gt;
2959&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd projects
2960&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;s3cmd sync --delete-removed --exclude &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;node_modules/*&amp;#39;&lt;/span&gt; --exclude &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;.git/*&amp;#39;&lt;/span&gt; --exclude &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;.venv/*&amp;#39;&lt;/span&gt; ./ s3://my-bucket-name/projects/
2961&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;When syncing int he other direction you will need to change the order of the
2962&lt;code&gt;SOURCE&lt;/code&gt; and &lt;code&gt;TARGET&lt;/code&gt; to &lt;code&gt;s3://my-bucket-name/projects/&lt;/code&gt; and &lt;code&gt;./&lt;/code&gt;.&lt;/p&gt;
2963&lt;blockquote&gt;
2964&lt;p&gt;Be sure that all the paths have trailing slash so that sync knows that this
2965are directories.&lt;/p&gt;
2966&lt;/blockquote&gt;
2967&lt;p&gt;I am planning to implement some sort of a &lt;code&gt;.ignore&lt;/code&gt; file that will enable me to
2968have a project-specific exclude options.&lt;/p&gt;
2969&lt;p&gt;I am currently running this every hour as a cronjob which is perfectly fine for
2970now when I am testing how this whole thing works and how it all will turn out.&lt;/p&gt;
2971&lt;p&gt;I have also created a small Gnome extension which is still very unstable, but
2972when/if this whole experiment pays of I will share on Github.&lt;/p&gt;
2973</content:encoded>
2974 </item>
2975
2976
2977
2978 <item>
2979 <title>Fix bind warning in .profile on login in Ubuntu</title>
2980 <link>https://mitjafelicijan.com/bind-warning-on-login-in-ubuntu.html</link>
2981 <pubDate>Tue, 08 Sep 2020 12:00:00 &#43;0200</pubDate>
2982 <guid>https://mitjafelicijan.com/bind-warning-on-login-in-ubuntu.html</guid>
2983 <description>Recently I moved back to bash as mydefault shell.</description>
2984 <content:encoded>&lt;p&gt;Recently I moved back to &lt;a href=&#34;https://www.gnu.org/software/bash/&#34;&gt;bash&lt;/a&gt; as my
2985default shell. I was previously using &lt;a href=&#34;https://fishshell.com/&#34;&gt;fish&lt;/a&gt; and got
2986used to the cool features it has. But, regardless of that, I wanted to move to a
2987more standard shell because I was hopping back and forth with exporting
2988variables and stuff like that which got pretty annoying.&lt;/p&gt;
2989&lt;p&gt;So I embarked on a mission to make &lt;a href=&#34;https://www.gnu.org/software/bash/&#34;&gt;bash&lt;/a&gt;
2990more like &lt;a href=&#34;https://fishshell.com/&#34;&gt;fish&lt;/a&gt; and in the process found that I really
2991missed autosuggest with TAB on changing directories.&lt;/p&gt;
2992&lt;p&gt;I found a nice alternative that emulates &lt;a href=&#34;http://zsh.sourceforge.net/&#34;&gt;zsh&lt;/a&gt; like
2993autosuggestion and autocomplete so I added the following to my &lt;code&gt;.bashrc&lt;/code&gt; file.&lt;/p&gt;
2994&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bind &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;TAB:menu-complete&amp;#34;&lt;/span&gt;
2995&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bind &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;set show-all-if-ambiguous on&amp;#34;&lt;/span&gt;
2996&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bind &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;set completion-ignore-case on&amp;#34;&lt;/span&gt;
2997&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bind &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;set menu-complete-display-prefix on&amp;#34;&lt;/span&gt;
2998&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bind &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;&amp;#34;\e[Z&amp;#34;:menu-complete-backward&amp;#39;&lt;/span&gt;
2999&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I haven&#39;t noticed anything wrong with this and all was working fine until I
3000restarted my machine and then I got this error.&lt;/p&gt;
3001&lt;figure&gt;
3002&lt;img src=&#34;/posts/profile-bind-error/error.jpg&#34; alt=&#34;Profile bind error&#34; /&gt;
3003&lt;/figure&gt;
3004&lt;p&gt;When I pressed OK, I got into the &lt;a href=&#34;https://wiki.gnome.org/Projects/GnomeShell&#34;&gt;Gnome
3005shell&lt;/a&gt; and all was working fine, but
3006the error was still bugging me. I started looking for the reason why this is
3007happening and found a solution to this error on &lt;a href=&#34;https://superuser.com/a/892682&#34;&gt;Remote SSH Commands - bash bind
3008warning: line editing not enabled&lt;/a&gt;.&lt;/p&gt;
3009&lt;p&gt;So I added a simple &lt;code&gt;if [ -t 1 ]&lt;/code&gt; around &lt;code&gt;bind&lt;/code&gt; statements to avoid running
3010commands that presume the session is interactive when it isn&#39;t.&lt;/p&gt;
3011&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt; [ -t 1 ]; &lt;span style=&#34;color:#00f&#34;&gt;then&lt;/span&gt;
3012&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; bind &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;TAB:menu-complete&amp;#34;&lt;/span&gt;
3013&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; bind &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;set show-all-if-ambiguous on&amp;#34;&lt;/span&gt;
3014&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; bind &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;set completion-ignore-case on&amp;#34;&lt;/span&gt;
3015&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; bind &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;set menu-complete-display-prefix on&amp;#34;&lt;/span&gt;
3016&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; bind &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;&amp;#34;\e[Z&amp;#34;:menu-complete-backward&amp;#39;&lt;/span&gt;
3017&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;fi&lt;/span&gt;
3018&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After logging out and back in the problem was gone.&lt;/p&gt;
3019</content:encoded>
3020 </item>
3021
3022
3023
3024 <item>
3025 <title>Getting started with MicroPython and ESP8266</title>
3026 <link>https://mitjafelicijan.com/esp8266-and-micropython-guide.html</link>
3027 <pubDate>Sun, 06 Sep 2020 12:00:00 &#43;0200</pubDate>
3028 <guid>https://mitjafelicijan.com/esp8266-and-micropython-guide.html</guid>
3029 <description>IntroductionA while ago I bought someESP8266 andESP32 dev boards to playaround with and I finally found a project to try it out.</description>
3030 <content:encoded>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;
3031&lt;p&gt;A while ago I bought some
3032&lt;a href=&#34;https://www.espressif.com/en/products/socs/esp8266&#34;&gt;ESP8266&lt;/a&gt; and
3033&lt;a href=&#34;https://www.espressif.com/en/products/socs/esp32&#34;&gt;ESP32&lt;/a&gt; dev boards to play
3034around with and I finally found a project to try it out.&lt;/p&gt;
3035&lt;p&gt;For my project, I used &lt;a href=&#34;https://www.espressif.com/en/products/socs/esp32&#34;&gt;ESP32&lt;/a&gt;
3036but I could easily choose
3037&lt;a href=&#34;https://www.espressif.com/en/products/socs/esp8266&#34;&gt;ESP8266&lt;/a&gt;. This guide
3038contains which tools I use and how I prepared my workspace to code for
3039&lt;a href=&#34;https://www.espressif.com/en/products/socs/esp8266&#34;&gt;ESP8266&lt;/a&gt;.&lt;/p&gt;
3040&lt;figure&gt;
3041&lt;img src=&#34;/posts/esp8366-micropython/boards.jpg&#34; alt=&#34;ESP8266 and ESP32 boards&#34; /&gt;
3042&lt;/figure&gt;
3043&lt;p&gt;This guide covers:&lt;/p&gt;
3044&lt;ul&gt;
3045&lt;li&gt;flashing SOC&lt;/li&gt;
3046&lt;li&gt;install proper tooling&lt;/li&gt;
3047&lt;li&gt;deploying a simple script&lt;/li&gt;
3048&lt;/ul&gt;
3049&lt;blockquote&gt;
3050&lt;p&gt;Make sure that you are using &lt;strong&gt;a good USB cable&lt;/strong&gt;. I had some problems with
3051mine and once I replaced it everything started to work.&lt;/p&gt;
3052&lt;/blockquote&gt;
3053&lt;h2 id=&#34;flashing-the-soc&#34;&gt;Flashing the SOC&lt;/h2&gt;
3054&lt;p&gt;Plug your ESP8266 to USB port and check if the device was recognized with
3055executing &lt;code&gt;dmesg | grep ch341-uart&lt;/code&gt;.&lt;/p&gt;
3056&lt;p&gt;Then check if the device is available under &lt;code&gt;/dev/&lt;/code&gt; by running &lt;code&gt;ls /dev/ttyUSB*&lt;/code&gt;.&lt;/p&gt;
3057&lt;blockquote&gt;
3058&lt;p&gt;&lt;strong&gt;Linux users&lt;/strong&gt;: if a device is not available be sure you are in &lt;code&gt;dialout&lt;/code&gt;
3059group. You can check this by executing &lt;code&gt;groups $USER&lt;/code&gt;. You can add a user to
3060&lt;code&gt;dialout&lt;/code&gt; group with &lt;code&gt;sudo adduser $USER dialout&lt;/code&gt;.&lt;/p&gt;
3061&lt;/blockquote&gt;
3062&lt;p&gt;After these conditions are meet go to the navigate to
3063&lt;a href=&#34;https://micropython.org/download/esp8266/&#34;&gt;https://micropython.org/download/esp8266/&lt;/a&gt;
3064and download &lt;code&gt;esp8266-20200902-v1.13.bin&lt;/code&gt;.&lt;/p&gt;
3065&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mkdir esp8266-test
3066&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd esp8266-test
3067&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3068&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;wget https://micropython.org/resources/firmware/esp8266-20200902-v1.13.bin
3069&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After obtaining firmware we will need some tooling to flash the firmware to the
3070board.&lt;/p&gt;
3071&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo pip3 install esptool
3072&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You can read more about &lt;code&gt;esptool&lt;/code&gt; at
3073&lt;a href=&#34;https://github.com/espressif/esptool/&#34;&gt;https://github.com/espressif/esptool/&lt;/a&gt;.&lt;/p&gt;
3074&lt;p&gt;Before flashing the firmware we need to erase the flash on device. Substitute
3075&lt;code&gt;USB0&lt;/code&gt; with the device listed in output of &lt;code&gt;ls /dev/ttyUSB*&lt;/code&gt;.&lt;/p&gt;
3076&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;esptool.py --port /dev/ttyUSB0 erase_flash
3077&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If flash was successfully erased it is now time to flash the new firmware to it.&lt;/p&gt;
3078&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;esptool.py --port /dev/ttyUSB0 --baud 460800 write_flash --flash_size=detect 0 esp8266-20200902-v1.13.bin
3079&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;If everything went ok you can try accessing MicroPython REPL with &lt;code&gt; screen /dev/ttyUSB0 115200&lt;/code&gt; or &lt;code&gt;picocom /dev/ttyUSB0 -b115200&lt;/code&gt;.&lt;/p&gt;
3080&lt;blockquote&gt;
3081&lt;p&gt;Sometimes you will need to press &lt;code&gt;ENTER&lt;/code&gt; in &lt;code&gt;screen&lt;/code&gt; or &lt;code&gt;picocom&lt;/code&gt; to access
3082REPL.&lt;/p&gt;
3083&lt;/blockquote&gt;
3084&lt;p&gt;When you are in REPL you can test if all is working properly following steps.&lt;/p&gt;
3085&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt; &lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; machine
3086&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt; machine.freq()
3087&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This should output a number representing a frequency of the CPU (mine was
3088&lt;code&gt;80000000&lt;/code&gt;).&lt;/p&gt;
3089&lt;p&gt;When you are in &lt;code&gt;screen&lt;/code&gt; or &lt;code&gt;picocom&lt;/code&gt; these can help you a bit.&lt;/p&gt;
3090&lt;table&gt;
3091&lt;thead&gt;
3092&lt;tr&gt;
3093&lt;th&gt;Key&lt;/th&gt;
3094&lt;th&gt;Command&lt;/th&gt;
3095&lt;/tr&gt;
3096&lt;/thead&gt;
3097&lt;tbody&gt;
3098&lt;tr&gt;
3099&lt;td&gt;CTRL&#43;d&lt;/td&gt;
3100&lt;td&gt;preforms soft reboot&lt;/td&gt;
3101&lt;/tr&gt;
3102&lt;tr&gt;
3103&lt;td&gt;CTRL&#43;a x&lt;/td&gt;
3104&lt;td&gt;exits picocom&lt;/td&gt;
3105&lt;/tr&gt;
3106&lt;tr&gt;
3107&lt;td&gt;CTRL&#43;a \&lt;/td&gt;
3108&lt;td&gt;exits screen&lt;/td&gt;
3109&lt;/tr&gt;
3110&lt;/tbody&gt;
3111&lt;/table&gt;
3112&lt;h2 id=&#34;install-better-tooling&#34;&gt;Install better tooling&lt;/h2&gt;
3113&lt;p&gt;Now, to make our lives a little bit easier there are couple of additional tools
3114that will make this whole experience a little more bearable.&lt;/p&gt;
3115&lt;p&gt;There are twq cool ways of uploading local files to SOC flash.&lt;/p&gt;
3116&lt;ul&gt;
3117&lt;li&gt;ampy → &lt;a href=&#34;https://github.com/scientifichackers/ampy&#34;&gt;https://github.com/scientifichackers/ampy&lt;/a&gt;&lt;/li&gt;
3118&lt;li&gt;rshell → &lt;a href=&#34;https://github.com/dhylands/rshell&#34;&gt;https://github.com/dhylands/rshell&lt;/a&gt;&lt;/li&gt;
3119&lt;/ul&gt;
3120&lt;h3 id=&#34;ampy&#34;&gt;ampy&lt;/h3&gt;
3121&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# installing ampy&lt;/span&gt;
3122&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo pip3 install adafruit-ampy
3123&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Listed below are some common commands I used.&lt;/p&gt;
3124&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# uploads file to flash&lt;/span&gt;
3125&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ampy --delay 2 --port /dev/ttyUSB0 put boot.py
3126&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3127&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# lists file on flash&lt;/span&gt;
3128&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ampy --delay 2 --port /dev/ttyUSB0 ls
3129&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3130&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# outputs contents of file on flash&lt;/span&gt;
3131&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ampy --delay 2 --port /dev/ttyUSB0 cat boot.py
3132&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
3133&lt;p&gt;I added &lt;code&gt;delay&lt;/code&gt; of 2 seconds because I had problems with executing commands.&lt;/p&gt;
3134&lt;/blockquote&gt;
3135&lt;h3 id=&#34;rshell&#34;&gt;rshell&lt;/h3&gt;
3136&lt;p&gt;Even though &lt;code&gt;ampy&lt;/code&gt; is a cool tool I opted with &lt;code&gt;rshell&lt;/code&gt; in the end since it&#39;s
3137much more polished and feature rich.&lt;/p&gt;
3138&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# installing ampy&lt;/span&gt;
3139&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo pip3 install rshell
3140&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now that &lt;code&gt;rshell&lt;/code&gt; is installed we can connect to the board.&lt;/p&gt;
3141&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rshell --buffer-size=30 -p /dev/ttyUSB0 -a
3142&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will open a shell inside bash and from here you can execute multiple
3143commands. You can check what is supported with &lt;code&gt;help&lt;/code&gt; once you are inside of a
3144shell.&lt;/p&gt;
3145&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;m@turing ~/Junk/esp8266-test
3146&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ rshell --buffer-size=30 -p /dev/ttyUSB0 -a
3147&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3148&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Using buffer-size of 30
3149&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Connecting to /dev/ttyUSB0 (buffer-size 30)...
3150&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Trying to connect to REPL connected
3151&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Testing &lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt; ubinascii.unhexlify exists ... Y
3152&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Retrieving root directories ... /boot.py/
3153&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Setting time ... Sep 06, 2020 23:54:28
3154&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Evaluating board_name ... pyboard
3155&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Retrieving time epoch ... Jan 01, 2000
3156&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Welcome to rshell. Use Control-D (or the exit command) to exit rshell.
3157&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/home/m/Junk/esp8266-test&amp;gt; help
3158&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3159&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Documented commands (type help &amp;lt;topic&amp;gt;):
3160&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;========================================
3161&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;args cat connect date edit filesize help mkdir rm shell
3162&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;boards cd cp echo exit filetype ls repl rsync
3163&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3164&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Use Control-D (or the exit command) to exit rshell.
3165&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
3166&lt;p&gt;Inside a shell &lt;code&gt;ls&lt;/code&gt; will display list of files on your machine. To get list
3167of files on flash folder &lt;code&gt;/pyboard&lt;/code&gt; is remapped inside the shell. To list files
3168on flash you must perform &lt;code&gt;ls /pyboard&lt;/code&gt;.&lt;/p&gt;
3169&lt;/blockquote&gt;
3170&lt;h4 id=&#34;moving-files-to-flash&#34;&gt;Moving files to flash&lt;/h4&gt;
3171&lt;p&gt;To avoid copying files all the time I used &lt;code&gt;rsync&lt;/code&gt; function from the inside of
3172&lt;code&gt;rshell&lt;/code&gt;.&lt;/p&gt;
3173&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rsync . /pyboard
3174&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h4 id=&#34;executing-scripts&#34;&gt;Executing scripts&lt;/h4&gt;
3175&lt;p&gt;It is a pain to continuously reboot the device to trigger &lt;code&gt;/pyboard/boot.py&lt;/code&gt; and
3176there is a better way of testing local scripts on remote device.&lt;/p&gt;
3177&lt;p&gt;Lets assume we have &lt;code&gt;src/freq.py&lt;/code&gt; file that displays CPU frequency of a remote
3178device.&lt;/p&gt;
3179&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# src/freq.py&lt;/span&gt;
3180&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3181&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; machine
3182&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(machine.freq())
3183&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now lets upload this and execute it.&lt;/p&gt;
3184&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# syncs files to remove device&lt;/span&gt;
3185&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;rsync ./src /pyboard
3186&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3187&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# goes into REPL&lt;/span&gt;
3188&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repl
3189&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3190&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# we import file by importing it without .py extension and this will run the script&lt;/span&gt;
3191&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt; import freq
3192&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3193&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# CTRL&#43;x will exit REPL&lt;/span&gt;
3194&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;additional-resources&#34;&gt;Additional resources&lt;/h2&gt;
3195&lt;ul&gt;
3196&lt;li&gt;&lt;a href=&#34;https://randomnerdtutorials.com/getting-started-micropython-esp32-esp8266/&#34;&gt;https://randomnerdtutorials.com/getting-started-micropython-esp32-esp8266/&lt;/a&gt;&lt;/li&gt;
3197&lt;li&gt;&lt;a href=&#34;http://docs.micropython.org/en/latest/esp8266/quickref.html&#34;&gt;http://docs.micropython.org/en/latest/esp8266/quickref.html&lt;/a&gt;&lt;/li&gt;
3198&lt;/ul&gt;
3199</content:encoded>
3200 </item>
3201
3202
3203
3204 <item>
3205 <title>Disable mouse wake from suspend with systemd service</title>
3206 <link>https://mitjafelicijan.com/disable-mouse-wake-from-suspend-with-systemd-service.html</link>
3207 <pubDate>Sat, 15 Aug 2020 12:00:00 &#43;0200</pubDate>
3208 <guid>https://mitjafelicijan.com/disable-mouse-wake-from-suspend-with-systemd-service.html</guid>
3209 <description>I recently bought ThinkPadX220 just as ajoke on eBay to test Linux distributions and play around with things and notdestroy my main machine.</description>
3210 <content:encoded>&lt;p&gt;I recently bought &lt;a href=&#34;https://www.laptopmag.com/reviews/laptops/lenovo-thinkpad-x220&#34;&gt;ThinkPad
3211X220&lt;/a&gt; just as a
3212joke on eBay to test Linux distributions and play around with things and not
3213destroy my main machine. Little to my knowledge I felt in love with it. Man,
3214they really made awesome machines back then.&lt;/p&gt;
3215&lt;p&gt;After changing disk that came with it to SSD and installing Ubuntu to test if 
3216everything works I noticed that even after a single touch of my external mouse
3217the system would wake up from sleep even though the lid was shut down.&lt;/p&gt;
3218&lt;p&gt;I wouldn&#39;t even noticed it if laptop didn&#39;t have &lt;a href=&#34;https://support.lenovo.com/lk/en/solutions/~/media/Images/ContentImages/p/pd025386_x1_status_03.ashx?w=426&amp;amp;h=262&#34;&gt;LED
3219sleep indicator&lt;/a&gt;.
3220I already had a bad experience with Linux and it&#39;s power management. I had a
3221&lt;a href=&#34;https://www.pcmag.com/reviews/dell-inspiron-15-7537&#34;&gt;Dell Inspiron 7537&lt;/a&gt; laptop
3222with a touchscreen and while traveling it decided to wake up and started cooking
3223in my backpack to the point that the digitizer responsible for touch actually
3224glue off and the whole screen got wrecked. So, I am a bit touchy about this.&lt;/p&gt;
3225&lt;p&gt;I went on solution hunting and to my surprise there is no easy way to disable
3226specific devices to perform wake up. Why is this not under the power management 
3227tab in setting is really strange.&lt;/p&gt;
3228&lt;p&gt;After googling for a solution I found &lt;a href=&#34;https://codetrips.com/2020/03/18/ubuntu-disable-mouse-wake-from-suspend/&#34;&gt;this nice article describing the
3229solution&lt;/a&gt;
3230that worked for me. The only problem with this solution was that he added his
3231solution to &lt;code&gt;.bashrc&lt;/code&gt; and this triggers &lt;code&gt;sudo&lt;/code&gt; that asks for a password each
3232time new terminal is opened, which get annoying quickly since I open a lot of
3233terminals all the time.&lt;/p&gt;
3234&lt;p&gt;I followed his instructions and got to solution &lt;code&gt;sudo sh -c &amp;quot;echo &#39;disabled&#39; &amp;gt; /sys/bus/usb/devices/2-1.1/power/wakeup&amp;quot;&lt;/code&gt;.&lt;/p&gt;
3235&lt;p&gt;I created a system service file &lt;code&gt;sudo nano /etc/systemd/system/disable-mouse-wakeup.service&lt;/code&gt; and removed &lt;code&gt;sudo&lt;/code&gt; and
3236replaced &lt;code&gt;sh&lt;/code&gt; with &lt;code&gt;/usr/bin/sh&lt;/code&gt; and pasted all that in &lt;code&gt;ExecStart&lt;/code&gt;.&lt;/p&gt;
3237&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;[Unit]&lt;/span&gt;
3238&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Description=&lt;span style=&#34;color:#a31515&#34;&gt;Disables wakeup on mouse event&lt;/span&gt;
3239&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;After=&lt;span style=&#34;color:#a31515&#34;&gt;network.target&lt;/span&gt;
3240&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;StartLimitIntervalSec=&lt;span style=&#34;color:#a31515&#34;&gt;0&lt;/span&gt;
3241&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3242&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;[Service]&lt;/span&gt;
3243&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Type=&lt;span style=&#34;color:#a31515&#34;&gt;simple&lt;/span&gt;
3244&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Restart=&lt;span style=&#34;color:#a31515&#34;&gt;always&lt;/span&gt;
3245&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RestartSec=&lt;span style=&#34;color:#a31515&#34;&gt;1&lt;/span&gt;
3246&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;User=&lt;span style=&#34;color:#a31515&#34;&gt;root&lt;/span&gt;
3247&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ExecStart=&lt;span style=&#34;color:#a31515&#34;&gt;/usr/bin/sh -c &amp;#34;echo &amp;#39;disabled&amp;#39; &amp;gt; /sys/bus/usb/devices/2-1.1/power/wakeup&amp;#34;&lt;/span&gt;
3248&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3249&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;[Install]&lt;/span&gt;
3250&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;WantedBy=&lt;span style=&#34;color:#a31515&#34;&gt;multi-user.target&lt;/span&gt;
3251&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After that I enabled, started and checked status of service.&lt;/p&gt;
3252&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo systemctl enable disable-mouse-wakeup.service
3253&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo systemctl start disable-mouse-wakeup.service
3254&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo systemctl status disable-mouse-wakeup.service
3255&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will permanently disable that device from wakeing up you computer on boot.
3256If you have many devices you would like to surpress from waking up your machine
3257I would create a shell script and call that instead of direclty doing it in
3258service file.&lt;/p&gt;
3259</content:encoded>
3260 </item>
3261
3262
3263
3264 <item>
3265 <title>Remote work and how it affects the daily lives of people</title>
3266 <link>https://mitjafelicijan.com/remote-work.html</link>
3267 <pubDate>Tue, 05 May 2020 12:00:00 &#43;0200</pubDate>
3268 <guid>https://mitjafelicijan.com/remote-work.html</guid>
3269 <description>I have been working remotely for the past 5 years.</description>
3270 <content:encoded>&lt;p&gt;I have been working remotely for the past 5 years. I love it. Love the freedom
3271and make your schedule thingy.&lt;/p&gt;
3272&lt;h2 id=&#34;you-work-more-not-less&#34;&gt;You work more not less&lt;/h2&gt;
3273&lt;p&gt;I&#39;ve heard from people things like: &amp;quot;Oh, you are so lucky, working from home,
3274having all the free time you want&amp;quot;. It was obvious they had no clue what means
3275working remotely. They had this romantic idea of remote work. You can watch TV
3276whenever you like, you can go outside for a picnic if you want and stuff like
3277that.&lt;/p&gt;
3278&lt;p&gt;This may be true if you work a day or two in a week from home. But if you go
3279completely remote all these changes completely. I take some time to acclimate
3280but then you start feeling the consequences of going fully remote. And it&#39;s not
3281all rainbows and unicorns. Rather the opposite.&lt;/p&gt;
3282&lt;h2 id=&#34;feeling-lost&#34;&gt;Feeling lost&lt;/h2&gt;
3283&lt;p&gt;At first, I remembered I felt lost. I was not used to this kind of environment.
3284It felt disoriented and a part of you that is used to procrastinate turns on.
3285You start thinking of a workday as a whole day. And soon this idea of &amp;quot;I can do
3286this later&amp;quot; starts creeping in. Well, I have the whole day ahead of me. I can do
3287this a bit later.&lt;/p&gt;
3288&lt;h2 id=&#34;hyper-performance&#34;&gt;Hyper-performance&lt;/h2&gt;
3289&lt;p&gt;As a direct result, you become more focused on your work since you don&#39;t have
3290all the interruptions common in the workplace. And you can quickly get used to
3291this hyper-performance. But this mode requires also a lot of peace and quiet.&lt;/p&gt;
3292&lt;p&gt;And here we come to the ugly parts of all this. &lt;strong&gt;People rarely have the
3293self-control&lt;/strong&gt; to not waste other people&#39;s time. It is paralyzing when people
3294start calling you, sending you chat messages, etc. The thing is, that when I
3295achieve this hyper-performance mode I am completely embroiled in the problem I
3296am solving and this kind of interruptions mess with your head. I need an hour at
3297least to get back in the zone. Sometimes not achieving the same focus the whole
3298day.&lt;/p&gt;
3299&lt;p&gt;I know that life is not how you want it to be and takes its route but from what
3300I&#39;ve learned this kind of interruptions can be avoided in 90% of the case easily
3301just by closing any chat programs and putting your phone in a drawer.&lt;/p&gt;
3302&lt;h2 id=&#34;suggestion-to-all-the-new-remote-workers&#34;&gt;Suggestion to all the new remote workers&lt;/h2&gt;
3303&lt;ul&gt;
3304&lt;li&gt;Stop wasting other people&#39;s time. You don&#39;t bother people at their desks in
3305the office either.&lt;/li&gt;
3306&lt;li&gt;Do not replace daily chats in the hallways with instant messaging software.
3307It will only interrupt people. Nothing good will come of it.&lt;/li&gt;
3308&lt;li&gt;Set your working hours and try to not allow it to bleed outside these
3309boundaries and maintain your routine.&lt;/li&gt;
3310&lt;li&gt;Be prepared that hours will be longer regardless of your good intentions and
3311your well thought of routine.&lt;/li&gt;
3312&lt;li&gt;Try to be hyper-focused and do only one thing at the time. Multitasking is the
3313enemy of progress.&lt;/li&gt;
3314&lt;li&gt;Avoid long meetings and if possible eliminate them. Rather take time to write
3315them out and allow others to respond in their own time. Meetings are usually a
3316large waste of time and most of the people attending them are there just
3317because the manager said so.&lt;/li&gt;
3318&lt;li&gt;The software will not solve your problems. And throwing money at problems
3319neither.&lt;/li&gt;
3320&lt;li&gt;If you are in a managerial position don&#39;t supervise any single minute of
3321workers. They are probably giving you more hours anyways. Track progress
3322weekly not daily. You hired them and give them the benefit of the doubt that
3323they will deliver what you agreed upon.&lt;/li&gt;
3324&lt;/ul&gt;
3325</content:encoded>
3326 </item>
3327
3328
3329
3330 <item>
3331 <title>My love and hate relationship with Node.js</title>
3332 <link>https://mitjafelicijan.com/my-love-and-hate-relationship-with-nodejs.html</link>
3333 <pubDate>Mon, 30 Mar 2020 12:00:00 &#43;0200</pubDate>
3334 <guid>https://mitjafelicijan.com/my-love-and-hate-relationship-with-nodejs.html</guid>
3335 <description>Previous project I was working on was being coded inGolang.</description>
3336 <content:encoded>&lt;p&gt;Previous project I was working on was being coded in
3337&lt;a href=&#34;https://golang.org/&#34;&gt;Golang&lt;/a&gt;. Also was my first project using it. And damn,
3338that was an awesome experience. The whole thing is just superb. From how errors
3339are handled. The C-like way you handle compiling. The way the language is
3340structured making it incredibly versatile and easy to learn.&lt;/p&gt;
3341&lt;p&gt;It may cause some pain for somebody that is not used of using interfaces to map
3342JSON and doing the recompilation all the time. But we have tools like
3343&lt;a href=&#34;http://eradman.com/entrproject/&#34;&gt;entr&lt;/a&gt; and
3344&lt;a href=&#34;https://www.gnu.org/software/make/&#34;&gt;make&lt;/a&gt; to fix that.&lt;/p&gt;
3345&lt;p&gt;But we are not here to talk about my undying love for &lt;strong&gt;Golang&lt;/strong&gt;. Only in some
3346way we probably should. It is an excellent example of how modern language should
3347be designed. And because I have used it extensively in the last couple of years
3348this probably taints my views of other languages. And is doing me a great
3349disservice. Nevertheless, here we are.&lt;/p&gt;
3350&lt;p&gt;About two years ago I started flirting with &lt;a href=&#34;https://nodejs.org/en/&#34;&gt;Node.js&lt;/a&gt;
3351for a project I started working on. What I wanted was to have things written in
3352a language that is widely used, and we could get additional developers for. As
3353much as &lt;strong&gt;Golang&lt;/strong&gt; is amazing it&#39;s really hard to get developers for it. Even
3354now. And after playing around with it for a week I felt in love with the speed
3355of iteration and massive package ecosystem. Do you want SSO? You got it! Do you
3356want some esoteric library for something? There is a strong chance somebody
3357wrote it. It is so extensive that you find yourself evaluating packages based on
3358&lt;strong&gt;GitHub stars&lt;/strong&gt; and number of contributors. You get swallowed by the vanity
3359metrics and that potentially will become the downfall of Node.js.&lt;/p&gt;
3360&lt;p&gt;Because of the sheer amount of choice I often got anxiety when choosing
3361libraries. Will I choose the correct one? Is this library something that will be
3362supported for a foreseeable future or not? I am used of using libraries that are
3363being in development for 10 years plus (Python, C) and that gave me some sort of
3364comfort. And it is probably unfair to Node.js and community to expect same
3365dedication.&lt;/p&gt;
3366&lt;p&gt;Moving forward ... Work started and things were great. &lt;strong&gt;Speed of iteration was
3367insane&lt;/strong&gt;. For some feature that I would need a day in Golang only took me hour
3368or two. I became lazy! Using packages all over the place. Falling into the same
3369trap as others. Packages on top of packages. And &lt;a href=&#34;https://www.npmjs.com/&#34;&gt;npm&lt;/a&gt;
3370didn&#39;t help at all. The way that the package manager works is just
3371horrendous. And not allowing to have node_modules outside the project is also
3372the stupidest idea ever.&lt;/p&gt;
3373&lt;p&gt;So at that point I started feeling the technical debt that comes with Node.js
3374and the whole ecosystem. What nobody tells you is that &lt;strong&gt;structuring large
3375Node.js apps&lt;/strong&gt; is more problematic than one would think. And going microservice
3376for every single thing is also a bad idea. The amount of networking you
3377introduce with that approach always ends up being a pain in the ass. And I don&#39;t
3378even want to go into system administration here. The overhead is
3379insane. Package-lock.json made many days feel like living hell for me. And I
3380would eat the cost of all this if it meant for better development
3381experience. Well, it didn&#39;t.&lt;/p&gt;
3382&lt;p&gt;The &lt;strong&gt;lack of Typescript&lt;/strong&gt; support in the interpreter is still mind boggling to
3383me. Why haven&#39;t they added native support yet for this is beyond me?! That would
3384have solved so many problems. Lack of type safety became a problem somewhere in
3385the middle of the project where the codebase was sufficiently large enough to
3386present problems. We started adding arguments to functions and there was &lt;strong&gt;no
3387way to implicitly define argument types&lt;/strong&gt;. And because at that point there were
3388a lot of functions, it became impossible to know what each one accepts,
3389development became more and more trial and error based.&lt;/p&gt;
3390&lt;p&gt;I tried &lt;strong&gt;implementing Typescript&lt;/strong&gt;, but that would present a large refactor
3391that we were not willing to do at that point. The benefits were not enough. I
3392also tried &lt;a href=&#34;https://flow.org/&#34;&gt;Flow - static type checker&lt;/a&gt; but implementation
3393was also horrible. What Typescript and Flow forces you is to have src folder and
3394then &lt;strong&gt;transpile&lt;/strong&gt; your code into dist folder and run it with node. WTH is that
3395all about. Why can&#39;t this be done in memory or some virtual file system? Why? I
3396see no reason why this couldn&#39;t be done like this. But it is what it is. I
3397abandoned all hope for static type checking.&lt;/p&gt;
3398&lt;p&gt;One of the problems that resulted from not having interfaces or types was
3399inability to model out our data from &lt;strong&gt;Elasticsearch&lt;/strong&gt;. I could have done a
3400&lt;strong&gt;pedestrian implementation&lt;/strong&gt; of it, but there must be a better way of doing
3401this without resorting to some hack basically. Or maybe I haven&#39;t found a
3402solution, which is also a possibility. I have looked, though. No juice!&lt;/p&gt;
3403&lt;p&gt;&lt;strong&gt;Error handling?&lt;/strong&gt; Is that a joke?&lt;/p&gt;
3404&lt;p&gt;Thank god for &lt;strong&gt;await/async&lt;/strong&gt;. Without it, I would have probably just abandoned
3405the whole thing and went with something else like Python. That&#39;s all I am going
3406to say about this :)&lt;/p&gt;
3407&lt;p&gt;I started asking myself a question if Node.js is actually ready to be used in a
3408&lt;strong&gt;large scale applications&lt;/strong&gt;? And this was a totally wrong question. What I
3409should have been asking myself was, how to use Node.js in large scale
3410application. And you don&#39;t get this in &lt;strong&gt;marketing material&lt;/strong&gt; for Express or Koa
3411etc. They never tell you this. Making Node.js scale on infrastructure or in
3412codebase is really &lt;strong&gt;more of an art than a science&lt;/strong&gt;. And just like with the
3413whole JavaScript ecosystem:&lt;/p&gt;
3414&lt;ul&gt;
3415&lt;li&gt;impossible to master,&lt;/li&gt;
3416&lt;li&gt;half of your time you work on your tooling,&lt;/li&gt;
3417&lt;li&gt;just accept transpilers that convert one code into another (holly smokes),&lt;/li&gt;
3418&lt;li&gt;error handling is a joke,&lt;/li&gt;
3419&lt;li&gt;standards? What standards?&lt;/li&gt;
3420&lt;/ul&gt;
3421&lt;p&gt;But on the other hand. As I did, you will also learn to love it. Learn to use it
3422quickly and do impossible things in crazy limited time.&lt;/p&gt;
3423&lt;p&gt;I hate to admit it. But I love Node.js. Dammit, I love it :)&lt;/p&gt;
3424&lt;p&gt;&lt;strong&gt;2023 Update&lt;/strong&gt;: I hate Node.js!&lt;/p&gt;
3425</content:encoded>
3426 </item>
3427
3428
3429
3430 <item>
3431 <title>The strange case of Elasticsearch allocation failure</title>
3432 <link>https://mitjafelicijan.com/the-strange-case-of-elasticsearch-allocation-failure.html</link>
3433 <pubDate>Sun, 29 Mar 2020 12:00:00 &#43;0200</pubDate>
3434 <guid>https://mitjafelicijan.com/the-strange-case-of-elasticsearch-allocation-failure.html</guid>
3435 <description>I&amp;#39;ve been using Elasticsearch in production for 5 years now and never had asingle problem with it.</description>
3436 <content:encoded>&lt;p&gt;I&#39;ve been using Elasticsearch in production for 5 years now and never had a
3437single problem with it. Hell, never even known there could be a problem. Just
3438worked. All this time. The first node that I deployed is still being used in
3439production, never updated, upgraded, touched in anyway.&lt;/p&gt;
3440&lt;p&gt;All this bliss came to an abrupt end this Friday when I got notification that
3441Elasticsearch cluster went warm. Well, warm is not that bad right? Wrong!
3442Quickly after that I got another email which sent chills down my spine. Cluster
3443is now red. RED! Now, shit really hit the fan!&lt;/p&gt;
3444&lt;p&gt;I tried googling what could be the problem and after executing allocation
3445function noticed that some shards were unassigned and 5 attempts were already
3446made (which is BTW to my luck the maximum) and that meant I am basically fucked.
3447They also applied that one should wait for cluster to re-balance itself. So, I
3448waited. One hour, two hours, several hours. Nothing, still RED.&lt;/p&gt;
3449&lt;p&gt;The strangest thing about it all was, that queries were still being fulfilled.
3450Data was coming out. On the outside it looked like nothing was wrong but
3451everybody that would look at the cluster would know immediately that something
3452was very very wrong and we were living on borrowed time here.&lt;/p&gt;
3453&lt;blockquote&gt;
3454&lt;p&gt;&lt;strong&gt;Please, DO NOT do what I did.&lt;/strong&gt; Seriously! Please ask someone on official
3455forums or if you know an expert please consult him. There could be million of
3456reasons and these solution fit my problem. Maybe in your case it would
3457disastrous. I had all the data backed up and even if I would fail spectacularly
3458I would be able to restore the data. It would be a huge pain and I would loose
3459couple of days but I had a plan B.&lt;/p&gt;
3460&lt;/blockquote&gt;
3461&lt;p&gt;Executing allocation and told me what the problem was but no clear solution yet.&lt;/p&gt;
3462&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GET /_cat/allocation?format=json
3463&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I got a message that &lt;code&gt;ALLOCATION_FAILED&lt;/code&gt; with additional info &lt;code&gt;failed to create shard, failure ioexception[failed to obtain in-memory shard lock]&lt;/code&gt;. Well
3464splendid! I must also say that our cluster is capable more than enough to handle
3465the traffic. Also JVM memory pressure never was an issue. So what happened
3466really then?&lt;/p&gt;
3467&lt;p&gt;I tried also re-routing failed ones with no success due to AWS restrictions on
3468having managed Elasticsearch cluster (they lock some of the functions).&lt;/p&gt;
3469&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;POST /_cluster/reroute?retry_failed=true
3470&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I got a message that significantly reduced my options.&lt;/p&gt;
3471&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
3472&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;Message&amp;#34;: &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Your request: &amp;#39;/_cluster/reroute&amp;#39; is not allowed.&amp;#34;&lt;/span&gt;
3473&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
3474&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After that I went on a hunt again. I won&#39;t bother you with all the details
3475because hours/days went by until I was finally able to re-index the problematic
3476index and hoped for the best. Until that moment even re-indexing was giving me
3477errors.&lt;/p&gt;
3478&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;POST _reindex
3479&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
3480&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;source&amp;#34;: {
3481&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;index&amp;#34;: &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;myindex&amp;#34;&lt;/span&gt;
3482&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; },
3483&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;dest&amp;#34;: {
3484&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;index&amp;#34;: &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;myindex-new&amp;#34;&lt;/span&gt;
3485&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
3486&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
3487&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;I needed to do this multiple times to get all the documents re-indexed. Then I
3488dropped the original one with the following command.&lt;/p&gt;
3489&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;DELETE /myindex
3490&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And re-indexed again new one in the original one (well by name only).&lt;/p&gt;
3491&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;POST _reindex
3492&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
3493&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;source&amp;#34;: {
3494&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;index&amp;#34;: &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;myindex-new&amp;#34;&lt;/span&gt;
3495&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; },
3496&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;dest&amp;#34;: {
3497&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;index&amp;#34;: &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;myindex&amp;#34;&lt;/span&gt;
3498&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
3499&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
3500&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;On the surface it looks like all is working but I have a long road in front of
3501me to get all the things working again. Cluster now shows that it is in Green
3502mode but I am also getting a notification that the cluster has processing status
3503which could mean million of things.&lt;/p&gt;
3504&lt;p&gt;Godspeed!&lt;/p&gt;
3505</content:encoded>
3506 </item>
3507
3508
3509
3510 <item>
3511 <title>Create placeholder images with sharp Node.js image processing library</title>
3512 <link>https://mitjafelicijan.com/create-placeholder-images-with-sharp.html</link>
3513 <pubDate>Fri, 27 Mar 2020 12:00:00 &#43;0200</pubDate>
3514 <guid>https://mitjafelicijan.com/create-placeholder-images-with-sharp.html</guid>
3515 <description>I have been searching for a solution to pre-generate some placeholder images forimage server I needed to develop that resizes images on S3.</description>
3516 <content:encoded>&lt;p&gt;I have been searching for a solution to pre-generate some placeholder images for
3517image server I needed to develop that resizes images on S3. I though this would
3518be a 15min job and quickly found out how very mistaken I was.&lt;/p&gt;
3519&lt;p&gt;Even though Node.js is not really the best way to do this kind of things (surely
3520something written in C or Rust or even Golang would be the correct way to do
3521this but we didn&#39;t need the speed in our case) I found an excellent library
3522&lt;a href=&#34;https://github.com/lovell/sharp&#34;&gt;sharp - High performance Node.js image
3523processing&lt;/a&gt;.&lt;/p&gt;
3524&lt;p&gt;Getting things running was a breeze.&lt;/p&gt;
3525&lt;h2 id=&#34;fetch-image-from-s3-and-save-resized&#34;&gt;Fetch image from S3 and save resized&lt;/h2&gt;
3526&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;const&lt;/span&gt; sharp = require(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;sharp&amp;#39;&lt;/span&gt;);
3527&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;const&lt;/span&gt; aws = require(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;aws-sdk&amp;#39;&lt;/span&gt;);
3528&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3529&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;const&lt;/span&gt; x,y = 100;
3530&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;const&lt;/span&gt; s3 = &lt;span style=&#34;color:#00f&#34;&gt;new&lt;/span&gt; aws.S3({});
3531&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3532&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;aws.config.update({
3533&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; secretAccessKey: &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;secretAccessKey&amp;#39;&lt;/span&gt;,
3534&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; accessKeyId: &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;accessKeyId&amp;#39;&lt;/span&gt;,
3535&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; region: &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;region&amp;#39;&lt;/span&gt;
3536&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});
3537&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3538&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;const&lt;/span&gt; originalImage = &lt;span style=&#34;color:#00f&#34;&gt;await&lt;/span&gt; s3.getObject({
3539&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; Bucket: &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;some-bucket-name&amp;#39;&lt;/span&gt;,
3540&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; Key: &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;image.jpg&amp;#39;&lt;/span&gt;,
3541&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}).promise();
3542&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3543&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;const&lt;/span&gt; resizedImage = &lt;span style=&#34;color:#00f&#34;&gt;await&lt;/span&gt; sharp(originalImage.Body)
3544&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; .resize(x, y)
3545&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; .jpeg({ progressive: &lt;span style=&#34;color:#00f&#34;&gt;true&lt;/span&gt; })
3546&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; .toBuffer();
3547&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3548&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;s3.putObject({
3549&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; Bucket: &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;some-bucket-name&amp;#39;&lt;/span&gt;,
3550&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; Key: &lt;span style=&#34;color:#a31515&#34;&gt;`optimized/&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;${&lt;/span&gt;x&lt;span style=&#34;color:#a31515&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;x&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;${&lt;/span&gt;y&lt;span style=&#34;color:#a31515&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;/image.jpg`&lt;/span&gt;,
3551&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; Body: resizedImage,
3552&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ContentType: &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;image/jpeg&amp;#39;&lt;/span&gt;,
3553&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ACL: &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;public-read&amp;#39;&lt;/span&gt;
3554&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}).promise();
3555&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;All this code was wrapped inside a web service with some additional security
3556checks and defensive coding to detect if key is missing on S3.&lt;/p&gt;
3557&lt;p&gt;And at that point I needed to return placeholder images as a response in case
3558key is missing or x,y are not allowed by the server etc. I could have created
3559PNG in Gimp and just serve them but I wanted to respect aspect ratio and I
3560didn&#39;t want to return some mangled images.&lt;/p&gt;
3561&lt;blockquote&gt;
3562&lt;p&gt;Main problem with finding a clean solution I could copy and paste and change a
3563bit was a task. API is changing constantly and there weren&#39;t clear examples or
3564I was unable to find them.&lt;/p&gt;
3565&lt;/blockquote&gt;
3566&lt;h2 id=&#34;generating-placeholder-images-using-svg&#34;&gt;Generating placeholder images using SVG&lt;/h2&gt;
3567&lt;p&gt;What I ended up was using SVG to generate text and created image with sharp and
3568used composition to combine both layers. Response returned by this function is a
3569buffer you can use to either upload to S3 or save to local file.&lt;/p&gt;
3570&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;const&lt;/span&gt; generatePlaceholderImageWithText = &lt;span style=&#34;color:#00f&#34;&gt;async&lt;/span&gt; (width, height, message) =&amp;gt; {
3571&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;const&lt;/span&gt; overlay = &lt;span style=&#34;color:#a31515&#34;&gt;`&amp;lt;svg width=&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;${&lt;/span&gt;width - 20&lt;span style=&#34;color:#a31515&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34; height=&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;${&lt;/span&gt;height - 20&lt;span style=&#34;color:#a31515&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&amp;gt;
3572&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt; &amp;lt;text x=&amp;#34;50%&amp;#34; y=&amp;#34;50%&amp;#34; font-family=&amp;#34;sans-serif&amp;#34; font-size=&amp;#34;16&amp;#34; text-anchor=&amp;#34;middle&amp;#34;&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;${&lt;/span&gt;message&lt;span style=&#34;color:#a31515&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&amp;lt;/text&amp;gt;
3573&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt; &amp;lt;/svg&amp;gt;`&lt;/span&gt;;
3574&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3575&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;await&lt;/span&gt; sharp({
3576&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; create: {
3577&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; width: width,
3578&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; height: height,
3579&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; channels: 4,
3580&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; background: { r: 230, g: 230, b: 230, alpha: 1 }
3581&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
3582&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; })
3583&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; .composite([{
3584&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; input: Buffer.from(overlay),
3585&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; gravity: &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;center&amp;#39;&lt;/span&gt;,
3586&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }])
3587&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; .jpeg()
3588&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; .toBuffer();
3589&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
3590&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That is about it. Nothing more to it. You can change the color of the image by
3591changing &lt;code&gt;background&lt;/code&gt; and if you want to change text styling you can adapt SVG
3592to your needs.&lt;/p&gt;
3593&lt;blockquote&gt;
3594&lt;p&gt;Also be careful about the length of the text. This function positions text at
3595the center and adds &lt;code&gt;20px&lt;/code&gt; padding on all sides. If text is longer than the
3596image it will get cut.&lt;/p&gt;
3597&lt;/blockquote&gt;
3598</content:encoded>
3599 </item>
3600
3601
3602
3603 <item>
3604 <title>Simple Server-Sent Events based PubSub Server</title>
3605 <link>https://mitjafelicijan.com/simple-server-sent-events-based-pubsub-server.html</link>
3606 <pubDate>Sun, 22 Mar 2020 12:00:00 &#43;0200</pubDate>
3607 <guid>https://mitjafelicijan.com/simple-server-sent-events-based-pubsub-server.html</guid>
3608 <description>Before we continue .</description>
3609 <content:encoded>&lt;h2 id=&#34;before-we-continue-&#34;&gt;Before we continue ...&lt;/h2&gt;
3610&lt;p&gt;Publisher Subscriber model is nothing new and there are many amazing solutions
3611out there, so writing a new one would be a waste of time if other solutions
3612wouldn&#39;t have quite complex install procedures and weren&#39;t so hard to maintain.
3613But to be fair, comparing this simple server with something like
3614&lt;a href=&#34;https://kafka.apache.org/&#34;&gt;Kafka&lt;/a&gt; or &lt;a href=&#34;https://www.rabbitmq.com/&#34;&gt;RabbitMQ&lt;/a&gt; is
3615laughable at the least. Those solutions are enterprise grade and have many
3616mechanisms there to ensure messages aren&#39;t lost and much more. Regardless of
3617these drawbacks, this method has been tested on a large website and worked until
3618now without any problems. So now, that we got that cleared up, let&#39;s continue.&lt;/p&gt;
3619&lt;p&gt;&lt;em&gt;&lt;strong&gt;Wiki definition:&lt;/strong&gt; Publish/subscribe messaging, or pub/sub messaging, is a
3620form of asynchronous service-to-service communication used in serverless and
3621microservices architectures. In a pub/sub model, any message published to a
3622topic is immediately received by all the subscribers to the topic.&lt;/em&gt;&lt;/p&gt;
3623&lt;h2 id=&#34;general-goals&#34;&gt;General goals&lt;/h2&gt;
3624&lt;ul&gt;
3625&lt;li&gt;provide a simple server that relays messages to all the connected clients,&lt;/li&gt;
3626&lt;li&gt;messages can be posted on specific topics,&lt;/li&gt;
3627&lt;li&gt;messages get sent via &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events&#34;&gt;Server-Sent
3628Events&lt;/a&gt;
3629to all the subscribers.&lt;/li&gt;
3630&lt;/ul&gt;
3631&lt;h2 id=&#34;how-exactly-does-the-pubsub-model-work&#34;&gt;How exactly does the pub/sub model work?&lt;/h2&gt;
3632&lt;p&gt;The easiest way to explain this is with diagram bellow. Basic function is
3633simple. We have subscribers that receive messages, and we have publishers that
3634create and post messages. Similar model is also well know pattern that works on
3635a premise of consumers and producers, and they take similar roles.&lt;/p&gt;
3636&lt;figure&gt;
3637&lt;img src=&#34;/posts/simple-pubsub-server/pubsub-overview.png&#34; alt=&#34;How PubSub works&#34; /&gt;
3638&lt;/figure&gt;
3639&lt;p&gt;&lt;strong&gt;These are some naive characteristics we want to achieve:&lt;/strong&gt;&lt;/p&gt;
3640&lt;ul&gt;
3641&lt;li&gt;producer is publishing messages to subscribe topic,&lt;/li&gt;
3642&lt;li&gt;consumer is receiving messages from subscribed topic,&lt;/li&gt;
3643&lt;li&gt;servers is also known as Broker,&lt;/li&gt;
3644&lt;li&gt;broker does not store messages or tracks success,&lt;/li&gt;
3645&lt;li&gt;broker uses
3646&lt;a href=&#34;https://en.wikipedia.org/wiki/FIFO_(computing_and_electronics)&#34;&gt;FIFO&lt;/a&gt; method
3647for delivering messages,&lt;/li&gt;
3648&lt;li&gt;if consumer wants to receive messages from a topic, producer and consumer
3649topics must match,&lt;/li&gt;
3650&lt;li&gt;consumer can subscribe to multiple topics,&lt;/li&gt;
3651&lt;li&gt;producer can publish to multiple topics,&lt;/li&gt;
3652&lt;li&gt;each message has a messageId.&lt;/li&gt;
3653&lt;/ul&gt;
3654&lt;p&gt;&lt;strong&gt;Known drawbacks:&lt;/strong&gt;&lt;/p&gt;
3655&lt;ul&gt;
3656&lt;li&gt;messages will not be stored in a persistent queue or unreceived messages like
3657&lt;a href=&#34;https://en.wikipedia.org/wiki/Dead_letter_queue&#34;&gt;DeadLetterQueue&lt;/a&gt; so old
3658messages could be lost on server restart,&lt;/li&gt;
3659&lt;li&gt;&lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events&#34;&gt;Server-Sent
3660Events&lt;/a&gt;
3661opens a long-running connection between the client and the server so make sure
3662if your setup is load balanced that the load balancer in this case can have
3663long opened connection,&lt;/li&gt;
3664&lt;li&gt;no system moderation due to the dynamic nature of creating queues.&lt;/li&gt;
3665&lt;/ul&gt;
3666&lt;h2 id=&#34;server-sent-events&#34;&gt;Server-Sent Events&lt;/h2&gt;
3667&lt;p&gt;Read more about it on &lt;a href=&#34;https://html.spec.whatwg.org/multipage/server-sent-events.html&#34;&gt;official specification
3668page&lt;/a&gt;.&lt;/p&gt;
3669&lt;h3 id=&#34;current-browser-support&#34;&gt;Current browser support&lt;/h3&gt;
3670&lt;figure&gt;
3671&lt;img src=&#34;/posts/simple-pubsub-server/caniuse.png&#34; alt=&#34;Browser support&#34; /&gt;
3672&lt;/figure&gt;
3673&lt;p&gt;Check
3674&lt;a href=&#34;https://caniuse.com/#feat=eventsource&#34;&gt;https://caniuse.com/#feat=eventsource&lt;/a&gt;
3675for latest information about browser support.&lt;/p&gt;
3676&lt;h3 id=&#34;known-issues&#34;&gt;Known issues&lt;/h3&gt;
3677&lt;ul&gt;
3678&lt;li&gt;Firefox 52 and below do not support EventSource in web/shared workers&lt;/li&gt;
3679&lt;li&gt;In Firefox prior to version 36 server-sent events do not reconnect
3680automatically in case of a connection interrupt (bug)&lt;/li&gt;
3681&lt;li&gt;Reportedly, CORS in EventSource is currently supported in Firefox 10&#43;, Opera
368212&#43;, Chrome 26&#43;, Safari 7.0&#43;.&lt;/li&gt;
3683&lt;li&gt;Antivirus software may block the event streaming data chunks.&lt;/li&gt;
3684&lt;/ul&gt;
3685&lt;p&gt;Source: &lt;a href=&#34;https://caniuse.com/#feat=eventsource&#34;&gt;https://caniuse.com/#feat=eventsource&lt;/a&gt;&lt;/p&gt;
3686&lt;h3 id=&#34;message-format&#34;&gt;Message format&lt;/h3&gt;
3687&lt;p&gt;The simplest message that can be sent is only with data attribute:&lt;/p&gt;
3688&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;data: this is a simple message
3689&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;blank line&amp;gt;
3690&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You can send message IDs to be used if the connection is dropped:&lt;/p&gt;
3691&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;id: 33
3692&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;data: this is line one
3693&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;data: this is line two
3694&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;blank line&amp;gt;
3695&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And you can specify your own event types (the above messages will all trigger
3696the message event):&lt;/p&gt;
3697&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;id: 36
3698&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;event: price
3699&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;data: 103.34
3700&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;blank line&amp;gt;
3701&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;server-requirements&#34;&gt;Server requirements&lt;/h3&gt;
3702&lt;p&gt;The important thing is how you send headers and which headers are sent by the
3703server that triggers browser to threat response as a EventStream.&lt;/p&gt;
3704&lt;p&gt;Headers responsible for this are:&lt;/p&gt;
3705&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Content-Type: text/event-stream
3706&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Cache-Control: no-cache
3707&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Connection: keep-alive
3708&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;debugging-with-google-chrome&#34;&gt;Debugging with Google Chrome&lt;/h3&gt;
3709&lt;p&gt;Google Chrome provides build-in debugging and exploration tool for &lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events&#34;&gt;Server-Sent
3710Events&lt;/a&gt;
3711which is quite nice and available from Developer Tools under Network tab.&lt;/p&gt;
3712&lt;blockquote&gt;
3713&lt;p&gt;You can debug only client side events that get received and not the server
3714ones. For debugging server events add &lt;code&gt;console.log&lt;/code&gt; to &lt;code&gt;server.js&lt;/code&gt; code and
3715print out events.&lt;/p&gt;
3716&lt;/blockquote&gt;
3717&lt;figure&gt;
3718&lt;img src=&#34;/posts/simple-pubsub-server/chrome-debugging.png&#34; alt=&#34;Google Chrome Developer Tools EventStream&#34; /&gt;
3719&lt;/figure&gt;
3720&lt;h2 id=&#34;server-implementation&#34;&gt;Server implementation&lt;/h2&gt;
3721&lt;p&gt;For the sake of this example we will use &lt;a href=&#34;https://nodejs.org/en/&#34;&gt;Node.js&lt;/a&gt; with
3722&lt;a href=&#34;https://expressjs.com&#34;&gt;Express&lt;/a&gt; as our router since this is the easiest way to
3723get started and we will use already written SSE library for node
3724&lt;a href=&#34;https://www.npmjs.com/package/sse-pubsub&#34;&gt;sse-pubsub&lt;/a&gt; so we don&#39;t reinvent the
3725wheel.&lt;/p&gt;
3726&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm init --yes
3727&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3728&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm install express
3729&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm install body-parser
3730&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;npm install sse-pubsub
3731&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Basic implementation of a server (&lt;code&gt;server.js&lt;/code&gt;):&lt;/p&gt;
3732&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;const&lt;/span&gt; express = require(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;express&amp;#39;&lt;/span&gt;);
3733&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;const&lt;/span&gt; bodyParser = require(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;body-parser&amp;#39;&lt;/span&gt;);
3734&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;const&lt;/span&gt; SSETopic = require(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;sse-pubsub&amp;#39;&lt;/span&gt;);
3735&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3736&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;const&lt;/span&gt; app = express();
3737&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;const&lt;/span&gt; port = process.env.PORT || 4000;
3738&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3739&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;// topics container
3740&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#00f&#34;&gt;const&lt;/span&gt; sseTopics = {};
3741&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3742&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;app.use(bodyParser.json());
3743&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3744&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;// open for all cors
3745&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt;app.all(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;*&amp;#39;&lt;/span&gt;, (req, res, next) =&amp;gt; {
3746&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; res.header(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;Access-Control-Allow-Origin&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;*&amp;#39;&lt;/span&gt;);
3747&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; res.header(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;Access-Control-Allow-Headers&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;X-Requested-With, Content-Type&amp;#39;&lt;/span&gt;);
3748&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; next();
3749&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});
3750&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3751&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;// preflight request error fix
3752&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt;app.options(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;*&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#00f&#34;&gt;async&lt;/span&gt; (req, res) =&amp;gt; {
3753&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; res.header(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;Access-Control-Allow-Origin&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;*&amp;#39;&lt;/span&gt;);
3754&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; res.header(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;Access-Control-Allow-Headers&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;X-Requested-With, Content-Type&amp;#39;&lt;/span&gt;);
3755&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; res.send(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;OK&amp;#39;&lt;/span&gt;);
3756&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});
3757&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3758&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;// serve the event streams
3759&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt;app.get(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;/stream/:topic&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#00f&#34;&gt;async&lt;/span&gt; (req, res, next) =&amp;gt; {
3760&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;const&lt;/span&gt; topic = req.params.topic;
3761&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3762&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt; (!(topic &lt;span style=&#34;color:#00f&#34;&gt;in&lt;/span&gt; sseTopics)) {
3763&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; sseTopics[topic] = &lt;span style=&#34;color:#00f&#34;&gt;new&lt;/span&gt; SSETopic({
3764&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; pingInterval: 0,
3765&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; maxStreamDuration: 15000,
3766&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; });
3767&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
3768&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3769&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;// subscribing client to topic
3770&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt; sseTopics[topic].subscribe(req, res);
3771&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});
3772&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3773&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;// accepts new messages into topic
3774&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt;app.post(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;/publish&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#00f&#34;&gt;async&lt;/span&gt; (req, res) =&amp;gt; {
3775&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;let&lt;/span&gt; body = req.body;
3776&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;let&lt;/span&gt; status = 200;
3777&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3778&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; console.log(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;Incoming message:&amp;#39;&lt;/span&gt;, req.body);
3779&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3780&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt; (
3781&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; body.hasOwnProperty(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;topic&amp;#39;&lt;/span&gt;) &amp;amp;&amp;amp;
3782&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; body.hasOwnProperty(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;event&amp;#39;&lt;/span&gt;) &amp;amp;&amp;amp;
3783&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; body.hasOwnProperty(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;message&amp;#39;&lt;/span&gt;)
3784&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ) {
3785&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;const&lt;/span&gt; topic = req.body.topic;
3786&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;const&lt;/span&gt; event = req.body.event;
3787&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;const&lt;/span&gt; message = req.body.message;
3788&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3789&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt; (topic &lt;span style=&#34;color:#00f&#34;&gt;in&lt;/span&gt; sseTopics) {
3790&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;// sends message to all the subscribers
3791&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt; sseTopics[topic].publish(message, event);
3792&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
3793&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; } &lt;span style=&#34;color:#00f&#34;&gt;else&lt;/span&gt; {
3794&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; status = 400;
3795&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
3796&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3797&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; res.status(status).send({
3798&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; status,
3799&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; });
3800&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});
3801&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3802&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;// returns JSON object of all opened topics
3803&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt;app.get(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;/status&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#00f&#34;&gt;async&lt;/span&gt; (req, res) =&amp;gt; {
3804&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; res.send(sseTopics);
3805&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});
3806&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3807&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;// health-check endpoint
3808&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt;app.get(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;/&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#00f&#34;&gt;async&lt;/span&gt; (req, res) =&amp;gt; {
3809&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; res.send(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;OK&amp;#39;&lt;/span&gt;);
3810&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});
3811&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3812&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;// return a 404 if no routes match
3813&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt;app.use((req, res, next) =&amp;gt; {
3814&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; res.set(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;Cache-Control&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;private, no-store&amp;#39;&lt;/span&gt;);
3815&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; res.status(404).end(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;Not found&amp;#39;&lt;/span&gt;);
3816&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});
3817&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3818&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;// starts the server
3819&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt;app.listen(port, () =&amp;gt; {
3820&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; console.log(&lt;span style=&#34;color:#a31515&#34;&gt;`PubSub server running on http://localhost:&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;${&lt;/span&gt;port&lt;span style=&#34;color:#a31515&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;`&lt;/span&gt;);
3821&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;});
3822&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;our-custom-message-format&#34;&gt;Our custom message format&lt;/h3&gt;
3823&lt;p&gt;Each message posted on a server must be in a specific format that out server
3824accepts. Having structure like this allows us to have multiple separated type of
3825events on each topic.&lt;/p&gt;
3826&lt;p&gt;With this we can separate streams and only receive events that belong to the
3827topic.&lt;/p&gt;
3828&lt;p&gt;One example would be, that we have index page and we want to receive messages
3829about new upvotes or new subscribers but we don&#39;t want to follow events for
3830other pages. This reduces clutter and overall network. And structure is much
3831nicer and maintanable.&lt;/p&gt;
3832&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
3833&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;topic&amp;#34;: &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;sample-topic&amp;#34;&lt;/span&gt;,
3834&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;event&amp;#34;: &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;sample-event&amp;#34;&lt;/span&gt;,
3835&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;message&amp;#34;: { &amp;#34;name&amp;#34;: &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;John&amp;#34;&lt;/span&gt; }
3836&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
3837&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;publisher-and-subscriber-clients&#34;&gt;Publisher and subscriber clients&lt;/h2&gt;
3838&lt;h3 id=&#34;publisher-and-subscriber-in-action&#34;&gt;Publisher and subscriber in action&lt;/h3&gt;
3839&lt;p&gt;&lt;video src=&#34;/posts/simple-pubsub-server/clients.m4v&#34; controls&gt;&lt;/video&gt;&lt;/p&gt;
3840&lt;p&gt;You can download &lt;a href=&#34;../simple-pubsub-server/sse-pubsub-server.zip&#34;&gt;the code&lt;/a&gt; and
3841follow along.&lt;/p&gt;
3842&lt;h3 id=&#34;publisher&#34;&gt;Publisher&lt;/h3&gt;
3843&lt;p&gt;As talked about above publisher is the one that send messages to the
3844broker/server. Message inside the payload can be whatever you want (string,
3845object, array). I would however personally avoid send large chunks of data like
3846blobs and such.&lt;/p&gt;
3847&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
3848&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;html lang=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;en&amp;#34;&lt;/span&gt;&amp;gt;
3849&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3850&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;head&amp;gt;
3851&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;meta charset=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;UTF-8&amp;#34;&lt;/span&gt;&amp;gt;
3852&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;meta name=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;viewport&amp;#34;&lt;/span&gt; content=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;width=device-width, initial-scale=1.0&amp;#34;&lt;/span&gt;&amp;gt;
3853&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;title&amp;gt;Publisher&amp;lt;/title&amp;gt;
3854&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;/head&amp;gt;
3855&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3856&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;body&amp;gt;
3857&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3858&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;h1&amp;gt;Publisher&amp;lt;/h1&amp;gt;
3859&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3860&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;fieldset&amp;gt;
3861&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;p&amp;gt;
3862&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;label&amp;gt;Server:&amp;lt;/label&amp;gt;
3863&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;input type=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;text&amp;#34;&lt;/span&gt; id=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;server&amp;#34;&lt;/span&gt; value=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;http://localhost:4000&amp;#34;&lt;/span&gt;&amp;gt;
3864&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;/p&amp;gt;
3865&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;p&amp;gt;
3866&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;label&amp;gt;Topic:&amp;lt;/label&amp;gt;
3867&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;input type=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;text&amp;#34;&lt;/span&gt; id=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;topic&amp;#34;&lt;/span&gt; value=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;sample-topic&amp;#34;&lt;/span&gt;&amp;gt;
3868&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;/p&amp;gt;
3869&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;p&amp;gt;
3870&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;label&amp;gt;Event:&amp;lt;/label&amp;gt;
3871&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;input type=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;text&amp;#34;&lt;/span&gt; id=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;event&amp;#34;&lt;/span&gt; value=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;sample-event&amp;#34;&lt;/span&gt;&amp;gt;
3872&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;/p&amp;gt;
3873&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;p&amp;gt;
3874&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;label&amp;gt;Message:&amp;lt;/label&amp;gt;
3875&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;input type=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;text&amp;#34;&lt;/span&gt; id=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;message&amp;#34;&lt;/span&gt; value=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;{&amp;#34;name&amp;#34;: &amp;#34;John&amp;#34;}&amp;#39;&lt;/span&gt;&amp;gt;
3876&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;/p&amp;gt;
3877&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;p&amp;gt;
3878&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;button type=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;button&amp;#34;&lt;/span&gt; id=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;button&amp;#34;&lt;/span&gt;&amp;gt;Publish message to topic&amp;lt;/button&amp;gt;
3879&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;/p&amp;gt;
3880&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;/fieldset&amp;gt;
3881&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3882&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;script&amp;gt;
3883&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3884&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;const&lt;/span&gt; button = document.querySelector(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;#button&amp;#39;&lt;/span&gt;);
3885&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;const&lt;/span&gt; server = document.querySelector(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;#server&amp;#39;&lt;/span&gt;);
3886&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;const&lt;/span&gt; topic = document.querySelector(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;#topic&amp;#39;&lt;/span&gt;);
3887&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;const&lt;/span&gt; event = document.querySelector(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;#event&amp;#39;&lt;/span&gt;);
3888&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;const&lt;/span&gt; message = document.querySelector(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;#message&amp;#39;&lt;/span&gt;);
3889&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3890&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; button.addEventListener(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;click&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#00f&#34;&gt;async&lt;/span&gt; (evt) =&amp;gt; {
3891&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;const&lt;/span&gt; req = &lt;span style=&#34;color:#00f&#34;&gt;await&lt;/span&gt; fetch(&lt;span style=&#34;color:#a31515&#34;&gt;`&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;${&lt;/span&gt;server.value&lt;span style=&#34;color:#a31515&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;/publish`&lt;/span&gt;, {
3892&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; method: &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;post&amp;#39;&lt;/span&gt;,
3893&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; headers: {
3894&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;Accept&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;application/json&amp;#39;&lt;/span&gt;,
3895&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;Content-Type&amp;#39;&lt;/span&gt;: &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;application/json&amp;#39;&lt;/span&gt;,
3896&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; },
3897&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; body: JSON.stringify({
3898&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; topic: topic.value,
3899&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; event: event.value,
3900&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; message: JSON.parse(message.value),
3901&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }),
3902&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; });
3903&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3904&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;const&lt;/span&gt; res = &lt;span style=&#34;color:#00f&#34;&gt;await&lt;/span&gt; req.json();
3905&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; console.log(res);
3906&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; });
3907&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3908&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;/script&amp;gt;
3909&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3910&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;/body&amp;gt;
3911&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3912&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/html&amp;gt;
3913&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;subscriber&#34;&gt;Subscriber&lt;/h3&gt;
3914&lt;p&gt;Subscriber is responsible for receiving new messages that come from server via
3915publisher. The code bellow is very rudimentary but works and follows the
3916implementation guidelines for EventSource.&lt;/p&gt;
3917&lt;p&gt;You can use either Developer Tools Console to see incoming messages or you can
3918defer to Debugging with Google Chrome section above to see all EventStream
3919messages.&lt;/p&gt;
3920&lt;blockquote&gt;
3921&lt;p&gt;Don&#39;t be alarmed if the subscriber gets disconnected from the server every so
3922often. The code we have here resets connection every 15s but it automatically
3923get reconnected and fetches all messages up to last received message id. This
3924setting can be adjusted in &lt;code&gt;server.js&lt;/code&gt; file; search for the
3925&lt;code&gt;maxStreamDuration&lt;/code&gt; variable.&lt;/p&gt;
3926&lt;/blockquote&gt;
3927&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
3928&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;html lang=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;en&amp;#34;&lt;/span&gt;&amp;gt;
3929&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3930&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;head&amp;gt;
3931&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;meta charset=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;UTF-8&amp;#34;&lt;/span&gt;&amp;gt;
3932&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;meta name=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;viewport&amp;#34;&lt;/span&gt; content=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;width=device-width, initial-scale=1.0&amp;#34;&lt;/span&gt;&amp;gt;
3933&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;title&amp;gt;Subscriber&amp;lt;/title&amp;gt;
3934&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;link rel=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt; href=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;style.css&amp;#34;&lt;/span&gt;&amp;gt;
3935&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;/head&amp;gt;
3936&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3937&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;body&amp;gt;
3938&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3939&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;h1&amp;gt;Subscriber&amp;lt;/h1&amp;gt;
3940&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3941&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;fieldset&amp;gt;
3942&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;p&amp;gt;
3943&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;label&amp;gt;Server:&amp;lt;/label&amp;gt;
3944&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;input type=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;text&amp;#34;&lt;/span&gt; id=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;server&amp;#34;&lt;/span&gt; value=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;http://localhost:4000&amp;#34;&lt;/span&gt;&amp;gt;
3945&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;/p&amp;gt;
3946&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;p&amp;gt;
3947&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;label&amp;gt;Topic:&amp;lt;/label&amp;gt;
3948&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;input type=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;text&amp;#34;&lt;/span&gt; id=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;topic&amp;#34;&lt;/span&gt; value=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;sample-topic&amp;#34;&lt;/span&gt;&amp;gt;
3949&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;/p&amp;gt;
3950&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;p&amp;gt;
3951&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;label&amp;gt;Event:&amp;lt;/label&amp;gt;
3952&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;input type=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;text&amp;#34;&lt;/span&gt; id=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;event&amp;#34;&lt;/span&gt; value=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;sample-event&amp;#34;&lt;/span&gt;&amp;gt;
3953&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;/p&amp;gt;
3954&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;p&amp;gt;
3955&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;button type=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;button&amp;#34;&lt;/span&gt; id=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;button&amp;#34;&lt;/span&gt;&amp;gt;Subscribe to topic&amp;lt;/button&amp;gt;
3956&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;/p&amp;gt;
3957&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;/fieldset&amp;gt;
3958&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3959&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;script&amp;gt;
3960&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3961&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;const&lt;/span&gt; button = document.querySelector(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;#button&amp;#39;&lt;/span&gt;);
3962&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;const&lt;/span&gt; server = document.querySelector(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;#server&amp;#39;&lt;/span&gt;);
3963&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;const&lt;/span&gt; topic = document.querySelector(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;#topic&amp;#39;&lt;/span&gt;);
3964&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;const&lt;/span&gt; event = document.querySelector(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;#event&amp;#39;&lt;/span&gt;);
3965&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3966&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; button.addEventListener(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;click&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#00f&#34;&gt;async&lt;/span&gt; (evt) =&amp;gt; {
3967&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3968&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;let&lt;/span&gt; es = &lt;span style=&#34;color:#00f&#34;&gt;new&lt;/span&gt; EventSource(&lt;span style=&#34;color:#a31515&#34;&gt;`&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;${&lt;/span&gt;server.value&lt;span style=&#34;color:#a31515&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;/stream/&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;${&lt;/span&gt;topic.value&lt;span style=&#34;color:#a31515&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;`&lt;/span&gt;);
3969&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3970&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; es.addEventListener(event.value, &lt;span style=&#34;color:#00f&#34;&gt;function&lt;/span&gt; (evt) {
3971&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; console.log(&lt;span style=&#34;color:#a31515&#34;&gt;`incoming message`&lt;/span&gt;, JSON.parse(evt.data));
3972&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; });
3973&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3974&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; es.addEventListener(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;open&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#00f&#34;&gt;function&lt;/span&gt; (evt) {
3975&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; console.log(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;connected&amp;#39;&lt;/span&gt;, evt);
3976&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; });
3977&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3978&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; es.addEventListener(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;error&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#00f&#34;&gt;function&lt;/span&gt; (evt) {
3979&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; console.log(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;error&amp;#39;&lt;/span&gt;, evt);
3980&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; });
3981&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3982&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; });
3983&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3984&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;/script&amp;gt;
3985&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3986&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;/body&amp;gt;
3987&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
3988&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/html&amp;gt;
3989&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;reading-further&#34;&gt;Reading further&lt;/h2&gt;
3990&lt;ul&gt;
3991&lt;li&gt;&lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events&#34;&gt;Using server-sent events&lt;/a&gt;&lt;/li&gt;
3992&lt;li&gt;&lt;a href=&#34;https://www.smashingmagazine.com/2018/02/sse-websockets-data-flow-http2/&#34;&gt;Using SSE Instead Of WebSockets For Unidirectional Data Flow Over HTTP/2&lt;/a&gt;&lt;/li&gt;
3993&lt;li&gt;&lt;a href=&#34;https://apifriends.com/api-streaming/server-sent-events/&#34;&gt;What is Server-Sent Events?&lt;/a&gt;&lt;/li&gt;
3994&lt;li&gt;&lt;a href=&#34;https://tools.ietf.org/id/draft-xie-bidirectional-messaging-01.html&#34;&gt;An HTTP/2 extension for bidirectional messaging communication&lt;/a&gt;&lt;/li&gt;
3995&lt;li&gt;&lt;a href=&#34;https://developers.google.com/web/fundamentals/performance/http2&#34;&gt;Introduction to HTTP/2&lt;/a&gt;&lt;/li&gt;
3996&lt;li&gt;&lt;a href=&#34;https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API&#34;&gt;The WebSocket API (WebSockets)&lt;/a&gt;&lt;/li&gt;
3997&lt;/ul&gt;
3998</content:encoded>
3999 </item>
4000
4001
4002
4003 <item>
4004 <title>Using sentiment analysis for clickbait detection in RSS feeds</title>
4005 <link>https://mitjafelicijan.com/using-sentiment-analysis-for-clickbait-detection-in-rss-feeds.html</link>
4006 <pubDate>Sat, 19 Oct 2019 12:00:00 &#43;0200</pubDate>
4007 <guid>https://mitjafelicijan.com/using-sentiment-analysis-for-clickbait-detection-in-rss-feeds.html</guid>
4008 <description>Initial thoughtsOne of the things that interested me for a while now is if major wellestablished news sites use click bait titles to drive additional traffic totheir sites and generate additional impressions.</description>
4009 <content:encoded>&lt;h2 id=&#34;initial-thoughts&#34;&gt;Initial thoughts&lt;/h2&gt;
4010&lt;p&gt;One of the things that interested me for a while now is if major well
4011established news sites use click bait titles to drive additional traffic to
4012their sites and generate additional impressions.&lt;/p&gt;
4013&lt;p&gt;Goal is to see how article titles and actual content of article differ from each
4014other and see if titles are clickbaited.&lt;/p&gt;
4015&lt;h2 id=&#34;preparing-and-cleaning-data&#34;&gt;Preparing and cleaning data&lt;/h2&gt;
4016&lt;p&gt;For this example I opted to just use RSS feed from a new website and decided to
4017go with &lt;a href=&#34;https://www.theguardian.com&#34;&gt;The Guardian&lt;/a&gt; World news. While this gets
4018us limited data (~40) articles and also description (actual content) is trimmed
4019this really doesn&#39;t reflect the actual article contents.&lt;/p&gt;
4020&lt;p&gt;To get better content I could use web scraping and use RSS as link list and
4021fetch contents directly from website, but for this simple example this will
4022suffice.&lt;/p&gt;
4023&lt;p&gt;There are couple of requirements we need to install before we continue:&lt;/p&gt;
4024&lt;ul&gt;
4025&lt;li&gt;&lt;code&gt;pip3 install feedparser&lt;/code&gt; (parses RSS feed from url)&lt;/li&gt;
4026&lt;li&gt;&lt;code&gt;pip3 install vaderSentiment&lt;/code&gt; (does sentiment polarity analysis)&lt;/li&gt;
4027&lt;li&gt;&lt;code&gt;pip3 install matplotlib&lt;/code&gt; (plots chart of results)&lt;/li&gt;
4028&lt;/ul&gt;
4029&lt;p&gt;So first we need to fetch RSS data and sanitize HTML content from description.&lt;/p&gt;
4030&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; re
4031&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; feedparser
4032&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4033&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;feed_url = &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;https://www.theguardian.com/world/rss&amp;#34;&lt;/span&gt;
4034&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;feed = feedparser.parse(feed_url)
4035&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4036&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# sanitize html&lt;/span&gt;
4037&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;for&lt;/span&gt; item &lt;span style=&#34;color:#00f&#34;&gt;in&lt;/span&gt; feed.entries:
4038&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; item.description = re.sub(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;&amp;lt;[^&amp;lt;]&#43;?&amp;gt;&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;&amp;#39;&lt;/span&gt;, item.description)
4039&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;perform-sentiment-analysis&#34;&gt;Perform sentiment analysis&lt;/h2&gt;
4040&lt;p&gt;Since we now have cleaned up data in our &lt;code&gt;feed.entries&lt;/code&gt; object we can start with
4041performing sentiment analysis.&lt;/p&gt;
4042&lt;p&gt;There are many sentiment analysis libraries available that range from rule-based
4043sentiment analysis up to machine learning supported analysis. To keep things
4044simple I decided to use rule-based analysis library
4045&lt;a href=&#34;https://github.com/cjhutto/vaderSentiment&#34;&gt;vaderSentiment&lt;/a&gt; from
4046&lt;a href=&#34;https://github.com/cjhutto&#34;&gt;C.J. Hutto&lt;/a&gt;. Really nice library and quite easy to
4047use.&lt;/p&gt;
4048&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;from&lt;/span&gt; vaderSentiment.vaderSentiment &lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; SentimentIntensityAnalyzer
4049&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;analyser = SentimentIntensityAnalyzer()
4050&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4051&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sentiment_results = []
4052&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;for&lt;/span&gt; item &lt;span style=&#34;color:#00f&#34;&gt;in&lt;/span&gt; feed.entries:
4053&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; sentiment_title = analyser.polarity_scores(item.title)
4054&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; sentiment_description = analyser.polarity_scores(item.description)
4055&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; sentiment_results.append([sentiment_title[&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;compound&amp;#39;&lt;/span&gt;], sentiment_description[&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;compound&amp;#39;&lt;/span&gt;]])
4056&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now that we have this data in a shape that is compatible with matplotlib we can
4057plot results to see the difference between title and description sentiment of an
4058article.&lt;/p&gt;
4059&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; matplotlib.pyplot &lt;span style=&#34;color:#00f&#34;&gt;as&lt;/span&gt; plt
4060&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4061&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;plt.rcParams[&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;figure.figsize&amp;#39;&lt;/span&gt;] = (15, 3)
4062&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;plt.plot(sentiment_results, drawstyle=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;steps&amp;#39;&lt;/span&gt;)
4063&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;plt.title(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;Sentiment analysis relationship between title and description (Guardian World News)&amp;#39;&lt;/span&gt;)
4064&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;plt.legend([&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;title&amp;#39;&lt;/span&gt;, &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;description&amp;#39;&lt;/span&gt;])
4065&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;plt.show()
4066&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;results-and-assets&#34;&gt;Results and assets&lt;/h2&gt;
4067&lt;ol&gt;
4068&lt;li&gt;Because of the small sample size further conclusions are impossible to make.&lt;/li&gt;
4069&lt;li&gt;Rule-based approach may not be the best way of doing this. By using deep
4070learning we would be able to get better insights.&lt;/li&gt;
4071&lt;li&gt;&lt;strong&gt;Next step would be to&lt;/strong&gt; periodically fetch RSS items and store them over a
4072longer period of time and then perform analysis again and use either machine
4073learning or deep learning on top of it.&lt;/li&gt;
4074&lt;/ol&gt;
4075&lt;figure&gt;
4076&lt;img src=&#34;/posts/sentiment-analysis/guardian-sa-title-desc-relationship.png&#34; alt=&#34;Relationship between title and description&#34; /&gt;
4077&lt;/figure&gt;
4078&lt;p&gt;Figure above displays difference between title and description sentiment for
4079specific RSS feed item. 1 means positive and -1 means negative sentiment.&lt;/p&gt;
4080&lt;p&gt;&lt;a href=&#34;/posts/sentiment-analysis/sentiment-analysis.ipynb&#34;&gt;» Download Jupyter Notebook&lt;/a&gt;&lt;/p&gt;
4081&lt;h2 id=&#34;going-further&#34;&gt;Going further&lt;/h2&gt;
4082&lt;ul&gt;
4083&lt;li&gt;&lt;a href=&#34;https://github.com/bswiss/news_mood&#34;&gt;Twitter Sentiment Analysis by Bryan Schwierzke&lt;/a&gt;&lt;/li&gt;
4084&lt;li&gt;&lt;a href=&#34;https://github.com/thisandagain/sentiment&#34;&gt;AFINN-based sentiment analysis for Node.js by Andrew Sliwinski&lt;/a&gt;&lt;/li&gt;
4085&lt;li&gt;&lt;a href=&#34;https://github.com/adeshpande3/LSTM-Sentiment-Analysis&#34;&gt;Sentiment Analysis with LSTMs in Tensorflow by Adit Deshpande&lt;/a&gt;&lt;/li&gt;
4086&lt;li&gt;&lt;a href=&#34;https://github.com/abdulfatir/twitter-sentiment-analysis&#34;&gt;Sentiment analysis on tweets using Naive Bayes, SVM, CNN, LSTM, etc. by Abdul Fatir&lt;/a&gt;&lt;/li&gt;
4087&lt;/ul&gt;
4088</content:encoded>
4089 </item>
4090
4091
4092
4093 <item>
4094 <title>Simplifying and reducing clutter in my life and work</title>
4095 <link>https://mitjafelicijan.com/simplifying-and-reducing-clutter.html</link>
4096 <pubDate>Mon, 14 Oct 2019 12:00:00 &#43;0200</pubDate>
4097 <guid>https://mitjafelicijan.com/simplifying-and-reducing-clutter.html</guid>
4098 <description>I recently moved my main working machine back from Hachintosh to Linux.</description>
4099 <content:encoded>&lt;p&gt;I recently moved my main working machine back from Hachintosh to Linux. Well the
4100experiment was interesting and I have done some great work on macOS but it was
4101time to move back.&lt;/p&gt;
4102&lt;p&gt;I actually really missed Linux. The simplicity of &lt;code&gt;apt-get&lt;/code&gt; or just the amount
4103of software that exists for Linux should be a no-brainer. I spent most of my
4104time on macOS finding solutions to make things work. Using
4105&lt;a href=&#34;https://brew.sh/&#34;&gt;Brew&lt;/a&gt; was just a horrible experience and far from package
4106managers of Linux. At least they managed to get that &lt;code&gt;sudo&lt;/code&gt; debacle sorted.&lt;/p&gt;
4107&lt;p&gt;Not all was bad. macOS in general was a perfectly good environment. Things like
4108Docker and tooling like this worked without any hiccups. My normal tools like
4109coding IDE worked flawlessly and the whole look and feel is just superb. I have
4110been using MacBook Air for couple of years so I was used to the system but never
4111as a daily driver.&lt;/p&gt;
4112&lt;p&gt;One of the things I did after I installed Linux back on my machine was cleaning
4113up my Dropbox folder. I have everything on Dropbox. Even projects folder. I
4114write code for living so my whole life revolves around couple of megs of code
4115(with assets). So it&#39;s not like I have huge files on my machine. I don&#39;t have
4116movies or music or pictures on my PC. All of that stuff is in cloud. I use
4117Google music and I have Netflix account which is more than enough for me.&lt;/p&gt;
4118&lt;p&gt;I also went and deleted some of the repositories on my Github account. I have
4119deleted more code than deployed. People find this strange but for me deleting
4120something feels so cathartic and also forces me to write better code next time
4121around when I am faced with similar problem. That was a huge relief if I am
4122being totally honest.&lt;/p&gt;
4123&lt;p&gt;Next step was to do something with my webpage. I have been using some scripts I
4124wrote a while ago to generate static pages from markdown source posts. I kept on
4125adding and adding stuff on top of it and it became a source of a
4126frustration. And this is just a simple blog and I was using gulp and npm.
4127Anyways after couple of hours of searching and testing static generators I found
4128an interesting one
4129&lt;a href=&#34;https://github.com/piranha/gostatic&#34;&gt;https://github.com/piranha/gostatic&lt;/a&gt; and I
4130just decided to use this one. It was the only one that had a simple templating
4131engine, not that I really need one. But others had this convoluted way of trying
4132to solve everything and at the end just required quite bigger learning curve I
4133was ready to go with. So I deleted couple of old posts, simplified HTML, trashed
4134most of the CSS and went with
4135&lt;a href=&#34;https://motherfuckingwebsite.com/&#34;&gt;https://motherfuckingwebsite.com/&lt;/a&gt;
4136aesthetics. Yeah, the previous site was more visually stimulating but all I
4137really care is the content at this point. And Times New Roman font is kind of
4138awesome.&lt;/p&gt;
4139&lt;p&gt;I stopped working on most of the projects in the past couple of months because
4140the overhead was just too insane. There comes a point when you stretch yourself
4141too much and then you stop progressing and with that comes dissatisfaction.&lt;/p&gt;
4142&lt;p&gt;So that&#39;s about it. Moving forward minimal style.&lt;/p&gt;
4143</content:encoded>
4144 </item>
4145
4146
4147
4148 <item>
4149 <title>Encoding binary data into DNA sequence</title>
4150 <link>https://mitjafelicijan.com/encoding-binary-data-into-dna-sequence.html</link>
4151 <pubDate>Thu, 03 Jan 2019 12:00:00 &#43;0200</pubDate>
4152 <guid>https://mitjafelicijan.com/encoding-binary-data-into-dna-sequence.html</guid>
4153 <description>Initial thoughtsImagine a world where you could go outside and take a leaf from a tree and putit through your personal DNA sequencer and get data like music, videos orcomputer programs from it.</description>
4154 <content:encoded>&lt;h2 id=&#34;initial-thoughts&#34;&gt;Initial thoughts&lt;/h2&gt;
4155&lt;p&gt;Imagine a world where you could go outside and take a leaf from a tree and put
4156it through your personal DNA sequencer and get data like music, videos or
4157computer programs from it. Well, this is all possible now. It was not done on a
4158large scale because it is quite expensive to create DNA strands but it&#39;s
4159possible.&lt;/p&gt;
4160&lt;p&gt;Encoding data into DNA sequence is relatively simple process once you understand
4161the relationship between binary data and nucleotides and scientists have been
4162making large leaps in this field in order to provide viable long-term storage
4163solution for our data that would potentially survive our specie if case of
4164global disaster. We could imprint all the world&#39;s knowledge into plants and
4165ensure the survival of our knowledge.&lt;/p&gt;
4166&lt;p&gt;More optimistic usage for this technology would be easier storage of ever
4167growing data we produce every day. Once machines for sequencing DNA become fast
4168enough and cheaper this could mean the next evolution of storing data and
4169abandoning classical hard and solid state drives in data warehouses.&lt;/p&gt;
4170&lt;p&gt;As we currently stand this is still not viable but it is quite an amazing and
4171cool technology.&lt;/p&gt;
4172&lt;p&gt;My interests in this field are purely in encoding processes and experimental
4173testing mainly because I don&#39;t have the access to this expensive machines. My
4174initial goal was to create a toolkit that can be used by everybody to encode
4175their data into a proper DNA sequence.&lt;/p&gt;
4176&lt;h2 id=&#34;glossary&#34;&gt;Glossary&lt;/h2&gt;
4177&lt;p&gt;&lt;strong&gt;deoxyribose&lt;/strong&gt; A five-carbon sugar molecule with a hydrogen atom rather than a
4178hydroxyl group in the 2′ position; the sugar component of DNA nucleotides.&lt;/p&gt;
4179&lt;p&gt;&lt;strong&gt;double helix&lt;/strong&gt; The molecular shape of DNA in which two strands of nucleotides
4180wind around each other in a spiral shape.&lt;/p&gt;
4181&lt;p&gt;&lt;strong&gt;nitrogenous base&lt;/strong&gt; A nitrogen-containing molecule that acts as a base; often
4182referring to one of the purine or pyrimidine components of nucleic acids.&lt;/p&gt;
4183&lt;p&gt;&lt;strong&gt;phosphate group&lt;/strong&gt; A molecular group consisting of a central phosphorus atom
4184bound to four oxygen atoms.&lt;/p&gt;
4185&lt;p&gt;&lt;strong&gt;RGB&lt;/strong&gt; The RGB color model is an additive color model in which red, green and
4186blue light are added together in various ways to reproduce a broad array of
4187colors.&lt;/p&gt;
4188&lt;p&gt;&lt;strong&gt;GCC&lt;/strong&gt; The GNU Compiler Collection is a compiler system produced by the GNU
4189Project supporting various programming languages.&lt;/p&gt;
4190&lt;h2 id=&#34;data-encoding&#34;&gt;Data encoding&lt;/h2&gt;
4191&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Encoding involves the use of a code to change original data into a
4192form that can be used by an external process.&lt;/p&gt;
4193&lt;p&gt;Encoding is the process of converting data into a format required for a number
4194of information processing needs, including:&lt;/p&gt;
4195&lt;ul&gt;
4196&lt;li&gt;Program compiling and execution&lt;/li&gt;
4197&lt;li&gt;Data transmission, storage and compression/decompression&lt;/li&gt;
4198&lt;li&gt;Application data processing, such as file conversion&lt;/li&gt;
4199&lt;/ul&gt;
4200&lt;p&gt;Encoding can have two meanings:&lt;/p&gt;
4201&lt;ul&gt;
4202&lt;li&gt;In computer technology, encoding is the process of applying a specific code,
4203such as letters, symbols and numbers, to data for conversion into an
4204equivalent cipher.&lt;/li&gt;
4205&lt;li&gt;In electronics, encoding refers to analog to digital conversion.&lt;/li&gt;
4206&lt;/ul&gt;
4207&lt;h2 id=&#34;quick-history-of-dna&#34;&gt;Quick history of DNA&lt;/h2&gt;
4208&lt;ul&gt;
4209&lt;li&gt;&lt;strong&gt;1869&lt;/strong&gt; - Friedrich Miescher identifies &amp;quot;nuclein&amp;quot;.&lt;/li&gt;
4210&lt;li&gt;&lt;strong&gt;1900s&lt;/strong&gt; - The Eugenics Movement.&lt;/li&gt;
4211&lt;li&gt;&lt;strong&gt;1900&lt;/strong&gt; – Mendel&#39;s theories are rediscovered by researchers.&lt;/li&gt;
4212&lt;li&gt;&lt;strong&gt;1944&lt;/strong&gt; - Oswald Avery identifies DNA as the &#39;transforming principle&#39;.&lt;/li&gt;
4213&lt;li&gt;&lt;strong&gt;1952&lt;/strong&gt; - Rosalind Franklin photographs crystallized DNA fibres.&lt;/li&gt;
4214&lt;li&gt;&lt;strong&gt;1953&lt;/strong&gt; - James Watson and Francis Crick discover the double helix structure of DNA.&lt;/li&gt;
4215&lt;li&gt;&lt;strong&gt;1965&lt;/strong&gt; - Marshall Nirenberg is the first person to sequence the bases in each codon.&lt;/li&gt;
4216&lt;li&gt;&lt;strong&gt;1983&lt;/strong&gt; - Huntington&#39;s disease is the first mapped genetic disease.&lt;/li&gt;
4217&lt;li&gt;&lt;strong&gt;1990&lt;/strong&gt; - The Human Genome Project begins.&lt;/li&gt;
4218&lt;li&gt;&lt;strong&gt;1995&lt;/strong&gt; - Haemophilus Influenzae is the first bacterium genome sequenced.&lt;/li&gt;
4219&lt;li&gt;&lt;strong&gt;1996&lt;/strong&gt; - Dolly the sheep is cloned.&lt;/li&gt;
4220&lt;li&gt;&lt;strong&gt;1999&lt;/strong&gt; - First human chromosome is decoded.&lt;/li&gt;
4221&lt;li&gt;&lt;strong&gt;2000&lt;/strong&gt; – Genetic code of the fruit fly is decoded.&lt;/li&gt;
4222&lt;li&gt;&lt;strong&gt;2002&lt;/strong&gt; – Mouse is the first mammal to have its genome decoded.&lt;/li&gt;
4223&lt;li&gt;&lt;strong&gt;2003&lt;/strong&gt; – The Human Genome Project is completed.&lt;/li&gt;
4224&lt;li&gt;&lt;strong&gt;2013&lt;/strong&gt; – DNA Worldwide and Eurofins Forensic discover identical twins have differences in their genetic makeup.&lt;/li&gt;
4225&lt;/ul&gt;
4226&lt;h2 id=&#34;what-is-dna&#34;&gt;What is DNA?&lt;/h2&gt;
4227&lt;p&gt;Deoxyribonucleic acid, a self-replicating material which is &lt;strong&gt;present in nearly
4228all living organisms&lt;/strong&gt; as the main constituent of chromosomes. It is the
4229&lt;strong&gt;carrier of genetic information&lt;/strong&gt;.&lt;/p&gt;
4230&lt;blockquote&gt;
4231&lt;p&gt;The nitrogen in our DNA, the calcium in our teeth, the iron in our blood,
4232the carbon in our apple pies were made in the interiors of collapsing stars.
4233We are made of starstuff.
4234&lt;strong&gt;-- Carl Sagan, Cosmos&lt;/strong&gt;&lt;/p&gt;
4235&lt;/blockquote&gt;
4236&lt;p&gt;The nucleotide in DNA consists of a sugar (deoxyribose), one of four bases
4237(cytosine (C), thymine (T), adenine (A), guanine (G)), and a phosphate.
4238Cytosine and thymine are pyrimidine bases, while adenine and guanine are purine
4239bases. The sugar and the base together are called a nucleoside.&lt;/p&gt;
4240&lt;figure&gt;
4241&lt;img src=&#34;/posts/dna-sequence/dna-basics.jpg&#34; alt=&#34;DNA&#34; /&gt;
4242&lt;figcaption&gt;&lt;p&gt;&lt;em&gt;DNA (a) forms a double stranded helix, and (b) adenine pairs with thymine and
4243cytosine pairs with guanine. (credit a: modification of work by Jerome Walker,
4244Dennis Myts)&lt;/em&gt;&lt;/p&gt;&lt;/figcaption&gt;
4245&lt;/figure&gt;
4246&lt;h2 id=&#34;encode-binary-data-into-dna-sequence&#34;&gt;Encode binary data into DNA sequence&lt;/h2&gt;
4247&lt;p&gt;As an input file you can use any file you want:&lt;/p&gt;
4248&lt;ul&gt;
4249&lt;li&gt;ASCII files,&lt;/li&gt;
4250&lt;li&gt;Compiled programs,&lt;/li&gt;
4251&lt;li&gt;Multimedia files (MP3, MP4, MVK, etc),&lt;/li&gt;
4252&lt;li&gt;Images,&lt;/li&gt;
4253&lt;li&gt;Database files,&lt;/li&gt;
4254&lt;li&gt;etc.&lt;/li&gt;
4255&lt;/ul&gt;
4256&lt;p&gt;Note: If you would copy all the bytes from RAM to file or pipe data to file you
4257could encode also this data as long as you provide file pointer to the encoder.&lt;/p&gt;
4258&lt;h3 id=&#34;basic-encoding&#34;&gt;Basic Encoding&lt;/h3&gt;
4259&lt;p&gt;As already mentioned, the Basic Encoding is based on a simple mapping. Since DNA
4260is composed of 4 nucleotides (Adenine, Cytosine, Guanine, Thymine; usually
4261referred using the first letter). Using this technique we can encode&lt;/p&gt;
4262&lt;p&gt;&lt;svg xmlns=&#34;http://www.w3.org/2000/svg&#34; xmlns:xlink=&#34;http://www.w3.org/1999/xlink&#34; viewBox=&#34;0 -907.9672135000189 11313.37788460873 1185.0382429179317&#34; style=&#34;width: 26.259ex; height: 2.721ex; vertical-align: -0.68ex; margin: 1px 0px;&#34;&gt;&lt;g stroke=&#34;black&#34; fill=&#34;black&#34; stroke-width=&#34;0&#34; transform=&#34;matrix(1 0 0 -1 0 0)&#34;&gt;&lt;use xmlns:xlink=&#34;http://www.w3.org/1999/xlink&#34; xlink:href=&#34;#MJMATHI-6C&#34;/&gt;&lt;use xmlns:xlink=&#34;http://www.w3.org/1999/xlink&#34; xlink:href=&#34;#MJMATHI-6F&#34; x=&#34;303&#34; y=&#34;0&#34;/&gt;&lt;g transform=&#34;translate(793,0)&#34;&gt;&lt;use xmlns:xlink=&#34;http://www.w3.org/1999/xlink&#34; xlink:href=&#34;#MJMATHI-67&#34;/&gt;&lt;use transform=&#34;scale(0.7071067811865476)&#34; xmlns:xlink=&#34;http://www.w3.org/1999/xlink&#34; xlink:href=&#34;#MJMAIN-32&#34; x=&#34;681&#34; y=&#34;-213&#34;/&gt;&lt;/g&gt;&lt;use xmlns:xlink=&#34;http://www.w3.org/1999/xlink&#34; xlink:href=&#34;#MJMAIN-28&#34; x=&#34;1732&#34; y=&#34;0&#34;/&gt;&lt;use xmlns:xlink=&#34;http://www.w3.org/1999/xlink&#34; xlink:href=&#34;#MJMAIN-34&#34; x=&#34;2126&#34; y=&#34;0&#34;/&gt;&lt;use xmlns:xlink=&#34;http://www.w3.org/1999/xlink&#34; xlink:href=&#34;#MJMAIN-29&#34; x=&#34;2631&#34; y=&#34;0&#34;/&gt;&lt;use xmlns:xlink=&#34;http://www.w3.org/1999/xlink&#34; xlink:href=&#34;#MJMAIN-3D&#34; x=&#34;3302&#34; y=&#34;0&#34;/&gt;&lt;use xmlns:xlink=&#34;http://www.w3.org/1999/xlink&#34; xlink:href=&#34;#MJMATHI-6C&#34; x=&#34;4363&#34; y=&#34;0&#34;/&gt;&lt;use xmlns:xlink=&#34;http://www.w3.org/1999/xlink&#34; xlink:href=&#34;#MJMATHI-6F&#34; x=&#34;4666&#34; y=&#34;0&#34;/&gt;&lt;g transform=&#34;translate(5156,0)&#34;&gt;&lt;use xmlns:xlink=&#34;http://www.w3.org/1999/xlink&#34; xlink:href=&#34;#MJMATHI-67&#34;/&gt;&lt;use transform=&#34;scale(0.7071067811865476)&#34; xmlns:xlink=&#34;http://www.w3.org/1999/xlink&#34; xlink:href=&#34;#MJMAIN-32&#34; x=&#34;681&#34; y=&#34;-213&#34;/&gt;&lt;/g&gt;&lt;use xmlns:xlink=&#34;http://www.w3.org/1999/xlink&#34; xlink:href=&#34;#MJMAIN-28&#34; x=&#34;6095&#34; y=&#34;0&#34;/&gt;&lt;g transform=&#34;translate(6489,0)&#34;&gt;&lt;use xmlns:xlink=&#34;http://www.w3.org/1999/xlink&#34; xlink:href=&#34;#MJMAIN-32&#34;/&gt;&lt;use transform=&#34;scale(0.7071067811865476)&#34; xmlns:xlink=&#34;http://www.w3.org/1999/xlink&#34; xlink:href=&#34;#MJMAIN-32&#34; x=&#34;714&#34; y=&#34;583&#34;/&gt;&lt;/g&gt;&lt;use xmlns:xlink=&#34;http://www.w3.org/1999/xlink&#34; xlink:href=&#34;#MJMAIN-29&#34; x=&#34;7451&#34; y=&#34;0&#34;/&gt;&lt;use xmlns:xlink=&#34;http://www.w3.org/1999/xlink&#34; xlink:href=&#34;#MJMAIN-3D&#34; x=&#34;8123&#34; y=&#34;0&#34;/&gt;&lt;use xmlns:xlink=&#34;http://www.w3.org/1999/xlink&#34; xlink:href=&#34;#MJMAIN-32&#34; x=&#34;9184&#34; y=&#34;0&#34;/&gt;&lt;use xmlns:xlink=&#34;http://www.w3.org/1999/xlink&#34; xlink:href=&#34;#MJMATHI-62&#34; x=&#34;9689&#34; y=&#34;0&#34;/&gt;&lt;use xmlns:xlink=&#34;http://www.w3.org/1999/xlink&#34; xlink:href=&#34;#MJMATHI-69&#34; x=&#34;10123&#34; y=&#34;0&#34;/&gt;&lt;use xmlns:xlink=&#34;http://www.w3.org/1999/xlink&#34; xlink:href=&#34;#MJMATHI-74&#34; x=&#34;10473&#34; y=&#34;0&#34;/&gt;&lt;use xmlns:xlink=&#34;http://www.w3.org/1999/xlink&#34; xlink:href=&#34;#MJMATHI-73&#34; x=&#34;10839&#34; y=&#34;0&#34;/&gt;&lt;/g&gt;&lt;defs id=&#34;MathJax_SVG_glyphs&#34;&gt;&lt;path id=&#34;MJSZ2-2211&#34; stroke-width=&#34;10&#34; d=&#34;M60 948Q63 950 665 950H1267L1325 815Q1384 677 1388 669H1348L1341 683Q1320 724 1285 761Q1235 809 1174 838T1033 881T882 898T699 902H574H543H251L259 891Q722 258 724 252Q725 250 724 246Q721 243 460 -56L196 -356Q196 -357 407 -357Q459 -357 548 -357T676 -358Q812 -358 896 -353T1063 -332T1204 -283T1307 -196Q1328 -170 1348 -124H1388Q1388 -125 1381 -145T1356 -210T1325 -294L1267 -449L666 -450Q64 -450 61 -448Q55 -446 55 -439Q55 -437 57 -433L590 177Q590 178 557 222T452 366T322 544L56 909L55 924Q55 945 60 948Z&#34;/&gt;&lt;path id=&#34;MJMATHI-69&#34; stroke-width=&#34;10&#34; d=&#34;M184 600Q184 624 203 642T247 661Q265 661 277 649T290 619Q290 596 270 577T226 557Q211 557 198 567T184 600ZM21 287Q21 295 30 318T54 369T98 420T158 442Q197 442 223 419T250 357Q250 340 236 301T196 196T154 83Q149 61 149 51Q149 26 166 26Q175 26 185 29T208 43T235 78T260 137Q263 149 265 151T282 153Q302 153 302 143Q302 135 293 112T268 61T223 11T161 -11Q129 -11 102 10T74 74Q74 91 79 106T122 220Q160 321 166 341T173 380Q173 404 156 404H154Q124 404 99 371T61 287Q60 286 59 284T58 281T56 279T53 278T49 278T41 278H27Q21 284 21 287Z&#34;/&gt;&lt;path id=&#34;MJMAIN-3D&#34; stroke-width=&#34;10&#34; d=&#34;M56 347Q56 360 70 367H707Q722 359 722 347Q722 336 708 328L390 327H72Q56 332 56 347ZM56 153Q56 168 72 173H708Q722 163 722 153Q722 140 707 133H70Q56 140 56 153Z&#34;/&gt;&lt;path id=&#34;MJMAIN-30&#34; stroke-width=&#34;10&#34; d=&#34;M96 585Q152 666 249 666Q297 666 345 640T423 548Q460 465 460 320Q460 165 417 83Q397 41 362 16T301 -15T250 -22Q224 -22 198 -16T137 16T82 83Q39 165 39 320Q39 494 96 585ZM321 597Q291 629 250 629Q208 629 178 597Q153 571 145 525T137 333Q137 175 145 125T181 46Q209 16 250 16Q290 16 318 46Q347 76 354 130T362 333Q362 478 354 524T321 597Z&#34;/&gt;&lt;path id=&#34;MJMATHI-6E&#34; stroke-width=&#34;10&#34; d=&#34;M21 287Q22 293 24 303T36 341T56 388T89 425T135 442Q171 442 195 424T225 390T231 369Q231 367 232 367L243 378Q304 442 382 442Q436 442 469 415T503 336T465 179T427 52Q427 26 444 26Q450 26 453 27Q482 32 505 65T540 145Q542 153 560 153Q580 153 580 145Q580 144 576 130Q568 101 554 73T508 17T439 -10Q392 -10 371 17T350 73Q350 92 386 193T423 345Q423 404 379 404H374Q288 404 229 303L222 291L189 157Q156 26 151 16Q138 -11 108 -11Q95 -11 87 -5T76 7T74 17Q74 30 112 180T152 343Q153 348 153 366Q153 405 129 405Q91 405 66 305Q60 285 60 284Q58 278 41 278H27Q21 284 21 287Z&#34;/&gt;&lt;path id=&#34;MJMAIN-28&#34; stroke-width=&#34;10&#34; d=&#34;M94 250Q94 319 104 381T127 488T164 576T202 643T244 695T277 729T302 750H315H319Q333 750 333 741Q333 738 316 720T275 667T226 581T184 443T167 250T184 58T225 -81T274 -167T316 -220T333 -241Q333 -250 318 -250H315H302L274 -226Q180 -141 137 -14T94 250Z&#34;/&gt;&lt;path id=&#34;MJMAIN-2B&#34; stroke-width=&#34;10&#34; d=&#34;M56 237T56 250T70 270H369V420L370 570Q380 583 389 583Q402 583 409 568V270H707Q722 262 722 250T707 230H409V-68Q401 -82 391 -82H389H387Q375 -82 369 -68V230H70Q56 237 56 250Z&#34;/&gt;&lt;path id=&#34;MJMAIN-31&#34; stroke-width=&#34;10&#34; d=&#34;M213 578L200 573Q186 568 160 563T102 556H83V602H102Q149 604 189 617T245 641T273 663Q275 666 285 666Q294 666 302 660V361L303 61Q310 54 315 52T339 48T401 46H427V0H416Q395 3 257 3Q121 3 100 0H88V46H114Q136 46 152 46T177 47T193 50T201 52T207 57T213 61V578Z&#34;/&gt;&lt;path id=&#34;MJMAIN-29&#34; stroke-width=&#34;10&#34; d=&#34;M60 749L64 750Q69 750 74 750H86L114 726Q208 641 251 514T294 250Q294 182 284 119T261 12T224 -76T186 -143T145 -194T113 -227T90 -246Q87 -249 86 -250H74Q66 -250 63 -250T58 -247T55 -238Q56 -237 66 -225Q221 -64 221 250T66 725Q56 737 55 738Q55 746 60 749Z&#34;/&gt;&lt;path id=&#34;MJMAIN-32&#34; stroke-width=&#34;10&#34; d=&#34;M109 429Q82 429 66 447T50 491Q50 562 103 614T235 666Q326 666 387 610T449 465Q449 422 429 383T381 315T301 241Q265 210 201 149L142 93L218 92Q375 92 385 97Q392 99 409 186V189H449V186Q448 183 436 95T421 3V0H50V19V31Q50 38 56 46T86 81Q115 113 136 137Q145 147 170 174T204 211T233 244T261 278T284 308T305 340T320 369T333 401T340 431T343 464Q343 527 309 573T212 619Q179 619 154 602T119 569T109 550Q109 549 114 549Q132 549 151 535T170 489Q170 464 154 447T109 429Z&#34;/&gt;&lt;path id=&#34;MJMATHI-6C&#34; stroke-width=&#34;10&#34; d=&#34;M117 59Q117 26 142 26Q179 26 205 131Q211 151 215 152Q217 153 225 153H229Q238 153 241 153T246 151T248 144Q247 138 245 128T234 90T214 43T183 6T137 -11Q101 -11 70 11T38 85Q38 97 39 102L104 360Q167 615 167 623Q167 626 166 628T162 632T157 634T149 635T141 636T132 637T122 637Q112 637 109 637T101 638T95 641T94 647Q94 649 96 661Q101 680 107 682T179 688Q194 689 213 690T243 693T254 694Q266 694 266 686Q266 675 193 386T118 83Q118 81 118 75T117 65V59Z&#34;/&gt;&lt;path id=&#34;MJMATHI-6F&#34; stroke-width=&#34;10&#34; d=&#34;M201 -11Q126 -11 80 38T34 156Q34 221 64 279T146 380Q222 441 301 441Q333 441 341 440Q354 437 367 433T402 417T438 387T464 338T476 268Q476 161 390 75T201 -11ZM121 120Q121 70 147 48T206 26Q250 26 289 58T351 142Q360 163 374 216T388 308Q388 352 370 375Q346 405 306 405Q243 405 195 347Q158 303 140 230T121 120Z&#34;/&gt;&lt;path id=&#34;MJMATHI-67&#34; stroke-width=&#34;10&#34; d=&#34;M311 43Q296 30 267 15T206 0Q143 0 105 45T66 160Q66 265 143 353T314 442Q361 442 401 394L404 398Q406 401 409 404T418 412T431 419T447 422Q461 422 470 413T480 394Q480 379 423 152T363 -80Q345 -134 286 -169T151 -205Q10 -205 10 -137Q10 -111 28 -91T74 -71Q89 -71 102 -80T116 -111Q116 -121 114 -130T107 -144T99 -154T92 -162L90 -164H91Q101 -167 151 -167Q189 -167 211 -155Q234 -144 254 -122T282 -75Q288 -56 298 -13Q311 35 311 43ZM384 328L380 339Q377 350 375 354T369 368T359 382T346 393T328 402T306 405Q262 405 221 352Q191 313 171 233T151 117Q151 38 213 38Q269 38 323 108L331 118L384 328Z&#34;/&gt;&lt;path id=&#34;MJMAIN-34&#34; stroke-width=&#34;10&#34; d=&#34;M462 0Q444 3 333 3Q217 3 199 0H190V46H221Q241 46 248 46T265 48T279 53T286 61Q287 63 287 115V165H28V211L179 442Q332 674 334 675Q336 677 355 677H373L379 671V211H471V165H379V114Q379 73 379 66T385 54Q393 47 442 46H471V0H462ZM293 211V545L74 212L183 211H293Z&#34;/&gt;&lt;path id=&#34;MJMATHI-62&#34; stroke-width=&#34;10&#34; d=&#34;M73 647Q73 657 77 670T89 683Q90 683 161 688T234 694Q246 694 246 685T212 542Q204 508 195 472T180 418L176 399Q176 396 182 402Q231 442 283 442Q345 442 383 396T422 280Q422 169 343 79T173 -11Q123 -11 82 27T40 150V159Q40 180 48 217T97 414Q147 611 147 623T109 637Q104 637 101 637H96Q86 637 83 637T76 640T73 647ZM336 325V331Q336 405 275 405Q258 405 240 397T207 376T181 352T163 330L157 322L136 236Q114 150 114 114Q114 66 138 42Q154 26 178 26Q211 26 245 58Q270 81 285 114T318 219Q336 291 336 325Z&#34;/&gt;&lt;path id=&#34;MJMATHI-74&#34; stroke-width=&#34;10&#34; d=&#34;M26 385Q19 392 19 395Q19 399 22 411T27 425Q29 430 36 430T87 431H140L159 511Q162 522 166 540T173 566T179 586T187 603T197 615T211 624T229 626Q247 625 254 615T261 596Q261 589 252 549T232 470L222 433Q222 431 272 431H323Q330 424 330 420Q330 398 317 385H210L174 240Q135 80 135 68Q135 26 162 26Q197 26 230 60T283 144Q285 150 288 151T303 153H307Q322 153 322 145Q322 142 319 133Q314 117 301 95T267 48T216 6T155 -11Q125 -11 98 4T59 56Q57 64 57 83V101L92 241Q127 382 128 383Q128 385 77 385H26Z&#34;/&gt;&lt;path id=&#34;MJMATHI-73&#34; stroke-width=&#34;10&#34; d=&#34;M131 289Q131 321 147 354T203 415T300 442Q362 442 390 415T419 355Q419 323 402 308T364 292Q351 292 340 300T328 326Q328 342 337 354T354 372T367 378Q368 378 368 379Q368 382 361 388T336 399T297 405Q249 405 227 379T204 326Q204 301 223 291T278 274T330 259Q396 230 396 163Q396 135 385 107T352 51T289 7T195 -10Q118 -10 86 19T53 87Q53 126 74 143T118 160Q133 160 146 151T160 120Q160 94 142 76T111 58Q109 57 108 57T107 55Q108 52 115 47T146 34T201 27Q237 27 263 38T301 66T318 97T323 122Q323 150 302 164T254 181T195 196T148 231Q131 256 131 289Z&#34;/&gt;&lt;/defs&gt;&lt;/svg&gt;&lt;/p&gt;
4263&lt;p&gt;using a single nucleotide. In this way, we are able to use the 4 bases that
4264compose the DNA strand to encode each byte of data.&lt;/p&gt;
4265&lt;table&gt;
4266&lt;thead&gt;
4267&lt;tr&gt;
4268&lt;th&gt;Two bits&lt;/th&gt;
4269&lt;th&gt;Nucleotides&lt;/th&gt;
4270&lt;/tr&gt;
4271&lt;/thead&gt;
4272&lt;tbody&gt;
4273&lt;tr&gt;
4274&lt;td&gt;00&lt;/td&gt;
4275&lt;td&gt;&lt;strong&gt;A&lt;/strong&gt; (Adenine)&lt;/td&gt;
4276&lt;/tr&gt;
4277&lt;tr&gt;
4278&lt;td&gt;10&lt;/td&gt;
4279&lt;td&gt;&lt;strong&gt;G&lt;/strong&gt; (Guanine)&lt;/td&gt;
4280&lt;/tr&gt;
4281&lt;tr&gt;
4282&lt;td&gt;01&lt;/td&gt;
4283&lt;td&gt;&lt;strong&gt;C&lt;/strong&gt; (Cytosine)&lt;/td&gt;
4284&lt;/tr&gt;
4285&lt;tr&gt;
4286&lt;td&gt;11&lt;/td&gt;
4287&lt;td&gt;&lt;strong&gt;T&lt;/strong&gt; (Thymine)&lt;/td&gt;
4288&lt;/tr&gt;
4289&lt;/tbody&gt;
4290&lt;/table&gt;
4291&lt;p&gt;With this in mind we can simply encode any data by using two-bit to Nucleotides
4292conversion.&lt;/p&gt;
4293&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{ Algorithm 1: Naive byte array to DNA encode }
4294&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;procedure EncodeToDNASequence(f) string
4295&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;begin
4296&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; enc string
4297&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;while&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;not&lt;/span&gt; eof(f) do
4298&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; c byte := buffer[0] { Read 1 byte &lt;span style=&#34;color:#00f&#34;&gt;from&lt;/span&gt; buffer }
4299&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; bin integer := sprintf(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;08b&amp;#39;&lt;/span&gt;, c) { Convert to string binary }
4300&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;for&lt;/span&gt; e &lt;span style=&#34;color:#00f&#34;&gt;in&lt;/span&gt; range[0, 2, 4, 6] do
4301&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt; e[0] == 48 &lt;span style=&#34;color:#00f&#34;&gt;and&lt;/span&gt; e[1] == 48 then { 0x00 - A (Adenine) }
4302&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; enc &#43;= &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;A&amp;#39;&lt;/span&gt;
4303&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt; e[0] == 48 &lt;span style=&#34;color:#00f&#34;&gt;and&lt;/span&gt; e[1] == 49 then { 0x01 - G (Guanine) }
4304&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; enc &#43;= &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;G&amp;#39;&lt;/span&gt;
4305&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt; e[0] == 49 &lt;span style=&#34;color:#00f&#34;&gt;and&lt;/span&gt; e[1] == 48 then { 0x10 - C (Cytosine) }
4306&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; enc &#43;= &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;C&amp;#39;&lt;/span&gt;
4307&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;else&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt; e[0] == 49 &lt;span style=&#34;color:#00f&#34;&gt;and&lt;/span&gt; e[1] == 49 then { 0x11 - T (Thymine) }
4308&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; enc &#43;= &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;T&amp;#39;&lt;/span&gt;
4309&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;return&lt;/span&gt; enc { Return DNA sequence }
4310&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;end
4311&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Another encoding would be &lt;strong&gt;Goldman encoding&lt;/strong&gt;. Using this encoding helps with
4312Nonsense mutation (amino acids replaced by a stop codon) that occurs and is the
4313most problematic during translation because it leads to truncated amino acid
4314sequences, which in turn results in truncated proteins.&lt;/p&gt;
4315&lt;p&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=a4PiGWNsIEU&#34;&gt;Where to store big data? In DNA: Nick Goldman at TEDxPrague&lt;/a&gt;&lt;/p&gt;
4316&lt;h3 id=&#34;fasta-file-format&#34;&gt;FASTA file format&lt;/h3&gt;
4317&lt;p&gt;In bioinformatics, FASTA format is a text-based format for representing either
4318nucleotide sequences or peptide sequences, in which nucleotides or amino acids
4319are represented using single-letter codes. The format also allows for sequence
4320names and comments to precede the sequences. The format originates from the
4321FASTA software package, but has now become a standard in the field of
4322bioinformatics.&lt;/p&gt;
4323&lt;p&gt;The first line in a FASTA file started either with a &amp;quot;&amp;gt;&amp;quot; (greater-than) symbol
4324or, less frequently, a &amp;quot;;&amp;quot; (semicolon) was taken as a comment. Subsequent lines
4325starting with a semicolon would be ignored by software. Since the only comment
4326used was the first, it quickly became used to hold a summary description of the
4327sequence, often starting with a unique library accession number, and with time
4328it has become commonplace to always use &amp;quot;&amp;gt;&amp;quot; for the first line and to not use
4329&amp;quot;;&amp;quot; comments (which would otherwise be ignored).&lt;/p&gt;
4330&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;;LCBO - Prolactin precursor - Bovine
4331&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;; a sample sequence in FASTA format
4332&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;MDSKGSSQKGSRLLLLLVVSNLLLCQGVVSTPVCPNGPGNCQVSLRDLFDRAVMVSHYIHDLSS
4333&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;EMFNEFDKRYAQGKGFITMALNSCHTSSLPTPEDKEQAQQTHHEVLMSLILGLLRSWNDPLYHL
4334&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;VTEVRGMKGAPDAILSRAIEIEEENKRLLEGMEMIFGQVIPGAKETEPYPVWSGLPSLQTKDED
4335&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ARYSAFYNLLHCLRRDSSKIDTYLKLLNCRIIYNNNC*
4336&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4337&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;MCHU - Calmodulin - Human, rabbit, bovine, rat, and chicken
4338&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ADQLTEEQIAEFKEAFSLFDKDGDGTITTKELGTVMRSLGQNPTEAELQDMINEVDADGNGTID
4339&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;FPEFLTMMARKMKDTDSEEEIREAFRVFDKDGNGYISAAELRHVMTNLGEKLTDEEVDEMIREA
4340&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;DIDGDGQVNYEEFVQMMTAK*
4341&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4342&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;gi|5524211|gb|AAD44166.1| cytochrome b [Elephas maximus maximus]
4343&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;LCLYTHIGRNIYYGSYLYSETWNTGIMLLLITMATAFMGYVLPWGQMSFWGATVITNLFSAIPYIGTNLV
4344&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;EWIWGGFSVDKATLNRFFAFHFILPFTMVALAGVHLTFLHETGSNNPLGLTSDSDKIPFHPYYTIKDFLG
4345&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;LLILILLLLLLALLSPDMLGDPDNHMPADPLNTPLHIKPEWYFLFAYAILRSVPNKLGGVLALFLSIVIL
4346&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GLMPFLHTSKHRSMMLRPLSQALFWTLTMDLLTLTWIGSQPVEYPYTIIGQMASILYFSIILAFLPIAGX
4347&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;IENY
4348&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;FASTA format was extended by &lt;a href=&#34;https://en.wikipedia.org/wiki/FASTQ_format&#34;&gt;FASTQ&lt;/a&gt;
4349format from the &lt;a href=&#34;https://www.sanger.ac.uk/&#34;&gt;Sanger Centre&lt;/a&gt; in Cambridge.&lt;/p&gt;
4350&lt;h3 id=&#34;png-encoded-dna-sequence&#34;&gt;PNG encoded DNA sequence&lt;/h3&gt;
4351&lt;table&gt;
4352&lt;thead&gt;
4353&lt;tr&gt;
4354&lt;th&gt;Nucleotides&lt;/th&gt;
4355&lt;th&gt;RGB&lt;/th&gt;
4356&lt;th&gt;Color name&lt;/th&gt;
4357&lt;/tr&gt;
4358&lt;/thead&gt;
4359&lt;tbody&gt;
4360&lt;tr&gt;
4361&lt;td&gt;A ➞ Adenine&lt;/td&gt;
4362&lt;td&gt;(0,0,255)&lt;/td&gt;
4363&lt;td&gt;Blue&lt;/td&gt;
4364&lt;/tr&gt;
4365&lt;tr&gt;
4366&lt;td&gt;G ➞ Guanine&lt;/td&gt;
4367&lt;td&gt;(0,100,0)&lt;/td&gt;
4368&lt;td&gt;Green&lt;/td&gt;
4369&lt;/tr&gt;
4370&lt;tr&gt;
4371&lt;td&gt;C ➞ Cytosine&lt;/td&gt;
4372&lt;td&gt;(255,0,0)&lt;/td&gt;
4373&lt;td&gt;Red&lt;/td&gt;
4374&lt;/tr&gt;
4375&lt;tr&gt;
4376&lt;td&gt;T ➞ Thymine&lt;/td&gt;
4377&lt;td&gt;(255,255,0)&lt;/td&gt;
4378&lt;td&gt;Yellow&lt;/td&gt;
4379&lt;/tr&gt;
4380&lt;/tbody&gt;
4381&lt;/table&gt;
4382&lt;p&gt;With this in mind we can create a simple algorithm to create PNG representation
4383of a DNA sequence.&lt;/p&gt;
4384&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{ Algorithm 2: Naive DNA to PNG encode &lt;span style=&#34;color:#00f&#34;&gt;from&lt;/span&gt; FASTA file }
4385&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;procedure EncodeDNASequenceToPNG(f)
4386&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;begin
4387&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; i image
4388&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;while&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;not&lt;/span&gt; eof(f) do
4389&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; c char := buffer[0] { Read 1 char &lt;span style=&#34;color:#00f&#34;&gt;from&lt;/span&gt; buffer }
4390&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; case c of
4391&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;A&amp;#39;&lt;/span&gt;: color := RGB(0, 0, 255) { Blue }
4392&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;G&amp;#39;&lt;/span&gt;: color := RGB(0, 100, 0) { Green }
4393&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;C&amp;#39;&lt;/span&gt;: color := RGB(255, 0, 0) { Red }
4394&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;T&amp;#39;&lt;/span&gt;: color := RGB(255, 255, 0) { Yellow }
4395&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; drawRect(i, [x, y], color)
4396&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; save(i) { Save PNG image }
4397&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;end
4398&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;encoding-text-file-in-practice&#34;&gt;Encoding text file in practice&lt;/h2&gt;
4399&lt;p&gt;In this example we will take a simple text file as our input stream for
4400encoding. This file will have a quote from Niels Bohr and saved as txt file.&lt;/p&gt;
4401&lt;blockquote&gt;
4402&lt;p&gt;How wonderful that we have met with a paradox. Now we have some hope of
4403making progress.
4404― Niels Bohr&lt;/p&gt;
4405&lt;/blockquote&gt;
4406&lt;p&gt;First we encode text file into FASTA file.&lt;/p&gt;
4407&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./dnae-encode -i quote.txt -o quote.fa
4408&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2019/01/10 00:38:29 Gathering input file stats
4409&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2019/01/10 00:38:29 Starting encoding ...
4410&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 106 B / 106 B [==================================] 100.00% 0s
4411&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2019/01/10 00:38:29 Saving to FASTA file ...
4412&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2019/01/10 00:38:29 Output FASTA file length is 438 B
4413&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2019/01/10 00:38:29 Process took 987.263µs
4414&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2019/01/10 00:38:29 Done ...
4415&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Output of &lt;code&gt;quote.fa&lt;/code&gt; file contains the encoded DNA sequence in ASCII format.&lt;/p&gt;
4416&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt;SEQ1
4417&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GACAGCTTGTGTACAAGTGTGCTTGCTCGCGAGCGGGTACGCGCGTGGGCTAACAAGTGA
4418&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GCCAGCAGGTGAACAAGTGTGCGGACAAGCCAGCAGGTGCGCGGACAAGCTGGCGGGTGA
4419&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ACAAGTGTGCCGGTGAGCCAACAAGCAGACAAGTAAGCAGGTACGCAGGCGAGCTTGTCA
4420&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ACTCACAAGATCGCTTGTGTACAAGTGTGCGGACAAGCCAGCAGGTGCGCGGACAAGTAT
4421&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GCTTGCTGGCGGACAAGCCAGCTTGTAAGCGGACAAGCTTGCGCACAAGCTGGCAGGCCT
4422&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;GCCGGCTCGCGTACAAATTCACAAGTAAGTACGCTTGCGTGTACGCGGGTATGTATACTC
4423&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;AACCTCACCAAACGGGACAAGATCGCCGGCGGGCTAGTATACAAGAACGCTTGCCAGTAC
4424&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;AACC
4425&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then we encode FASTA file from previous operation to encode this data into PNG.&lt;/p&gt;
4426&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./dnae-png -i quote.fa -o quote.png
4427&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2019/01/10 00:40:09 Gathering input file stats ...
4428&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2019/01/10 00:40:09 Deconstructing FASTA file ...
4429&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2019/01/10 00:40:09 Compositing image file ...
4430&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; 424 / 424 [==================================] 100.00% 0s
4431&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2019/01/10 00:40:09 Saving output file ...
4432&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2019/01/10 00:40:09 Output image file length is 1.1 kB
4433&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2019/01/10 00:40:09 Process took 19.036117ms
4434&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2019/01/10 00:40:09 Done ...
4435&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After encoding into PNG format this file looks like this.&lt;/p&gt;
4436&lt;figure&gt;
4437&lt;img src=&#34;/posts/dna-sequence/quote.png&#34; alt=&#34;Encoded Quote in PNG format&#34; /&gt;
4438&lt;figcaption&gt;&lt;p&gt;The larger the input stream is the larger the PNG file would be.&lt;/p&gt;&lt;/figcaption&gt;
4439&lt;/figure&gt;
4440&lt;p&gt;Compiled basic Hello World C program with
4441&lt;a href=&#34;https://www.gnu.org/software/gcc/&#34;&gt;GCC&lt;/a&gt; would &lt;a href=&#34;/posts/dna-sequence/sample.png&#34;&gt;look
4442like&lt;/a&gt;.&lt;/p&gt;
4443&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;// gcc -O3 -o sample sample.c
4444&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#00f&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#00f&#34;&gt;
4445&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;&lt;/span&gt;
4446&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;main() {
4447&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; printf(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Hello, world!&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt;);
4448&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;return&lt;/span&gt; 0;
4449&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
4450&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;toolkit-for-encoding-data&#34;&gt;Toolkit for encoding data&lt;/h2&gt;
4451&lt;p&gt;I have created a toolkit with two main programs:&lt;/p&gt;
4452&lt;ul&gt;
4453&lt;li&gt;dnae-encode (encodes file into FASTA file)&lt;/li&gt;
4454&lt;li&gt;dnae-png (encodes FASTA file into PNG)&lt;/li&gt;
4455&lt;/ul&gt;
4456&lt;p&gt;Toolkit with full source code is available on
4457&lt;a href=&#34;https://github.com/mitjafelicijan/dna-encoding&#34;&gt;github.com/mitjafelicijan/dna-encoding&lt;/a&gt;.&lt;/p&gt;
4458&lt;h3 id=&#34;dnae-encode&#34;&gt;dnae-encode&lt;/h3&gt;
4459&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt; ./dnae-encode --help
4460&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;usage: dnae-encode --input=INPUT [&amp;lt;flags&amp;gt;]
4461&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4462&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;A command-line application that encodes file into DNA sequence.
4463&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4464&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Flags:
4465&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; --help Show context-sensitive help (also try --help-long and --help-man).
4466&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; -i, --input=INPUT Input file (ASCII or binary) which will be encoded into DNA sequence.
4467&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; -o, --output=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;out.fa&amp;#34;&lt;/span&gt; Output file which stores DNA sequence in FASTA format.
4468&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; -s, --sequence=SEQ1 The description line (defline) or header/identifier line, gives a name and/or a unique identifier &lt;span style=&#34;color:#00f&#34;&gt;for&lt;/span&gt; the sequence.
4469&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; -c, --columns=60 Row characters length (no more than 120 characters). Devices preallocate fixed line sizes in software.
4470&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; --version Show application version.
4471&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;dnae-png&#34;&gt;dnae-png&lt;/h3&gt;
4472&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;gt; ./dnae-png --help
4473&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;usage: dnae-png --input=INPUT [&amp;lt;flags&amp;gt;]
4474&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4475&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;A command-line application that encodes FASTA file into PNG image.
4476&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4477&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Flags:
4478&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; --help Show context-sensitive help (also try --help-long and --help-man).
4479&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; -i, --input=INPUT Input FASTA file which will be encoded into PNG image.
4480&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; -o, --output=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;out.png&amp;#34;&lt;/span&gt; Output file in PNG format that represents DNA sequence in graphical way.
4481&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; -s, --size=10 Size of pairings of DNA bases on image in pixels (lower resolution lower file size).
4482&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; --version Show application version.
4483&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;benchmarks&#34;&gt;Benchmarks&lt;/h2&gt;
4484&lt;p&gt;First we generate some binary sample data with dd.&lt;/p&gt;
4485&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dd &lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt;=&amp;lt;(openssl enc -aes-256-ctr -pass pass:&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#00f&#34;&gt;$(&lt;/span&gt;dd &lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt;=/dev/urandom bs=128 count=1 2&amp;gt;/dev/null | base64&lt;span style=&#34;color:#00f&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt; -nosalt &amp;lt; /dev/zero) of=1KB.bin bs=1KB count=1 iflag=fullblock
4486&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;figure&gt;
4487&lt;img src=&#34;/posts/dna-sequence/sample-binary-file.png&#34; alt=&#34;Sample binary file 1KB&#34; /&gt;
4488&lt;figcaption&gt;&lt;p&gt;Our freshly generated 1KB file looks something like this (its full of
4489garbage data as intended).&lt;/p&gt;&lt;/figcaption&gt;
4490&lt;/figure&gt;
4491&lt;p&gt;We create following binary files:&lt;/p&gt;
4492&lt;ul&gt;
4493&lt;li&gt;1KB.bin&lt;/li&gt;
4494&lt;li&gt;10KB.bin&lt;/li&gt;
4495&lt;li&gt;100KB.bin&lt;/li&gt;
4496&lt;li&gt;1MB.bin&lt;/li&gt;
4497&lt;li&gt;10MB.bin&lt;/li&gt;
4498&lt;li&gt;100MB.bin&lt;/li&gt;
4499&lt;/ul&gt;
4500&lt;p&gt;After this we create FASTA files for all the binary files by encoding them
4501into DNA sequence.&lt;/p&gt;
4502&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./dnae-encode -i 100MB.bin -o 100MB.fa
4503&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Then we GZIP all the FASTA files to see how much the can be compressed.&lt;/p&gt;
4504&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;gzip -9 &amp;lt; 10MB.fa &amp;gt; 10MB.fa.gz
4505&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;figure&gt;
4506&lt;img src=&#34;/posts/dna-sequence/chart-speed.svg&#34; alt=&#34;Encode to FASTA&#34; /&gt;
4507&lt;figcaption&gt;&lt;p&gt;The speed increase that occurs when encoding to FASTA format.&lt;/p&gt;&lt;/figcaption&gt;
4508&lt;/figure&gt;
4509&lt;figure&gt;
4510&lt;img src=&#34;/posts/dna-sequence/chart-size.svg&#34; alt=&#34;File sizes&#34; /&gt;
4511&lt;figcaption&gt;&lt;p&gt;Size of the out file after encoding.&lt;/p&gt;&lt;/figcaption&gt;
4512&lt;/figure&gt;
4513&lt;p&gt;&lt;a href=&#34;/posts/dna-sequence/benchmarks.csv&#34;&gt;Download CSV file with benchmarks&lt;/a&gt;.&lt;/p&gt;
4514&lt;h2 id=&#34;references&#34;&gt;References&lt;/h2&gt;
4515&lt;ul&gt;
4516&lt;li&gt;&lt;a href=&#34;https://www.techopedia.com/definition/948/encoding&#34;&gt;https://www.techopedia.com/definition/948/encoding&lt;/a&gt;&lt;/li&gt;
4517&lt;li&gt;&lt;a href=&#34;https://www.dna-worldwide.com/resource/160/history-dna-timeline&#34;&gt;https://www.dna-worldwide.com/resource/160/history-dna-timeline&lt;/a&gt;&lt;/li&gt;
4518&lt;li&gt;&lt;a href=&#34;https://opentextbc.ca/biology/chapter/9-1-the-structure-of-dna/&#34;&gt;https://opentextbc.ca/biology/chapter/9-1-the-structure-of-dna/&lt;/a&gt;&lt;/li&gt;
4519&lt;li&gt;&lt;a href=&#34;https://arxiv.org/abs/1801.04774&#34;&gt;https://arxiv.org/abs/1801.04774&lt;/a&gt;&lt;/li&gt;
4520&lt;li&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/FASTA_format&#34;&gt;https://en.wikipedia.org/wiki/FASTA_format&lt;/a&gt;&lt;/li&gt;
4521&lt;/ul&gt;
4522</content:encoded>
4523 </item>
4524
4525
4526
4527 <item>
4528 <title>Using DigitalOcean Spaces Object Storage with FUSE</title>
4529 <link>https://mitjafelicijan.com/using-digitalocean-spaces-object-storage-with-fuse.html</link>
4530 <pubDate>Tue, 16 Jan 2018 12:00:00 &#43;0200</pubDate>
4531 <guid>https://mitjafelicijan.com/using-digitalocean-spaces-object-storage-with-fuse.html</guid>
4532 <description>Couple of months ago DigitalOcean introduced newproduct calledSpaces whichis Object Storage very similar to Amazon&amp;#39;s S3.</description>
4533 <content:encoded>&lt;p&gt;Couple of months ago &lt;a href=&#34;https://www.digitalocean.com&#34;&gt;DigitalOcean&lt;/a&gt; introduced new
4534product called
4535&lt;a href=&#34;https://blog.digitalocean.com/introducing-spaces-object-storage/&#34;&gt;Spaces&lt;/a&gt; which
4536is Object Storage very similar to Amazon&#39;s S3. This really peaked my interest,
4537because this was something I was missing and even the thought of going over the
4538internet for such functionality was in no interest to me. Also in fashion with
4539their previous pricing this also is very cheap and pricing page is a no-brainer
4540compared to AWS or GCE. &lt;a href=&#34;https://www.digitalocean.com/pricing/&#34;&gt;Prices are clearly and precisely defined and
4541outlined&lt;/a&gt;. You must love them for that
4542:)&lt;/p&gt;
4543&lt;h2 id=&#34;initial-requirements&#34;&gt;Initial requirements&lt;/h2&gt;
4544&lt;ul&gt;
4545&lt;li&gt;Is it possible to use them as a mounted drive with FUSE? (tl;dr YES)&lt;/li&gt;
4546&lt;li&gt;Will the performance degrade over time and over different sizes of objects?
4547(tl;dr NO&amp;amp;YES)&lt;/li&gt;
4548&lt;li&gt;Can storage be mounted on multiple machines at the same time and be writable?
4549(tl;dr YES)&lt;/li&gt;
4550&lt;/ul&gt;
4551&lt;blockquote&gt;
4552&lt;p&gt;Let me be clear. This scripts I use are made just for benchmarking and are not
4553intended to be used in real-life situations. Besides that, I am looking into
4554using this approaches but adding caching service in front of it and then
4555dumping everything as an object to storage. This could potentially be some
4556interesting post of itself. But in case you would need real-time data without
4557eventual consistency please take this scripts as they are: not usable in such
4558situations.&lt;/p&gt;
4559&lt;/blockquote&gt;
4560&lt;h2 id=&#34;is-it-possible-to-use-them-as-a-mounted-drive-with-fuse&#34;&gt;Is it possible to use them as a mounted drive with FUSE?&lt;/h2&gt;
4561&lt;p&gt;Well, actually they can be used in such manor. Because they are similar to &lt;a href=&#34;https://aws.amazon.com/s3/&#34;&gt;AWS
4562S3&lt;/a&gt; many tools are available and you can find many
4563articles and &lt;a href=&#34;https://stackoverflow.com/search?q=s3&#43;fuse&#34;&gt;Stackoverflow items&lt;/a&gt;.&lt;/p&gt;
4564&lt;p&gt;To make this work you will need DigitalOcean account. If you don&#39;t have one you
4565will not be able to test this code. But if you have an account then you go and
4566&lt;a href=&#34;https://cloud.digitalocean.com/droplets/new?size=s-1vcpu-1gb&amp;amp;region=ams3&amp;amp;distro=debian&amp;amp;distroImage=debian-9-x64&amp;amp;options=private_networking,install_agent&#34;&gt;create new
4567Droplet&lt;/a&gt;.
4568If you click on this link you will already have preselected Debian 9 with
4569smallest VM option.&lt;/p&gt;
4570&lt;ul&gt;
4571&lt;li&gt;Please be sure to add you SSH key, because we will login to this machine
4572remotely.&lt;/li&gt;
4573&lt;li&gt;If you change your region please remember which one you choose because we will
4574need this information when we try to mount space to our machine.&lt;/li&gt;
4575&lt;/ul&gt;
4576&lt;p&gt;Instuctions on how to use SSH keys and how to setup them are available in
4577article &lt;a href=&#34;https://www.digitalocean.com/community/tutorials/how-to-use-ssh-keys-with-digitalocean-droplets&#34;&gt;How To Use SSH Keys with DigitalOcean
4578Droplets&lt;/a&gt;.&lt;/p&gt;
4579&lt;figure&gt;
4580&lt;img src=&#34;/posts/do-fuse/fuse-droplets.png&#34; alt=&#34;DigitalOcean Droplets&#34; /&gt;
4581&lt;/figure&gt;
4582&lt;p&gt;After we created Droplet it&#39;s time to create new Space. This is done by clicking
4583on a button &lt;a href=&#34;https://cloud.digitalocean.com/spaces/new&#34;&gt;Create&lt;/a&gt; (right top
4584corner) and selecting Spaces. Choose pronounceable &lt;code&gt;Unique name&lt;/code&gt; because we
4585will use it in examples below. You can either choose Private or Public, it
4586doesn&#39;t matter in our case. And you can always change that in the future.&lt;/p&gt;
4587&lt;p&gt;When you have created new Space we should &lt;a href=&#34;https://cloud.digitalocean.com/settings/api/tokens&#34;&gt;generate Access
4588key&lt;/a&gt;. This link will guide
4589to the page when you can generate this key. After you create new one, please
4590save provided Key and Secret because Secret will not be shown again.&lt;/p&gt;
4591&lt;figure&gt;
4592&lt;img src=&#34;/posts/do-fuse/fuse-spaces.png&#34; alt=&#34;DigitalOcean Spaces&#34; /&gt;
4593&lt;/figure&gt;
4594&lt;p&gt;Now that we have new Space and Access key we should SSH into our machine.&lt;/p&gt;
4595&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# replace IP with the ip of your newly created droplet&lt;/span&gt;
4596&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ssh root@IP
4597&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4598&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# this will install utilities for mounting storage objects as FUSE&lt;/span&gt;
4599&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;apt install s3fs
4600&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4601&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# we now need to provide credentials (access key we created earlier)&lt;/span&gt;
4602&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# replace KEY and SECRET with your own credentials but leave the colon between them&lt;/span&gt;
4603&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# we also need to set proper permissions&lt;/span&gt;
4604&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;KEY:SECRET&amp;#34;&lt;/span&gt; &amp;gt; .passwd-s3fs
4605&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;chmod 600 .passwd-s3fs
4606&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4607&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# now we mount space to our machine&lt;/span&gt;
4608&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# replace UNIQUE-NAME with the name you choose earlier&lt;/span&gt;
4609&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# if you choose different region for your space be careful about -ourl option (ams3)&lt;/span&gt;
4610&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;s3fs UNIQUE-NAME /mnt/ -ourl=https://ams3.digitaloceanspaces.com -ouse_cache=/tmp
4611&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4612&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# now we try to create a file&lt;/span&gt;
4613&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# once you mount it may take a couple of seconds to retrieve data&lt;/span&gt;
4614&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Hello cruel world&amp;#34;&lt;/span&gt; &amp;gt; /mnt/hello.txt
4615&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;After all this you can return to your browser and go to &lt;a href=&#34;https://cloud.digitalocean.com/spaces&#34;&gt;DigitalOcean
4616Spaces&lt;/a&gt; and click on your created
4617space. If file hello.txt is present you have successfully mounted space to your
4618machine and wrote data to it.&lt;/p&gt;
4619&lt;p&gt;I choose the same region for my Droplet and my Space but you don&#39;t have to. You
4620can have different regions. What this actually does to performance I don&#39;t know.&lt;/p&gt;
4621&lt;p&gt;Additional information on FUSE:&lt;/p&gt;
4622&lt;ul&gt;
4623&lt;li&gt;&lt;a href=&#34;https://github.com/s3fs-fuse/s3fs-fuse&#34;&gt;Github project page for s3fs&lt;/a&gt;&lt;/li&gt;
4624&lt;li&gt;&lt;a href=&#34;https://en.wikipedia.org/wiki/Filesystem_in_Userspace&#34;&gt;FUSE - Filesystem in Userspace&lt;/a&gt;&lt;/li&gt;
4625&lt;/ul&gt;
4626&lt;h2 id=&#34;will-the-performance-degrade-over-time-and-over-different-sizes-of-objects&#34;&gt;Will the performance degrade over time and over different sizes of objects?&lt;/h2&gt;
4627&lt;p&gt;For this task I didn&#39;t want to just read and write text files or uploading
4628images. I actually wanted to figure out if using something like SQlite is viable
4629in this case.&lt;/p&gt;
4630&lt;h3 id=&#34;measurement-experiment-1-file-copy&#34;&gt;Measurement experiment 1: File copy&lt;/h3&gt;
4631&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# first we create some dummy files at different sizes&lt;/span&gt;
4632&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dd &lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt;=/dev/zero of=10KB.dat bs=1024 count=10 &lt;span style=&#34;color:#008000&#34;&gt;#10KB&lt;/span&gt;
4633&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dd &lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt;=/dev/zero of=100KB.dat bs=1024 count=100 &lt;span style=&#34;color:#008000&#34;&gt;#100KB&lt;/span&gt;
4634&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dd &lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt;=/dev/zero of=1MB.dat bs=1024 count=1024 &lt;span style=&#34;color:#008000&#34;&gt;#1MB&lt;/span&gt;
4635&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dd &lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt;=/dev/zero of=10MB.dat bs=1024 count=10240 &lt;span style=&#34;color:#008000&#34;&gt;#10MB&lt;/span&gt;
4636&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4637&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# now we set time command to only return real&lt;/span&gt;
4638&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;TIMEFORMAT=%R
4639&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4640&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# now lets test it&lt;/span&gt;
4641&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;(time cp 10KB.dat /mnt/) |&amp;amp; tee -a 10KB.results.txt
4642&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4643&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# and now we automate&lt;/span&gt;
4644&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# this will perform the same operation 100 times&lt;/span&gt;
4645&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# this will output results into separated files based on objecty size&lt;/span&gt;
4646&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;n=0; &lt;span style=&#34;color:#00f&#34;&gt;while&lt;/span&gt; (( n&#43;&#43; &amp;lt; 100 )); &lt;span style=&#34;color:#00f&#34;&gt;do&lt;/span&gt; (time cp 10KB.dat /mnt/10KB.$n.dat) |&amp;amp; tee -a 10KB.results.txt; &lt;span style=&#34;color:#00f&#34;&gt;done&lt;/span&gt;
4647&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;n=0; &lt;span style=&#34;color:#00f&#34;&gt;while&lt;/span&gt; (( n&#43;&#43; &amp;lt; 100 )); &lt;span style=&#34;color:#00f&#34;&gt;do&lt;/span&gt; (time cp 100KB.dat /mnt/100KB.$n.dat) |&amp;amp; tee -a 100KB.results.txt; &lt;span style=&#34;color:#00f&#34;&gt;done&lt;/span&gt;
4648&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;n=0; &lt;span style=&#34;color:#00f&#34;&gt;while&lt;/span&gt; (( n&#43;&#43; &amp;lt; 100 )); &lt;span style=&#34;color:#00f&#34;&gt;do&lt;/span&gt; (time cp 1MB.dat /mnt/1MB.$n.dat) |&amp;amp; tee -a 1MB.results.txt; &lt;span style=&#34;color:#00f&#34;&gt;done&lt;/span&gt;
4649&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;n=0; &lt;span style=&#34;color:#00f&#34;&gt;while&lt;/span&gt; (( n&#43;&#43; &amp;lt; 100 )); &lt;span style=&#34;color:#00f&#34;&gt;do&lt;/span&gt; (time cp 10MB.dat /mnt/10MB.$n.dat) |&amp;amp; tee -a 10MB.results.txt; &lt;span style=&#34;color:#00f&#34;&gt;done&lt;/span&gt;
4650&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Files of size 100MB were not successfully transferred and ended up displaying
4651error (cp: failed to close &#39;/mnt/100MB.1.dat&#39;: Operation not permitted).&lt;/p&gt;
4652&lt;p&gt;As I suspected, object size is not really that important. Sadly I don&#39;t have the
4653time to test performance over periods of time. But if some of you would do it
4654please send me your data. I would be interested in seeing results.&lt;/p&gt;
4655&lt;p&gt;&lt;strong&gt;Here are plotted results&lt;/strong&gt;&lt;/p&gt;
4656&lt;p&gt;You can download &lt;a href=&#34;/posts/do-fuse/copy-benchmarks.tsv&#34;&gt;raw result here&lt;/a&gt;.
4657Measurements are in seconds.&lt;/p&gt;
4658&lt;script src=&#34;//cdn.plot.ly/plotly-latest.min.js&#34;&gt;&lt;/script&gt;
4659&lt;div id=&#34;copy-benchmarks&#34;&gt;&lt;/div&gt;
4660&lt;script&gt;
4661(function(){
4662 var request = new XMLHttpRequest();
4663 request.open(&#34;GET&#34;, &#34;/posts/do-fuse/copy-benchmarks.tsv&#34;, true);
4664 request.onload = function() {
4665 if (request.status &gt;= 200 &amp;&amp; request.status &lt; 400) {
4666 var payload = request.responseText.trim();
4667 var tsv = payload.split(&#34;\n&#34;);
4668 for (var i=0; i&lt;tsv.length; i&#43;&#43;) { tsv[i] = tsv[i].split(&#34;\t&#34;); }
4669 var traces = [];
4670 var headers = tsv[0];
4671 tsv.shift();
4672 Array.prototype.forEach.call(headers, function(el, idx) {
4673 var x = [];
4674 var y = [];
4675 for (var j=0; j&lt;tsv.length; j&#43;&#43;) {
4676 x.push(j);
4677 y.push(parseFloat(tsv[j][idx].replace(&#34;,&#34;, &#34;.&#34;)));
4678 }
4679 traces.push({ x: x, y: y, type: &#34;scatter&#34;, name: el, line: { width: 1, shape: &#34;spline&#34; } });
4680 });
4681 var copy = Plotly.newPlot(&#34;copy-benchmarks&#34;, traces, { legend: {&#34;orientation&#34;: &#34;h&#34;}, height: 400, margin: { l: 40, r: 0, b: 20, t: 30, pad: 0 }, yaxis: { title: &#34;execution time in seconds&#34;, titlefont: { size: 12 } }, xaxis: { title: &#34;fn(i)&#34;, titlefont: { size: 12 } } });
4682 } else { }
4683 };
4684 request.onerror = function() { };
4685 request.send(null);
4686})();
4687&lt;/script&gt;
4688&lt;p&gt;As far as these tests show, performance is quite stable and can be predicted
4689which is fantastic. But this is a small test and spans only over couple of
4690hours. So you should not completely trust them.&lt;/p&gt;
4691&lt;h3 id=&#34;measurement-experiment-2-sqlite-performanse&#34;&gt;Measurement experiment 2: SQLite performanse&lt;/h3&gt;
4692&lt;p&gt;I was unable to use database file directly from mounted drive so this is a no-go
4693as I suspected. So I executed code below on a local disk just to get some
4694benchmarks. I inserted 1000 records with DROPTABLE, CREATETABLE, INSERTMANY,
4695FETCHALL, COMMIT for 1000 times to generate statistics. As you can see
4696performance of SQLite is quite amazing. You could then potentially just copy
4697file to mounted drive and be done with it.&lt;/p&gt;
4698&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; time
4699&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; sqlite3
4700&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; sys
4701&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4702&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt; len(sys.argv) &amp;lt; 3:
4703&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; print(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;usage: python sqlite-benchmark.py DB_PATH NUM_RECORDS REPEAT&amp;#34;&lt;/span&gt;)
4704&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; exit()
4705&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4706&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;def&lt;/span&gt; data_iter(x):
4707&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;for&lt;/span&gt; i &lt;span style=&#34;color:#00f&#34;&gt;in&lt;/span&gt; range(x):
4708&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;yield&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;m&amp;#34;&lt;/span&gt; &#43; str(i), &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;f&amp;#34;&lt;/span&gt; &#43; str(i*i)
4709&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4710&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;header_line = &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;%s&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;\t&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;%s&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;\t&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;%s&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;\t&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;%s&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;\t&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;%s&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt; % (&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;DROPTABLE&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;CREATETABLE&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;INSERTMANY&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;FETCHALL&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;COMMIT&amp;#34;&lt;/span&gt;)
4711&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;with&lt;/span&gt; open(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;sqlite-benchmarks.tsv&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;w&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#00f&#34;&gt;as&lt;/span&gt; fp:
4712&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; fp.write(header_line)
4713&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4714&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;start_time = time.time()
4715&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;conn = sqlite3.connect(sys.argv[1])
4716&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;c = conn.cursor()
4717&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;end_time = time.time()
4718&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;result_time = CONNECT = end_time - start_time
4719&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;CONNECT: &lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;%g&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt; seconds&amp;#34;&lt;/span&gt; % (result_time))
4720&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4721&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;start_time = time.time()
4722&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;c.execute(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;PRAGMA journal_mode=WAL&amp;#34;&lt;/span&gt;)
4723&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;c.execute(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;PRAGMA temp_store=MEMORY&amp;#34;&lt;/span&gt;)
4724&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;c.execute(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;PRAGMA synchronous=OFF&amp;#34;&lt;/span&gt;)
4725&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;result_time = PRAGMA = end_time - start_time
4726&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;PRAGMA: &lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;%g&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt; seconds&amp;#34;&lt;/span&gt; % (result_time))
4727&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4728&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;for&lt;/span&gt; i &lt;span style=&#34;color:#00f&#34;&gt;in&lt;/span&gt; range(int(sys.argv[3])):
4729&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; print(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;#&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;%i&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt; % (i))
4730&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4731&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; start_time = time.time()
4732&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; c.execute(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;drop table if exists test&amp;#34;&lt;/span&gt;)
4733&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; end_time = time.time()
4734&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; result_time = DROPTABLE = end_time - start_time
4735&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; print(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;DROPTABLE: &lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;%g&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt; seconds&amp;#34;&lt;/span&gt; % (result_time))
4736&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4737&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; start_time = time.time()
4738&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; c.execute(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;create table if not exists test(a,b)&amp;#34;&lt;/span&gt;)
4739&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; end_time = time.time()
4740&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; result_time = CREATETABLE = end_time - start_time
4741&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; print(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;CREATETABLE: &lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;%g&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt; seconds&amp;#34;&lt;/span&gt; % (result_time))
4742&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4743&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; start_time = time.time()
4744&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; c.executemany(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;INSERT INTO test VALUES (?, ?)&amp;#34;&lt;/span&gt;, data_iter(int(sys.argv[2])))
4745&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; end_time = time.time()
4746&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; result_time = INSERTMANY = end_time - start_time
4747&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; print(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;INSERTMANY: &lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;%g&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt; seconds&amp;#34;&lt;/span&gt; % (result_time))
4748&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4749&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; start_time = time.time()
4750&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; c.execute(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;select count(*) from test&amp;#34;&lt;/span&gt;)
4751&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; res = c.fetchall()
4752&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; end_time = time.time()
4753&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; result_time = FETCHALL = end_time - start_time
4754&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; print(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;FETCHALL: &lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;%g&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt; seconds&amp;#34;&lt;/span&gt; % (result_time))
4755&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4756&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; start_time = time.time()
4757&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; conn.commit()
4758&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; end_time = time.time()
4759&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; result_time = COMMIT = end_time - start_time
4760&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; print(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;COMMIT: &lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;%g&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt; seconds&amp;#34;&lt;/span&gt; % (result_time))
4761&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4762&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; print
4763&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; log_line = &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;%f&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;\t&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;%f&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;\t&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;%f&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;\t&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;%f&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;\t&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;%f&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;\n&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt; % (DROPTABLE, CREATETABLE, INSERTMANY, FETCHALL, COMMIT)
4764&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;with&lt;/span&gt; open(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;sqlite-benchmarks.tsv&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;a&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#00f&#34;&gt;as&lt;/span&gt; fp:
4765&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; fp.write(log_line)
4766&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4767&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;start_time = time.time()
4768&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;conn.close()
4769&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;end_time = time.time()
4770&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;result_time = CLOSE = end_time - start_time
4771&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;CLOSE: &lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;%g&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt; seconds&amp;#34;&lt;/span&gt; % (result_time))
4772&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;You can download &lt;a href=&#34;/posts/do-fuse/sqlite-benchmarks.tsv&#34;&gt;raw result here&lt;/a&gt;. And
4773again, these results are done on a local block storage and do not represent
4774capabilities of object storage. With my current approach and state of the test
4775code these can not be done. I would need to make Python code much more robust
4776and check locking etc.&lt;/p&gt;
4777&lt;div id=&#34;sqlite-benchmarks&#34;&gt;&lt;/div&gt;
4778&lt;script&gt;
4779(function(){
4780 var request = new XMLHttpRequest();
4781 request.open(&#34;GET&#34;, &#34;/posts/do-fuse/sqlite-benchmarks.tsv&#34;, true);
4782 request.onload = function() {
4783 if (request.status &gt;= 200 &amp;&amp; request.status &lt; 400) {
4784 var payload = request.responseText.trim();
4785 var tsv = payload.split(&#34;\n&#34;);
4786 for (var i=0; i&lt;tsv.length; i&#43;&#43;) { tsv[i] = tsv[i].split(&#34;\t&#34;); }
4787 var traces = [];
4788 var headers = tsv[0];
4789 tsv.shift();
4790 Array.prototype.forEach.call(headers, function(el, idx) {
4791 var x = [];
4792 var y = [];
4793 for (var j=0; j&lt;tsv.length; j&#43;&#43;) {
4794 x.push(j);
4795 y.push(parseFloat(tsv[j][idx].replace(&#34;,&#34;, &#34;.&#34;)));
4796 }
4797 traces.push({ x: x, y: y, type: &#34;scatter&#34;, name: el, line: { width: 1, shape: &#34;spline&#34; } });
4798 });
4799 var sqlite = Plotly.newPlot(&#34;sqlite-benchmarks&#34;, traces, { legend: {&#34;orientation&#34;: &#34;h&#34;}, height: 400, margin: { l: 50, r: 0, b: 20, t: 30, pad: 0 }, yaxis: { title: &#34;execution time in seconds&#34;, titlefont: { size: 12 } } });
4800 } else { }
4801 };
4802 request.onerror = function() { };
4803 request.send(null);
4804})();
4805&lt;/script&gt;
4806&lt;h2 id=&#34;can-storage-be-mounted-on-multiple-machines-at-the-same-time-and-be-writable&#34;&gt;Can storage be mounted on multiple machines at the same time and be writable?&lt;/h2&gt;
4807&lt;p&gt;Well, this one didn&#39;t take long to test. And the answer is &lt;strong&gt;YES&lt;/strong&gt;. I mounted
4808space on both machines and measured same performance on both machines. But
4809because file is downloaded before write and then uploaded on complete there
4810could potentially be problems is another process is trying to access the same
4811file.&lt;/p&gt;
4812&lt;h2 id=&#34;observations-and-conslusion&#34;&gt;Observations and conslusion&lt;/h2&gt;
4813&lt;p&gt;Using Spaces in this way makes it easier to access and manage files. But besides
4814that you would need to write additional code to make this one play nice with you
4815applications.&lt;/p&gt;
4816&lt;p&gt;Nevertheless, this was extremely simple to setup and use and this is just
4817another excellent product in DigitalOcean product line. I found this exercise
4818very valuable and am thinking about implementing some sort of mechanism for
4819SQLite, so data can be stored on Spaces and accessed by many VM&#39;s. For a project
4820where data doesn&#39;t need to be accessible in real-time and can have couple of
4821minutes old data this would be very interesting. If any of you find this
4822proposal interesting please write in a comment box below or shoot me an email
4823and I will keep you posted.&lt;/p&gt;
4824</content:encoded>
4825 </item>
4826
4827
4828
4829 <item>
4830 <title>Simple IOT application supported by real-time monitoring and data history</title>
4831 <link>https://mitjafelicijan.com/simple-iot-application.html</link>
4832 <pubDate>Fri, 11 Aug 2017 12:00:00 &#43;0200</pubDate>
4833 <guid>https://mitjafelicijan.com/simple-iot-application.html</guid>
4834 <description>Initial thoughtsI have been developing these kind of application for the better part of my last5 years and people keep asking me how to approach developing such applicationand I will give a try explaining it here.</description>
4835 <content:encoded>&lt;h2 id=&#34;initial-thoughts&#34;&gt;Initial thoughts&lt;/h2&gt;
4836&lt;p&gt;I have been developing these kind of application for the better part of my last
48375 years and people keep asking me how to approach developing such application
4838and I will give a try explaining it here.&lt;/p&gt;
4839&lt;p&gt;IOT applications are really no different than any other kind of applications.
4840We have data that needs to be collected and visualized in some form of tables or
4841charts. The main difference here is that most of the times these data is
4842collected by some kind of device foreign to developer that mainly operates in
4843web domain. But fear not, it&#39;s not that different than writing some JavaScript.&lt;/p&gt;
4844&lt;p&gt;There are many devices able to transmit data via wireless or wired network by
4845default but for the sake of example we will be using commonly known Arduino with
4846wireless module already on the board → &lt;a href=&#34;https://store.arduino.cc/arduino-mkr1000&#34;&gt;Arduino
4847MKR1000&lt;/a&gt;.&lt;/p&gt;
4848&lt;p&gt;In order to make this little project as accessible to others as possible I will
4849try to make it as inexpensive as possible. And by this I mean that I will avoid
4850using hosted virtual servers and will be using my own laptop as a server. But
4851you must buy Arduino MKR1000 to follow steps below. But if you would want to
4852deploy this software I would suggest using
4853&lt;a href=&#34;https://www.digitalocean.com&#34;&gt;DigitalOcean&lt;/a&gt; → smallest VPS is only per month
4854making this one of the most affordable option out there. Please notice that this
4855software will not run on stock web hosting that only supports LAMP (Linux,
4856Apache, MySQL, and PHP).&lt;/p&gt;
4857&lt;p&gt;But before we begin please take notice that this is strictly experimental code
4858and not well optimized and there are much better ways in handling some aspects
4859of the application but that requires much deeper knowledge of technology that is
4860not needed for an example like this.&lt;/p&gt;
4861&lt;p&gt;&lt;strong&gt;Development steps&lt;/strong&gt;&lt;/p&gt;
4862&lt;ol&gt;
4863&lt;li&gt;Simple Python API that will receive and store incoming data.&lt;/li&gt;
4864&lt;li&gt;Prototype C&#43;&#43; code that will read &amp;quot;sensor data&amp;quot; and transmit it to API.&lt;/li&gt;
4865&lt;li&gt;Data visualization with charts → extends Python web application.&lt;/li&gt;
4866&lt;/ol&gt;
4867&lt;p&gt;Step 1. and 3. will share the same web application. One route will be dedicated
4868to API and another to serving HTML with chart.&lt;/p&gt;
4869&lt;p&gt;Schema below represents what we will try to achieve and how different parts
4870correlates to each other.&lt;/p&gt;
4871&lt;figure&gt;
4872&lt;img src=&#34;/posts/iot-application/simple-iot-application-overview.svg&#34; alt=&#34;Overview&#34; /&gt;
4873&lt;/figure&gt;
4874&lt;h2 id=&#34;simple-python-api&#34;&gt;Simple Python API&lt;/h2&gt;
4875&lt;p&gt;I have always been a fan of simplicity so we will be using &lt;a href=&#34;https://bottlepy.org/docs/dev/&#34;&gt;Bottle: Python Web
4876Framework&lt;/a&gt;. It is a single file web framework
4877that seriously simplifies working with routes, templating and has built-in web
4878server that satisfies our need in this case.&lt;/p&gt;
4879&lt;p&gt;First we need to install bottle package. This can be done by downloading
4880&lt;code&gt;bottle.py&lt;/code&gt; and placing it in the root of your application or by using pip
4881software &lt;code&gt;pip install bottle --user&lt;/code&gt;.&lt;/p&gt;
4882&lt;p&gt;If you are using Linux or MacOS then Python is already installed. If you will
4883try to test this on Windows please install &lt;a href=&#34;https://www.python.org/downloads/windows/&#34;&gt;Python for
4884Windows&lt;/a&gt;. There may be some problems
4885with path when you will try to launch &lt;code&gt;python webapp.py&lt;/code&gt; so please take care
4886of this before you continue.&lt;/p&gt;
4887&lt;h3 id=&#34;basic-web-application&#34;&gt;Basic web application&lt;/h3&gt;
4888&lt;p&gt;Most basic bottle application is quite simple. Paste code below in
4889&lt;code&gt;webapp.py&lt;/code&gt; file and save.&lt;/p&gt;
4890&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# -*- coding: utf-8 -*-&lt;/span&gt;
4891&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4892&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; bottle
4893&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4894&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# initializing bottle app&lt;/span&gt;
4895&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;app = bottle.Bottle()
4896&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4897&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# triggered when / is accessed from browser&lt;/span&gt;
4898&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# only accepts GET → no POST allowed&lt;/span&gt;
4899&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@app.route(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;, method=[&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;GET&amp;#34;&lt;/span&gt;])
4900&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;def&lt;/span&gt; route_default():
4901&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;howdy from python&amp;#34;&lt;/span&gt;
4902&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4903&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# starting server on http://0.0.0.0:5000&lt;/span&gt;
4904&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt; __name__ == &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;__main__&amp;#34;&lt;/span&gt;:
4905&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; bottle.run(
4906&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; app = app,
4907&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; host = &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;0.0.0.0&amp;#34;&lt;/span&gt;,
4908&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; port = 5000,
4909&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; debug = &lt;span style=&#34;color:#00f&#34;&gt;True&lt;/span&gt;,
4910&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; reloader = &lt;span style=&#34;color:#00f&#34;&gt;True&lt;/span&gt;,
4911&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; catchall = &lt;span style=&#34;color:#00f&#34;&gt;True&lt;/span&gt;,
4912&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; )
4913&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To run this simple application you should open command prompt or terminal on
4914your machine and go to the folder containing your file and type &lt;code&gt;python webapp.py&lt;/code&gt;. If everything goes ok then open your web browser and point it to
4915&lt;code&gt;http://0.0.0.0:5000&lt;/code&gt;.&lt;/p&gt;
4916&lt;p&gt;If you would like change the port of your application (like port 80) and not use
4917root to run your app this will present a problem. The TCP/IP port numbers below
49181024 are privileged ports → this is a security feature. So in order of
4919simplicity and security use a port number above 1024 like I have used port 5000.&lt;/p&gt;
4920&lt;p&gt;If this fails at any time please fix it before you continue, because nothing
4921below will work otherwise.&lt;/p&gt;
4922&lt;p&gt;We use 0.0.0.0 as default host so that this app is available over your local
4923network. If you find your local ip &lt;code&gt;ifconfig&lt;/code&gt; and try accessing this site
4924with your phone (if on same network/router as your machine) this should work as
4925well (example of such ip &lt;code&gt;http://192.168.1.15:5000&lt;/code&gt;). This is a must have
4926because Arduino will be accessing this application to send it&#39;s data.&lt;/p&gt;
4927&lt;h3 id=&#34;web-application-security&#34;&gt;Web application security&lt;/h3&gt;
4928&lt;p&gt;There is a lot to be said about security and is a topic of many books. Of course
4929all this can not be written here but to just establish some basic security → you
4930should always use SSL with your application. Some fantastic free certificates
4931are available by &lt;a href=&#34;https://letsencrypt.org&#34;&gt;Let&#39;s Encrypt - Free SSL/TLS
4932Certificates&lt;/a&gt;. With SSL certificate installed you
4933should then make use of HTTP headers and send your &amp;quot;API key&amp;quot; via a header. If
4934your key is send via header then this key is encrypted by SSL and send encrypted
4935over the network. Never send your api keys by GET parameter like
4936&lt;code&gt;http://example.com/?api_key=somekeyvalue&lt;/code&gt;. The problem that this kind of
4937sending presents is that this key is visible in logs and by network sniffers.&lt;/p&gt;
4938&lt;p&gt;There is a fantastic article describing some aspects about security: &lt;a href=&#34;https://www.keycdn.com/blog/web-application-security-best-practices/&#34;&gt;11 Web
4939Application Security Best
4940Practices&lt;/a&gt;. Please
4941check it out.&lt;/p&gt;
4942&lt;h3 id=&#34;simple-api-for-writing-data-points&#34;&gt;Simple API for writing data-points&lt;/h3&gt;
4943&lt;p&gt;We will now be using boilerplate code from example above and extend it to be
4944SQLite3 because it plays well with Python and can store quite large amount of
4945able to write data received by API to local storage. For example use I will use
4946data. I have been using it to collect gigabytes of data in a single database
4947without any corruption or problems → your experience may vary.&lt;/p&gt;
4948&lt;p&gt;To avoid learning SQLite I will be using &lt;a href=&#34;https://dataset.readthedocs.io/en/latest/index.html&#34;&gt;Dataset: databases for lazy
4949people&lt;/a&gt;. This package
4950abstracts SQL and simplifies writing and reading data from database. You should
4951install this package with pip software &lt;code&gt;pip install dataset --user&lt;/code&gt;.&lt;/p&gt;
4952&lt;p&gt;Because API will use POST method I will be testing if code works correctly by
4953using &lt;a href=&#34;https://chrome.google.com/webstore/detail/restlet-client-rest-api-t/aejoelaoggembcahagimdiliamlcdmfm&#34;&gt;Restlet Client for Google
4954Chrome&lt;/a&gt;.
4955This software also allows you to set headers → for basic security with API_KEY.&lt;/p&gt;
4956&lt;p&gt;To quickly generate passwords or API keys I usually use this nifty website
4957&lt;a href=&#34;https://randomkeygen.com/&#34;&gt;RandomKeygen&lt;/a&gt;.&lt;/p&gt;
4958&lt;p&gt;Copy and paste code below over your previous code in file &lt;code&gt;webapp.py&lt;/code&gt;.&lt;/p&gt;
4959&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# -*- coding: utf-8 -*-&lt;/span&gt;
4960&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4961&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; time
4962&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; bottle
4963&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; random
4964&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; dataset
4965&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4966&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# initializing bottle app&lt;/span&gt;
4967&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;app = bottle.Bottle()
4968&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4969&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# connects to sqlite database&lt;/span&gt;
4970&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# check_same_thread=False allows using it in multi-threaded mode&lt;/span&gt;
4971&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;app.config[&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;dsn&amp;#34;&lt;/span&gt;] = dataset.connect(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;sqlite:///data.db?check_same_thread=False&amp;#34;&lt;/span&gt;)
4972&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4973&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# api key that will be used in Arduino code&lt;/span&gt;
4974&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;app.config[&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;api_key&amp;#34;&lt;/span&gt;] = &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;JtF2aUE5SGHfVJBCG5SH&amp;#34;&lt;/span&gt;
4975&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4976&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# triggered when /api is accessed from browser&lt;/span&gt;
4977&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# only accepts POST → no GET allowed&lt;/span&gt;
4978&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@app.route(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;/api&amp;#34;&lt;/span&gt;, method=[&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;POST&amp;#34;&lt;/span&gt;])
4979&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;def&lt;/span&gt; route_default():
4980&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; status = 400
4981&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ts = int(time.time()) &lt;span style=&#34;color:#008000&#34;&gt;# current timestamp&lt;/span&gt;
4982&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; value = bottle.request.body.read() &lt;span style=&#34;color:#008000&#34;&gt;# data from device&lt;/span&gt;
4983&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; api_key = bottle.request.get_header(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Api_Key&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#008000&#34;&gt;# api key from header&lt;/span&gt;
4984&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4985&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;# outputs to console received data for debug reason&lt;/span&gt;
4986&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; print &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt; :: &lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt;.format(value, api_key)
4987&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4988&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;# if api_key is correct and value is present&lt;/span&gt;
4989&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;# then writes attribute to point table&lt;/span&gt;
4990&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt; api_key == app.config[&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;api_key&amp;#34;&lt;/span&gt;] &lt;span style=&#34;color:#00f&#34;&gt;and&lt;/span&gt; value:
4991&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; app.config[&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;dsn&amp;#34;&lt;/span&gt;][&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;point&amp;#34;&lt;/span&gt;].insert(dict(ts=ts, value=value))
4992&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; status = 200
4993&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4994&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;# we only need to return status&lt;/span&gt;
4995&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;return&lt;/span&gt; bottle.HTTPResponse(status=status, body=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
4996&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
4997&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# starting server on http://0.0.0.0:5000&lt;/span&gt;
4998&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt; __name__ == &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;__main__&amp;#34;&lt;/span&gt;:
4999&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; bottle.run(
5000&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; app = app,
5001&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; host = &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;0.0.0.0&amp;#34;&lt;/span&gt;,
5002&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; port = 5000,
5003&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; debug = &lt;span style=&#34;color:#00f&#34;&gt;True&lt;/span&gt;,
5004&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; reloader = &lt;span style=&#34;color:#00f&#34;&gt;True&lt;/span&gt;,
5005&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; catchall = &lt;span style=&#34;color:#00f&#34;&gt;True&lt;/span&gt;,
5006&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; )
5007&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To run this simply go to folder containing python file and run &lt;code&gt;python webapp.py&lt;/code&gt; from terminal. If everything goes ok you should have simple API
5008available via POST method on /api route.&lt;/p&gt;
5009&lt;p&gt;After testing the service with Restlet Client you should be able to view your
5010data in a database file &lt;code&gt;data.db&lt;/code&gt;.&lt;/p&gt;
5011&lt;figure&gt;
5012&lt;img src=&#34;/posts/iot-application/iot-rest-example.png&#34; alt=&#34;REST settings example&#34; /&gt;
5013&lt;/figure&gt;
5014&lt;p&gt;You can also check the contents of new database file by using desktop client
5015for SQLite → &lt;a href=&#34;http://sqlitebrowser.org/&#34;&gt;DB Browser for SQLite&lt;/a&gt;.&lt;/p&gt;
5016&lt;figure&gt;
5017&lt;img src=&#34;/posts/iot-application/iot-sqlite-db.png&#34; alt=&#34;SQLite database example&#34; /&gt;
5018&lt;/figure&gt;
5019&lt;p&gt;Table structure is as simple as it can be. We have ts (timestamp) and value
5020(value from Arduino). As you can see timestamp is generated on API side. If you
5021would happen to have atomic clock on Arduino it would be then better to generate
5022and send timestamp with the value. This would be particularity useful if we
5023would be collecting sensor data at a higher frequency and then sending this data
5024in bulk to API.&lt;/p&gt;
5025&lt;p&gt;If you will deploy this app with uWSGI and multi-threaded, use DSN (Data Source
5026Name) url with &lt;code&gt;?check_same_thread=False&lt;/code&gt;.&lt;/p&gt;
5027&lt;p&gt;Ok, now that we have some sort of a working API with some basic security so
5028unwanted people can not post data to your database can we proceed further and
5029try to program Arduino to send data to API.&lt;/p&gt;
5030&lt;h2 id=&#34;sending-data-to-api-with-arduino-mkr1000&#34;&gt;Sending data to API with Arduino MKR1000&lt;/h2&gt;
5031&lt;p&gt;First of all you should have MKR1000 module and microUSB cable to proceed. If
5032you have ever done any work with Arduino you should know that you also need
5033&lt;a href=&#34;https://www.arduino.cc/en/Main/Software&#34;&gt;Arduino IDE&lt;/a&gt;. On provided link you
5034should be able to download and install IDE. Once that task is completed and you
5035have successfully run blink example you should proceed to the next step.&lt;/p&gt;
5036&lt;p&gt;In order to use wireless capabilities of MKR1000 you need to first install
5037&lt;a href=&#34;https://www.arduino.cc/en/Reference/WiFi101&#34;&gt;WiFi101 library&lt;/a&gt; in Arduino IDE.
5038Please check before you install, you may already have it installed.&lt;/p&gt;
5039&lt;p&gt;Code below is a working example that sends data to API. Before you try to test
5040your code make sure you have run Python web application. Then change settings
5041for wifi, api endpoint and api_key. If by some reason code bellow doesn&#39;t work
5042for you please leave a comment and I&#39;ll try to help.&lt;/p&gt;
5043&lt;p&gt;Once you have opened IDE and copied this code try to compile and upload it.
5044Then open &amp;quot;Serial monitor&amp;quot; to see if any output is presented by Arduino.&lt;/p&gt;
5045&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;&amp;lt;WiFi101.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#00f&#34;&gt;
5046&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;&lt;/span&gt;
5047&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;// wifi settings
5048&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#2b91af&#34;&gt;char&lt;/span&gt; ssid[] = &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;ssid-name&amp;#34;&lt;/span&gt;;
5049&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#2b91af&#34;&gt;char&lt;/span&gt; pass[] = &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;ssid-password&amp;#34;&lt;/span&gt;;
5050&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5051&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;// api server enpoint
5052&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#2b91af&#34;&gt;char&lt;/span&gt; server[] = &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;192.168.6.22&amp;#34;&lt;/span&gt;;
5053&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#2b91af&#34;&gt;int&lt;/span&gt; port = 5000;
5054&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5055&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;// api key that must be the same as the one in Python code
5056&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt;String api_key = &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;JtF2aUE5SGHfVJBCG5SH&amp;#34;&lt;/span&gt;;
5057&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5058&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;// frequency data is sent in ms - every 5 seconds
5059&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#2b91af&#34;&gt;int&lt;/span&gt; timeout = 1000 * 5;
5060&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5061&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#2b91af&#34;&gt;int&lt;/span&gt; status = WL_IDLE_STATUS;
5062&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5063&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#2b91af&#34;&gt;void&lt;/span&gt; setup() {
5064&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5065&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;// initialize serial and wait for port to open:
5066&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt; Serial.begin(9600);
5067&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; delay(1000);
5068&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5069&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;// check for the presence of the shield
5070&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt; (WiFi.status() == WL_NO_SHIELD) {
5071&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; Serial.println(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;WiFi shield not present&amp;#34;&lt;/span&gt;);
5072&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;while&lt;/span&gt; (true);
5073&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
5074&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5075&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;// attempt to connect to wifi network
5076&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;while&lt;/span&gt; (status != WL_CONNECTED) {
5077&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; Serial.print(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Attempting to connect to SSID: &amp;#34;&lt;/span&gt;);
5078&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; Serial.println(ssid);
5079&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; status = WiFi.begin(ssid, pass);
5080&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;// wait 10 seconds for connection
5081&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt; delay(10000);
5082&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
5083&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5084&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;// output wifi status to serial monitor
5085&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt; Serial.print(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;SSID: &amp;#34;&lt;/span&gt;);
5086&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; Serial.println(WiFi.SSID());
5087&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5088&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; IPAddress ip = WiFi.localIP();
5089&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; Serial.print(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;IP Address: &amp;#34;&lt;/span&gt;);
5090&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; Serial.println(ip);
5091&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5092&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#2b91af&#34;&gt;long&lt;/span&gt; rssi = WiFi.RSSI();
5093&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; Serial.print(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;signal strength (RSSI):&amp;#34;&lt;/span&gt;);
5094&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; Serial.print(rssi);
5095&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; Serial.println(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34; dBm&amp;#34;&lt;/span&gt;);
5096&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
5097&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5098&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#2b91af&#34;&gt;void&lt;/span&gt; loop() {
5099&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; WiFiClient client;
5100&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5101&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt; (client.connect(server, port)) {
5102&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5103&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;// I use random number generator for this example
5104&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt; &lt;span style=&#34;color:#008000&#34;&gt;// but you can use analog or digital inputs from arduino
5105&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt; String content = String(random(1000));
5106&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5107&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; client.println(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;POST /api HTTP/1.1&amp;#34;&lt;/span&gt;);
5108&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; client.println(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Connection: close&amp;#34;&lt;/span&gt;);
5109&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; client.println(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Api-Key: &amp;#34;&lt;/span&gt; &#43; api_key);
5110&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; client.println(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Content-Length: &amp;#34;&lt;/span&gt; &#43; String(content.length()));
5111&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; client.println();
5112&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; client.println(content);
5113&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5114&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; delay(100);
5115&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; client.stop();
5116&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; Serial.println(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Data sent successfully ...&amp;#34;&lt;/span&gt;);
5117&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5118&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; } &lt;span style=&#34;color:#00f&#34;&gt;else&lt;/span&gt; {
5119&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; Serial.println(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Problem sending data ...&amp;#34;&lt;/span&gt;);
5120&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
5121&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5122&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;// waits for x seconds and continue looping
5123&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt; delay(timeout);
5124&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
5125&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;As seen from example you can notice that Arduino is generating random integer
5126between [ 0 .. 1000 ]. You can easily replace this with a temperature sensor or
5127any other kind of sensor.&lt;/p&gt;
5128&lt;p&gt;Now that we have API under the hood and Arduino is sending demo data we can now
5129focus on data visualization.&lt;/p&gt;
5130&lt;h2 id=&#34;data-visualization&#34;&gt;Data visualization&lt;/h2&gt;
5131&lt;p&gt;Before we continue we should examine our project folder structure. Currently we
5132only have two files in our project:&lt;/p&gt;
5133&lt;p&gt;&lt;em&gt;simple-iot-app/&lt;/em&gt;&lt;/p&gt;
5134&lt;ul&gt;
5135&lt;li&gt;&lt;em&gt;webapp.py&lt;/em&gt;&lt;/li&gt;
5136&lt;li&gt;&lt;em&gt;data.db&lt;/em&gt;&lt;/li&gt;
5137&lt;/ul&gt;
5138&lt;p&gt;We will now add HTML template that will contain CSS and JavaScript code inline
5139for the simplicity reason. And for the bottle framework to be able to scan root
5140application folder for templates we will add &lt;code&gt;bottle.TEMPLATE_PATH.insert(0, &amp;quot;./&amp;quot;)&lt;/code&gt; in &lt;code&gt;webapp.py&lt;/code&gt;. By default bottle framework uses &lt;code&gt;views/&lt;/code&gt;
5141subfolder to store templates. This is not the ideal situation and if you will
5142use bottle to develop web applications you should use native behavior and store
5143templates in it&#39;s predefined folder. But for the sake of example we will
5144over-ride this. Be careful to fully replace your code with new code that is
5145provided below. Avoid partially replacing code in file :) Also new code for
5146reading data-points is provided in Python example below.&lt;/p&gt;
5147&lt;p&gt;First we add new route to our web application. It should be trigger when browser
5148hits root of application &lt;code&gt;http://0.0.0.0:5000/&lt;/code&gt;. This route will do nothing
5149more than render &lt;code&gt;frontend.html&lt;/code&gt; template. This is done by &lt;code&gt;return bottle.template(&amp;quot;frontend.html&amp;quot;)&lt;/code&gt;. Check code below to further examine how
5150exactly this is done.&lt;/p&gt;
5151&lt;p&gt;Now we will expand &lt;code&gt;/api&lt;/code&gt; route and use different methods to write or read
5152data-points. For writing data-point we will use POST method and for reading
5153points we will use GET method. GET method will return JSON object with latest
5154readings and historical data.&lt;/p&gt;
5155&lt;p&gt;There is a fantastic JavaScript library for plotting time-series charts called
5156&lt;a href=&#34;https://www.metricsgraphicsjs.org&#34;&gt;MetricsGraphics.js&lt;/a&gt; that is based on
5157&lt;a href=&#34;https://d3js.org/&#34;&gt;D3.js&lt;/a&gt; library for visualizing data.&lt;/p&gt;
5158&lt;p&gt;Data schema required by MetricsGraphics.js → to achieve this we need to
5159transform data from database into this format:&lt;/p&gt;
5160&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;[
5161&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {
5162&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;date&amp;#34;: &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;2017-08-11 01:07:20&amp;#34;&lt;/span&gt;,
5163&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;value&amp;#34;: 933
5164&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; },
5165&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {
5166&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;date&amp;#34;: &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;2017-08-11 01:07:30&amp;#34;&lt;/span&gt;,
5167&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;value&amp;#34;: 743
5168&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
5169&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;]
5170&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Web application is now complete and we only need &lt;code&gt;frontend.html&lt;/code&gt; that we
5171will develop now. If you would try to start web app now and go to root app this
5172will return error because we don&#39;t have frontend.html yet.&lt;/p&gt;
5173&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# -*- coding: utf-8 -*-&lt;/span&gt;
5174&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5175&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; time
5176&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; bottle
5177&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; json
5178&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; datetime
5179&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; random
5180&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; dataset
5181&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5182&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# initializing bottle app&lt;/span&gt;
5183&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;app = bottle.Bottle()
5184&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5185&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# adds root directory as template folder&lt;/span&gt;
5186&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bottle.TEMPLATE_PATH.insert(0, &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;./&amp;#34;&lt;/span&gt;)
5187&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5188&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# connects to sqlite database&lt;/span&gt;
5189&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# check_same_thread=False allows using it in multi-threaded mode&lt;/span&gt;
5190&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;app.config[&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;db&amp;#34;&lt;/span&gt;] = dataset.connect(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;sqlite:///data.db?check_same_thread=False&amp;#34;&lt;/span&gt;)
5191&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5192&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# api key that will be used in Arduino code&lt;/span&gt;
5193&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;app.config[&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;api_key&amp;#34;&lt;/span&gt;] = &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;JtF2aUE5SGHfVJBCG5SH&amp;#34;&lt;/span&gt;
5194&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5195&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# triggered when / is accessed from browser&lt;/span&gt;
5196&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# only accepts GET → no POST allowed&lt;/span&gt;
5197&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@app.route(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;, method=[&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;GET&amp;#34;&lt;/span&gt;])
5198&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;def&lt;/span&gt; route_default():
5199&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;return&lt;/span&gt; bottle.template(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;frontend.html&amp;#34;&lt;/span&gt;)
5200&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5201&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# triggered when /api is accessed from browser&lt;/span&gt;
5202&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# accepts POST and GET&lt;/span&gt;
5203&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@app.route(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;/api&amp;#34;&lt;/span&gt;, method=[&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;GET&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;POST&amp;#34;&lt;/span&gt;])
5204&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;def&lt;/span&gt; route_default():
5205&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5206&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;# if method is POST then we write datapoint&lt;/span&gt;
5207&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt; bottle.request.method == &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;POST&amp;#34;&lt;/span&gt;:
5208&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; status = 400
5209&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ts = int(time.time()) &lt;span style=&#34;color:#008000&#34;&gt;# current timestamp&lt;/span&gt;
5210&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; value = bottle.request.body.read() &lt;span style=&#34;color:#008000&#34;&gt;# data from device&lt;/span&gt;
5211&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; api_key = bottle.request.get_header(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Api-Key&amp;#34;&lt;/span&gt;) &lt;span style=&#34;color:#008000&#34;&gt;# api key from header&lt;/span&gt;
5212&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5213&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;# outputs to console recieved data for debug reason&lt;/span&gt;
5214&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; print &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&amp;gt;&amp;gt;&amp;gt; &lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt; :: &lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;{}&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt;.format(value, api_key)
5215&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5216&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;# if api_key is correct and value is present&lt;/span&gt;
5217&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;# then writes attribute to point table&lt;/span&gt;
5218&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt; api_key == app.config[&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;api_key&amp;#34;&lt;/span&gt;] &lt;span style=&#34;color:#00f&#34;&gt;and&lt;/span&gt; value:
5219&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; app.config[&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;db&amp;#34;&lt;/span&gt;][&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;point&amp;#34;&lt;/span&gt;].insert(dict(ts=ts, value=value))
5220&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; status = 200
5221&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5222&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;# we only need to return status&lt;/span&gt;
5223&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;return&lt;/span&gt; bottle.HTTPResponse(status=status, body=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&amp;#34;&lt;/span&gt;)
5224&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5225&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;# if method is GET then we read datapoint&lt;/span&gt;
5226&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;else&lt;/span&gt;:
5227&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; response = []
5228&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; datapoints = app.config[&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;db&amp;#34;&lt;/span&gt;][&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;point&amp;#34;&lt;/span&gt;].all()
5229&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5230&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;for&lt;/span&gt; point &lt;span style=&#34;color:#00f&#34;&gt;in&lt;/span&gt; datapoints:
5231&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; response.append({
5232&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;date&amp;#34;&lt;/span&gt;: datetime.datetime.fromtimestamp(int(point[&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;ts&amp;#34;&lt;/span&gt;])).strftime(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;%Y-%m-&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;%d&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt; %H:%M:%S&amp;#34;&lt;/span&gt;),
5233&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;value&amp;#34;&lt;/span&gt;: point[&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;value&amp;#34;&lt;/span&gt;]
5234&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; })
5235&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5236&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; bottle.response.content_type = &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;application/json&amp;#34;&lt;/span&gt;
5237&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;return&lt;/span&gt; json.dumps(response)
5238&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5239&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# starting server on http://0.0.0.0:5000&lt;/span&gt;
5240&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt; __name__ == &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;__main__&amp;#34;&lt;/span&gt;:
5241&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; bottle.run(
5242&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; app = app,
5243&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; host = &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;0.0.0.0&amp;#34;&lt;/span&gt;,
5244&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; port = 5000,
5245&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; debug = &lt;span style=&#34;color:#00f&#34;&gt;True&lt;/span&gt;,
5246&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; reloader = &lt;span style=&#34;color:#00f&#34;&gt;True&lt;/span&gt;,
5247&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; catchall = &lt;span style=&#34;color:#00f&#34;&gt;True&lt;/span&gt;,
5248&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; )
5249&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And now finally we can implement &lt;code&gt;frontend.html&lt;/code&gt;. Create file with this name
5250and copy code below. When you are done you can start web application. Steps for
5251this part are listed below the code.&lt;/p&gt;
5252&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
5253&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;html&amp;gt;
5254&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5255&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;head&amp;gt;
5256&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;meta charset=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;utf-8&amp;#34;&lt;/span&gt;&amp;gt;
5257&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;title&amp;gt;Simple IOT application&amp;lt;/title&amp;gt;
5258&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;/head&amp;gt;
5259&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5260&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;body&amp;gt;
5261&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5262&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;h1&amp;gt;Simple IOT application&amp;lt;/h1&amp;gt;
5263&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5264&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;div class=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;chart-placeholder&amp;#34;&lt;/span&gt;&amp;gt;
5265&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;div id=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;chart&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/div&amp;gt;
5266&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;/div&amp;gt;
5267&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5268&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;&amp;lt;!-- application main script --&amp;gt;&lt;/span&gt;
5269&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;script src=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;
5270&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;script src=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;
5271&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;script src=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;https://cdnjs.cloudflare.com/ajax/libs/metrics-graphics/2.11.0/metricsgraphics.min.js&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;
5272&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;script&amp;gt;
5273&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;function&lt;/span&gt; fetch_and_render() {
5274&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; d3.json(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;/api&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#00f&#34;&gt;function&lt;/span&gt;(data) {
5275&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; data = MG.convert.date(data, &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;date&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;%Y-%m-%d %H:%M:%S&amp;#34;&lt;/span&gt;);
5276&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; MG.data_graphic({
5277&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; data: data,
5278&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; chart_type: &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;line&amp;#34;&lt;/span&gt;,
5279&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; full_width: &lt;span style=&#34;color:#00f&#34;&gt;true&lt;/span&gt;,
5280&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; height: 270,
5281&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; target: document.getElementById(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;chart&amp;#34;&lt;/span&gt;),
5282&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; x_accessor: &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;date&amp;#34;&lt;/span&gt;,
5283&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; y_accessor: &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;value&amp;#34;&lt;/span&gt;
5284&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; });
5285&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; });
5286&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
5287&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; window.onload = &lt;span style=&#34;color:#00f&#34;&gt;function&lt;/span&gt;() {
5288&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;// initial call for rendering
5289&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt; fetch_and_render();
5290&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5291&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;// updates chart every 5 seconds
5292&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt; setInterval(&lt;span style=&#34;color:#00f&#34;&gt;function&lt;/span&gt;() {
5293&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; fetch_and_render();
5294&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }, 5000);
5295&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
5296&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;/script&amp;gt;
5297&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5298&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;&amp;lt;!-- application styles --&amp;gt;&lt;/span&gt;
5299&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;style&amp;gt;
5300&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; body {
5301&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;font&lt;/span&gt;: 13&lt;span style=&#34;color:#2b91af&#34;&gt;px&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;sans-serif&lt;/span&gt;;
5302&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;padding&lt;/span&gt;: 20&lt;span style=&#34;color:#2b91af&#34;&gt;px&lt;/span&gt; 50&lt;span style=&#34;color:#2b91af&#34;&gt;px&lt;/span&gt;;
5303&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
5304&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; .&lt;span style=&#34;color:#2b91af&#34;&gt;chart-placeholder&lt;/span&gt; {
5305&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;border&lt;/span&gt;: 2&lt;span style=&#34;color:#2b91af&#34;&gt;px&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;solid&lt;/span&gt; #ccc;
5306&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;width&lt;/span&gt;: 100&lt;span style=&#34;color:#2b91af&#34;&gt;%&lt;/span&gt;;
5307&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;user-select&lt;/span&gt;: &lt;span style=&#34;color:#00f&#34;&gt;none&lt;/span&gt;;
5308&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
5309&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;/* chart styles */&lt;/span&gt;
5310&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; .&lt;span style=&#34;color:#2b91af&#34;&gt;mg-line1-color&lt;/span&gt; {
5311&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; stroke: &lt;span style=&#34;color:#00f&#34;&gt;red&lt;/span&gt;;
5312&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; stroke-width: 2;
5313&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
5314&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; .&lt;span style=&#34;color:#2b91af&#34;&gt;mg-main-area&lt;/span&gt;, .&lt;span style=&#34;color:#2b91af&#34;&gt;mg-main-line&lt;/span&gt; {
5315&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; fill: #fff;
5316&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
5317&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; .&lt;span style=&#34;color:#2b91af&#34;&gt;mg-x-axis&lt;/span&gt; line, .&lt;span style=&#34;color:#2b91af&#34;&gt;mg-y-axis&lt;/span&gt; line {
5318&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; stroke: #b3b2b2;
5319&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; stroke-width: 1&lt;span style=&#34;color:#2b91af&#34;&gt;px&lt;/span&gt;;
5320&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
5321&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;/style&amp;gt;
5322&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5323&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;/body&amp;gt;
5324&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5325&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/html&amp;gt;
5326&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now the folder structure should look like:&lt;/p&gt;
5327&lt;p&gt;&lt;em&gt;simple-iot-app/&lt;/em&gt;&lt;/p&gt;
5328&lt;ul&gt;
5329&lt;li&gt;&lt;em&gt;webapp.py&lt;/em&gt;&lt;/li&gt;
5330&lt;li&gt;&lt;em&gt;data.db&lt;/em&gt;&lt;/li&gt;
5331&lt;li&gt;&lt;em&gt;frontend.html&lt;/em&gt;&lt;/li&gt;
5332&lt;/ul&gt;
5333&lt;p&gt;Ok, lets now start application and start feeding it data.&lt;/p&gt;
5334&lt;ol&gt;
5335&lt;li&gt;&lt;code&gt;python webapp.py&lt;/code&gt;&lt;/li&gt;
5336&lt;li&gt;connect Arduino MKR1000 to power source&lt;/li&gt;
5337&lt;li&gt;open browser and go to &lt;code&gt;http://0.0.0.0:5000&lt;/code&gt;&lt;/li&gt;
5338&lt;/ol&gt;
5339&lt;p&gt;If everything goes well you should be seeing new data-points rendered on chart
5340every 5 seconds.&lt;/p&gt;
5341&lt;p&gt;If you navigate to &lt;code&gt;http://0.0.0.0:5000&lt;/code&gt; you should see rendered chart as
5342shown on picture below.&lt;/p&gt;
5343&lt;figure&gt;
5344&lt;img src=&#34;/posts/iot-application/iot-app-output.png&#34; alt=&#34;Application output&#34; /&gt;
5345&lt;/figure&gt;
5346&lt;p&gt;Complete application with all the code is available for
5347&lt;a href=&#34;/posts/iot-application/simple-iot-application.zip&#34;&gt;download&lt;/a&gt;.&lt;/p&gt;
5348&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
5349&lt;p&gt;I hope this clarifies some aspects of IOT application development. Of course
5350this is a minimal example and is far from what can be done in real life with
5351some further dive into other technologies.&lt;/p&gt;
5352&lt;p&gt;If you would like to continue exploring IOT world here are some interesting
5353resources for you to examine:&lt;/p&gt;
5354&lt;ul&gt;
5355&lt;li&gt;&lt;a href=&#34;https://www.allaboutcircuits.com/projects/reading-sensors-with-an-arduino/&#34;&gt;Reading Sensors with an Arduino&lt;/a&gt;&lt;/li&gt;
5356&lt;li&gt;&lt;a href=&#34;http://www.hivemq.com/blog/how-to-get-started-with-mqtt&#34;&gt;MQTT 101 – How to Get Started with the lightweight IoT Protocol&lt;/a&gt;&lt;/li&gt;
5357&lt;li&gt;&lt;a href=&#34;https://www.html5rocks.com/en/tutorials/eventsource/basics/&#34;&gt;Stream Updates with Server-Sent Events&lt;/a&gt;&lt;/li&gt;
5358&lt;li&gt;&lt;a href=&#34;http://www.tutorialspoint.com/internet_of_things/&#34;&gt;Internet of Things (IoT) Tutorials&lt;/a&gt;&lt;/li&gt;
5359&lt;/ul&gt;
5360&lt;p&gt;Any comment or additional ideas are welcomed in comments below.&lt;/p&gt;
5361</content:encoded>
5362 </item>
5363
5364
5365
5366 <item>
5367 <title>Profiling Python web applications with visual tools</title>
5368 <link>https://mitjafelicijan.com/profiling-python-web-applications-with-visual-tools.html</link>
5369 <pubDate>Fri, 21 Apr 2017 12:00:00 &#43;0200</pubDate>
5370 <guid>https://mitjafelicijan.com/profiling-python-web-applications-with-visual-tools.html</guid>
5371 <description>I have been profiling my software with KCachegrind for a long time now and I wasmissing this option when I am developing API&amp;#39;s or other web services.</description>
5372 <content:encoded>&lt;p&gt;I have been profiling my software with KCachegrind for a long time now and I was
5373missing this option when I am developing API&#39;s or other web services. I always
5374knew that this is possible but never really took the time and dive into it.&lt;/p&gt;
5375&lt;p&gt;Before we begin there are some requirements. We will need to:&lt;/p&gt;
5376&lt;ul&gt;
5377&lt;li&gt;implement &lt;a href=&#34;https://docs.python.org/2/library/profile.html#module-cProfile&#34;&gt;cProfile&lt;/a&gt; into our web app,&lt;/li&gt;
5378&lt;li&gt;convert output to &lt;a href=&#34;http://valgrind.org/docs/manual/cl-manual.html&#34;&gt;callgrind&lt;/a&gt; format with &lt;a href=&#34;https://pypi.python.org/pypi/pyprof2calltree/&#34;&gt;pyprof2calltree&lt;/a&gt;,&lt;/li&gt;
5379&lt;li&gt;visualize data with &lt;a href=&#34;http://kcachegrind.sourceforge.net/html/Home.html&#34;&gt;KCachegrind&lt;/a&gt; or &lt;a href=&#34;http://www.profilingviewer.com/&#34;&gt;Profiling Viewer&lt;/a&gt;.&lt;/li&gt;
5380&lt;/ul&gt;
5381&lt;p&gt;If you are using MacOS you should check out &lt;a href=&#34;http://www.profilingviewer.com/&#34;&gt;Profiling
5382Viewer&lt;/a&gt; or
5383&lt;a href=&#34;http://www.maccallgrind.com/&#34;&gt;MacCallGrind&lt;/a&gt;.&lt;/p&gt;
5384&lt;figure&gt;
5385&lt;img src=&#34;/posts/python-profiling/kcachegrind.png&#34; alt=&#34;KCachegrind&#34; /&gt;
5386&lt;/figure&gt;
5387&lt;p&gt;We will be dividing this post into two main categories:&lt;/p&gt;
5388&lt;ul&gt;
5389&lt;li&gt;writing simple web-service,&lt;/li&gt;
5390&lt;li&gt;visualize profile of this web-service.&lt;/li&gt;
5391&lt;/ul&gt;
5392&lt;h2 id=&#34;simple-web-service&#34;&gt;Simple web-service&lt;/h2&gt;
5393&lt;p&gt;Let&#39;s use virtualenv so we won&#39;t pollute our base system. If you don&#39;t have
5394virtualenv installed on your system you can install it with pip command.&lt;/p&gt;
5395&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# let&amp;#39;s install virtualenv globally&lt;/span&gt;
5396&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo pip install virtualenv
5397&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5398&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# let&amp;#39;s also install pyprof2calltree globally&lt;/span&gt;
5399&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo pip install pyprof2calltree
5400&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5401&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# now we create project&lt;/span&gt;
5402&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ mkdir demo-project
5403&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cd demo-project/
5404&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5405&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# now let&amp;#39;s create folder where we will store profiles&lt;/span&gt;
5406&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ mkdir prof
5407&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5408&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# now we create empty virtualenv in venv/ folder&lt;/span&gt;
5409&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ virtualenv --no-site-packages venv
5410&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5411&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# we now need to activate virtualenv&lt;/span&gt;
5412&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ source venv/bin/activate
5413&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5414&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# you can check if virtualenv was correctly initialized by&lt;/span&gt;
5415&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# checking where your python interpreter is located&lt;/span&gt;
5416&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# if command bellow points to your created directory and not some&lt;/span&gt;
5417&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# system dir like /usr/bin/python then everything is fine&lt;/span&gt;
5418&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ which python
5419&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5420&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# we can check now if all is good ➜ if ok couple of&lt;/span&gt;
5421&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# lines will be displayed&lt;/span&gt;
5422&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ pip freeze
5423&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# appdirs==1.4.3&lt;/span&gt;
5424&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# packaging==16.8&lt;/span&gt;
5425&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# pyparsing==2.2.0&lt;/span&gt;
5426&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# six==1.10.0&lt;/span&gt;
5427&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5428&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# now we are ready to install bottlepy ➜ web micro-framework&lt;/span&gt;
5429&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ pip install bottle
5430&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5431&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# you can deactivate virtualenv but you will then go&lt;/span&gt;
5432&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# under system domain ➜ for now don&amp;#39;t deactivate&lt;/span&gt;
5433&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ deactivate
5434&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We are now ready to write simple web service. Let&#39;s create file app.py and paste
5435code bellow in this newly created file.&lt;/p&gt;
5436&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# -*- coding: utf-8 -*-&lt;/span&gt;
5437&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5438&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; bottle
5439&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; random
5440&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; cProfile
5441&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5442&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;app = bottle.Bottle()
5443&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5444&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# this function is a decorator and encapsulates function&lt;/span&gt;
5445&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# and performs profiling and then saves it to subfolder&lt;/span&gt;
5446&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# prof/function-name.prof&lt;/span&gt;
5447&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# in our example only awesome_random_number function will&lt;/span&gt;
5448&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# be profiled because it has do_cprofile defined&lt;/span&gt;
5449&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;def&lt;/span&gt; do_cprofile(func):
5450&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;def&lt;/span&gt; profiled_func(*args, **kwargs):
5451&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; profile = cProfile.Profile()
5452&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;try&lt;/span&gt;:
5453&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; profile.enable()
5454&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; result = func(*args, **kwargs)
5455&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; profile.disable()
5456&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;return&lt;/span&gt; result
5457&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;finally&lt;/span&gt;:
5458&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; profile.dump_stats(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;prof/&amp;#34;&lt;/span&gt; &#43; str(func.__name__) &#43; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;.prof&amp;#34;&lt;/span&gt;)
5459&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;return&lt;/span&gt; profiled_func
5460&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5461&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5462&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# we use profiling over specific function with including&lt;/span&gt;
5463&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# @do_cprofile above function declaration&lt;/span&gt;
5464&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@app.route(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;/&amp;#34;&lt;/span&gt;)
5465&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@do_cprofile
5466&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;def&lt;/span&gt; awesome_random_number():
5467&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; awesome_random_number = random.randint(0, 100)
5468&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;awesome random number is &amp;#34;&lt;/span&gt; &#43; str(awesome_random_number)
5469&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5470&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;@app.route(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;/test&amp;#34;&lt;/span&gt;)
5471&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;def&lt;/span&gt; test():
5472&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;return&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;dummy test&amp;#34;&lt;/span&gt;
5473&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5474&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt; __name__ == &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;__main__&amp;#39;&lt;/span&gt;:
5475&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; bottle.run(
5476&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; app = app,
5477&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; host = &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;0.0.0.0&amp;#34;&lt;/span&gt;,
5478&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; port = 4000
5479&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; )
5480&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5481&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# run with &amp;#39;python app.py&amp;#39;&lt;/span&gt;
5482&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# open browser &amp;#39;http://0.0.0.0:4000&amp;#39;&lt;/span&gt;
5483&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;When browser hits awesome_random_number() function profile is created in prof/
5484subfolder.&lt;/p&gt;
5485&lt;h2 id=&#34;visualize-profile&#34;&gt;Visualize profile&lt;/h2&gt;
5486&lt;p&gt;Now let&#39;s create callgrind format from this cProfile output.&lt;/p&gt;
5487&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cd prof/
5488&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ pyprof2calltree -i awesome_random_number.prof
5489&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# this creates &amp;#39;awesome_random_number.prof.log&amp;#39; file in the same folder&lt;/span&gt;
5490&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This file can be opened with visualizing tools listed above. In this case we
5491will be using Profilling Viewer under MacOS. You can open image in new tab. As
5492you can see from this example there is hierarchy of execution order of your
5493code.&lt;/p&gt;
5494&lt;figure&gt;
5495&lt;img src=&#34;/posts/python-profiling/profiling-viewer.png&#34; alt=&#34;Profilling Viewer&#34; /&gt;
5496&lt;/figure&gt;
5497&lt;blockquote&gt;
5498&lt;p&gt;Make sure you convert output of the cProfile output every time you want to
5499refresh and take a look at your possible optimizations because cProfile updates
5500.prof file every time browser hits the function.&lt;/p&gt;
5501&lt;/blockquote&gt;
5502&lt;p&gt;This is just a simple example but when you are developing real-life applications
5503this can be very illuminating, especially to see which parts of your code are
5504bottlenecks and need to be optimized.&lt;/p&gt;
5505&lt;h2 id=&#34;update-2017-04-22&#34;&gt;Update 2017-04-22&lt;/h2&gt;
5506&lt;p&gt;Reddit user &lt;a href=&#34;https://www.reddit.com/user/mvt&#34;&gt;mvt&lt;/a&gt; also recommended this awesome
5507web based profile visualizer &lt;a href=&#34;https://jiffyclub.github.io/snakeviz/&#34;&gt;SnakeViz&lt;/a&gt;
5508that directly takes output from
5509&lt;a href=&#34;https://docs.python.org/2/library/profile.html#module-cProfile&#34;&gt;cProfile&lt;/a&gt;
5510module.&lt;/p&gt;
5511&lt;div class=&#34;reddit-embed&#34; data-embed-media=&#34;www.redditmedia.com&#34; data-embed-parent=&#34;false&#34; data-embed-live=&#34;false&#34; data-embed-uuid=&#34;583880c1-002e-41ed-a373-020a0ef2cff9&#34; data-embed-created=&#34;2017-04-22T19:46:54.810Z&#34;&gt;&lt;a href=&#34;https://www.reddit.com/r/Python/comments/66v373/profiling_python_web_applications_with_visual/dgljhsb/&#34;&gt;Comment&lt;/a&gt; from discussion &lt;a href=&#34;https://www.reddit.com/r/Python/comments/66v373/profiling_python_web_applications_with_visual/&#34;&gt;Profiling Python web applications with visual tools&lt;/a&gt;.&lt;/div&gt;&lt;script async src=&#34;https://www.redditstatic.com/comment-embed.js&#34;&gt;&lt;/script&gt;
5512&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# let&amp;#39;s install it globally as well&lt;/span&gt;
5513&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ sudo pip install snakeviz
5514&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5515&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# now let&amp;#39;s visualize&lt;/span&gt;
5516&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ cd prof/
5517&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ snakeviz awesome_random_number.prof
5518&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# this automatically opens browser window and&lt;/span&gt;
5519&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# shows visualized profile&lt;/span&gt;
5520&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;figure&gt;
5521&lt;img src=&#34;/posts/python-profiling/snakeviz.png&#34; alt=&#34;SnakeViz&#34; /&gt;
5522&lt;/figure&gt;
5523&lt;p&gt;Reddit user &lt;a href=&#34;https://www.reddit.com/user/ccharles&#34;&gt;ccharles&lt;/a&gt; suggested a better
5524way for installing pip software by targeting user level instead of using sudo.&lt;/p&gt;
5525&lt;div class=&#34;reddit-embed&#34; data-embed-media=&#34;www.redditmedia.com&#34; data-embed-parent=&#34;false&#34; data-embed-live=&#34;false&#34; data-embed-uuid=&#34;f4f0459e-684d-441e-bebe-eb49b2f0a31d&#34; data-embed-created=&#34;2017-04-22T19:46:10.874Z&#34;&gt;&lt;a href=&#34;https://www.reddit.com/r/Python/comments/66v373/profiling_python_web_applications_with_visual/dglpzkx/&#34;&gt;Comment&lt;/a&gt; from discussion &lt;a href=&#34;https://www.reddit.com/r/Python/comments/66v373/profiling_python_web_applications_with_visual/&#34;&gt;Profiling Python web applications with visual tools&lt;/a&gt;.&lt;/div&gt;&lt;script async src=&#34;https://www.redditstatic.com/comment-embed.js&#34;&gt;&lt;/script&gt;
5526&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# now we need to add this path to our $PATH variable&lt;/span&gt;
5527&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# we do this my adding this line at the end of your&lt;/span&gt;
5528&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# ~/.bashrc file&lt;/span&gt;
5529&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PATH=$PATH:$HOME/.local/bin/
5530&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5531&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# in order to use this new configuration you can close&lt;/span&gt;
5532&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# and reopen terminal or reload .bashrc file&lt;/span&gt;
5533&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ source ~/.bashrc
5534&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5535&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# now let&amp;#39;s test if new directory is present in $PATH&lt;/span&gt;
5536&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ echo $PATH
5537&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5538&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# now we can install on user level by adding --user&lt;/span&gt;
5539&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# without use of sudo&lt;/span&gt;
5540&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;$ pip install snakeviz --user
5541&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Or as suggested by &lt;a href=&#34;https://www.reddit.com/user/mvt&#34;&gt;mvt&lt;/a&gt; you can
5542use &lt;a href=&#34;https://github.com/mitsuhiko/pipsi&#34;&gt;pipsi&lt;/a&gt;.&lt;/p&gt;
5543</content:encoded>
5544 </item>
5545
5546
5547
5548 <item>
5549 <title>What I&#39;ve learned developing ad server</title>
5550 <link>https://mitjafelicijan.com/what-i-ve-learned-developing-ad-server.html</link>
5551 <pubDate>Mon, 17 Apr 2017 12:00:00 &#43;0200</pubDate>
5552 <guid>https://mitjafelicijan.com/what-i-ve-learned-developing-ad-server.html</guid>
5553 <description>For the past year and half I have been developing native advertising server thatcontextually matches ads and displays them in different template forms onvariety of websites.</description>
5554 <content:encoded>&lt;p&gt;For the past year and half I have been developing native advertising server that
5555contextually matches ads and displays them in different template forms on
5556variety of websites. This project grew from serving thousands of ads per day to
5557millions.&lt;/p&gt;
5558&lt;p&gt;The system is made from couple of core components:&lt;/p&gt;
5559&lt;ul&gt;
5560&lt;li&gt;API for serving ads,&lt;/li&gt;
5561&lt;li&gt;Utils - cronjobs and queue management tools,&lt;/li&gt;
5562&lt;li&gt;Dashboard UI.&lt;/li&gt;
5563&lt;/ul&gt;
5564&lt;p&gt;Initial release was using &lt;a href=&#34;https://www.mongodb.com/&#34;&gt;MongoDB&lt;/a&gt; for full-text
5565search but was later replaced by &lt;a href=&#34;https://www.elastic.co/&#34;&gt;Elasticsearch&lt;/a&gt; for
5566better CPU utilization and better search performance. This provided us with many
5567amazing functionalities of &lt;a href=&#34;https://www.elastic.co/&#34;&gt;Elasticsearch&lt;/a&gt;. You should
5568check it out if you do any search related operations.&lt;/p&gt;
5569&lt;p&gt;Because the premise of the server is to provide native ad experience, they are
5570rendered on the client side via simple templating engine. This ensures that ads
5571can be displayed number of different ways based on the visual style of the
5572page. And this makes JavaScript client library quite complex.&lt;/p&gt;
5573&lt;p&gt;So now that you know basic information about the product lets get into the
5574lessons we learned.&lt;/p&gt;
5575&lt;h2 id=&#34;aggregate-everything&#34;&gt;Aggregate everything&lt;/h2&gt;
5576&lt;p&gt;After beta version was released everything (impressions, clicks, etc) was
5577written in nanosecond resolution in the database. At that time we were using
5578&lt;a href=&#34;https://www.postgresql.org/&#34;&gt;PostgreSQL&lt;/a&gt; and database quickly grew way above
5579200GB in disk space. And that was problematic. Statistics took disturbingly long
5580time to aggregate. Also using indexes on stats table in database was no help
5581after we reached 500 million datapoints.&lt;/p&gt;
5582&lt;blockquote&gt;
5583&lt;p&gt;There is a marketing product information and there is real life experience.
5584And the tend to be quite the opposite.&lt;/p&gt;
5585&lt;/blockquote&gt;
5586&lt;p&gt;This was the reason that now everything is aggregated on daily basis and this
5587data is then fed to Elastic in form of daily summary. With this we achieved we
5588can now track many more dimensions such as zone, channel and platform
5589information. And with this information we can now adapt occurrences of ads on
5590specific places more precisely.&lt;/p&gt;
5591&lt;p&gt;We have also adapted &lt;a href=&#34;https://redis.io/&#34;&gt;Redis&lt;/a&gt; as a full-time citizen in our
5592stack. Because Redis also stores information on a local disk we have some sort
5593of backup if server would accidentally suffer some failure.&lt;/p&gt;
5594&lt;p&gt;All the real-time statistics for ad serving and redirecting is presented as
5595counters in Redis instance and daily extracted and pushed to Elastic.&lt;/p&gt;
5596&lt;h2 id=&#34;measure-everything&#34;&gt;Measure everything&lt;/h2&gt;
5597&lt;p&gt;The thing about software is that we really don&#39;t know how well it is performing
5598under load until such load is presented. When testing locally everything is fine
5599but when on production things tend to fall apart.&lt;/p&gt;
5600&lt;p&gt;As a solution for this we are measuring everything we can. Function execution
5601time (by encapsulating functions with timers), server performance (cpu, memory,
5602disk, etc), Nginx and &lt;a href=&#34;https://uwsgi-docs.readthedocs.io/&#34;&gt;uWSGI&lt;/a&gt; performance.
5603We sacrifice a bit of performance for the sake of this information. And we store
5604all this information for later analysis.&lt;/p&gt;
5605&lt;p&gt;&lt;strong&gt;Example of function execution time&lt;/strong&gt;&lt;/p&gt;
5606&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
5607&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;get_final_filtered_ads&amp;#34;: {
5608&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;counter&amp;#34;: 1931250,
5609&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;avg&amp;#34;: 0.0066143431,
5610&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;elapsed&amp;#34;: 12773.9500310003
5611&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; },
5612&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;store_keywords_statistics&amp;#34;: {
5613&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;counter&amp;#34;: 1931011,
5614&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;avg&amp;#34;: 0.0004605267,
5615&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;elapsed&amp;#34;: 889.2821669996
5616&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; },
5617&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;match_by_context&amp;#34;: {
5618&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;counter&amp;#34;: 1931011,
5619&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;avg&amp;#34;: 0.0055960716,
5620&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;elapsed&amp;#34;: 10806.0758889999
5621&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; },
5622&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;match_by_high_performance&amp;#34;: {
5623&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;counter&amp;#34;: 262,
5624&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;avg&amp;#34;: 0.0152770229,
5625&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;elapsed&amp;#34;: 4.00258
5626&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; },
5627&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;store_impression_stats&amp;#34;: {
5628&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;counter&amp;#34;: 1931250,
5629&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;avg&amp;#34;: 0.0006189991,
5630&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;#34;elapsed&amp;#34;: 1195.4419869999
5631&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
5632&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
5633&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;We have also started profiling with &lt;a href=&#34;https://pymotw.com/2/profile/&#34;&gt;cProfile&lt;/a&gt;
5634and then visualizing with &lt;a href=&#34;http://kcachegrind.sourceforge.net/&#34;&gt;KCachegrind&lt;/a&gt;.
5635This provides much more detailed look into code execution.&lt;/p&gt;
5636&lt;h2 id=&#34;cache-control-is-your-friend&#34;&gt;Cache control is your friend&lt;/h2&gt;
5637&lt;p&gt;Because we use Javascript library for rendering ads we rely on this script
5638extensively and when in need we need to be able to change behavior of the script
5639quickly.&lt;/p&gt;
5640&lt;p&gt;In our case we can not simply replace javascript url in html code. It usually
5641takes a day or two for the guys who maintain sites to change code or add
5642?ver=xxx attribute. And this makes rapid deployment and testing very difficult
5643and time consuming. There is a limitation of how much you can test locally.&lt;/p&gt;
5644&lt;p&gt;We are now in the process of integrating &lt;a href=&#34;https://www.google.com/analytics/tag-manager/&#34;&gt;Google Tag
5645Manager&lt;/a&gt; but couple of websites
5646are developed on ASP.net platform that have some problems with tag manager. With
5647a solution below we are certain that we are serving latest version of the
5648script.&lt;/p&gt;
5649&lt;p&gt;And it only takes one mistake and users have the script cached and in case of
5650caching it for 1 year you probably know where the problem is.&lt;/p&gt;
5651&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# nginx ➜ /etc/nginx/sites-available/default
5652&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#00f&#34;&gt;location&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;/static/&lt;/span&gt; {
5653&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;alias&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;/path-to-static-content/&lt;/span&gt;;
5654&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;autoindex&lt;/span&gt; off;
5655&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;charset&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;utf-8&lt;/span&gt;;
5656&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;gzip&lt;/span&gt; on;
5657&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;gzip_types&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;text/plain&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;application/javascript&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;application/x-javascript&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;text/javascript&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;text/xml&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;text/css&lt;/span&gt;;
5658&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;location&lt;/span&gt; ~&lt;span style=&#34;color:#a31515&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;\.(ico|gif|jpeg|jpg|png|woff|ttf|otf|svg|woff2|eot)&lt;/span&gt;$ {
5659&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;expires&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;1y&lt;/span&gt;;
5660&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;add_header&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;Pragma&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;public&lt;/span&gt;;
5661&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;add_header&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;Cache-Control&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;public&amp;#34;&lt;/span&gt;;
5662&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
5663&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;location&lt;/span&gt; ~&lt;span style=&#34;color:#a31515&#34;&gt;*&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;\.(css|js|txt)&lt;/span&gt;$ {
5664&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;expires&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;3600s&lt;/span&gt;;
5665&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;add_header&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;Pragma&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;public&lt;/span&gt;;
5666&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;add_header&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;Cache-Control&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;public,&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;must-revalidate&amp;#34;&lt;/span&gt;;
5667&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
5668&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
5669&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Also be careful when redirecting to url in your python code. We noticed that if
5670we didn&#39;t precisely setup cache control and expire headers in response we didn&#39;t
5671get the request on the server and therefore couldn&#39;t measure clicks. So when
5672redirecting do as follows and there will be no problems.&lt;/p&gt;
5673&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# python ➜ bottlepy web micro-framework&lt;/span&gt;
5674&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;response = bottle.HTTPResponse(status=302)
5675&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;response.set_header(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Cache-Control&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;no-store, no-cache, must-revalidate&amp;#34;&lt;/span&gt;)
5676&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;response.set_header(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Expires&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Thu, 01 Jan 1970 00:00:00 GMT&amp;#34;&lt;/span&gt;)
5677&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;response.set_header(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Location&amp;#34;&lt;/span&gt;, url)
5678&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;return&lt;/span&gt; response
5679&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;blockquote&gt;
5680&lt;p&gt;Cache control in browsers is quite aggressive and you need to be precise to
5681avoid future problems. We learned that lesson the hard way.&lt;/p&gt;
5682&lt;/blockquote&gt;
5683&lt;h2 id=&#34;learn-nginx&#34;&gt;Learn NGINX&lt;/h2&gt;
5684&lt;p&gt;When deciding on a web server we went with Nginx as a reverse proxy for our
5685applications. We adapted micro-service oriented architecture early in the
5686project to ensure when we scale we can easily add additional servers to our
5687cluster. And Nginx was crucial to perform load balancing and static content
5688delivery.&lt;/p&gt;
5689&lt;p&gt;At first our config file was quite simple and later grew larger. After patching
5690and adding new settings I sat down and learned more about the guts of Nginx.
5691This proved to be very useful and we were able to squeeze much more out of our
5692setup. So I advise you to take your time and read through the
5693&lt;a href=&#34;https://nginx.org/en/docs/&#34;&gt;documentation&lt;/a&gt;. This saved us a lot of headache.
5694Googling for solutions only goes so far.&lt;/p&gt;
5695&lt;h2 id=&#34;use-redismemcached&#34;&gt;Use Redis/Memcached&lt;/h2&gt;
5696&lt;p&gt;As explained above we are using caching basically for everything. It is the
5697corner stone of our services. At first we were very careful about the quantity
5698of things we stored in &lt;a href=&#34;https://redis.io/&#34;&gt;Redis&lt;/a&gt;. But we later found out that
5699the memory footprint is very low even when storing large amount of data in it.&lt;/p&gt;
5700&lt;p&gt;So we gradually increased our usage to caching whole HTML outputs of dashboard.
5701This improved our performance in order of magnitude. And by using native TTL
5702support this goes hand in hand with our needs.&lt;/p&gt;
5703&lt;p&gt;The reason why we choose &lt;a href=&#34;https://redis.io/&#34;&gt;Redis&lt;/a&gt; over
5704&lt;a href=&#34;https://memcached.org/&#34;&gt;Memcached&lt;/a&gt; was the nature of scalability of Redis out
5705of the box. But all this can be achieved with Memcached.&lt;/p&gt;
5706&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
5707&lt;p&gt;There are a lot more details that could have been written and every single topic
5708in here deserves it&#39;s own post but you probably got the idea about the problems
5709we faced.&lt;/p&gt;
5710</content:encoded>
5711 </item>
5712
5713
5714
5715 <item>
5716 <title>Golang profiling simplified</title>
5717 <link>https://mitjafelicijan.com/golang-profiling-simplified.html</link>
5718 <pubDate>Tue, 07 Mar 2017 12:00:00 &#43;0200</pubDate>
5719 <guid>https://mitjafelicijan.com/golang-profiling-simplified.html</guid>
5720 <description>Many posts have been written regarding profiling in Golang and I haven’t foundproper tutorial regarding this.</description>
5721 <content:encoded>&lt;p&gt;Many posts have been written regarding profiling in Golang and I haven’t found
5722proper tutorial regarding this. Almost all of them are missing some part of
5723important information and it gets pretty frustrating when you have a deadline
5724and are not finding simple distilled solution.&lt;/p&gt;
5725&lt;p&gt;Nevertheless, after searching and experimenting I have found a solution that
5726works for me and probably should also for you.&lt;/p&gt;
5727&lt;h2 id=&#34;where-are-my-pprof-files&#34;&gt;Where are my pprof files?&lt;/h2&gt;
5728&lt;p&gt;By default pprof files are generated in /tmp/ folder. You can override folder
5729where this files are generated programmatically in your golang code as we will
5730see below in example.&lt;/p&gt;
5731&lt;h2 id=&#34;why-is-my-cpu-profile-empty&#34;&gt;Why is my CPU profile empty?&lt;/h2&gt;
5732&lt;p&gt;I have found out that sometimes CPU profile is empty because program was not
5733executing long enough. Programs, that execute too quickly don’t produce pprof
5734file in my cases. Well, file is generated but only contains 4KB of information.&lt;/p&gt;
5735&lt;h2 id=&#34;profiling&#34;&gt;Profiling&lt;/h2&gt;
5736&lt;p&gt;As you can see from examples we are executing dummy_benchmark functions to
5737ensure some sort of execution. Memory profiling can be done without such a
5738“complex” function. But CPU profiling needs it.&lt;/p&gt;
5739&lt;p&gt;Both memory and CPU profiling examples are almost the same. Only parameters in
5740main function when calling profile.Start are different. When we set
5741profile.ProfilePath(“.”) we tell profiler to store pprof files in the same
5742folder as our program.&lt;/p&gt;
5743&lt;h3 id=&#34;memory-profiling&#34;&gt;Memory profiling&lt;/h3&gt;
5744&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;package&lt;/span&gt; main
5745&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5746&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; (
5747&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;
5748&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;time&amp;#34;&lt;/span&gt;
5749&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;github.com/pkg/profile&amp;#34;&lt;/span&gt;
5750&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
5751&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5752&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;func&lt;/span&gt; dummy_benchmark() {
5753&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5754&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; fmt.Println(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;first set ...&amp;#34;&lt;/span&gt;)
5755&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;for&lt;/span&gt; i := 0; i &amp;lt; 918231333; i&#43;&#43; {
5756&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; i *= 2
5757&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; i /= 2
5758&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
5759&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5760&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;-time.After(time.Second*3)
5761&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5762&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; fmt.Println(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;sencond set ...&amp;#34;&lt;/span&gt;)
5763&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;for&lt;/span&gt; i := 0; i &amp;lt; 9182312232; i&#43;&#43; {
5764&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; i *= 2
5765&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; i /= 2
5766&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
5767&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
5768&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5769&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;func&lt;/span&gt; main() {
5770&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;defer&lt;/span&gt; profile.Start(profile.MemProfile, profile.ProfilePath(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt;), profile.NoShutdownHook).Stop()
5771&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; dummy_benchmark()
5772&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
5773&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;cpu-profiling&#34;&gt;CPU profiling&lt;/h3&gt;
5774&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;package&lt;/span&gt; main
5775&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5776&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; (
5777&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;fmt&amp;#34;&lt;/span&gt;
5778&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;time&amp;#34;&lt;/span&gt;
5779&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;github.com/pkg/profile&amp;#34;&lt;/span&gt;
5780&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;)
5781&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5782&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;func&lt;/span&gt; dummy_benchmark() {
5783&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5784&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; fmt.Println(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;first set ...&amp;#34;&lt;/span&gt;)
5785&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;for&lt;/span&gt; i := 0; i &amp;lt; 918231333; i&#43;&#43; {
5786&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; i *= 2
5787&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; i /= 2
5788&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
5789&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5790&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;-time.After(time.Second*3)
5791&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5792&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; fmt.Println(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;sencond set ...&amp;#34;&lt;/span&gt;)
5793&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;for&lt;/span&gt; i := 0; i &amp;lt; 9182312232; i&#43;&#43; {
5794&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; i *= 2
5795&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; i /= 2
5796&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
5797&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
5798&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5799&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;func&lt;/span&gt; main() {
5800&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;defer&lt;/span&gt; profile.Start(profile.CPUProfile, profile.ProfilePath(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;.&amp;#34;&lt;/span&gt;), profile.NoShutdownHook).Stop()
5801&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; dummy_benchmark()
5802&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
5803&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h3 id=&#34;generating-profiling-reports&#34;&gt;Generating profiling reports&lt;/h3&gt;
5804&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# memory profiling&lt;/span&gt;
5805&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;go build mem.go
5806&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./mem
5807&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;go tool pprof -pdf ./mem mem.pprof &amp;gt; mem.pdf
5808&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
5809&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# cpu profiling&lt;/span&gt;
5810&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;go build cpu.go
5811&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./cpu
5812&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;go tool pprof -pdf ./cpu cpu.pprof &amp;gt; cpu.pdf
5813&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This will generate PDF document with visualized profile.&lt;/p&gt;
5814&lt;ul&gt;
5815&lt;li&gt;&lt;a href=&#34;/posts/go-profiling/golang-profiling-mem.pdf&#34;&gt;Memory PDF profile example&lt;/a&gt;&lt;/li&gt;
5816&lt;li&gt;&lt;a href=&#34;/posts/go-profiling/golang-profiling-cpu.pdf&#34;&gt;CPU PDF profile example&lt;/a&gt;&lt;/li&gt;
5817&lt;/ul&gt;
5818</content:encoded>
5819 </item>
5820
5821
5822
5823 <item>
5824 <title>Software development and my favorite pitfalls</title>
5825 <link>https://mitjafelicijan.com/software-development-pitfalls.html</link>
5826 <pubDate>Tue, 10 Nov 2015 12:00:00 &#43;0200</pubDate>
5827 <guid>https://mitjafelicijan.com/software-development-pitfalls.html</guid>
5828 <description>Over the years I had the privilege to work on some very excited projects both insoftware development field and also in electronics field and every experiencetaught me some invaluable lessons about how NOT TO approach development.</description>
5829 <content:encoded>&lt;p&gt;Over the years I had the privilege to work on some very excited projects both in
5830software development field and also in electronics field and every experience
5831taught me some invaluable lessons about how NOT TO approach development. And
5832through this post I will try to point out some absurd, outdated techniques I
5833find the most annoying and damaging during a development cycle. There will be
5834swearing because this topic really gets on my nerves and I never coherently
5835tried to explain them in writing. So if I get heated up, please bear with me.&lt;/p&gt;
5836&lt;p&gt;As new methods of project management are emerging, underlying processes still
5837stay old and outdated. This is mainly because we as people are unable to
5838completely shift away from these approaches.&lt;/p&gt;
5839&lt;p&gt;I was always struggling with communication, and many times that cost me a
5840relationship or two because I was not on the ball all the time. Through every
5841experience, I became more convinced that I am the problem and never ever doubted
5842that the problem may be that communication never evolved a single step from
5843emails. And if you think for a second, not many things have changed around this
5844topic. We just have different representations of email (message boards, chats,
5845project management tools). And I believe this is the real issue we are facing
5846now.&lt;/p&gt;
5847&lt;p&gt;There are many articles written about hyper connectivity and the effects that
5848are a direct result of it. But mainstream does nothing towards it. We are just
5849putting out fires, and we do nothing to prevent it. I am certain this will be a
5850major source of grief in coming years. And what we all can do to avoid this is
5851to change our mindset and experiment on our communication skills, development
5852approaches. We need to maximize possible output that a person can give. And to
5853achieve this we need to listen to them, encourage them. I know that not
5854everybody is a naturally born leader, but with enough practice and encouragement
5855they also can become active participants in leadership.&lt;/p&gt;
5856&lt;p&gt;There are many talks now about methodologies such as Scrum, Kanban, Cleanroom
5857and they all fucking piss me of :). These are all boxes that imprison people and
5858take away their freedom of thought. This is a straightforward mindfuck /
5859amputation of creativity.&lt;/p&gt;
5860&lt;p&gt;Let me list a couple of things that I find really destructive and bad for a
5861project and in a long run company.&lt;/p&gt;
5862&lt;h2 id=&#34;ping-emails&#34;&gt;Ping emails&lt;/h2&gt;
5863&lt;p&gt;Ping emails are emails you have to write as soon as you receive an email. Its
5864sole purpose is to inform the sender that you received their email, and you are
5865working on it. Its result is only to calm down the sender that their task is
5866being dealt with. It’s intent basically is, I did my job by sending you this
5867email, so I am on clear grounds. I categorize this email as fuck you email.
5868This is one of the most irritating types of emails I need to write. This is the
5869ultimate control freak show you can experience, and it gives the sender a false
5870feeling of control. Newsflash: We do not live in 1982 where there was a
5871possibility that email never reached the destination. I really hate this from
5872the bottom of my heart.&lt;/p&gt;
5873&lt;p&gt;They should be like: “Yes, I am fucking alive, and I am at your service my
5874leash!”. I guess if I would reply like this, I wouldn’t have to write any more
5875of this kind of messages.&lt;/p&gt;
5876&lt;h2 id=&#34;everybody-is-a-project-manager&#34;&gt;Everybody is a project manager&lt;/h2&gt;
5877&lt;p&gt;Well, this is a tough one. I noticed that as soon as you let people to give
5878their suggestions, you are basically screwed. There is a truth in the saying:
5879“Give low expectations and deliver little more than you promised.”.&lt;/p&gt;
5880&lt;p&gt;People tend to take a role of a manager as soon as they are presented with an
5881opportunity. And by getting angry at them, you only provoke yourself. They are
5882not at fault. You just need to tell them they are only giving suggestions and
5883not tasks at the beginning and everything will be alright. But if you give them
5884a feeling that they are in control, you will have immense problems explaining
5885why their features are not in current release.&lt;/p&gt;
5886&lt;p&gt;Project mission must be always leading project requirements and any deviation
5887from it will result in major project butchering. And by this, I mean that the
5888project will get its own path, and you will be left with half done software that
5889helps nobody. Clear mission goals and clean execution will allow you to develop
5890software will clear intent.&lt;/p&gt;
5891&lt;h2 id=&#34;we-are-never-wrong&#34;&gt;We are never wrong&lt;/h2&gt;
5892&lt;p&gt;I find this type of arrogance the worst. We must always conduct ourselves that
5893we are infallible and cannot make mistakes. As soon as a procedure or process is
5894established, there is no room for changes or improvements. This is the most
5895idiotic thing someone can say of think. I think that processes need to involve
5896and change over time. This is imperative and need to have in your organization
5897if you want to improve and develop company. We all need to grow balls and change
5898everything in order to adapt to current situations. Being a prisoner of
5899predefined processes kills creativity.&lt;/p&gt;
5900&lt;p&gt;I am constantly trying new software for project managing and communication. I
5901believe every team has its own dynamic, and it needs to be discovered
5902organically and naturally through many experiments. By putting the team in a
5903box, you are amputating their creativity and therefore minimizing their
5904potential. But if you talk to an executive, you will mainly find archetypical
5905thinking and a strong need to compartmentalize everything from business
5906processes to resource management. And this type of management that often
5907displays micromanagement techniques only works for short periods (couple of
5908years) and then employees either leave the company or become basically retarded
5909drones on autopilot.&lt;/p&gt;
5910&lt;h2 id=&#34;micromanaging&#34;&gt;Micromanaging&lt;/h2&gt;
5911&lt;p&gt;This basically implies that everybody on the team is an idiot who needs to have
5912a to-do list that they cannot write themselves. How about spoon-feeding the team
5913at launch because besides the team leader, everybody must be a retarded idiot at
5914best?&lt;/p&gt;
5915&lt;p&gt;I prefer milestones as they give developers much more freedom and creativity in
5916developing and not waste their time checking some bizarre to-do list that was
5917not even thought through. Projects constantly change throughout the development
5918cycle, and all you are left at the end is a list of unchecked tasks and the
5919wrath of management why they are not completed. Best WTF moment!&lt;/p&gt;
5920&lt;h2 id=&#34;human-contact--no-need-for-it&#34;&gt;Human contact — no need for it!&lt;/h2&gt;
5921&lt;p&gt;We are vigorously trying to eliminate physical contact by replacing short
5922meetings with software, with no regards that we are not machines. Many times a
5923simple 5-min meeting at morning can solve most of the problems. In rapid
5924development, short bursts of man to man communication is possibly the best way
5925to go.&lt;/p&gt;
5926&lt;p&gt;We now have all this software available, and all what we get out of it is a
5927giant clusterfuck. An obstacle and not a solution. So, why we still use them?&lt;/p&gt;
5928&lt;h2 id=&#34;mvp-is-killing-innovation&#34;&gt;MVP is killing innovation&lt;/h2&gt;
5929&lt;p&gt;Many will disagree with me on this one, but I stand strong by this statement.
5930What I noticed in my experience that all this buzz words around us only mislead
5931and capture us in a circle of solving issues that already have a solution, but
5932we are unable to see it without using some fancy word for it.&lt;/p&gt;
5933&lt;p&gt;The toughest thing to do for a developer is to minimize requirements. Well, this
5934is though only for bad developers. Yes, I said it. There are many types of
5935developers out there. And those unable to minimize feature scope are the ones
5936you don’t need on your team. Their only goal is to solve problems that exist
5937only in their heads. And then you have to argue with them, and waste energy on
5938them, instead of developing your awesome product. They are a cancer and I
5939suggest you cut them off.&lt;/p&gt;
5940&lt;p&gt;MVP as an idea is great, but sadly people don’t understand underlying
5941philosophy, and they spent too much time focusing and fixating on something that
5942every sane person with normal IQ will understand without some made up
5943acronym. And the result is a lot of talking and barely no execution.&lt;/p&gt;
5944&lt;p&gt;Well, MVP is not directly killing innovation, but stupid people do when they try
5945to understand it.&lt;/p&gt;
5946&lt;h2 id=&#34;pressure-wasteland&#34;&gt;Pressure wasteland&lt;/h2&gt;
5947&lt;p&gt;You must never allow to be pressured into confirming a deadline if you are not
5948confident. We often feel a need that we are in service of others, which is true
5949to some extent. But it is also true that others are in service to us to some
5950extent. And we forget this all the time. We are all pressured all the time to
5951make decisions just to calm other people down. And when they leave your office
5952you experience WTF moment :) How the hell did they manage to fuck me up again?&lt;/p&gt;
5953&lt;p&gt;People need to realize that the more pressure you put on somebody, the less they
5954will be able to do. So 5-min update email requests will only resolve in mental
5955breakdown and inability to work that day. Constant poking is probably the only
5956thing I lose my mind instantly. For all you that are doing this: “Stop bothering
5957us with your insecurities and let us do our job. We will do it quicker and
5958better without you breathing down our necks.”&lt;/p&gt;
5959&lt;p&gt;If this happens to me, I end up with no energy at the end. Don’t you get it?
5960You will get much more from and out of me if you ask me like a human person and
5961not your personal butler. On a long run, you are destroying your relationships
5962and nobody would want to work with you. Your schizophrenic approach will damage
5963only you in a long run. Nobody is anybody’s property.&lt;/p&gt;
5964&lt;h2 id=&#34;conclusion&#34;&gt;Conclusion&lt;/h2&gt;
5965&lt;p&gt;I am guilty of many things described in this post. And I find it hard sometimes
5966to acknowledge this. And I lie to myself and try vigorously to find some
5967explanation why I do these things. There is always space for growth. And maybe
5968you will also find some of yourself in this post and realize what needs to
5969change for you to evolve.&lt;/p&gt;
5970</content:encoded>
5971 </item>
5972
5973
5974
5975 <item>
5976 <title>Wireless sensor networks</title>
5977 <link>https://mitjafelicijan.com/wireless-sensor-networks.html</link>
5978 <pubDate>Thu, 24 Oct 2013 12:00:00 &#43;0200</pubDate>
5979 <guid>https://mitjafelicijan.com/wireless-sensor-networks.html</guid>
5980 <description>Zigbee networks have this wonderful capability to self-heal, which means theycan reorder connections between them if one of them is inoperable.</description>
5981 <content:encoded>&lt;p&gt;Zigbee networks have this wonderful capability to self-heal, which means they
5982can reorder connections between them if one of them is inoperable. This works
5983our of the box when you deploy them. But you have to have in mind that achieving
5984this is not as easy as you would think. None of it is plug&amp;amp;play. So to make
5985your life a bit easier, here are some pointers which, I hope, will help you.&lt;/p&gt;
5986&lt;ul&gt;
5987&lt;li&gt;Be careful when you are ordering your equipment abroad. There are many rules
5988and regulations you need to comply before you get your Xbee radios. What they
5989do is they wait until you prove that you won’t use the technology for some
5990kind of evil take over control of the world project :). For this, they have
5991EAR (Export Administration Regulations) which basically means “This product
5992may require a license to export from the United States.”.&lt;/li&gt;
5993&lt;li&gt;I don’t know if this applies for every country, but when we purchased our Xbee
5994radios from Mouser, this was mandatory! What we needed to do was to print out
5995a form and write information about our company and send them a copy via
5996email. With this document, we proved that we are a legitimate company.&lt;/li&gt;
5997&lt;li&gt;When you complete your purchase and send all the documentation, you are not
5998clear yet. Then customs will take it from there :). There will be some
5999additional costs. Before purchasing, make sure you have as much information
6000about costs as possible. Because it can get costly in the end.&lt;/li&gt;
6001&lt;li&gt;I suggest you use companies from your country. You can seriously cut your
6002costs. Here in Slovenia, the best option so far as I know is Farnell. And
6003based on my personal experience, they rock! All I need to say!&lt;/li&gt;
6004&lt;li&gt;Make plans when ordering larger quantities. Do not, I say, do not make your
6005orders in December! :) Believe me! You will have problems with stock they can
6006provide for you. So, we were forced to buy some things from Mouser, which was
6007extremely painful because of all the regulations you need to obey when
6008importing goods from the USA.&lt;/li&gt;
6009&lt;li&gt;Make sure that firmware version on your Xbee radios is exactly the same! Do
6010not get creative!!! I propose using templates. You can get template by
6011exporting settings/profile in X-CTU application. Make sure you have enabled
6012“Upgrade firmware” so you can be sure each radio has the same firmware.&lt;/li&gt;
6013&lt;li&gt;And again: make plans! Plan everything! In months advanced! You will thank me
6014later :)&lt;/li&gt;
6015&lt;li&gt;Test, test, test. Wireless networks can be tricky.&lt;/li&gt;
6016&lt;/ul&gt;
6017&lt;p&gt;If you are serious, I suggest you buy this book, Building Wireless Sensor
6018Networks. You will get a glimpse of how networks work in lumens terms. It is a
6019good starting point for everybody who wants to build wireless networks.&lt;/p&gt;
6020&lt;p&gt;&lt;strong&gt;Additional resources:&lt;/strong&gt;&lt;/p&gt;
6021&lt;ul&gt;
6022&lt;li&gt;&lt;a href=&#34;http://www.digi.com/aboutus/export/generalexportinfo&#34;&gt;http://www.digi.com/aboutus/export/generalexportinfo&lt;/a&gt;&lt;/li&gt;
6023&lt;li&gt;&lt;a href=&#34;http://doresearch.stanford.edu/research-scholarship/export-controls/export-controlled-or-embargoed-countries-entities-and-persons&#34;&gt;http://doresearch.stanford.edu/research-scholarship/export-controls/export-controlled-or-embargoed-countries-entities-and-persons&lt;/a&gt;&lt;/li&gt;
6024&lt;li&gt;&lt;a href=&#34;http://www.bis.doc.gov/licensing/exportingbasics.htm&#34;&gt;http://www.bis.doc.gov/licensing/exportingbasics.htm&lt;/a&gt;&lt;/li&gt;
6025&lt;/ul&gt;
6026</content:encoded>
6027 </item>
6028
6029
6030
6031 <item>
6032 <title>LED technology might not be as eco-friendly as you think</title>
6033 <link>https://mitjafelicijan.com/led-technology-not-so-eco.html</link>
6034 <pubDate>Fri, 09 Mar 2012 12:00:00 &#43;0200</pubDate>
6035 <guid>https://mitjafelicijan.com/led-technology-not-so-eco.html</guid>
6036 <description>There is a lot of talk about LED technology.</description>
6037 <content:encoded>&lt;p&gt;There is a lot of talk about LED technology. It is beginning to infiltrate
6038industry at a fast rate, and it’s a challenge for designers and also engineers.
6039I wondered when a weakness will be revealed. Then I stomped on an article
6040talking about harm in using LED technology. It looks like this magical
6041technology is not so magical and eco-friendly.&lt;/p&gt;
6042&lt;p&gt;A new study from the University of California indicates that LED lights contain
6043toxic metals, and should be produced, used and disposed of carefully. Besides
6044the lead and nickel, the bulbs and their associated parts were also found to
6045contain arsenic, copper, and other metals that have been linked to different
6046cancers, neurological damage, kidney disease, hypertension, skin rashes and
6047other illnesses in humans, and to ecological damage in waterways.&lt;/p&gt;
6048&lt;p&gt;Since then, I haven’t yet found any regulation for disposal of LED lights or any
6049other regulation or standard. This might be a problem in the future. And it is a
6050massive drawback. This might have quite an impact on consumer market.&lt;/p&gt;
6051&lt;p&gt;Nevertheless, there is a potential, and I am sure the market will adapt. I also
6052hope I will be reading documents regarding solution for this concern soon.&lt;/p&gt;
6053&lt;p&gt;&lt;strong&gt;Additional resources:&lt;/strong&gt;&lt;/p&gt;
6054&lt;ul&gt;
6055&lt;li&gt;&lt;a href=&#34;http://ezinearticles.com/?Recycling-and-Disposal-of-Light-Bulbs&amp;amp;id=1091304&#34;&gt;Recycling and Disposal of Light Bulbs&lt;/a&gt;&lt;/li&gt;
6056&lt;li&gt;&lt;a href=&#34;http://www.ehow.com/how_7483442_dispose-lowenergy-light-bulb.html&#34;&gt;How to Dispose of a Low-Energy Light Bulb&lt;/a&gt;&lt;/li&gt;
6057&lt;/ul&gt;
6058</content:encoded>
6059 </item>
6060
6061
6062
6063 <item>
6064 <title>Most likely to succeed in the year of 2011</title>
6065 <link>https://mitjafelicijan.com/most-likely-to-succeed-in-year-of-2011.html</link>
6066 <pubDate>Thu, 13 Jan 2011 12:00:00 &#43;0200</pubDate>
6067 <guid>https://mitjafelicijan.com/most-likely-to-succeed-in-year-of-2011.html</guid>
6068 <description>The year of 2010 was definitely the year of Geo-location.</description>
6069 <content:encoded>&lt;p&gt;The year of 2010 was definitely the year of Geo-location. The market responded
6070beautifully and lots of very cool services were launched. We all have to thank
6071the mobile market for such extensive adoption. With new generations of mobile
6072phones that are not only buffed with high-tech hardware but are also affordable.
6073We can now manage tasks that were not so long time ago, almost Star Trek’ish.
6074And all this had and has great influence on the destination to which we are
6075going now.&lt;/p&gt;
6076&lt;p&gt;Reading all this articles about new innovation about new thriving technologies
6077makes me wonder what’s the next step. The future is the mesh, like Lisa Gansky
6078said in her book The Mesh.&lt;/p&gt;
6079&lt;p&gt;Many still have conservative views on distributed systems. The problems with
6080security of information. Fear of not controlling every aspect of information
6081flow. I am very opened to distributed systems and heterogeneous applications,
6082and I think this is the correct and best way to proceed.&lt;/p&gt;
6083&lt;p&gt;This year will definitely be about communication platforms. Mobile to mobile.
6084Machine to mobile and vice versa. All the tech is available and ready to put
6085into action. Wireless is today’s new mantra. And the concept of semantic web is
6086now ready for industry.&lt;/p&gt;
6087&lt;p&gt;Applications and developers now can gain access to new layers of systems and can
6088prepare and build solutions to meet the high quality needs of market. The speed
6089is everything now.&lt;/p&gt;
6090&lt;p&gt;My vote goes to “Machine to Machine” and “Embedded Systems”!&lt;/p&gt;
6091&lt;ul&gt;
6092&lt;li&gt;&lt;a href=&#34;http://en.wikipedia.org/wiki/Machine-to-Machine&#34;&gt;Machine-to-Machine&lt;/a&gt;&lt;/li&gt;
6093&lt;li&gt;&lt;a href=&#34;http://www.bitxml.org/&#34;&gt;The ultimate M2M communication protocol&lt;/a&gt;&lt;/li&gt;
6094&lt;li&gt;&lt;a href=&#34;http://www.coosproject.org/maven-site/1.0.0/project-info.html&#34;&gt;COOS Project (connectivity initiative)&lt;/a&gt;&lt;/li&gt;
6095&lt;li&gt;&lt;a href=&#34;http://m2m.com/index.jspa&#34;&gt;Community for machine-to-machine&lt;/a&gt;&lt;/li&gt;
6096&lt;li&gt;&lt;a href=&#34;http://en.wikipedia.org/wiki/Embedded_system&#34;&gt;Embedded system&lt;/a&gt;&lt;/li&gt;
6097&lt;/ul&gt;
6098</content:encoded>
6099 </item>
6100
6101
6102 </channel>
6103</rss>
diff --git a/public/install-plan9port-linux.html b/public/install-plan9port-linux.html
deleted file mode 100755
index efcd342..0000000
--- a/public/install-plan9port-linux.html
+++ /dev/null
@@ -1,51 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Install Plan9port on Linux</title><meta name=description content="Install Plan9port on Linux."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Install Plan9port on Linux</h1><p><cap>note</cap>, May 12, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>Install Plan9port on Linux. This applies to
10<a href=https://9fans.github.io/plan9port/>Plan9port</a>. This is a port of many Plan 9
11programs to Unix-like operating systems. Useful for programs like <code>9term</code> and
12<code>rc</code>.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>sudo apt-get install gcc libx11-dev libxt-dev libxext-dev libfontconfig1-dev
13</span></span><span style=display:flex><span>git clone https://github.com/9fans/plan9port $HOME/plan9
14</span></span><span style=display:flex><span>cd $HOME/plan9/plan9port
15</span></span><span style=display:flex><span>./INSTALL -r $HOME/plan9
16</span></span></code></pre></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
17a lock on a Linux NFS server, which turned
18out to be specific to NFS v3 (which I really should have seen coming,
19since it involved NLM and lockd). Finding the NFS v4 client that
20owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
21and Bradley Kuhn, are interacting on the OSI's license-discuss
22list where the're doing
23bad computer history and insisting that a guy Larry Rosen
24coincidentally interviewed for a book years ago is clearly the origin of
25somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
26i2c, plan9
27Another month, another file system.
28Well, if you can’t fix it in software, fix it in hardware (looking at
29you, bme680, we’re not
30done yet). The show must go on, as they say, and I would like my
31experiments to go on.
32So a “new” addition to the environmental sensor family connected to
33the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
34this mortal coil, we are endowed with self-awareness, agency, and free will.
35Each of the 8 billion members of this human race represents a unique person, a
36unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
37My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
381.0 has been released:
39wifi_da-1.0.sit
40(StuffIt 3 archive)
41SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
42This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
43classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
44In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
45Design Goals
46I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
47at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
48catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
49specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
50 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
51 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/led-technology-not-so-eco.html b/public/led-technology-not-so-eco.html
deleted file mode 100755
index 6d7a588..0000000
--- a/public/led-technology-not-so-eco.html
+++ /dev/null
@@ -1,56 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>LED technology might not be as eco-friendly as you think</title><meta name=description content="There is a lot of talk about LED technology."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>LED technology might not be as eco-friendly as you think</h1><p><cap>post</cap>, Mar 9, 2012 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>There is a lot of talk about LED technology. It is beginning to infiltrate
10industry at a fast rate, and it’s a challenge for designers and also engineers.
11I wondered when a weakness will be revealed. Then I stomped on an article
12talking about harm in using LED technology. It looks like this magical
13technology is not so magical and eco-friendly.<p>A new study from the University of California indicates that LED lights contain
14toxic metals, and should be produced, used and disposed of carefully. Besides
15the lead and nickel, the bulbs and their associated parts were also found to
16contain arsenic, copper, and other metals that have been linked to different
17cancers, neurological damage, kidney disease, hypertension, skin rashes and
18other illnesses in humans, and to ecological damage in waterways.<p>Since then, I haven’t yet found any regulation for disposal of LED lights or any
19other regulation or standard. This might be a problem in the future. And it is a
20massive drawback. This might have quite an impact on consumer market.<p>Nevertheless, there is a potential, and I am sure the market will adapt. I also
21hope I will be reading documents regarding solution for this concern soon.<p><strong>Additional resources:</strong><ul><li><a href="http://ezinearticles.com/?Recycling-and-Disposal-of-Light-Bulbs&amp;id=1091304">Recycling and Disposal of Light Bulbs</a><li><a href=http://www.ehow.com/how_7483442_dispose-lowenergy-light-bulb.html>How to Dispose of a Low-Energy Light Bulb</a></ul></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
22a lock on a Linux NFS server, which turned
23out to be specific to NFS v3 (which I really should have seen coming,
24since it involved NLM and lockd). Finding the NFS v4 client that
25owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
26and Bradley Kuhn, are interacting on the OSI's license-discuss
27list where the're doing
28bad computer history and insisting that a guy Larry Rosen
29coincidentally interviewed for a book years ago is clearly the origin of
30somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
31i2c, plan9
32Another month, another file system.
33Well, if you can’t fix it in software, fix it in hardware (looking at
34you, bme680, we’re not
35done yet). The show must go on, as they say, and I would like my
36experiments to go on.
37So a “new” addition to the environmental sensor family connected to
38the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
39this mortal coil, we are endowed with self-awareness, agency, and free will.
40Each of the 8 billion members of this human race represents a unique person, a
41unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
42My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
431.0 has been released:
44wifi_da-1.0.sit
45(StuffIt 3 archive)
46SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
47This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
48classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
49In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
50Design Goals
51I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
52at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
53catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
54specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
55 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
56 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/linux-cheatsheet.html b/public/linux-cheatsheet.html
deleted file mode 100755
index 54ebb26..0000000
--- a/public/linux-cheatsheet.html
+++ /dev/null
@@ -1,144 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>List of essential Linux commands for server management</title><meta name=description content="Generate SSH keyssh-keygen -t ed25519 -C &amp;#34;your_email@example."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>List of essential Linux commands for server management</h1><p><cap>post</cap>, Aug 1, 2021 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p><strong>Generate SSH key</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>ssh-keygen -t ed25519 -C <span style=color:#a31515>&#34;your_email@example.com&#34;</span>
10</span></span><span style=display:flex><span>
11</span></span><span style=display:flex><span><span style=color:green># when no support for Ed25519 present</span>
12</span></span><span style=display:flex><span>ssh-keygen -t rsa -b 4096 -C <span style=color:#a31515>&#34;your_email@example.com&#34;</span>
13</span></span></code></pre><p>Note: By default SSH keys get stored to <code>/home/&lt;username>/.ssh/</code> folder.<p><strong>Login to host via SSH</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># connect to host as your local username</span>
14</span></span><span style=display:flex><span>ssh host
15</span></span><span style=display:flex><span>
16</span></span><span style=display:flex><span><span style=color:green># connect to host as user</span>
17</span></span><span style=display:flex><span>ssh &lt;user&gt;@&lt;host&gt;
18</span></span><span style=display:flex><span>
19</span></span><span style=display:flex><span><span style=color:green># connect to host using port</span>
20</span></span><span style=display:flex><span>ssh -p &lt;port&gt; &lt;user&gt;@&lt;host&gt;
21</span></span></code></pre><p><strong>Execute command on a server through SSH</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># execute one command</span>
22</span></span><span style=display:flex><span>ssh root@100.100.100.100 <span style=color:#a31515>&#34;ls /root&#34;</span>
23</span></span><span style=display:flex><span>
24</span></span><span style=display:flex><span><span style=color:green># execute many commands</span>
25</span></span><span style=display:flex><span>ssh root@100.100.100.100 <span style=color:#a31515>&#34;cd /root;touch file.txt&#34;</span>
26</span></span></code></pre><p><strong>Displays currently logged in users in the system</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>w
27</span></span></code></pre><p><strong>Displays Linux system information</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>uname
28</span></span></code></pre><p><strong>Displays kernel release information</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>uname -r
29</span></span></code></pre><p><strong>Shows the system hostname</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>hostname
30</span></span></code></pre><p><strong>Shows system reboot history</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>last reboot
31</span></span></code></pre><p><strong>Displays information about the user</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>sudo apt install finger
32</span></span><span style=display:flex><span>finger &lt;username&gt;
33</span></span></code></pre><p><strong>Displays IP addresses and all the network interfaces</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>ip addr show
34</span></span></code></pre><p><strong>Downloads a file from an online source</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>wget https://example.com/example.tgz
35</span></span></code></pre><p>Note: If URL contains ?, & enclose the URL in double quotes.<p><strong>Compress a file with gzip</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># will not keep the original file</span>
36</span></span><span style=display:flex><span>gzip file.txt
37</span></span><span style=display:flex><span>
38</span></span><span style=display:flex><span><span style=color:green># will keep the original file</span>
39</span></span><span style=display:flex><span>gzip --keep file.txt
40</span></span></code></pre><p><strong>Interactive disk usage analyzer</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>sudo apt install ncdu
41</span></span><span style=display:flex><span>
42</span></span><span style=display:flex><span>ncdu
43</span></span><span style=display:flex><span>ncdu &lt;path/to/directory&gt;
44</span></span></code></pre><p><strong>Install Node.js using the Node Version Manager</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.35.3/install.sh | bash
45</span></span><span style=display:flex><span>source ~/.bashrc
46</span></span><span style=display:flex><span>
47</span></span><span style=display:flex><span>nvm install v13
48</span></span></code></pre><p><strong>Too long; didn't read</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>npm install -g tldr
49</span></span><span style=display:flex><span>
50</span></span><span style=display:flex><span>tldr tar
51</span></span></code></pre><p><strong>Combine all Nginx access logs to one big log file</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>zcat -f /var/log/nginx/access.log* &gt; /var/log/nginx/access-all.log
52</span></span></code></pre><p><strong>Set up Redis server</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>sudo apt install redis-server redis-tools
53</span></span><span style=display:flex><span>
54</span></span><span style=display:flex><span><span style=color:green># check if server is running</span>
55</span></span><span style=display:flex><span>sudo service redis status
56</span></span><span style=display:flex><span>
57</span></span><span style=display:flex><span><span style=color:green># set and get a key value</span>
58</span></span><span style=display:flex><span>redis-cli set mykey myvalue
59</span></span><span style=display:flex><span>redis-cli get mykey
60</span></span><span style=display:flex><span>
61</span></span><span style=display:flex><span><span style=color:green># interactive shell</span>
62</span></span><span style=display:flex><span>redis-cli
63</span></span></code></pre><p><strong>Generate statistics of your webserver</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>sudo apt install goaccess
64</span></span><span style=display:flex><span>
65</span></span><span style=display:flex><span><span style=color:green># check if installed</span>
66</span></span><span style=display:flex><span>goaccess -v
67</span></span><span style=display:flex><span>
68</span></span><span style=display:flex><span><span style=color:green># combine logs</span>
69</span></span><span style=display:flex><span>zcat -f /var/log/nginx/access.log* &gt; /var/log/nginx/access-all.log
70</span></span><span style=display:flex><span>
71</span></span><span style=display:flex><span><span style=color:green># export to single html</span>
72</span></span><span style=display:flex><span>goaccess <span style=color:#a31515>\
73</span></span></span><span style=display:flex><span><span style=color:#a31515></span> --log-file=/var/log/nginx/access-all.log <span style=color:#a31515>\
74</span></span></span><span style=display:flex><span><span style=color:#a31515></span> --log-format=COMBINED <span style=color:#a31515>\
75</span></span></span><span style=display:flex><span><span style=color:#a31515></span> --exclude-ip=0.0.0.0 <span style=color:#a31515>\
76</span></span></span><span style=display:flex><span><span style=color:#a31515></span> --ignore-crawlers <span style=color:#a31515>\
77</span></span></span><span style=display:flex><span><span style=color:#a31515></span> --real-os <span style=color:#a31515>\
78</span></span></span><span style=display:flex><span><span style=color:#a31515></span> --output=/var/www/html/stats.html
79</span></span><span style=display:flex><span>
80</span></span><span style=display:flex><span><span style=color:green># cleanup afterwards</span>
81</span></span><span style=display:flex><span>rm /var/log/nginx/access-all.log
82</span></span></code></pre><p><strong>Search for a given pattern in files</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>grep -r ‘pattern’ files
83</span></span></code></pre><p><strong>Find proccess ID for a specific program</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>pgrep nginx
84</span></span></code></pre><p><strong>Print name of current/working directory</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>pwd
85</span></span></code></pre><p><strong>Creates a blank new file</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>touch newfile.txt
86</span></span></code></pre><p><strong>Displays first lines in a file</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># -n &lt;x&gt; presents the number of lines (10 by default)</span>
87</span></span><span style=display:flex><span>head -n 20 somefile.txt
88</span></span></code></pre><p><strong>Displays last lines in a file</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># -n &lt;x&gt; presents the number of lines (10 by default)</span>
89</span></span><span style=display:flex><span>tail -n 20 somefile.txt
90</span></span><span style=display:flex><span>
91</span></span><span style=display:flex><span><span style=color:green># -f follows the changes in file (doesn&#39;t closes)</span>
92</span></span><span style=display:flex><span>tail -f somefile.txt
93</span></span></code></pre><p><strong>Count lines in a file</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>wc -l somefile.txt
94</span></span></code></pre><p><strong>Find all instances of the file</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>sudo apt install mlocate
95</span></span><span style=display:flex><span>
96</span></span><span style=display:flex><span>locate somefile.txt
97</span></span></code></pre><p><strong>Find file names that begin with ‘index’ in /home folder</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>find /home/ -name <span style=color:#a31515>&#34;index&#34;</span>
98</span></span></code></pre><p><strong>Find files larger than 100MB in the home folder</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>find /home -size +100M
99</span></span></code></pre><p><strong>Displays block devices related information</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>lsblk
100</span></span></code></pre><p><strong>Displays free space on mounted systems</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>df -h
101</span></span></code></pre><p><strong>Displays free and used memory in the system</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>free -h
102</span></span></code></pre><p><strong>Displays all active listening ports</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>sudo apt install net-tools
103</span></span><span style=display:flex><span>
104</span></span><span style=display:flex><span>netstat -pnltu
105</span></span></code></pre><p><strong>Kill a process violently</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>kill -9 &lt;pid&gt;
106</span></span></code></pre><p><strong>List files opened by user</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>lsof -u &lt;user&gt;
107</span></span></code></pre><p><strong>Execute "df -h", showing periodic updates</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># -n 1 means every second</span>
108</span></span><span style=display:flex><span>watch -n 1 df -h
109</span></span></code></pre></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
110a lock on a Linux NFS server, which turned
111out to be specific to NFS v3 (which I really should have seen coming,
112since it involved NLM and lockd). Finding the NFS v4 client that
113owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
114and Bradley Kuhn, are interacting on the OSI's license-discuss
115list where the're doing
116bad computer history and insisting that a guy Larry Rosen
117coincidentally interviewed for a book years ago is clearly the origin of
118somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
119i2c, plan9
120Another month, another file system.
121Well, if you can’t fix it in software, fix it in hardware (looking at
122you, bme680, we’re not
123done yet). The show must go on, as they say, and I would like my
124experiments to go on.
125So a “new” addition to the environmental sensor family connected to
126the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
127this mortal coil, we are endowed with self-awareness, agency, and free will.
128Each of the 8 billion members of this human race represents a unique person, a
129unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
130My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
1311.0 has been released:
132wifi_da-1.0.sit
133(StuffIt 3 archive)
134SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
135This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
136classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
137In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
138Design Goals
139I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
140at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
141catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
142specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
143 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
144 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/make-b-w-svg-charts-with-matplotlib.html b/public/make-b-w-svg-charts-with-matplotlib.html
deleted file mode 100755
index f68a7d3..0000000
--- a/public/make-b-w-svg-charts-with-matplotlib.html
+++ /dev/null
@@ -1,86 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Make B/W SVG charts with matplotlib</title><meta name=description content="Install pip requirements."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Make B/W SVG charts with matplotlib</h1><p><cap>note</cap>, Aug 1, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>Install pip requirements.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>pip install matplotlib
10</span></span><span style=display:flex><span>pip install pandas
11</span></span></code></pre><p>Example of data being used.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>Epoch,Connect (NLB),Processing (NLB),Waiting (NLB),Total (NLB),Connect (ALB),Processing (ALB),Waiting (ALB),Total (ALB)
12</span></span><span style=display:flex><span>1,57.7,315.7,309.4,321.6,9,104.4,98.3,105.7
13</span></span><span style=display:flex><span>2,121.9,114.4,100.3,176.9,5.8,99.1,97.1,101.1
14</span></span><span style=display:flex><span>3,5.3,229.4,231.2,231.4,14.2,83,69.4,87.9
15</span></span><span style=display:flex><span>4,4.2,134.5,112.2,135.3,5.3,132.4,105.5,134.1
16</span></span><span style=display:flex><span>5,5.8,247.4,246.8,248.1,6,74.3,70.2,75.5
17</span></span><span style=display:flex><span>6,9.9,122.9,100.6,122.7,7.5,241.1,79.3,242.3
18</span></span><span style=display:flex><span>7,6.1,170.2,106.4,170.5,7.2,382.4,375.1,383.8
19</span></span><span style=display:flex><span>8,6.6,194.3,201.4,195.5,7.1,130.9,104.8,132.6
20</span></span><span style=display:flex><span>9,6.4,146.1,122.3,147.7,9.4,95.6,74,96.4
21</span></span></code></pre><p>In the code you can use <code>df</code> as dataframes and use the headers like <code>df["Epoch"]</code>.
22This is how you get a column data with pandas.<p>The Python code responsible for generating a chart:<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>import</span> csv
23</span></span><span style=display:flex><span><span style=color:#00f>import</span> sys
24</span></span><span style=display:flex><span>
25</span></span><span style=display:flex><span><span style=color:#00f>import</span> matplotlib.pyplot <span style=color:#00f>as</span> plt
26</span></span><span style=display:flex><span><span style=color:#00f>import</span> pandas <span style=color:#00f>as</span> pd
27</span></span><span style=display:flex><span>
28</span></span><span style=display:flex><span><span style=color:green># Read the data</span>
29</span></span><span style=display:flex><span>df = pd.read_csv(<span style=color:#a31515>&#34;data.csv&#34;</span>)
30</span></span><span style=display:flex><span>
31</span></span><span style=display:flex><span><span style=color:green># Settings</span>
32</span></span><span style=display:flex><span>plt.title(<span style=color:#a31515>&#34;Connect median NLB vs ALB&#34;</span>)
33</span></span><span style=display:flex><span>plt.tight_layout(pad=2)
34</span></span><span style=display:flex><span>fig = plt.gcf()
35</span></span><span style=display:flex><span>fig.set_size_inches(10, 4)
36</span></span><span style=display:flex><span>
37</span></span><span style=display:flex><span><span style=color:green># Plotting</span>
38</span></span><span style=display:flex><span>plt.plot(df[<span style=color:#a31515>&#34;Epoch&#34;</span>], df[<span style=color:#a31515>&#34;Connect (ALB)&#34;</span>], label = <span style=color:#a31515>&#34;ALB&#34;</span>, color=<span style=color:#a31515>&#34;black&#34;</span>, linestyle=<span style=color:#a31515>&#34;-&#34;</span>)
39</span></span><span style=display:flex><span>plt.plot(df[<span style=color:#a31515>&#34;Epoch&#34;</span>], df[<span style=color:#a31515>&#34;Connect (NLB)&#34;</span>], label = <span style=color:#a31515>&#34;NLB&#34;</span>, color=<span style=color:#a31515>&#34;black&#34;</span>, linestyle=<span style=color:#a31515>&#34;--&#34;</span>)
40</span></span><span style=display:flex><span>
41</span></span><span style=display:flex><span><span style=color:green># Adding x and y axis labels</span>
42</span></span><span style=display:flex><span>plt.xlabel(<span style=color:#a31515>&#34;Epoch&#34;</span>, fontstyle=<span style=color:#a31515>&#34;italic&#34;</span>)
43</span></span><span style=display:flex><span>plt.ylabel(<span style=color:#a31515>&#34;Median value (ms)&#34;</span>, fontstyle=<span style=color:#a31515>&#34;italic&#34;</span>)
44</span></span><span style=display:flex><span>
45</span></span><span style=display:flex><span><span style=color:green># Legend</span>
46</span></span><span style=display:flex><span>legend = plt.legend()
47</span></span><span style=display:flex><span>legend.get_frame().set_linewidth(0)
48</span></span><span style=display:flex><span>
49</span></span><span style=display:flex><span><span style=color:green># Export as SVG</span>
50</span></span><span style=display:flex><span>plt.savefig(<span style=color:#a31515>&#34;plot.svg&#34;</span>, format=<span style=color:#a31515>&#34;svg&#34;</span>)
51</span></span></code></pre><figure><img src=/notes/plot.svg alt="SVG Chart"></figure><p>The image above is SVG and you can zoom in and out and check that the image is vector.</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
52a lock on a Linux NFS server, which turned
53out to be specific to NFS v3 (which I really should have seen coming,
54since it involved NLM and lockd). Finding the NFS v4 client that
55owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
56and Bradley Kuhn, are interacting on the OSI's license-discuss
57list where the're doing
58bad computer history and insisting that a guy Larry Rosen
59coincidentally interviewed for a book years ago is clearly the origin of
60somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
61i2c, plan9
62Another month, another file system.
63Well, if you can’t fix it in software, fix it in hardware (looking at
64you, bme680, we’re not
65done yet). The show must go on, as they say, and I would like my
66experiments to go on.
67So a “new” addition to the environmental sensor family connected to
68the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
69this mortal coil, we are endowed with self-awareness, agency, and free will.
70Each of the 8 billion members of this human race represents a unique person, a
71unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
72My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
731.0 has been released:
74wifi_da-1.0.sit
75(StuffIt 3 archive)
76SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
77This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
78classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
79In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
80Design Goals
81I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
82at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
83catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
84specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
85 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
86 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/making-cgit-look-nicer.html b/public/making-cgit-look-nicer.html
deleted file mode 100755
index cdcddab..0000000
--- a/public/making-cgit-look-nicer.html
+++ /dev/null
@@ -1,228 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Making cgit look nicer</title><meta name=description content="For personal use I have a private Git serverset up and I use GitHub just as a mirror."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Making cgit look nicer</h1><p><cap>note</cap>, Jun 24, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>For personal use I have a <a href=https://git.mitjafelicijan.com>private Git server</a>
10set up and I use GitHub just as a mirror. By default the cgit theme looks a bit
11dated so I made the flowing theme.<ul><li><code>/etc/cgitrc</code></ul><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>css=<span style=color:#a31515>/cgit.css</span>
12</span></span><span style=display:flex><span>logo=<span style=color:#a31515>/startrek.gif</span>
13</span></span><span style=display:flex><span>favicon=<span style=color:#a31515>/favicon.png</span>
14</span></span><span style=display:flex><span>source-filter=<span style=color:#a31515>/usr/lib/cgit/filters/syntax-highlighting-edited.sh</span>
15</span></span><span style=display:flex><span>about-filter=<span style=color:#a31515>/usr/lib/cgit/filters/about-formatting.sh</span>
16</span></span><span style=display:flex><span>
17</span></span><span style=display:flex><span>local-time=<span style=color:#a31515>1</span>
18</span></span><span style=display:flex><span>snapshots=<span style=color:#a31515>tar.gz</span>
19</span></span><span style=display:flex><span>repository-sort=<span style=color:#a31515>age</span>
20</span></span><span style=display:flex><span>cache-size=<span style=color:#a31515>1000</span>
21</span></span><span style=display:flex><span>branch-sort=<span style=color:#a31515>age</span>
22</span></span><span style=display:flex><span>summary-log=<span style=color:#a31515>200</span>
23</span></span><span style=display:flex><span>max-atom-items=<span style=color:#a31515>50</span>
24</span></span><span style=display:flex><span>max-repo-count=<span style=color:#a31515>100</span>
25</span></span><span style=display:flex><span>
26</span></span><span style=display:flex><span>enable-index-owner=<span style=color:#a31515>0</span>
27</span></span><span style=display:flex><span>enable-follow-links=<span style=color:#a31515>1</span>
28</span></span><span style=display:flex><span>enable-log-filecount=<span style=color:#a31515>1</span>
29</span></span><span style=display:flex><span>enable-log-linecount=<span style=color:#a31515>1</span>
30</span></span><span style=display:flex><span>
31</span></span><span style=display:flex><span>root-title=<span style=color:#a31515>Place for code, experiments and other bullshit!</span>
32</span></span><span style=display:flex><span>root-desc=
33</span></span><span style=display:flex><span>clone-url=<span style=color:#a31515>git@git.mitjafelicijan.com:/home/git/$CGIT_REPO_URL</span>
34</span></span><span style=display:flex><span>
35</span></span><span style=display:flex><span>mimetype.gif=<span style=color:#a31515>image/gif</span>
36</span></span><span style=display:flex><span>mimetype.html=<span style=color:#a31515>text/html</span>
37</span></span><span style=display:flex><span>mimetype.jpg=<span style=color:#a31515>image/jpeg</span>
38</span></span><span style=display:flex><span>mimetype.jpeg=<span style=color:#a31515>image/jpeg</span>
39</span></span><span style=display:flex><span>mimetype.pdf=<span style=color:#a31515>application/pdf</span>
40</span></span><span style=display:flex><span>mimetype.png=<span style=color:#a31515>image/png</span>
41</span></span><span style=display:flex><span>mimetype.svg=<span style=color:#a31515>image/svg+xml</span>
42</span></span><span style=display:flex><span>
43</span></span><span style=display:flex><span>readme=<span style=color:#a31515>:README.md</span>
44</span></span><span style=display:flex><span>readme=<span style=color:#a31515>:readme.md</span>
45</span></span><span style=display:flex><span>
46</span></span><span style=display:flex><span><span style=color:green># Must be at the end!</span>
47</span></span><span style=display:flex><span>virtual-root=<span style=color:#a31515>/</span>
48</span></span><span style=display:flex><span>scan-path=<span style=color:#a31515>/home/git/</span>
49</span></span></code></pre><p>For <code>syntax-highlighting-edited.sh</code> follow instructions on
50<a href=https://wiki.archlinux.org/title/Cgit#Using_highlight>https://wiki.archlinux.org/title/Cgit</a>.<ul><li><code>/usr/share/cgit/cgit.css</code></ul><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>* {
51</span></span><span style=display:flex><span> <span style=color:#00f>font-size</span>: 11<span style=color:#2b91af>pt</span>;
52</span></span><span style=display:flex><span>}
53</span></span><span style=display:flex><span>
54</span></span><span style=display:flex><span>body {
55</span></span><span style=display:flex><span> <span style=color:#00f>font-family</span>: <span style=color:#00f>monospace</span>;
56</span></span><span style=display:flex><span> <span style=color:#00f>background</span>: <span style=color:#00f>white</span>;
57</span></span><span style=display:flex><span> <span style=color:#00f>padding</span>: 1<span style=color:#2b91af>em</span>;
58</span></span><span style=display:flex><span>}
59</span></span><span style=display:flex><span>
60</span></span><span style=display:flex><span>th, td {
61</span></span><span style=display:flex><span> <span style=color:#00f>text-align</span>: <span style=color:#00f>left</span>;
62</span></span><span style=display:flex><span>}
63</span></span><span style=display:flex><span>
64</span></span><span style=display:flex><span><span style=color:green>/* HEADER */</span>
65</span></span><span style=display:flex><span>
66</span></span><span style=display:flex><span>#header {
67</span></span><span style=display:flex><span> <span style=color:#00f>margin-bottom</span>: 1<span style=color:#2b91af>em</span>;
68</span></span><span style=display:flex><span>}
69</span></span><span style=display:flex><span>
70</span></span><span style=display:flex><span>#header .<span style=color:#2b91af>logo</span> img {
71</span></span><span style=display:flex><span> <span style=color:#00f>display</span>: <span style=color:#00f>block</span>;
72</span></span><span style=display:flex><span> <span style=color:#00f>height</span>: 3<span style=color:#2b91af>em</span>;
73</span></span><span style=display:flex><span> <span style=color:#00f>margin-right</span>: 10<span style=color:#2b91af>px</span>;
74</span></span><span style=display:flex><span>}
75</span></span><span style=display:flex><span>
76</span></span><span style=display:flex><span>#header .<span style=color:#2b91af>sub</span>.<span style=color:#2b91af>right</span> {
77</span></span><span style=display:flex><span> <span style=color:#00f>display</span>: <span style=color:#00f>none</span>;
78</span></span><span style=display:flex><span>}
79</span></span><span style=display:flex><span>
80</span></span><span style=display:flex><span><span style=color:green>/* FOOTER */</span>
81</span></span><span style=display:flex><span>
82</span></span><span style=display:flex><span>.<span style=color:#2b91af>footer</span> {
83</span></span><span style=display:flex><span> <span style=color:#00f>margin-top</span>: 2<span style=color:#2b91af>em</span>;
84</span></span><span style=display:flex><span> <span style=color:#00f>font-style</span>: <span style=color:#00f>italic</span>;
85</span></span><span style=display:flex><span>}
86</span></span><span style=display:flex><span>
87</span></span><span style=display:flex><span>.<span style=color:#2b91af>footer</span>, .<span style=color:#2b91af>footer</span> a {
88</span></span><span style=display:flex><span> <span style=color:#00f>color</span>: <span style=color:#00f>gray</span>;
89</span></span><span style=display:flex><span>}
90</span></span><span style=display:flex><span>
91</span></span><span style=display:flex><span><span style=color:green>/* TABS */</span>
92</span></span><span style=display:flex><span>
93</span></span><span style=display:flex><span>.<span style=color:#2b91af>tabs</span> a {
94</span></span><span style=display:flex><span> <span style=color:#00f>margin-bottom</span>: 2<span style=color:#2b91af>em</span>;
95</span></span><span style=display:flex><span> <span style=color:#00f>display</span>: <span style=color:#00f>inline-block</span>;
96</span></span><span style=display:flex><span> <span style=color:#00f>margin-right</span>: 1<span style=color:#2b91af>em</span>;
97</span></span><span style=display:flex><span>}
98</span></span><span style=display:flex><span>
99</span></span><span style=display:flex><span>.<span style=color:#2b91af>tabs</span> td a:only-child {
100</span></span><span style=display:flex><span> <span style=color:#00f>display</span>: <span style=color:#00f>none</span>;
101</span></span><span style=display:flex><span>}
102</span></span><span style=display:flex><span>
103</span></span><span style=display:flex><span><span style=color:green>/* HIDING ELEMENTS */</span>
104</span></span><span style=display:flex><span>
105</span></span><span style=display:flex><span>.<span style=color:#2b91af>cgit-panel</span>, .<span style=color:#2b91af>form</span> {
106</span></span><span style=display:flex><span> <span style=color:#00f>display</span>: <span style=color:#00f>none</span>;
107</span></span><span style=display:flex><span>}
108</span></span><span style=display:flex><span>
109</span></span><span style=display:flex><span><span style=color:green>/* LISTS */</span>
110</span></span><span style=display:flex><span>
111</span></span><span style=display:flex><span>.<span style=color:#2b91af>list</span> td, .<span style=color:#2b91af>list</span> th {
112</span></span><span style=display:flex><span> <span style=color:#00f>padding-right</span>: 2<span style=color:#2b91af>em</span>;
113</span></span><span style=display:flex><span>}
114</span></span><span style=display:flex><span>
115</span></span><span style=display:flex><span>.<span style=color:#2b91af>list</span> .<span style=color:#2b91af>nohover</span> a {
116</span></span><span style=display:flex><span> <span style=color:#00f>color</span>: <span style=color:#00f>black</span>;
117</span></span><span style=display:flex><span>}
118</span></span><span style=display:flex><span>
119</span></span><span style=display:flex><span>.<span style=color:#2b91af>list</span> .<span style=color:#2b91af>button</span> {
120</span></span><span style=display:flex><span> <span style=color:#00f>padding-right</span>: 0.5<span style=color:#2b91af>em</span>;
121</span></span><span style=display:flex><span>}
122</span></span><span style=display:flex><span>
123</span></span><span style=display:flex><span><span style=color:green>/* COMMIT */</span>
124</span></span><span style=display:flex><span>
125</span></span><span style=display:flex><span>.<span style=color:#2b91af>commit-subject</span> {
126</span></span><span style=display:flex><span> <span style=color:#00f>padding</span>: 1<span style=color:#2b91af>em</span> 0;
127</span></span><span style=display:flex><span>}
128</span></span><span style=display:flex><span>
129</span></span><span style=display:flex><span>.<span style=color:#2b91af>decoration</span> a {
130</span></span><span style=display:flex><span> <span style=color:#00f>padding-left</span>: 0.5<span style=color:#2b91af>em</span>;
131</span></span><span style=display:flex><span>}
132</span></span><span style=display:flex><span>
133</span></span><span style=display:flex><span>.<span style=color:#2b91af>commit-info</span> th {
134</span></span><span style=display:flex><span> <span style=color:#00f>padding-right</span>: 1<span style=color:#2b91af>em</span>;
135</span></span><span style=display:flex><span>}
136</span></span><span style=display:flex><span>
137</span></span><span style=display:flex><span>.<span style=color:#2b91af>commit-subject</span> {
138</span></span><span style=display:flex><span> <span style=color:#00f>padding</span>: 2<span style=color:#2b91af>em</span> 0;
139</span></span><span style=display:flex><span>}
140</span></span><span style=display:flex><span>
141</span></span><span style=display:flex><span>table.<span style=color:#2b91af>diff</span> div.<span style=color:#2b91af>head</span> {
142</span></span><span style=display:flex><span> <span style=color:#00f>padding-top</span>: 2<span style=color:#2b91af>em</span>;
143</span></span><span style=display:flex><span>}
144</span></span><span style=display:flex><span>
145</span></span><span style=display:flex><span>table.<span style=color:#2b91af>diffstat</span> td {
146</span></span><span style=display:flex><span> <span style=color:#00f>padding-right</span>: 1<span style=color:#2b91af>em</span>;
147</span></span><span style=display:flex><span>}
148</span></span><span style=display:flex><span>
149</span></span><span style=display:flex><span><span style=color:green>/* CONTENT */</span>
150</span></span><span style=display:flex><span>
151</span></span><span style=display:flex><span>.<span style=color:#2b91af>linenumbers</span> {
152</span></span><span style=display:flex><span> <span style=color:#00f>padding-right</span>: 0.5<span style=color:#2b91af>em</span>;
153</span></span><span style=display:flex><span>}
154</span></span><span style=display:flex><span>
155</span></span><span style=display:flex><span>.<span style=color:#2b91af>linenumbers</span> a {
156</span></span><span style=display:flex><span> <span style=color:#00f>color</span>: <span style=color:#00f>gray</span>;
157</span></span><span style=display:flex><span>}
158</span></span><span style=display:flex><span>
159</span></span><span style=display:flex><span>.<span style=color:#2b91af>pager</span> {
160</span></span><span style=display:flex><span> <span style=color:#00f>display</span>: <span style=color:#00f>flex</span>;
161</span></span><span style=display:flex><span> <span style=color:#00f>list-style-type</span>: <span style=color:#00f>none</span>;
162</span></span><span style=display:flex><span> <span style=color:#00f>padding</span>: 0;
163</span></span><span style=display:flex><span> gap: 0.5<span style=color:#2b91af>em</span>;
164</span></span><span style=display:flex><span>}
165</span></span><span style=display:flex><span>
166</span></span><span style=display:flex><span><span style=color:green>/* DIFF COLORS */</span>
167</span></span><span style=display:flex><span>
168</span></span><span style=display:flex><span>table.<span style=color:#2b91af>diff</span> {
169</span></span><span style=display:flex><span> <span style=color:#00f>width</span>: 100<span style=color:#2b91af>%</span>;
170</span></span><span style=display:flex><span>}
171</span></span><span style=display:flex><span>
172</span></span><span style=display:flex><span>table.<span style=color:#2b91af>diff</span> td {
173</span></span><span style=display:flex><span> <span style=color:#00f>white-space</span>: <span style=color:#00f>pre</span>;
174</span></span><span style=display:flex><span>}
175</span></span><span style=display:flex><span>
176</span></span><span style=display:flex><span>table.<span style=color:#2b91af>diff</span> td div.<span style=color:#2b91af>head</span> {
177</span></span><span style=display:flex><span> <span style=color:#00f>font-weight</span>: <span style=color:#00f>bold</span>;
178</span></span><span style=display:flex><span> <span style=color:#00f>margin-top</span>: 1<span style=color:#2b91af>em</span>;
179</span></span><span style=display:flex><span> <span style=color:#00f>color</span>: <span style=color:#00f>black</span>;
180</span></span><span style=display:flex><span>}
181</span></span><span style=display:flex><span>
182</span></span><span style=display:flex><span>table.<span style=color:#2b91af>diff</span> td div.<span style=color:#2b91af>hunk</span> {
183</span></span><span style=display:flex><span> <span style=color:#00f>color</span>: #009;
184</span></span><span style=display:flex><span>}
185</span></span><span style=display:flex><span>
186</span></span><span style=display:flex><span>table.<span style=color:#2b91af>diff</span> td div.<span style=color:#2b91af>add</span> {
187</span></span><span style=display:flex><span> <span style=color:#00f>color</span>: <span style=color:#00f>green</span>;
188</span></span><span style=display:flex><span>}
189</span></span><span style=display:flex><span>
190</span></span><span style=display:flex><span>table.<span style=color:#2b91af>diff</span> td div.<span style=color:#2b91af>del</span> {
191</span></span><span style=display:flex><span> <span style=color:#00f>color</span>: <span style=color:#00f>red</span>;
192</span></span><span style=display:flex><span>}
193</span></span></code></pre></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
194a lock on a Linux NFS server, which turned
195out to be specific to NFS v3 (which I really should have seen coming,
196since it involved NLM and lockd). Finding the NFS v4 client that
197owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
198and Bradley Kuhn, are interacting on the OSI's license-discuss
199list where the're doing
200bad computer history and insisting that a guy Larry Rosen
201coincidentally interviewed for a book years ago is clearly the origin of
202somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
203i2c, plan9
204Another month, another file system.
205Well, if you can’t fix it in software, fix it in hardware (looking at
206you, bme680, we’re not
207done yet). The show must go on, as they say, and I would like my
208experiments to go on.
209So a “new” addition to the environmental sensor family connected to
210the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
211this mortal coil, we are endowed with self-awareness, agency, and free will.
212Each of the 8 billion members of this human race represents a unique person, a
213unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
214My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
2151.0 has been released:
216wifi_da-1.0.sit
217(StuffIt 3 archive)
218SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
219This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
220classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
221In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
222Design Goals
223I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
224at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
225catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
226specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
227 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
228 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/mass-set-permission.html b/public/mass-set-permission.html
deleted file mode 100755
index 774b36b..0000000
--- a/public/mass-set-permission.html
+++ /dev/null
@@ -1,46 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Change permissions of matching files recursively</title><meta name=description content="Replace *."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Change permissions of matching files recursively</h1><p><cap>note</cap>, May 16, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>Replace <code>*.xml</code> with your pattern. This will remove executable bit from all
10files matching the pattern. Change <code>+</code> to <code>-</code> to add executable bit.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>find . -type f -name <span style=color:#a31515>&#34;*.xml&#34;</span> -exec chmod -x {} +
11</span></span></code></pre></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
12a lock on a Linux NFS server, which turned
13out to be specific to NFS v3 (which I really should have seen coming,
14since it involved NLM and lockd). Finding the NFS v4 client that
15owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
16and Bradley Kuhn, are interacting on the OSI's license-discuss
17list where the're doing
18bad computer history and insisting that a guy Larry Rosen
19coincidentally interviewed for a book years ago is clearly the origin of
20somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
21i2c, plan9
22Another month, another file system.
23Well, if you can’t fix it in software, fix it in hardware (looking at
24you, bme680, we’re not
25done yet). The show must go on, as they say, and I would like my
26experiments to go on.
27So a “new” addition to the environmental sensor family connected to
28the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
29this mortal coil, we are endowed with self-awareness, agency, and free will.
30Each of the 8 billion members of this human race represents a unique person, a
31unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
32My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
331.0 has been released:
34wifi_da-1.0.sit
35(StuffIt 3 archive)
36SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
37This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
38classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
39In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
40Design Goals
41I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
42at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
43catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
44specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
45 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
46 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/most-likely-to-succeed-in-year-of-2011.html b/public/most-likely-to-succeed-in-year-of-2011.html
deleted file mode 100755
index 9b8649a..0000000
--- a/public/most-likely-to-succeed-in-year-of-2011.html
+++ /dev/null
@@ -1,60 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Most likely to succeed in the year of 2011</title><meta name=description content="The year of 2010 was definitely the year of Geo-location."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Most likely to succeed in the year of 2011</h1><p><cap>post</cap>, Jan 13, 2011 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>The year of 2010 was definitely the year of Geo-location. The market responded
10beautifully and lots of very cool services were launched. We all have to thank
11the mobile market for such extensive adoption. With new generations of mobile
12phones that are not only buffed with high-tech hardware but are also affordable.
13We can now manage tasks that were not so long time ago, almost Star Trek’ish.
14And all this had and has great influence on the destination to which we are
15going now.<p>Reading all this articles about new innovation about new thriving technologies
16makes me wonder what’s the next step. The future is the mesh, like Lisa Gansky
17said in her book The Mesh.<p>Many still have conservative views on distributed systems. The problems with
18security of information. Fear of not controlling every aspect of information
19flow. I am very opened to distributed systems and heterogeneous applications,
20and I think this is the correct and best way to proceed.<p>This year will definitely be about communication platforms. Mobile to mobile.
21Machine to mobile and vice versa. All the tech is available and ready to put
22into action. Wireless is today’s new mantra. And the concept of semantic web is
23now ready for industry.<p>Applications and developers now can gain access to new layers of systems and can
24prepare and build solutions to meet the high quality needs of market. The speed
25is everything now.<p>My vote goes to “Machine to Machine” and “Embedded Systems”!<ul><li><a href=http://en.wikipedia.org/wiki/Machine-to-Machine>Machine-to-Machine</a><li><a href=http://www.bitxml.org/>The ultimate M2M communication protocol</a><li><a href=http://www.coosproject.org/maven-site/1.0.0/project-info.html>COOS Project (connectivity initiative)</a><li><a href=http://m2m.com/index.jspa>Community for machine-to-machine</a><li><a href=http://en.wikipedia.org/wiki/Embedded_system>Embedded system</a></ul></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
26a lock on a Linux NFS server, which turned
27out to be specific to NFS v3 (which I really should have seen coming,
28since it involved NLM and lockd). Finding the NFS v4 client that
29owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
30and Bradley Kuhn, are interacting on the OSI's license-discuss
31list where the're doing
32bad computer history and insisting that a guy Larry Rosen
33coincidentally interviewed for a book years ago is clearly the origin of
34somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
35i2c, plan9
36Another month, another file system.
37Well, if you can’t fix it in software, fix it in hardware (looking at
38you, bme680, we’re not
39done yet). The show must go on, as they say, and I would like my
40experiments to go on.
41So a “new” addition to the environmental sensor family connected to
42the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
43this mortal coil, we are endowed with self-awareness, agency, and free will.
44Each of the 8 billion members of this human race represents a unique person, a
45unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
46My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
471.0 has been released:
48wifi_da-1.0.sit
49(StuffIt 3 archive)
50SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
51This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
52classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
53In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
54Design Goals
55I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
56at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
57catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
58specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
59 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
60 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/mount-plan9-over-network.html b/public/mount-plan9-over-network.html
deleted file mode 100755
index ddd2960..0000000
--- a/public/mount-plan9-over-network.html
+++ /dev/null
@@ -1,51 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Mount Plan9 over network</title><meta name=description content="First install libfuse with sudo apt install libfuse-dev."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Mount Plan9 over network</h1><p><cap>note</cap>, May 7, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><ul><li>First install libfuse with sudo apt install libfuse-dev.<li>Then clone <a href=https://github.com/ftrvxmtrx/9pfs>https://github.com/ftrvxmtrx/9pfs</a> and compile it with make.<li>Copy 9pfs to your path.</ul><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># On Plan9 side</span>
10</span></span><span style=display:flex><span>ip/ipconfig <span style=color:green># enables network</span>
11</span></span><span style=display:flex><span>aux/listen1 -tv tcp!*!9999 /bin/exportfs -r tmp <span style=color:green># export tmp folder</span>
12</span></span><span style=display:flex><span>
13</span></span><span style=display:flex><span><span style=color:green># On Linux side</span>
14</span></span><span style=display:flex><span>9pfs 172.18.0.1 -p 9999 local_folder <span style=color:green># mount</span>
15</span></span><span style=display:flex><span>umount local_folder <span style=color:green># unmount</span>
16</span></span></code></pre></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
17a lock on a Linux NFS server, which turned
18out to be specific to NFS v3 (which I really should have seen coming,
19since it involved NLM and lockd). Finding the NFS v4 client that
20owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
21and Bradley Kuhn, are interacting on the OSI's license-discuss
22list where the're doing
23bad computer history and insisting that a guy Larry Rosen
24coincidentally interviewed for a book years ago is clearly the origin of
25somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
26i2c, plan9
27Another month, another file system.
28Well, if you can’t fix it in software, fix it in hardware (looking at
29you, bme680, we’re not
30done yet). The show must go on, as they say, and I would like my
31experiments to go on.
32So a “new” addition to the environmental sensor family connected to
33the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
34this mortal coil, we are endowed with self-awareness, agency, and free will.
35Each of the 8 billion members of this human race represents a unique person, a
36unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
37My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
381.0 has been released:
39wifi_da-1.0.sit
40(StuffIt 3 archive)
41SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
42This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
43classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
44In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
45Design Goals
46I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
47at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
48catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
49specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
50 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
51 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/my-love-and-hate-relationship-with-nodejs.html b/public/my-love-and-hate-relationship-with-nodejs.html
deleted file mode 100755
index c22bad6..0000000
--- a/public/my-love-and-hate-relationship-with-nodejs.html
+++ /dev/null
@@ -1,110 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>My love and hate relationship with Node.js</title><meta name=description content="Previous project I was working on was being coded inGolang."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>My love and hate relationship with Node.js</h1><p><cap>post</cap>, Mar 30, 2020 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>Previous project I was working on was being coded in
10<a href=https://golang.org/>Golang</a>. Also was my first project using it. And damn,
11that was an awesome experience. The whole thing is just superb. From how errors
12are handled. The C-like way you handle compiling. The way the language is
13structured making it incredibly versatile and easy to learn.<p>It may cause some pain for somebody that is not used of using interfaces to map
14JSON and doing the recompilation all the time. But we have tools like
15<a href=http://eradman.com/entrproject/>entr</a> and
16<a href=https://www.gnu.org/software/make/>make</a> to fix that.<p>But we are not here to talk about my undying love for <strong>Golang</strong>. Only in some
17way we probably should. It is an excellent example of how modern language should
18be designed. And because I have used it extensively in the last couple of years
19this probably taints my views of other languages. And is doing me a great
20disservice. Nevertheless, here we are.<p>About two years ago I started flirting with <a href=https://nodejs.org/en/>Node.js</a>
21for a project I started working on. What I wanted was to have things written in
22a language that is widely used, and we could get additional developers for. As
23much as <strong>Golang</strong> is amazing it's really hard to get developers for it. Even
24now. And after playing around with it for a week I felt in love with the speed
25of iteration and massive package ecosystem. Do you want SSO? You got it! Do you
26want some esoteric library for something? There is a strong chance somebody
27wrote it. It is so extensive that you find yourself evaluating packages based on
28<strong>GitHub stars</strong> and number of contributors. You get swallowed by the vanity
29metrics and that potentially will become the downfall of Node.js.<p>Because of the sheer amount of choice I often got anxiety when choosing
30libraries. Will I choose the correct one? Is this library something that will be
31supported for a foreseeable future or not? I am used of using libraries that are
32being in development for 10 years plus (Python, C) and that gave me some sort of
33comfort. And it is probably unfair to Node.js and community to expect same
34dedication.<p>Moving forward ... Work started and things were great. <strong>Speed of iteration was
35insane</strong>. For some feature that I would need a day in Golang only took me hour
36or two. I became lazy! Using packages all over the place. Falling into the same
37trap as others. Packages on top of packages. And <a href=https://www.npmjs.com/>npm</a>
38didn't help at all. The way that the package manager works is just
39horrendous. And not allowing to have node_modules outside the project is also
40the stupidest idea ever.<p>So at that point I started feeling the technical debt that comes with Node.js
41and the whole ecosystem. What nobody tells you is that <strong>structuring large
42Node.js apps</strong> is more problematic than one would think. And going microservice
43for every single thing is also a bad idea. The amount of networking you
44introduce with that approach always ends up being a pain in the ass. And I don't
45even want to go into system administration here. The overhead is
46insane. Package-lock.json made many days feel like living hell for me. And I
47would eat the cost of all this if it meant for better development
48experience. Well, it didn't.<p>The <strong>lack of Typescript</strong> support in the interpreter is still mind boggling to
49me. Why haven't they added native support yet for this is beyond me?! That would
50have solved so many problems. Lack of type safety became a problem somewhere in
51the middle of the project where the codebase was sufficiently large enough to
52present problems. We started adding arguments to functions and there was <strong>no
53way to implicitly define argument types</strong>. And because at that point there were
54a lot of functions, it became impossible to know what each one accepts,
55development became more and more trial and error based.<p>I tried <strong>implementing Typescript</strong>, but that would present a large refactor
56that we were not willing to do at that point. The benefits were not enough. I
57also tried <a href=https://flow.org/>Flow - static type checker</a> but implementation
58was also horrible. What Typescript and Flow forces you is to have src folder and
59then <strong>transpile</strong> your code into dist folder and run it with node. WTH is that
60all about. Why can't this be done in memory or some virtual file system? Why? I
61see no reason why this couldn't be done like this. But it is what it is. I
62abandoned all hope for static type checking.<p>One of the problems that resulted from not having interfaces or types was
63inability to model out our data from <strong>Elasticsearch</strong>. I could have done a
64<strong>pedestrian implementation</strong> of it, but there must be a better way of doing
65this without resorting to some hack basically. Or maybe I haven't found a
66solution, which is also a possibility. I have looked, though. No juice!<p><strong>Error handling?</strong> Is that a joke?<p>Thank god for <strong>await/async</strong>. Without it, I would have probably just abandoned
67the whole thing and went with something else like Python. That's all I am going
68to say about this :)<p>I started asking myself a question if Node.js is actually ready to be used in a
69<strong>large scale applications</strong>? And this was a totally wrong question. What I
70should have been asking myself was, how to use Node.js in large scale
71application. And you don't get this in <strong>marketing material</strong> for Express or Koa
72etc. They never tell you this. Making Node.js scale on infrastructure or in
73codebase is really <strong>more of an art than a science</strong>. And just like with the
74whole JavaScript ecosystem:<ul><li>impossible to master,<li>half of your time you work on your tooling,<li>just accept transpilers that convert one code into another (holly smokes),<li>error handling is a joke,<li>standards? What standards?</ul><p>But on the other hand. As I did, you will also learn to love it. Learn to use it
75quickly and do impossible things in crazy limited time.<p>I hate to admit it. But I love Node.js. Dammit, I love it :)<p><strong>2023 Update</strong>: I hate Node.js!</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
76a lock on a Linux NFS server, which turned
77out to be specific to NFS v3 (which I really should have seen coming,
78since it involved NLM and lockd). Finding the NFS v4 client that
79owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
80and Bradley Kuhn, are interacting on the OSI's license-discuss
81list where the're doing
82bad computer history and insisting that a guy Larry Rosen
83coincidentally interviewed for a book years ago is clearly the origin of
84somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
85i2c, plan9
86Another month, another file system.
87Well, if you can’t fix it in software, fix it in hardware (looking at
88you, bme680, we’re not
89done yet). The show must go on, as they say, and I would like my
90experiments to go on.
91So a “new” addition to the environmental sensor family connected to
92the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
93this mortal coil, we are endowed with self-awareness, agency, and free will.
94Each of the 8 billion members of this human race represents a unique person, a
95unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
96My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
971.0 has been released:
98wifi_da-1.0.sit
99(StuffIt 3 archive)
100SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
101This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
102classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
103In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
104Design Goals
105I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
106at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
107catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
108specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
109 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
110 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/non-blocking-shell-exec-csharp.html b/public/non-blocking-shell-exec-csharp.html
deleted file mode 100755
index a580997..0000000
--- a/public/non-blocking-shell-exec-csharp.html
+++ /dev/null
@@ -1,69 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Execute not blocking async shell command in C#</title><meta name=description content="Execute a shell command in async in C# while not blocking the UI thread."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Execute not blocking async shell command in C#</h1><p><cap>note</cap>, May 22, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>Execute a shell command in async in C# while not blocking the UI thread.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>private</span> <span style=color:#00f>async</span> Task executeCopyCommand()
10</span></span><span style=display:flex><span>{
11</span></span><span style=display:flex><span> <span style=color:#00f>await</span> Task.Run(() =&gt;
12</span></span><span style=display:flex><span> {
13</span></span><span style=display:flex><span> <span style=color:#2b91af>var</span> processStartInfo = <span style=color:#00f>new</span> ProcessStartInfo(<span style=color:#a31515>&#34;cmd&#34;</span>, <span style=color:#a31515>&#34;/c dir&#34;</span>)
14</span></span><span style=display:flex><span> {
15</span></span><span style=display:flex><span> RedirectStandardOutput = <span style=color:#00f>true</span>,
16</span></span><span style=display:flex><span> UseShellExecute = <span style=color:#00f>false</span>,
17</span></span><span style=display:flex><span> CreateNoWindow = <span style=color:#00f>true</span>
18</span></span><span style=display:flex><span> };
19</span></span><span style=display:flex><span>
20</span></span><span style=display:flex><span> <span style=color:#2b91af>var</span> process = <span style=color:#00f>new</span> Process
21</span></span><span style=display:flex><span> {
22</span></span><span style=display:flex><span> StartInfo = processStartInfo
23</span></span><span style=display:flex><span> };
24</span></span><span style=display:flex><span>
25</span></span><span style=display:flex><span> process.Start();
26</span></span><span style=display:flex><span> process.WaitForExit();
27</span></span><span style=display:flex><span> });
28</span></span><span style=display:flex><span>}
29</span></span></code></pre><p>Make sure that <code>async</code> is present in the function definition and <code>await</code> is used
30in the method that calls <code>executeCopyCommand()</code>.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>private</span> <span style=color:#00f>async</span> <span style=color:#00f>void</span> button_Click(<span style=color:#2b91af>object</span> sender, EventArgs e)
31</span></span><span style=display:flex><span>{
32</span></span><span style=display:flex><span> <span style=color:#00f>await</span> executeCopyCommand();
33</span></span><span style=display:flex><span>}
34</span></span></code></pre></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
35a lock on a Linux NFS server, which turned
36out to be specific to NFS v3 (which I really should have seen coming,
37since it involved NLM and lockd). Finding the NFS v4 client that
38owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
39and Bradley Kuhn, are interacting on the OSI's license-discuss
40list where the're doing
41bad computer history and insisting that a guy Larry Rosen
42coincidentally interviewed for a book years ago is clearly the origin of
43somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
44i2c, plan9
45Another month, another file system.
46Well, if you can’t fix it in software, fix it in hardware (looking at
47you, bme680, we’re not
48done yet). The show must go on, as they say, and I would like my
49experiments to go on.
50So a “new” addition to the environmental sensor family connected to
51the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
52this mortal coil, we are endowed with self-awareness, agency, and free will.
53Each of the 8 billion members of this human race represents a unique person, a
54unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
55My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
561.0 has been released:
57wifi_da-1.0.sit
58(StuffIt 3 archive)
59SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
60This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
61classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
62In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
63Design Goals
64I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
65at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
66catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
67specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
68 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
69 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/notes.xml b/public/notes.xml
deleted file mode 100755
index 89e9881..0000000
--- a/public/notes.xml
+++ /dev/null
@@ -1,1569 +0,0 @@
1<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
2 <channel>
3 <title>Mitja Felicijan's notes</title>
4 <link>https://mitjafelicijan.com</link>
5 <description>You do not learn by relaxing. You learn by violently assaulting your problem until it surrenders its mysteries to you.</description>
6 <language>en-us</language>
7
8
9
10 <item>
11 <title>Compile drawterm on Fedora 38</title>
12 <link>https://mitjafelicijan.com/compile-drawterm-on-fedora-38.html</link>
13 <pubDate>Mon, 25 Sep 2023 09:04:28 &#43;0200</pubDate>
14 <guid>https://mitjafelicijan.com/compile-drawterm-on-fedora-38.html</guid>
15 <description>First install two dependencies:sudo dnf install libX11-devel libXt-develClone the repo and compile it:git clone git://git.</description>
16 <content:encoded>&lt;p&gt;First install two dependencies:&lt;/p&gt;
17&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo dnf install libX11-devel libXt-devel
18&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Clone the repo and compile it:&lt;/p&gt;
19&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git clone git://git.9front.org/plan9front/drawterm
20&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd drawterm
21&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CONF=unix make
22&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;That should produce &lt;code&gt;drawterm&lt;/code&gt; binary.&lt;/p&gt;
23</content:encoded>
24 </item>
25
26
27
28 <item>
29 <title>AWS EB PyYAML fix</title>
30 <link>https://mitjafelicijan.com/aws-eb-pyyaml-fix.html</link>
31 <pubDate>Mon, 18 Sep 2023 07:27:29 &#43;0200</pubDate>
32 <guid>https://mitjafelicijan.com/aws-eb-pyyaml-fix.html</guid>
33 <description>Recent update of my system completely borked EB CLIon my machine.</description>
34 <content:encoded>&lt;p&gt;Recent update of my system completely borked &lt;a href=&#34;https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/eb-cli3-install-advanced.html&#34;&gt;EB CLI&lt;/a&gt;
35on my machine.&lt;/p&gt;
36&lt;p&gt;I tried installing it with &lt;code&gt;pip install awsebcli --upgrade --user&lt;/code&gt; and it failed.&lt;/p&gt;
37&lt;p&gt;The error was the following.&lt;/p&gt;
38&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Collecting PyYAML&amp;lt;6.1,&amp;gt;=5.3.1 (from awsebcli)
39&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; Using cached PyYAML-5.4.1.tar.gz (175 kB)
40&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; Installing build dependencies ... done
41&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; Getting requirements to build wheel ... error
42&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; error: subprocess-exited-with-error
43&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
44&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; × Getting requirements to build wheel did not run successfully.
45&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; │ exit code: 1
46&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ╰─&amp;gt; [68 lines of output]
47&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To fix this issue with PyYAML you must install PyYAML separately.&lt;/p&gt;
48&lt;p&gt;Do the following and try installing &lt;code&gt;eb&lt;/code&gt; again after.&lt;/p&gt;
49&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;Cython &amp;lt; 3.0&amp;#39;&lt;/span&gt; &amp;gt; /tmp/constraint.txt
50&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;PIP_CONSTRAINT=/tmp/constraint.txt pip install &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;PyYAML==5.4.1&amp;#39;&lt;/span&gt;
51&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded>
52 </item>
53
54
55
56 <item>
57 <title>Floods in Slovenia up close</title>
58 <link>https://mitjafelicijan.com/floods-in-slovenia.html</link>
59 <pubDate>Sat, 05 Aug 2023 07:06:50 &#43;0200</pubDate>
60 <guid>https://mitjafelicijan.com/floods-in-slovenia.html</guid>
61 <description></description>
62 <content:encoded>&lt;p&gt;&lt;video src=&#34;/notes/floods/IMG_1471.mp4&#34; controls&gt;&lt;/video&gt;&lt;/p&gt;
63&lt;p&gt;&lt;video src=&#34;/notes/floods/IMG_1474.mp4&#34; controls&gt;&lt;/video&gt;&lt;/p&gt;
64&lt;figure&gt;
65&lt;img src=&#34;/notes/floods/IMG_1469.webp&#34; alt=&#34;&#34; /&gt;
66&lt;/figure&gt;
67&lt;figure&gt;
68&lt;img src=&#34;/notes/floods/IMG_1470.webp&#34; alt=&#34;&#34; /&gt;
69&lt;/figure&gt;
70&lt;p&gt;&lt;video src=&#34;/notes/floods/IMG_1461.mp4&#34; controls&gt;&lt;/video&gt;&lt;/p&gt;
71&lt;p&gt;&lt;video src=&#34;/notes/floods/IMG_1466.mp4&#34; controls&gt;&lt;/video&gt;&lt;/p&gt;
72</content:encoded>
73 </item>
74
75
76
77 <item>
78 <title>Make B/W SVG charts with matplotlib</title>
79 <link>https://mitjafelicijan.com/make-b-w-svg-charts-with-matplotlib.html</link>
80 <pubDate>Tue, 01 Aug 2023 17:04:10 &#43;0200</pubDate>
81 <guid>https://mitjafelicijan.com/make-b-w-svg-charts-with-matplotlib.html</guid>
82 <description>Install pip requirements.</description>
83 <content:encoded>&lt;p&gt;Install pip requirements.&lt;/p&gt;
84&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pip install matplotlib
85&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;pip install pandas
86&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Example of data being used.&lt;/p&gt;
87&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Epoch,Connect (NLB),Processing (NLB),Waiting (NLB),Total (NLB),Connect (ALB),Processing (ALB),Waiting (ALB),Total (ALB)
88&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;1,57.7,315.7,309.4,321.6,9,104.4,98.3,105.7
89&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;2,121.9,114.4,100.3,176.9,5.8,99.1,97.1,101.1
90&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;3,5.3,229.4,231.2,231.4,14.2,83,69.4,87.9
91&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;4,4.2,134.5,112.2,135.3,5.3,132.4,105.5,134.1
92&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;5,5.8,247.4,246.8,248.1,6,74.3,70.2,75.5
93&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;6,9.9,122.9,100.6,122.7,7.5,241.1,79.3,242.3
94&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;7,6.1,170.2,106.4,170.5,7.2,382.4,375.1,383.8
95&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;8,6.6,194.3,201.4,195.5,7.1,130.9,104.8,132.6
96&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9,6.4,146.1,122.3,147.7,9.4,95.6,74,96.4
97&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;In the code you can use &lt;code&gt;df&lt;/code&gt; as dataframes and use the headers like &lt;code&gt;df[&amp;quot;Epoch&amp;quot;]&lt;/code&gt;.
98This is how you get a column data with pandas.&lt;/p&gt;
99&lt;p&gt;The Python code responsible for generating a chart:&lt;/p&gt;
100&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; csv
101&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; sys
102&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
103&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; matplotlib.pyplot &lt;span style=&#34;color:#00f&#34;&gt;as&lt;/span&gt; plt
104&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; pandas &lt;span style=&#34;color:#00f&#34;&gt;as&lt;/span&gt; pd
105&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
106&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# Read the data&lt;/span&gt;
107&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;df = pd.read_csv(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;data.csv&amp;#34;&lt;/span&gt;)
108&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
109&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# Settings&lt;/span&gt;
110&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;plt.title(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Connect median NLB vs ALB&amp;#34;&lt;/span&gt;)
111&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;plt.tight_layout(pad=2)
112&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fig = plt.gcf()
113&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;fig.set_size_inches(10, 4)
114&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
115&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# Plotting&lt;/span&gt;
116&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;plt.plot(df[&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Epoch&amp;#34;&lt;/span&gt;], df[&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Connect (ALB)&amp;#34;&lt;/span&gt;], label = &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;ALB&amp;#34;&lt;/span&gt;, color=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;black&amp;#34;&lt;/span&gt;, linestyle=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;-&amp;#34;&lt;/span&gt;)
117&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;plt.plot(df[&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Epoch&amp;#34;&lt;/span&gt;], df[&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Connect (NLB)&amp;#34;&lt;/span&gt;], label = &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;NLB&amp;#34;&lt;/span&gt;, color=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;black&amp;#34;&lt;/span&gt;, linestyle=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;--&amp;#34;&lt;/span&gt;)
118&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
119&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# Adding x and y axis labels&lt;/span&gt;
120&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;plt.xlabel(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Epoch&amp;#34;&lt;/span&gt;, fontstyle=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;italic&amp;#34;&lt;/span&gt;)
121&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;plt.ylabel(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Median value (ms)&amp;#34;&lt;/span&gt;, fontstyle=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;italic&amp;#34;&lt;/span&gt;)
122&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
123&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# Legend&lt;/span&gt;
124&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;legend = plt.legend()
125&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;legend.get_frame().set_linewidth(0)
126&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
127&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# Export as SVG&lt;/span&gt;
128&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;plt.savefig(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;plot.svg&amp;#34;&lt;/span&gt;, format=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;svg&amp;#34;&lt;/span&gt;)
129&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;figure&gt;
130&lt;img src=&#34;/notes/plot.svg&#34; alt=&#34;SVG Chart&#34; /&gt;
131&lt;/figure&gt;
132&lt;p&gt;The image above is SVG and you can zoom in and out and check that the image is vector.&lt;/p&gt;
133</content:encoded>
134 </item>
135
136
137
138 <item>
139 <title>Set color temperature of displays on i3</title>
140 <link>https://mitjafelicijan.com/set-color-temperature-of-displays-on-i3.html</link>
141 <pubDate>Fri, 14 Jul 2023 09:19:31 &#43;0200</pubDate>
142 <guid>https://mitjafelicijan.com/set-color-temperature-of-displays-on-i3.html</guid>
143 <description>I have been using Gnome&amp;#39;s night shift for a while now and I have been missingthis feature under i3wm.</description>
144 <content:encoded>&lt;p&gt;I have been using Gnome&#39;s night shift for a while now and I have been missing
145this feature under i3wm. This can be done with
146&lt;a href=&#34;https://linux.die.net/man/1/redshift&#34;&gt;redshift&lt;/a&gt;.&lt;/p&gt;
147&lt;ul&gt;
148&lt;li&gt;On Debian install with &lt;code&gt;sudo apt install redshift&lt;/code&gt;&lt;/li&gt;
149&lt;li&gt;And then manually set it with &lt;code&gt;redshift -O 3000&lt;/code&gt;&lt;/li&gt;
150&lt;li&gt;Reset the current settings with &lt;code&gt;redshift -x&lt;/code&gt;&lt;/li&gt;
151&lt;/ul&gt;
152</content:encoded>
153 </item>
154
155
156
157 <item>
158 <title>Fix screen tearing on Debian 12 Xorg and i3</title>
159 <link>https://mitjafelicijan.com/fix-screen-tearing-on-debian-12-xorg-and-i3.html</link>
160 <pubDate>Mon, 10 Jul 2023 04:21:48 &#43;0200</pubDate>
161 <guid>https://mitjafelicijan.com/fix-screen-tearing-on-debian-12-xorg-and-i3.html</guid>
162 <description>I have been experiencing some issues with Intel® Integrated HD Graphics 3000under Debian 12 with Xorg and i3.</description>
163 <content:encoded>&lt;p&gt;I have been experiencing some issues with Intel® Integrated HD Graphics 3000
164under Debian 12 with Xorg and i3. Using &lt;code&gt;picom&lt;/code&gt; compositor didn&#39;t help. To fix
165this issue create new file &lt;code&gt;/etc/X11/xorg.conf.d/20-intel.conf&lt;/code&gt; as root and put
166the following in the file.&lt;/p&gt;
167&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Section &amp;#34;Device&amp;#34;
168&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; Identifier &amp;#34;Intel Graphics&amp;#34;
169&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; Driver &amp;#34;intel&amp;#34;
170&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; Option &amp;#34;TearFree&amp;#34; &amp;#34;true&amp;#34;
171&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;EndSection
172&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Reboot the system and that should be it.&lt;/p&gt;
173</content:encoded>
174 </item>
175
176
177
178 <item>
179 <title>Online radio streaming with MPV from terminal</title>
180 <link>https://mitjafelicijan.com/online-radio-streaming-with-mpv-from-terminal.html</link>
181 <pubDate>Mon, 10 Jul 2023 03:34:45 &#43;0200</pubDate>
182 <guid>https://mitjafelicijan.com/online-radio-streaming-with-mpv-from-terminal.html</guid>
183 <description>Recently I have been using my Thinkpad x220 more and there are some constraintsI have faced with it.</description>
184 <content:encoded>&lt;p&gt;Recently I have been using my Thinkpad x220 more and there are some constraints
185I have faced with it. CPU is not as powerful as on my main machine and I really
186want to listen to some music while using the machine. Browsers really are bloat.&lt;/p&gt;
187&lt;p&gt;Check out this site &lt;a href=&#34;https://streamurl.link/&#34;&gt;https://streamurl.link/&lt;/a&gt; and copy the stream url and then do
188&lt;code&gt;mpv streamlink&lt;/code&gt;.&lt;/p&gt;
189</content:encoded>
190 </item>
191
192
193
194
195
196
197
198 <item>
199 <title>60&#39;s IBM Computers Commercial</title>
200 <link>https://mitjafelicijan.com/60s-ibm-computers-commercial.html</link>
201 <pubDate>Thu, 29 Jun 2023 22:13:45 &#43;0200</pubDate>
202 <guid>https://mitjafelicijan.com/60s-ibm-computers-commercial.html</guid>
203 <description>Likely aired during an hour-long program during the 1960s, long commercials suchas this typically aired during hour-long programs.</description>
204 <content:encoded>&lt;p&gt;Likely aired during an hour-long program during the 1960s, long commercials such
205as this typically aired during hour-long programs. They would &lt;em&gt;not&lt;/em&gt; have aired
206during a half-hour program.&lt;/p&gt;
207&lt;p&gt;&lt;video
208poster=&#34;/notes/60s-ibm-computers-commercial.jpg&#34;
209src=&#34;/notes/60s-ibm-computers-commercial.mp4&#34;
210controls&gt;&lt;/video&gt;&lt;/p&gt;
211</content:encoded>
212 </item>
213
214
215
216 <item>
217 <title>10/GUI 10 Finger Multitouch User Interface</title>
218 <link>https://mitjafelicijan.com/10gui-10-finger-multitouch-user-interface.html</link>
219 <pubDate>Thu, 29 Jun 2023 14:51:39 &#43;0200</pubDate>
220 <guid>https://mitjafelicijan.com/10gui-10-finger-multitouch-user-interface.html</guid>
221 <description>Message from 10/GUI team (page 10gui.</description>
222 <content:encoded>&lt;p&gt;Message from 10/GUI team (page 10gui.com does not exist anymore):&lt;/p&gt;
223&lt;p&gt;&lt;em&gt;Over a quarter-century ago, Xerox introduced the modern graphical user
224interface paradigm we today take for granted.&lt;/em&gt;&lt;/p&gt;
225&lt;p&gt;&lt;em&gt;That it has endured is a testament to the genius of its design. But the
226industry is now at a crossroads: New technologies promise higher-bandwidth
227interaction, but have yet to find a truly viable implementation.&lt;/em&gt;&lt;/p&gt;
228&lt;p&gt;&lt;em&gt;10/GUI aims to bridge this gap by rethinking the desktop to leverage technology
229in an intuitive and powerful way.&lt;/em&gt;&lt;/p&gt;
230&lt;p&gt;&lt;video
231poster=&#34;/notes/10gui-10-finger-multitouch-user-interface.jpg&#34;
232src=&#34;/notes/10gui-10-finger-multitouch-user-interface.mp4&#34;
233controls&gt;&lt;/video&gt;&lt;/p&gt;
234</content:encoded>
235 </item>
236
237
238
239 <item>
240 <title>Alacritty open links with modifier</title>
241 <link>https://mitjafelicijan.com/alacritty-open-links-with-modifier.html</link>
242 <pubDate>Sun, 25 Jun 2023 17:17:16 &#43;0200</pubDate>
243 <guid>https://mitjafelicijan.com/alacritty-open-links-with-modifier.html</guid>
244 <description>Alacritty by default makes all links in the terminal output clickable and thisgets annoying rather quickly.</description>
245 <content:encoded>&lt;p&gt;Alacritty by default makes all links in the terminal output clickable and this
246gets annoying rather quickly. I liked the default behavior of Gnome terminal
247where you needed to hold Control key and then you could click and open links.&lt;/p&gt;
248&lt;p&gt;To achieve this in Alacritty you need to provide a &lt;code&gt;hint&lt;/code&gt; in the configuration
249file. Config file is located at &lt;code&gt;~/.config/alacritty/alacritty.yml&lt;/code&gt;.&lt;/p&gt;
250&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;hints:
251&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; enabled:
252&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; - regex: &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;(mailto:|gemini:|gopher:|https:|http:|news:|file:|git:|ssh:|ftp:)\
253&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt; [^\u0000-\u001F\u007F-\u009F&amp;lt;&amp;gt;\&amp;#34;\\s{-}\\^⟨⟩`]&#43;&amp;#34;&lt;/span&gt;
254&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; command: xdg-open
255&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; post_processing: &lt;span style=&#34;color:#00f&#34;&gt;true&lt;/span&gt;
256&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; mouse:
257&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; enabled: &lt;span style=&#34;color:#00f&#34;&gt;true&lt;/span&gt;
258&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; mods: Control
259&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;The following should work under any Linux system. For macOS, you will need to
260change &lt;code&gt;command: xdg-open&lt;/code&gt; to something else.&lt;/p&gt;
261&lt;p&gt;Now the links will be visible and clickable only when Control key is being
262pressed.&lt;/p&gt;
263&lt;p&gt;Source: &lt;a href=&#34;https://github.com/alacritty/alacritty/issues/5246&#34;&gt;https://github.com/alacritty/alacritty/issues/5246&lt;/a&gt;&lt;/p&gt;
264</content:encoded>
265 </item>
266
267
268
269 <item>
270 <title>Development environments with Nix</title>
271 <link>https://mitjafelicijan.com/development-environments-with-nix.html</link>
272 <pubDate>Sun, 25 Jun 2023 16:38:10 &#43;0200</pubDate>
273 <guid>https://mitjafelicijan.com/development-environments-with-nix.html</guid>
274 <description>Nix is amazing for making reproducible cross OS development environment.</description>
275 <content:encoded>&lt;p&gt;Nix is amazing for making reproducible cross OS development environment.&lt;/p&gt;
276&lt;p&gt;First you need to &lt;a href=&#34;https://nixos.org/download.html&#34;&gt;install Nix package
277manager&lt;/a&gt;.&lt;/p&gt;
278&lt;ul&gt;
279&lt;li&gt;Create a file &lt;code&gt;shell.nix&lt;/code&gt; in your project folder.&lt;/li&gt;
280&lt;li&gt;In the section that has &lt;code&gt;python3&lt;/code&gt; etc add programs you want to use. These can
281be CLI or GUI applications. It doesn&#39;t matter to Nix.&lt;/li&gt;
282&lt;/ul&gt;
283&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{ pkgs ? &lt;span style=&#34;color:#00f&#34;&gt;import&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;lt;nixpkgs&amp;gt;&lt;/span&gt; {} }:
284&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; pkgs.mkShell {
285&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; nativeBuildInputs = &lt;span style=&#34;color:#00f&#34;&gt;with&lt;/span&gt; pkgs.buildPackages; [
286&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; python3
287&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; tinycc
288&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ];
289&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
290&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And then run it &lt;code&gt;nix-shell&lt;/code&gt;. By default it will look for &lt;code&gt;shell.nix&lt;/code&gt; file. If
291you want to specify a different file use &lt;code&gt;nix-shell file.nix&lt;/code&gt;. That is about it.&lt;/p&gt;
292&lt;p&gt;When the shell is spawned it could happen that your &lt;code&gt;PS1&lt;/code&gt; prompt will be
293overwritten and your prompt will look differently. In that case you need to
294either do &lt;code&gt;NIX_SHELL_PRESERVE_PROMPT=1 nix shell&lt;/code&gt; or add
295&lt;code&gt;NIX_SHELL_PRESERVE_PROMPT&lt;/code&gt; variable to your &lt;code&gt;bashrc&lt;/code&gt; or &lt;code&gt;zshrc&lt;/code&gt; file and set it
296to &lt;code&gt;1&lt;/code&gt;.&lt;/p&gt;
297&lt;p&gt;I also have a modified &lt;code&gt;PS1&lt;/code&gt; prompt for Bash that I use and it also catches the
298usage of Nix shell.&lt;/p&gt;
299&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;NIX_SHELL_PRESERVE_PROMPT=1
300&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
301&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;parse_git_branch() {
302&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; git branch 2&amp;gt; /dev/null | sed -e &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;/^[^*]/d&amp;#39;&lt;/span&gt; -e &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;s/* \(.*\)/ (\1)/&amp;#39;&lt;/span&gt;
303&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
304&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
305&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;is_inside_nix_shell() {
306&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; nix_shell_name=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#00f&#34;&gt;$(&lt;/span&gt;basename &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt;$IN_NIX_SHELL&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt; 2&amp;gt;/dev/null&lt;span style=&#34;color:#00f&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt;
307&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt; [[ -n &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt;$nix_shell_name&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt; ]]; &lt;span style=&#34;color:#00f&#34;&gt;then&lt;/span&gt;
308&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; echo &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34; \e[0;36m(nix-shell)\e[0m&amp;#34;&lt;/span&gt;
309&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;fi&lt;/span&gt;
310&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
311&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
312&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;export PS1=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;[\033[38;5;9m\]\u@\h\[&lt;/span&gt;&lt;span style=&#34;color:#00f&#34;&gt;$(&lt;/span&gt;tput sgr0&lt;span style=&#34;color:#00f&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;\]]&lt;/span&gt;&lt;span style=&#34;color:#00f&#34;&gt;$(&lt;/span&gt;is_inside_nix_shell&lt;span style=&#34;color:#00f&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;\[\033[33m\]\$(parse_git_branch)\[\033[00m\] \w\[&lt;/span&gt;&lt;span style=&#34;color:#00f&#34;&gt;$(&lt;/span&gt;tput sgr0&lt;span style=&#34;color:#00f&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;\] \n&lt;/span&gt;$&lt;span style=&#34;color:#a31515&#34;&gt; &amp;#34;&lt;/span&gt;
313&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And this is what it looks like when you are in a Nix shell. Otherwise that part
314of prompt is omitted&lt;/p&gt;
315&lt;figure&gt;
316&lt;img src=&#34;/notes/ps1-prompt.png&#34; alt=&#34;PS1 Prompt&#34; /&gt;
317&lt;/figure&gt;
318&lt;p&gt;More resources:&lt;/p&gt;
319&lt;ul&gt;
320&lt;li&gt;&lt;a href=&#34;https://nixos.wiki/wiki/Development_environment_with_nix-shell&#34;&gt;https://nixos.wiki/wiki/Development_environment_with_nix-shell&lt;/a&gt;&lt;/li&gt;
321&lt;li&gt;&lt;a href=&#34;https://nixos.wiki/wiki/Main_Page&#34;&gt;https://nixos.wiki/wiki/Main_Page&lt;/a&gt;&lt;/li&gt;
322&lt;li&gt;&lt;a href=&#34;https://itsfoss.com/why-use-nixos/&#34;&gt;https://itsfoss.com/why-use-nixos/&lt;/a&gt;&lt;/li&gt;
323&lt;li&gt;&lt;a href=&#34;https://mynixos.com/&#34;&gt;https://mynixos.com/&lt;/a&gt;&lt;/li&gt;
324&lt;/ul&gt;
325</content:encoded>
326 </item>
327
328
329
330 <item>
331 <title>Making cgit look nicer</title>
332 <link>https://mitjafelicijan.com/making-cgit-look-nicer.html</link>
333 <pubDate>Sat, 24 Jun 2023 13:33:58 &#43;0200</pubDate>
334 <guid>https://mitjafelicijan.com/making-cgit-look-nicer.html</guid>
335 <description>For personal use I have a private Git serverset up and I use GitHub just as a mirror.</description>
336 <content:encoded>&lt;p&gt;For personal use I have a &lt;a href=&#34;https://git.mitjafelicijan.com&#34;&gt;private Git server&lt;/a&gt;
337set up and I use GitHub just as a mirror. By default the cgit theme looks a bit
338dated so I made the flowing theme.&lt;/p&gt;
339&lt;ul&gt;
340&lt;li&gt;&lt;code&gt;/etc/cgitrc&lt;/code&gt;&lt;/li&gt;
341&lt;/ul&gt;
342&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;css=&lt;span style=&#34;color:#a31515&#34;&gt;/cgit.css&lt;/span&gt;
343&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;logo=&lt;span style=&#34;color:#a31515&#34;&gt;/startrek.gif&lt;/span&gt;
344&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;favicon=&lt;span style=&#34;color:#a31515&#34;&gt;/favicon.png&lt;/span&gt;
345&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;source-filter=&lt;span style=&#34;color:#a31515&#34;&gt;/usr/lib/cgit/filters/syntax-highlighting-edited.sh&lt;/span&gt;
346&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;about-filter=&lt;span style=&#34;color:#a31515&#34;&gt;/usr/lib/cgit/filters/about-formatting.sh&lt;/span&gt;
347&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
348&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;local-time=&lt;span style=&#34;color:#a31515&#34;&gt;1&lt;/span&gt;
349&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;snapshots=&lt;span style=&#34;color:#a31515&#34;&gt;tar.gz&lt;/span&gt;
350&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;repository-sort=&lt;span style=&#34;color:#a31515&#34;&gt;age&lt;/span&gt;
351&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cache-size=&lt;span style=&#34;color:#a31515&#34;&gt;1000&lt;/span&gt;
352&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;branch-sort=&lt;span style=&#34;color:#a31515&#34;&gt;age&lt;/span&gt;
353&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;summary-log=&lt;span style=&#34;color:#a31515&#34;&gt;200&lt;/span&gt;
354&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;max-atom-items=&lt;span style=&#34;color:#a31515&#34;&gt;50&lt;/span&gt;
355&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;max-repo-count=&lt;span style=&#34;color:#a31515&#34;&gt;100&lt;/span&gt;
356&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
357&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;enable-index-owner=&lt;span style=&#34;color:#a31515&#34;&gt;0&lt;/span&gt;
358&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;enable-follow-links=&lt;span style=&#34;color:#a31515&#34;&gt;1&lt;/span&gt;
359&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;enable-log-filecount=&lt;span style=&#34;color:#a31515&#34;&gt;1&lt;/span&gt;
360&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;enable-log-linecount=&lt;span style=&#34;color:#a31515&#34;&gt;1&lt;/span&gt;
361&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
362&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;root-title=&lt;span style=&#34;color:#a31515&#34;&gt;Place for code, experiments and other bullshit!&lt;/span&gt;
363&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;root-desc=
364&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;clone-url=&lt;span style=&#34;color:#a31515&#34;&gt;git@git.mitjafelicijan.com:/home/git/$CGIT_REPO_URL&lt;/span&gt;
365&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
366&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mimetype.gif=&lt;span style=&#34;color:#a31515&#34;&gt;image/gif&lt;/span&gt;
367&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mimetype.html=&lt;span style=&#34;color:#a31515&#34;&gt;text/html&lt;/span&gt;
368&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mimetype.jpg=&lt;span style=&#34;color:#a31515&#34;&gt;image/jpeg&lt;/span&gt;
369&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mimetype.jpeg=&lt;span style=&#34;color:#a31515&#34;&gt;image/jpeg&lt;/span&gt;
370&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mimetype.pdf=&lt;span style=&#34;color:#a31515&#34;&gt;application/pdf&lt;/span&gt;
371&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mimetype.png=&lt;span style=&#34;color:#a31515&#34;&gt;image/png&lt;/span&gt;
372&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mimetype.svg=&lt;span style=&#34;color:#a31515&#34;&gt;image/svg&#43;xml&lt;/span&gt;
373&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
374&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;readme=&lt;span style=&#34;color:#a31515&#34;&gt;:README.md&lt;/span&gt;
375&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;readme=&lt;span style=&#34;color:#a31515&#34;&gt;:readme.md&lt;/span&gt;
376&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
377&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# Must be at the end!&lt;/span&gt;
378&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;virtual-root=&lt;span style=&#34;color:#a31515&#34;&gt;/&lt;/span&gt;
379&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;scan-path=&lt;span style=&#34;color:#a31515&#34;&gt;/home/git/&lt;/span&gt;
380&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;For &lt;code&gt;syntax-highlighting-edited.sh&lt;/code&gt; follow instructions on
381&lt;a href=&#34;https://wiki.archlinux.org/title/Cgit#Using_highlight&#34;&gt;https://wiki.archlinux.org/title/Cgit&lt;/a&gt;.&lt;/p&gt;
382&lt;ul&gt;
383&lt;li&gt;&lt;code&gt;/usr/share/cgit/cgit.css&lt;/code&gt;&lt;/li&gt;
384&lt;/ul&gt;
385&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;* {
386&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;font-size&lt;/span&gt;: 11&lt;span style=&#34;color:#2b91af&#34;&gt;pt&lt;/span&gt;;
387&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
388&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
389&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;body {
390&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;font-family&lt;/span&gt;: &lt;span style=&#34;color:#00f&#34;&gt;monospace&lt;/span&gt;;
391&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;background&lt;/span&gt;: &lt;span style=&#34;color:#00f&#34;&gt;white&lt;/span&gt;;
392&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;padding&lt;/span&gt;: 1&lt;span style=&#34;color:#2b91af&#34;&gt;em&lt;/span&gt;;
393&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
394&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
395&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;th, td {
396&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;text-align&lt;/span&gt;: &lt;span style=&#34;color:#00f&#34;&gt;left&lt;/span&gt;;
397&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
398&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
399&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;/* HEADER */&lt;/span&gt;
400&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
401&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#header {
402&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;margin-bottom&lt;/span&gt;: 1&lt;span style=&#34;color:#2b91af&#34;&gt;em&lt;/span&gt;;
403&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
404&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
405&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#header .&lt;span style=&#34;color:#2b91af&#34;&gt;logo&lt;/span&gt; img {
406&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;display&lt;/span&gt;: &lt;span style=&#34;color:#00f&#34;&gt;block&lt;/span&gt;;
407&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;height&lt;/span&gt;: 3&lt;span style=&#34;color:#2b91af&#34;&gt;em&lt;/span&gt;;
408&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;margin-right&lt;/span&gt;: 10&lt;span style=&#34;color:#2b91af&#34;&gt;px&lt;/span&gt;;
409&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
410&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
411&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;#header .&lt;span style=&#34;color:#2b91af&#34;&gt;sub&lt;/span&gt;.&lt;span style=&#34;color:#2b91af&#34;&gt;right&lt;/span&gt; {
412&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;display&lt;/span&gt;: &lt;span style=&#34;color:#00f&#34;&gt;none&lt;/span&gt;;
413&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
414&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
415&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;/* FOOTER */&lt;/span&gt;
416&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
417&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#2b91af&#34;&gt;footer&lt;/span&gt; {
418&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;margin-top&lt;/span&gt;: 2&lt;span style=&#34;color:#2b91af&#34;&gt;em&lt;/span&gt;;
419&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;font-style&lt;/span&gt;: &lt;span style=&#34;color:#00f&#34;&gt;italic&lt;/span&gt;;
420&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
421&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
422&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#2b91af&#34;&gt;footer&lt;/span&gt;, .&lt;span style=&#34;color:#2b91af&#34;&gt;footer&lt;/span&gt; a {
423&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;color&lt;/span&gt;: &lt;span style=&#34;color:#00f&#34;&gt;gray&lt;/span&gt;;
424&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
425&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
426&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;/* TABS */&lt;/span&gt;
427&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
428&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#2b91af&#34;&gt;tabs&lt;/span&gt; a {
429&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;margin-bottom&lt;/span&gt;: 2&lt;span style=&#34;color:#2b91af&#34;&gt;em&lt;/span&gt;;
430&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;display&lt;/span&gt;: &lt;span style=&#34;color:#00f&#34;&gt;inline-block&lt;/span&gt;;
431&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;margin-right&lt;/span&gt;: 1&lt;span style=&#34;color:#2b91af&#34;&gt;em&lt;/span&gt;;
432&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
433&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
434&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#2b91af&#34;&gt;tabs&lt;/span&gt; td a:only-child {
435&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;display&lt;/span&gt;: &lt;span style=&#34;color:#00f&#34;&gt;none&lt;/span&gt;;
436&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
437&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
438&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;/* HIDING ELEMENTS */&lt;/span&gt;
439&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
440&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#2b91af&#34;&gt;cgit-panel&lt;/span&gt;, .&lt;span style=&#34;color:#2b91af&#34;&gt;form&lt;/span&gt; {
441&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;display&lt;/span&gt;: &lt;span style=&#34;color:#00f&#34;&gt;none&lt;/span&gt;;
442&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
443&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
444&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;/* LISTS */&lt;/span&gt;
445&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
446&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#2b91af&#34;&gt;list&lt;/span&gt; td, .&lt;span style=&#34;color:#2b91af&#34;&gt;list&lt;/span&gt; th {
447&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;padding-right&lt;/span&gt;: 2&lt;span style=&#34;color:#2b91af&#34;&gt;em&lt;/span&gt;;
448&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
449&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
450&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#2b91af&#34;&gt;list&lt;/span&gt; .&lt;span style=&#34;color:#2b91af&#34;&gt;nohover&lt;/span&gt; a {
451&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;color&lt;/span&gt;: &lt;span style=&#34;color:#00f&#34;&gt;black&lt;/span&gt;;
452&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
453&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
454&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#2b91af&#34;&gt;list&lt;/span&gt; .&lt;span style=&#34;color:#2b91af&#34;&gt;button&lt;/span&gt; {
455&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;padding-right&lt;/span&gt;: 0.5&lt;span style=&#34;color:#2b91af&#34;&gt;em&lt;/span&gt;;
456&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
457&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
458&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;/* COMMIT */&lt;/span&gt;
459&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
460&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#2b91af&#34;&gt;commit-subject&lt;/span&gt; {
461&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;padding&lt;/span&gt;: 1&lt;span style=&#34;color:#2b91af&#34;&gt;em&lt;/span&gt; 0;
462&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
463&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
464&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#2b91af&#34;&gt;decoration&lt;/span&gt; a {
465&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;padding-left&lt;/span&gt;: 0.5&lt;span style=&#34;color:#2b91af&#34;&gt;em&lt;/span&gt;;
466&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
467&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
468&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#2b91af&#34;&gt;commit-info&lt;/span&gt; th {
469&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;padding-right&lt;/span&gt;: 1&lt;span style=&#34;color:#2b91af&#34;&gt;em&lt;/span&gt;;
470&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
471&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
472&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#2b91af&#34;&gt;commit-subject&lt;/span&gt; {
473&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;padding&lt;/span&gt;: 2&lt;span style=&#34;color:#2b91af&#34;&gt;em&lt;/span&gt; 0;
474&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
475&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
476&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;table.&lt;span style=&#34;color:#2b91af&#34;&gt;diff&lt;/span&gt; div.&lt;span style=&#34;color:#2b91af&#34;&gt;head&lt;/span&gt; {
477&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;padding-top&lt;/span&gt;: 2&lt;span style=&#34;color:#2b91af&#34;&gt;em&lt;/span&gt;;
478&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
479&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
480&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;table.&lt;span style=&#34;color:#2b91af&#34;&gt;diffstat&lt;/span&gt; td {
481&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;padding-right&lt;/span&gt;: 1&lt;span style=&#34;color:#2b91af&#34;&gt;em&lt;/span&gt;;
482&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
483&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
484&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;/* CONTENT */&lt;/span&gt;
485&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
486&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#2b91af&#34;&gt;linenumbers&lt;/span&gt; {
487&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;padding-right&lt;/span&gt;: 0.5&lt;span style=&#34;color:#2b91af&#34;&gt;em&lt;/span&gt;;
488&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
489&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
490&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#2b91af&#34;&gt;linenumbers&lt;/span&gt; a {
491&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;color&lt;/span&gt;: &lt;span style=&#34;color:#00f&#34;&gt;gray&lt;/span&gt;;
492&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
493&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
494&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;.&lt;span style=&#34;color:#2b91af&#34;&gt;pager&lt;/span&gt; {
495&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;display&lt;/span&gt;: &lt;span style=&#34;color:#00f&#34;&gt;flex&lt;/span&gt;;
496&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;list-style-type&lt;/span&gt;: &lt;span style=&#34;color:#00f&#34;&gt;none&lt;/span&gt;;
497&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;padding&lt;/span&gt;: 0;
498&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; gap: 0.5&lt;span style=&#34;color:#2b91af&#34;&gt;em&lt;/span&gt;;
499&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
500&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
501&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;/* DIFF COLORS */&lt;/span&gt;
502&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
503&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;table.&lt;span style=&#34;color:#2b91af&#34;&gt;diff&lt;/span&gt; {
504&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;width&lt;/span&gt;: 100&lt;span style=&#34;color:#2b91af&#34;&gt;%&lt;/span&gt;;
505&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
506&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
507&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;table.&lt;span style=&#34;color:#2b91af&#34;&gt;diff&lt;/span&gt; td {
508&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;white-space&lt;/span&gt;: &lt;span style=&#34;color:#00f&#34;&gt;pre&lt;/span&gt;;
509&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
510&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
511&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;table.&lt;span style=&#34;color:#2b91af&#34;&gt;diff&lt;/span&gt; td div.&lt;span style=&#34;color:#2b91af&#34;&gt;head&lt;/span&gt; {
512&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;font-weight&lt;/span&gt;: &lt;span style=&#34;color:#00f&#34;&gt;bold&lt;/span&gt;;
513&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;margin-top&lt;/span&gt;: 1&lt;span style=&#34;color:#2b91af&#34;&gt;em&lt;/span&gt;;
514&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;color&lt;/span&gt;: &lt;span style=&#34;color:#00f&#34;&gt;black&lt;/span&gt;;
515&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
516&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
517&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;table.&lt;span style=&#34;color:#2b91af&#34;&gt;diff&lt;/span&gt; td div.&lt;span style=&#34;color:#2b91af&#34;&gt;hunk&lt;/span&gt; {
518&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;color&lt;/span&gt;: #009;
519&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
520&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
521&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;table.&lt;span style=&#34;color:#2b91af&#34;&gt;diff&lt;/span&gt; td div.&lt;span style=&#34;color:#2b91af&#34;&gt;add&lt;/span&gt; {
522&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;color&lt;/span&gt;: &lt;span style=&#34;color:#00f&#34;&gt;green&lt;/span&gt;;
523&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
524&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
525&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;table.&lt;span style=&#34;color:#2b91af&#34;&gt;diff&lt;/span&gt; td div.&lt;span style=&#34;color:#2b91af&#34;&gt;del&lt;/span&gt; {
526&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;color&lt;/span&gt;: &lt;span style=&#34;color:#00f&#34;&gt;red&lt;/span&gt;;
527&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
528&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded>
529 </item>
530
531
532
533 <item>
534 <title>Simple presentations with Markdown</title>
535 <link>https://mitjafelicijan.com/presentations-with-markdown.html</link>
536 <pubDate>Wed, 21 Jun 2023 08:54:48 &#43;0200</pubDate>
537 <guid>https://mitjafelicijan.com/presentations-with-markdown.html</guid>
538 <description>A simple way to make presentations without using desktop apps or using onlineservices is https://github.</description>
539 <content:encoded>&lt;p&gt;A simple way to make presentations without using desktop apps or using online
540services is &lt;a href=&#34;https://github.com/remarkjs/remark&#34;&gt;https://github.com/remarkjs/remark&lt;/a&gt;.&lt;/p&gt;
541&lt;p&gt;First create &lt;code&gt;index.html&lt;/code&gt; and be sure you make changes to &lt;code&gt;config&lt;/code&gt; variable.&lt;/p&gt;
542&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;&amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;
543&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;html&amp;gt;
544&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
545&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;head&amp;gt;
546&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;title&amp;gt;&amp;lt;/title&amp;gt;
547&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;meta charset=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;utf-8&amp;#34;&lt;/span&gt;&amp;gt;
548&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;style&amp;gt;
549&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; body {
550&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;font-family&lt;/span&gt;: &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;SF Pro Display&amp;#39;&lt;/span&gt;;
551&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
552&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
553&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; .&lt;span style=&#34;color:#2b91af&#34;&gt;remark-code&lt;/span&gt;,
554&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; .&lt;span style=&#34;color:#2b91af&#34;&gt;remark-inline-code&lt;/span&gt; {
555&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;font-family&lt;/span&gt;: &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;SF Mono&amp;#39;&lt;/span&gt;;
556&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;font-size&lt;/span&gt;: &lt;span style=&#34;color:#00f&#34;&gt;medium&lt;/span&gt;;
557&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;background-color&lt;/span&gt;: &lt;span style=&#34;color:#00f&#34;&gt;gainsboro&lt;/span&gt;;
558&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;border-radius&lt;/span&gt;: 5&lt;span style=&#34;color:#2b91af&#34;&gt;px&lt;/span&gt;;
559&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;padding&lt;/span&gt;: 0 5&lt;span style=&#34;color:#2b91af&#34;&gt;px&lt;/span&gt;;
560&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
561&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;/style&amp;gt;
562&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/head&amp;gt;
563&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
564&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;body&amp;gt;
565&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;textarea id=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;source&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/textarea&amp;gt;
566&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;script src=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;https://remarkjs.com/downloads/remark-latest.min.js&amp;#34;&lt;/span&gt;&amp;gt;&amp;lt;/script&amp;gt;
567&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;script&amp;gt;
568&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;const&lt;/span&gt; config = {
569&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; title: &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;My presentation&amp;#39;&lt;/span&gt;,
570&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; file: &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;presentation.md&amp;#39;&lt;/span&gt;,
571&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; };
572&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
573&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; document.title = config.title;
574&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; remark.create({ sourceUrl: config.file });
575&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &amp;lt;/script&amp;gt;
576&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/body&amp;gt;
577&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
578&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;/html&amp;gt;
579&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Now the markdown file &lt;code&gt;presentation.md&lt;/code&gt; with presenetation. &lt;code&gt;---&lt;/code&gt; is used to
580separate slides. Other stuff is just pure markdown.&lt;/p&gt;
581&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;class: center, middle
582&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
583&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;# Main title of the presentation
584&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;&lt;/span&gt;
585&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;---
586&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
587&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;# Fist slide
588&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;&lt;/span&gt;
589&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;Eveniet mollitia nemo architecto rerum aut iure iste. Sit nihil nobis libero iusto fugit nam laudantium ut. Dignissimos corrupti laudantium nisi.
590&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
591&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;-&lt;/span&gt; Lorem ipsum dolor sit amet, consectetur adipiscing elit.
592&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;-&lt;/span&gt; Integer aliquet mauris a felis fringilla, ut congue massa finibus.
593&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
594&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;---
595&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
596&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;# Slide two
597&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;font-weight:bold&#34;&gt;&lt;/span&gt;
598&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;-&lt;/span&gt; Lorem ipsum dolor sit amet, consectetur adipiscing elit.
599&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;-&lt;/span&gt; Vestibulum eget leo ac dolor venenatis pulvinar.
600&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded>
601 </item>
602
603
604
605 <item>
606 <title>Bulk thumbnails</title>
607 <link>https://mitjafelicijan.com/bulk-make-thumbnails.html</link>
608 <pubDate>Sun, 04 Jun 2023 20:46:56 &#43;0200</pubDate>
609 <guid>https://mitjafelicijan.com/bulk-make-thumbnails.html</guid>
610 <description>Make bulk thumbnails of JPGs with ImageMagick.</description>
611 <content:encoded>&lt;p&gt;Make bulk thumbnails of JPGs with ImageMagick.&lt;/p&gt;
612&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;#!/bin/bash
613&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;&lt;/span&gt;
614&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;directory=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;./images/&amp;#34;&lt;/span&gt;
615&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dimensions=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;360x360&amp;#34;&lt;/span&gt;
616&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
617&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;for&lt;/span&gt; file in &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt;$directory&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt;*.jpg; &lt;span style=&#34;color:#00f&#34;&gt;do&lt;/span&gt;
618&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; convert &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt;$file&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt; -resize $dimensions &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt;$file&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;${&lt;/span&gt;file%.*&lt;span style=&#34;color:#a31515&#34;&gt;}&lt;/span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;-thumbnail.jpg&amp;#34;&lt;/span&gt;
619&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;done&lt;/span&gt;
620&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded>
621 </item>
622
623
624
625 <item>
626 <title>Edsger W. Dijkstra Manuscripts ebook</title>
627 <link>https://mitjafelicijan.com/ewd-manuscripts-ebook.html</link>
628 <pubDate>Thu, 01 Jun 2023 22:47:56 &#43;0200</pubDate>
629 <guid>https://mitjafelicijan.com/ewd-manuscripts-ebook.html</guid>
630 <description>I love reading the original manuscripts of Edsger W.</description>
631 <content:encoded>&lt;p&gt;I love reading the original manuscripts of Edsger W. Dijkstra. They are
632available online at the University of Texas at Austin website, but I also found
633MOBI version. I converted it into ePub as well.&lt;/p&gt;
634&lt;p&gt;Downloads:&lt;/p&gt;
635&lt;ul&gt;
636&lt;li&gt;&lt;a href=&#34;https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/ewd-manuscripts.mobi&#34;&gt;MOBI version of all Manuscripts&lt;/a&gt;&lt;/li&gt;
637&lt;li&gt;&lt;a href=&#34;https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/ewd-manuscripts.epub&#34;&gt;ePub version of all Manuscripts&lt;/a&gt;&lt;/li&gt;
638&lt;/ul&gt;
639&lt;p&gt;Sources and credits:&lt;/p&gt;
640&lt;ul&gt;
641&lt;li&gt;&lt;a href=&#34;https://www.cs.utexas.edu/users/EWD/index00xx.html&#34;&gt;Original manuscripts from University of Texas at Austin&lt;/a&gt;&lt;/li&gt;
642&lt;li&gt;&lt;a href=&#34;https://github.com/evmn/The-Manuscripts-of-Edsger-W.-Dijkstra&#34;&gt;Original repository of MOBI version&lt;/a&gt;&lt;/li&gt;
643&lt;/ul&gt;
644</content:encoded>
645 </item>
646
647
648
649
650
651 <item>
652 <title>Extending dte editor</title>
653 <link>https://mitjafelicijan.com/extending-dte-editor.html</link>
654 <pubDate>Wed, 31 May 2023 08:12:45 &#43;0200</pubDate>
655 <guid>https://mitjafelicijan.com/extending-dte-editor.html</guid>
656 <description>dte is an interesting editor I startedusing lately more and more.</description>
657 <content:encoded>&lt;p&gt;&lt;a href=&#34;https://craigbarnes.gitlab.io/dte/&#34;&gt;&lt;code&gt;dte&lt;/code&gt;&lt;/a&gt; is an interesting editor I started
658using lately more and more. Since it is using
659&lt;a href=&#34;https://linux.die.net/man/3/execvp&#34;&gt;&lt;code&gt;execvp()&lt;/code&gt;&lt;/a&gt; it can be easily extended. I
660needed comment/uncomment feature so I created a small utility that does this for
661me. Code lives on repository &lt;a href=&#34;https://git.mitjafelicijan.com/dte-extensions.git/about/&#34;&gt;dte
662extensions&lt;/a&gt; but this
663utilities can be used for whatever you want. Make sure you have version 1.11 or
664above.&lt;/p&gt;
665&lt;p&gt;Next one will be invoking formatter based on the type of a file.&lt;/p&gt;
666&lt;p&gt;My config that works for me.&lt;/p&gt;
667&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set show-line-numbers true;
668&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set tab-width 4;
669&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;set &lt;span style=&#34;color:#00f&#34;&gt;case&lt;/span&gt;-sensitive-search false;
670&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
671&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# Special aliases&lt;/span&gt;
672&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;alias m_comment &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;exec -s -i line -o buffer -e errmsg ~/.dte/bin/comment&amp;#39;&lt;/span&gt;
673&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;alias m_format &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;save; exec go fmt .; reload&amp;#39;&lt;/span&gt;
674&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;alias m_duplicate &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;copy;paste&amp;#39;&lt;/span&gt;;
675&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
676&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# Useful aliases.&lt;/span&gt;
677&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;alias m_force_close &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;quit -f&amp;#39;&lt;/span&gt;;
678&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;alias m_reload &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;close; open $FILE&amp;#39;&lt;/span&gt;
679&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
680&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# Key bindings.&lt;/span&gt;
681&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bind M-s save;
682&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bind M-q m_force_close;
683&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bind M-z refresh;
684&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bind C-down blkdown;
685&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bind C-up blkup;
686&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bind C-_ m_comment;
687&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bind M-. m_format;
688&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;bind C-d m_duplicate;
689&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
690&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# Syntax highlighting.&lt;/span&gt;
691&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;hi preproc magenta;
692&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;hi keyword red;
693&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;hi linenumber blue;
694&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;hi comment cyan;
695&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded>
696 </item>
697
698
699
700 <item>
701 <title>Grep to Less that maintain colors</title>
702 <link>https://mitjafelicijan.com/grep-to-less-maintain-colors.html</link>
703 <pubDate>Mon, 29 May 2023 21:27:07 &#43;0200</pubDate>
704 <guid>https://mitjafelicijan.com/grep-to-less-maintain-colors.html</guid>
705 <description>I often use grep to search for todo&amp;#39;s in my code and other people&amp;#39;s code andthen pipe them in less and I missed having colors that grep outputs in less.</description>
706 <content:encoded>&lt;p&gt;I often use &lt;code&gt;grep&lt;/code&gt; to search for todo&#39;s in my code and other people&#39;s code and
707then pipe them in &lt;code&gt;less&lt;/code&gt; and I missed having colors that grep outputs in &lt;code&gt;less&lt;/code&gt;.&lt;/p&gt;
708&lt;ul&gt;
709&lt;li&gt;Grep&#39;s &lt;code&gt;--color=always&lt;/code&gt; use markers to highlight the matching strings.&lt;/li&gt;
710&lt;li&gt;Less&#39;s &lt;code&gt;-R&lt;/code&gt; option outputs &amp;quot;raw&amp;quot; control characters.&lt;/li&gt;
711&lt;/ul&gt;
712&lt;p&gt;You could use &lt;code&gt;alias grep=&#39;grep --color=always&#39;&lt;/code&gt; and &lt;code&gt;alias less=&#39;less -R&#39;&lt;/code&gt; or
713create todo function in your &lt;code&gt;.bashrc&lt;/code&gt; that accepts first argument as search
714string.&lt;/p&gt;
715&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# This is where the magic happens.&lt;/span&gt;
716&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;grep --color=always -rni &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;TODO:&amp;#34;&lt;/span&gt; | less -R
717&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;figure&gt;
718&lt;img src=&#34;/notes/grep-less.png&#34; alt=&#34;Less and grep&#34; /&gt;
719&lt;/figure&gt;
720</content:encoded>
721 </item>
722
723
724
725 <item>
726 <title>Easy measure time took in a bash script</title>
727 <link>https://mitjafelicijan.com/easy-time-took-in-bash.html</link>
728 <pubDate>Sun, 28 May 2023 17:53:20 &#43;0200</pubDate>
729 <guid>https://mitjafelicijan.com/easy-time-took-in-bash.html</guid>
730 <description>In Bash, the $SECONDS variable is a special variable that automatically keepstrack of the number of seconds since the current shell or script startedexecuting.</description>
731 <content:encoded>&lt;p&gt;In Bash, the &lt;code&gt;$SECONDS&lt;/code&gt; variable is a special variable that automatically keeps
732track of the number of seconds since the current shell or script started
733executing. It starts counting from the moment the script begins running.&lt;/p&gt;
734&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;#!/bin/bash
735&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;&lt;/span&gt;
736&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# Reset the timer to zero.&lt;/span&gt;
737&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;SECONDS=0
738&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
739&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# Do something.&lt;/span&gt;
740&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sleep 5
741&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
742&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# Print the time elapsed.&lt;/span&gt;
743&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;echo &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Time taken: &lt;/span&gt;$SECONDS&lt;span style=&#34;color:#a31515&#34;&gt; seconds&amp;#34;&lt;/span&gt;
744&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded>
745 </item>
746
747
748
749 <item>
750 <title>Make DCSS playable on 4k displays</title>
751 <link>https://mitjafelicijan.com/dcss-on-4k-display.html</link>
752 <pubDate>Sat, 27 May 2023 19:35:11 &#43;0200</pubDate>
753 <guid>https://mitjafelicijan.com/dcss-on-4k-display.html</guid>
754 <description>Dungeon Crawl Stone Soup has a a very small font by default.</description>
755 <content:encoded>&lt;p&gt;Dungeon Crawl Stone Soup has a a very small font by default. On a 4k display, it
756is barely readable. This is how I made it playable.&lt;/p&gt;
757&lt;p&gt;Make a file &lt;code&gt;~/.crawlrc&lt;/code&gt; with the following content:&lt;/p&gt;
758&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# Adjust the sizes to your liking.&lt;/span&gt;
759&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
760&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tile_font_crt_size = &lt;span style=&#34;color:#a31515&#34;&gt;32&lt;/span&gt;
761&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tile_font_stat_size = &lt;span style=&#34;color:#a31515&#34;&gt;32&lt;/span&gt;
762&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tile_font_msg_size = &lt;span style=&#34;color:#a31515&#34;&gt;32&lt;/span&gt;
763&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tile_font_tip_size = &lt;span style=&#34;color:#a31515&#34;&gt;32&lt;/span&gt;
764&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tile_font_lbl_size = &lt;span style=&#34;color:#a31515&#34;&gt;32&lt;/span&gt;
765&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;tile_sidebar_pixels = &lt;span style=&#34;color:#a31515&#34;&gt;64&lt;/span&gt;
766&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;To zoom in and out in viewport, press &lt;code&gt;Ctrl&#43;&lt;/code&gt; and &lt;code&gt;Ctrl-&lt;/code&gt; respectively.&lt;/p&gt;
767&lt;p&gt;All the possible options are documented in the &lt;a href=&#34;https://github.com/crawl/crawl/blob/master/crawl-ref/docs/options_guide.txt&#34;&gt;Dungeon Crawl Stone Soup Options
768Guide&lt;/a&gt;
769file.&lt;/p&gt;
770</content:encoded>
771 </item>
772
773
774
775 <item>
776 <title>Drawing Pixels in Plan9</title>
777 <link>https://mitjafelicijan.com/drawing-pixels-in-plan9.html</link>
778 <pubDate>Sat, 27 May 2023 17:41:33 &#43;0200</pubDate>
779 <guid>https://mitjafelicijan.com/drawing-pixels-in-plan9.html</guid>
780 <description>I have started exploring Plan9&amp;#39;s graphics capabilities.</description>
781 <content:encoded>&lt;p&gt;I have started exploring Plan9&#39;s graphics capabilities. This is a hello world
782alternative for drawing that draws a yellow square on a blue background.&lt;/p&gt;
783&lt;p&gt;More information:&lt;/p&gt;
784&lt;ul&gt;
785&lt;li&gt;&lt;a href=&#34;https://github.com/0intro/plan9/blob/main/sys/include/draw.h&#34;&gt;draw.h header file&lt;/a&gt;
786contains all the drawing functions&lt;/li&gt;
787&lt;li&gt;&lt;a href=&#34;https://9fans.github.io/plan9port/man/man3/draw.html&#34;&gt;draw man page&lt;/a&gt;
788has a bit more digestable descriptions of the draw functions&lt;/li&gt;
789&lt;li&gt;&lt;a href=&#34;https://9fans.github.io/plan9port/man/man3/graphics.html&#34;&gt;graphics man page&lt;/a&gt;
790has a bit more digestable descriptions of the graphics functions&lt;/li&gt;
791&lt;li&gt;&lt;a href=&#34;https://9fans.github.io/plan9port/man/man3/&#34;&gt;all man pages&lt;/a&gt;
792can be a valuable resource for learning about the system&lt;/li&gt;
793&lt;/ul&gt;
794&lt;figure&gt;
795&lt;img src=&#34;/notes/plan9-pixels.png&#34; alt=&#34;Plan9 Howdy World!&#34; /&gt;
796&lt;/figure&gt;
797&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;// main.c
798&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#00f&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;&amp;lt;u.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#00f&#34;&gt;
799&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;&amp;lt;libc.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#00f&#34;&gt;
800&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;&amp;lt;draw.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#00f&#34;&gt;
801&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;&amp;lt;cursor.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#00f&#34;&gt;
802&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;&lt;/span&gt;
803&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#2b91af&#34;&gt;void&lt;/span&gt;
804&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;main()
805&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
806&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ulong co;
807&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; Image *im, *bg;
808&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; co = 0x0000FFFF;
809&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
810&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt; (initdraw(nil, nil, argv0) &amp;lt; 0)
811&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {
812&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; sysfatal(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;%s: %r&amp;#34;&lt;/span&gt;, argv0);
813&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
814&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
815&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; im = allocimage(display, Rect(0, 0, 300, 300), RGB24, 0, DYellow);
816&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; bg = allocimage(display, Rect(0, 0, 1, 1), RGB24, 1, co);
817&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
818&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt; (im == nil || bg == nil)
819&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {
820&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; sysfatal(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;not enough memory&amp;#34;&lt;/span&gt;);
821&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; }
822&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
823&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; draw(screen, screen-&amp;gt;r, bg, nil, ZP);
824&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; draw(screen, screen-&amp;gt;r, im, nil, Pt(-40, -40));
825&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
826&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; flushimage(display, Refnone);
827&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
828&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;// Wait 10 seconds before exiting.
829&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt; sleep(10000);
830&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
831&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; exits(nil);
832&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
833&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And then compile with &lt;code&gt;mk&lt;/code&gt; (mkfile below):&lt;/p&gt;
834&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# mkfile
835&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt;&lt;span style=&#34;&#34;&gt;&amp;lt;/$objtype/mkfile&lt;/span&gt;
836&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
837&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;RC=/rc/bin
838&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;BIN=/$objtype/bin
839&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;MAN=/sys/man
840&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
841&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;main:
842&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; $CC $CFLAGS main.c
843&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; $LD $LDFLAGS -o main main.$O
844&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;And run with &lt;code&gt;./main&lt;/code&gt;. To exit the program, press &lt;code&gt;Delete key&lt;/code&gt; (strange but this
845is the alternative for Ctrl&#43;C).&lt;/p&gt;
846&lt;p&gt;&lt;em&gt;This is &lt;strong&gt;very cool&lt;/strong&gt; indeed!&lt;/em&gt;&lt;/p&gt;
847</content:encoded>
848 </item>
849
850
851
852 <item>
853 <title>Cronjobs on Github with Github Actions</title>
854 <link>https://mitjafelicijan.com/cronjobs-github-with-actions.html</link>
855 <pubDate>Sat, 27 May 2023 00:35:36 &#43;0200</pubDate>
856 <guid>https://mitjafelicijan.com/cronjobs-github-with-actions.html</guid>
857 <description>In the root of your repository create a folder .</description>
858 <content:encoded>&lt;p&gt;In the root of your repository create a folder &lt;code&gt;.github/workflows&lt;/code&gt; and in that
859folder create a file a file &lt;code&gt;cron.yaml&lt;/code&gt;. This file can be named whatever you
860wish. But it has to be a &lt;code&gt;yaml&lt;/code&gt; file.&lt;/p&gt;
861&lt;p&gt;File below (&lt;code&gt;.github/workflows/cron.yaml&lt;/code&gt;) describes an action that will trigger
862every six hours and it will curl example.com.&lt;/p&gt;
863&lt;p&gt;However. Be sure that you have enough credits. Free account is not that generous
864with the minutes they give you for free. Check more about GitHub Actions usage
865on their website &lt;a href=&#34;https://docs.github.com/en/actions&#34;&gt;https://docs.github.com/en/actions&lt;/a&gt;.&lt;/p&gt;
866&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# .github/workflows/cron.yaml&lt;/span&gt;
867&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;name: Do a curl every 6 hours
868&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;on:
869&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; schedule:
870&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; - cron: &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;0 */6 * * *&amp;#39;&lt;/span&gt;
871&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;jobs:
872&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; cron:
873&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; runs-on: ubuntu-latest
874&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; steps:
875&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; - name: Call some url
876&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; run: curl &amp;#39;https://example.com&amp;#39;
877&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded>
878 </item>
879
880
881
882 <item>
883 <title>Dungeon Crawl Stone Soup - New player guide</title>
884 <link>https://mitjafelicijan.com/dcss-new-player-guide.html</link>
885 <pubDate>Thu, 25 May 2023 22:00:00 &#43;0200</pubDate>
886 <guid>https://mitjafelicijan.com/dcss-new-player-guide.html</guid>
887 <description>An amazing game deserves an amazing guide.</description>
888 <content:encoded>&lt;p&gt;An amazing game deserves an amazing guide. All this material can be find in some
889form on another on &lt;a href=&#34;https://github.com/crawl/crawl&#34;&gt;craw&#39;s&lt;/a&gt; official repository.&lt;/p&gt;
890&lt;ul&gt;
891&lt;li&gt;&lt;a href=&#34;/notes/dcss-quickstart.pdf&#34;&gt;DCSS Quickstart&lt;/a&gt; - Very short introduction to the
892game&lt;/li&gt;
893&lt;li&gt;&lt;a href=&#34;/notes/dcss_manual.pdf&#34;&gt;DCSS Manual&lt;/a&gt; - Extensive manual about the game&lt;/li&gt;
894&lt;/ul&gt;
895&lt;figure&gt;
896&lt;img src=&#34;/notes/dcss.jpg&#34; alt=&#34;Dungeon Crawl Stone Soup&#34; /&gt;
897&lt;/figure&gt;
898&lt;p&gt;&lt;strong&gt;Movement and Exploration&lt;/strong&gt;&lt;/p&gt;
899&lt;ul&gt;
900&lt;li&gt;You can move around with the numpad (try numlock on and off), vi-keys, or
901clicking with the mouse. Arrow keys work, though you can&#39;t move diagonally
902with them. Pressing Shift and a direction will move until you see/hit
903something.&lt;/li&gt;
904&lt;li&gt;Pressing &lt;code&gt;&amp;gt;&lt;/code&gt; will take you down a staircase, and &lt;code&gt;&amp;lt;&lt;/code&gt; to go up a staircase.&lt;/li&gt;
905&lt;li&gt;You can open doors by walking into them, and close them with &lt;code&gt;C&lt;/code&gt;.&lt;/li&gt;
906&lt;li&gt;You can autoexplore by pressing &lt;code&gt;o&lt;/code&gt;.&lt;/li&gt;
907&lt;li&gt;You can re-view recent messages with &lt;code&gt;Ctrl-p&lt;/code&gt;.&lt;/li&gt;
908&lt;/ul&gt;
909&lt;p&gt;&lt;strong&gt;Monsters and Combat&lt;/strong&gt;&lt;/p&gt;
910&lt;ul&gt;
911&lt;li&gt;You can pick up items with &lt;code&gt;,&lt;/code&gt; or &lt;code&gt;g&lt;/code&gt;.&lt;/li&gt;
912&lt;li&gt;Wield weapons with &lt;code&gt;w&lt;/code&gt;. Weapons have different stats.
913&lt;ul&gt;
914&lt;li&gt;(You may also engage in Unarmed Combat, though it isn&#39;t very effective when
915untrained).&lt;/li&gt;
916&lt;/ul&gt;
917&lt;/li&gt;
918&lt;li&gt;Attack monsters in melee by walking in their direction (or with
919Ctrl-direction).&lt;/li&gt;
920&lt;li&gt;You can wait with &lt;code&gt;.&lt;/code&gt; or &lt;code&gt;s&lt;/code&gt;, passing your turn - such as to get monsters into
921a corridor with you.&lt;/li&gt;
922&lt;li&gt;You can rest with &lt;code&gt;5&lt;/code&gt;, waiting until you are fully healed, or something
923noteworthy happens.&lt;/li&gt;
924&lt;li&gt;Either mouseover and rightclick, or use &lt;code&gt;x&lt;/code&gt; then &lt;code&gt;v&lt;/code&gt; on the monster to examine
925monsters. Monsters with a red border are &#39;dangerous&#39; relative to your current
926XP level (XL).&lt;/li&gt;
927&lt;li&gt;Quiver (often ranged) actions for further use with &lt;code&gt;Q&lt;/code&gt;.&lt;/li&gt;
928&lt;li&gt;You can fire ranged weapons manually with &lt;code&gt;f&lt;/code&gt;, or auto-target your quiver with
929&lt;code&gt;p&lt;/code&gt; or &lt;code&gt;Shift-Tab&lt;/code&gt;. Throwing weapons can be thrown immediately, while
930launchers (like bows) need to be wielded first.&lt;/li&gt;
931&lt;/ul&gt;
932&lt;p&gt;&lt;strong&gt;Items and Inventory&lt;/strong&gt;&lt;/p&gt;
933&lt;ul&gt;
934&lt;li&gt;View your inventory by pressing &lt;code&gt;i&lt;/code&gt;. Most item related commands can also be
935done with this menu.&lt;/li&gt;
936&lt;li&gt;You can wear amour with &lt;code&gt;W;&lt;/code&gt; amour gives &lt;code&gt;AC&lt;/code&gt;, while heavier body armour
937reduces &lt;code&gt;EV&lt;/code&gt;.&lt;/li&gt;
938&lt;li&gt;Autoexplore will automatically pick up useful items, such as potions and
939scrolls, if you aren&#39;t in danger.&lt;/li&gt;
940&lt;li&gt;You can read scrolls with &lt;code&gt;r&lt;/code&gt; and drink (&amp;quot;quaff&amp;quot;) potions with &lt;code&gt;q&lt;/code&gt;.&lt;/li&gt;
941&lt;li&gt;Equipment items may have brands, with special properties. Branded equipment is
942blue when unidentified.&lt;/li&gt;
943&lt;li&gt;Equipment items may be artifacts, often with unique properties, and are
944unmodifiable. They are written in white.&lt;/li&gt;
945&lt;li&gt;You can evoke wands with &lt;code&gt;V&lt;/code&gt;.&lt;/li&gt;
946&lt;li&gt;You can put on jewelry with &lt;code&gt;P&lt;/code&gt;, and remove it with &lt;code&gt;R&lt;/code&gt;.&lt;/li&gt;
947&lt;li&gt;Gold is used in shops, which can be interacted with by either &lt;code&gt;&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;&lt;/code&gt;.&lt;/li&gt;
948&lt;/ul&gt;
949&lt;p&gt;&lt;strong&gt;Magic and Spellcasting&lt;/strong&gt;&lt;/p&gt;
950&lt;ul&gt;
951&lt;li&gt;Once you find a spellbook, you can memorize spells with &lt;code&gt;M&lt;/code&gt;.&lt;/li&gt;
952&lt;li&gt;You need to be the same XL as the spell&#39;s spell level in order to learn it, in
953addition to training magical skill (to lower failure rate).&lt;/li&gt;
954&lt;li&gt;Cast spells by pressing &lt;code&gt;z&lt;/code&gt;, then the letter assigned to the spell. You may
955also Quiver a spell and then use it like a ranged weapon (with Shift-Tab).&lt;/li&gt;
956&lt;li&gt;You can view your memorized spells by pressing &lt;code&gt;I&lt;/code&gt; (capital-i) or &lt;code&gt;z&lt;/code&gt;.&lt;/li&gt;
957&lt;li&gt;Like HP, you can recover MP by resting (with 5).&lt;/li&gt;
958&lt;li&gt;Many spells can be positioned more effectively, or combined with other spells,
959in order to get (more effective) use out of them.&lt;/li&gt;
960&lt;li&gt;Heavier body amour and shields hamper spellcasting.&lt;/li&gt;
961&lt;/ul&gt;
962&lt;p&gt;&lt;strong&gt;Gods and Divine Abilities&lt;/strong&gt;&lt;/p&gt;
963&lt;ul&gt;
964&lt;li&gt;You may look at a god&#39;s overview by praying at their altar (with &lt;code&gt;&amp;gt;&lt;/code&gt; or &lt;code&gt;&amp;lt;&lt;/code&gt;).
965After praying, you can worship the god by pressing Enter afterwards.&lt;/li&gt;
966&lt;li&gt;Gods all have unique features about them. Trog, the god of the tutorial, is
967also the god of rage and bloodshed, and so despises spellcasting.&lt;/li&gt;
968&lt;li&gt;Gods like and dislike different things. Most gods either like killing things
969(like Trog) or exploring new areas (like Elyvilon), rewarding you piety
970(divine favor) for doing so.&lt;/li&gt;
971&lt;li&gt;You should learn to use and even rely on divine abilities often, as they are
972usually very strong. Trog&#39;s Berserk gives you 1.5x health, 1.5x speed (to all
973valid actions), and a big damage boost. Note that Berserk prevents most
974actions other than move and melee attack, and runs out very quickly if you
975aren&#39;t attacking. And after berserk ends, you are slowed down and can&#39;t
976berserk again for a short time.&lt;/li&gt;
977&lt;li&gt;In addition, the vast majority of abilities consume piety in the process.
978Regardless, this ability is very cheap, and the benefits are incredible, so
979don&#39;t hold back!&lt;/li&gt;
980&lt;li&gt;Pressing &lt;code&gt;^&lt;/code&gt; will let you view your current god, abilities, and piety.&lt;/li&gt;
981&lt;/ul&gt;
982</content:encoded>
983 </item>
984
985
986
987 <item>
988 <title>Display xterm color palette</title>
989 <link>https://mitjafelicijan.com/xterm-color-palette.html</link>
990 <pubDate>Thu, 25 May 2023 12:00:00 &#43;0200</pubDate>
991 <guid>https://mitjafelicijan.com/xterm-color-palette.html</guid>
992 <description>bash xterm-palette.</description>
993 <content:encoded>&lt;ul&gt;
994&lt;li&gt;&lt;code&gt;bash xterm-palette.sh&lt;/code&gt; - will show you number of max colors available&lt;/li&gt;
995&lt;li&gt;&lt;code&gt;bash xterm-palette.sh -v&lt;/code&gt; - will create a list of all colors with codes&lt;/li&gt;
996&lt;/ul&gt;
997&lt;figure&gt;
998&lt;img src=&#34;/notes/xterm-palette.png&#34; alt=&#34;xterm color palette&#34; /&gt;
999&lt;/figure&gt;
1000&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;#!/usr/bin/env bash
1001&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;&lt;/span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# xterm-palette.sh&lt;/span&gt;
1002&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1003&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;trap &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;tput sgr0&amp;#39;&lt;/span&gt; exit &lt;span style=&#34;color:#008000&#34;&gt;# Clean up even if user hits ^C&lt;/span&gt;
1004&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1005&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;function&lt;/span&gt; setfg () {
1006&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; printf &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;\e[38;5;%dm&amp;#39;&lt;/span&gt; $1
1007&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
1008&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1009&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;function&lt;/span&gt; setbg () {
1010&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; printf &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;\e[48;5;%dm&amp;#39;&lt;/span&gt; $1
1011&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
1012&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1013&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;function&lt;/span&gt; showcolors() {
1014&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;# Given an integer, display that many colors&lt;/span&gt;
1015&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;for&lt;/span&gt; ((i=0; i&amp;lt;$1; i&#43;&#43;))
1016&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;do&lt;/span&gt;
1017&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; printf &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;%4d &amp;#39;&lt;/span&gt; $i
1018&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; setbg $i
1019&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; tput el
1020&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; tput sgr0
1021&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; echo
1022&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;done&lt;/span&gt;
1023&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; tput sgr0 el
1024&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
1025&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1026&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# First, test if terminal supports OSC 4 at all.&lt;/span&gt;
1027&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;printf &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;\e]4;%d;?\a&amp;#39;&lt;/span&gt; 0
1028&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;read -d &lt;span style=&#34;color:#a31515&#34;&gt;$&amp;#39;\a&amp;#39;&lt;/span&gt; -s -t 0.1 &amp;lt;/dev/tty
1029&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt; [ -z &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt;$REPLY&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt; ]
1030&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;then&lt;/span&gt;
1031&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;# OSC 4 not supported, so we&amp;#39;ll fall back to terminfo&lt;/span&gt;
1032&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; max=&lt;span style=&#34;color:#00f&#34;&gt;$(&lt;/span&gt;tput colors&lt;span style=&#34;color:#00f&#34;&gt;)&lt;/span&gt;
1033&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;else&lt;/span&gt;
1034&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;# OSC 4 is supported, so use it for a binary search&lt;/span&gt;
1035&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; min=0
1036&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; max=256
1037&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;while&lt;/span&gt; [[ &lt;span style=&#34;color:#00f&#34;&gt;$((&lt;/span&gt;min&#43;1&lt;span style=&#34;color:#00f&#34;&gt;))&lt;/span&gt; -lt $max ]]
1038&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;do&lt;/span&gt;
1039&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; i=&lt;span style=&#34;color:#00f&#34;&gt;$((&lt;/span&gt; (min&#43;max)/2 &lt;span style=&#34;color:#00f&#34;&gt;))&lt;/span&gt;
1040&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; printf &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;\e]4;%d;?\a&amp;#39;&lt;/span&gt; $i
1041&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; read -d &lt;span style=&#34;color:#a31515&#34;&gt;$&amp;#39;\a&amp;#39;&lt;/span&gt; -s -t 0.1 &amp;lt;/dev/tty
1042&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt; [ -z &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt;$REPLY&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt; ]
1043&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;then&lt;/span&gt;
1044&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; max=$i
1045&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;else&lt;/span&gt;
1046&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; min=$i
1047&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;fi&lt;/span&gt;
1048&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;done&lt;/span&gt;
1049&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;fi&lt;/span&gt;
1050&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1051&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1052&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# If -v is given, show all the colors&lt;/span&gt;
1053&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;case&lt;/span&gt; &lt;span style=&#34;color:#a31515&#34;&gt;${&lt;/span&gt;1-none&lt;span style=&#34;color:#a31515&#34;&gt;}&lt;/span&gt; in
1054&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; none)
1055&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; echo $max
1056&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ;;
1057&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; -v)
1058&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; showcolors $max
1059&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ;;
1060&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; *)
1061&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt; [[ &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt;$1&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&lt;/span&gt; -gt 0 ]]; &lt;span style=&#34;color:#00f&#34;&gt;then&lt;/span&gt;
1062&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; showcolors $1
1063&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;else&lt;/span&gt;
1064&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; echo $max
1065&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;fi&lt;/span&gt;
1066&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; ;;
1067&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;esac&lt;/span&gt; | less --raw-control-chars --QUIT-AT-EOF --no-init
1068&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded>
1069 </item>
1070
1071
1072
1073 <item>
1074 <title>Sane defaults for tmux with more visible statusbar</title>
1075 <link>https://mitjafelicijan.com/tmux-sane-defaults.html</link>
1076 <pubDate>Thu, 25 May 2023 12:00:00 &#43;0200</pubDate>
1077 <guid>https://mitjafelicijan.com/tmux-sane-defaults.html</guid>
1078 <description># Remap prefix from &amp;#39;C-b&amp;#39; to &amp;#39;M-a&amp;#39;.</description>
1079 <content:encoded>&lt;pre&gt;&lt;code class=&#34;language-conf&#34;&gt;# Remap prefix from &#39;C-b&#39; to &#39;M-a&#39;.
1080unbind C-b
1081set-option -g prefix M-a
1082bind-key M-a send-prefix
1083
1084# Split panes using | and -.
1085bind | split-window -h
1086bind - split-window -v
1087unbind &#39;&amp;quot;&#39;
1088unbind %
1089
1090# Start counting windows with 1.
1091set-option -g allow-rename on
1092set -g base-index 1
1093setw -g pane-base-index 1
1094
1095# Statusbar: purple bg and white fg.
1096set -g status-bg &#39;#480b8e&#39;
1097set -g status-fg &#39;#ffffff&#39;
1098
1099# Active window: black bg and white fg.
1100set -g window-status-current-format &amp;quot;#[fg=#ffffff]#[bg=#111111]#[fg=#ffffff]#[bg=#111111] #I:#W #[fg=#ffffff]#[bg=#111111]&amp;quot;
1101
1102# Disable mouse mode (tmux 2.1 and above).
1103set -g mouse off
1104&lt;/code&gt;&lt;/pre&gt;
1105</content:encoded>
1106 </item>
1107
1108
1109
1110 <item>
1111 <title>My brand new Plan9/9front desktop</title>
1112 <link>https://mitjafelicijan.com/fresh-9front-desktop.html</link>
1113 <pubDate>Wed, 24 May 2023 12:00:00 &#43;0200</pubDate>
1114 <guid>https://mitjafelicijan.com/fresh-9front-desktop.html</guid>
1115 <description>I have been experimenting with Plan9/9front for a week now.</description>
1116 <content:encoded>&lt;p&gt;I have been experimenting with Plan9/9front for a week now. Noice! This is how
1117my desktop looks like.&lt;/p&gt;
1118&lt;figure&gt;
1119&lt;img src=&#34;/notes/9front-desktop.png&#34; alt=&#34;9front desktop&#34; /&gt;
1120&lt;/figure&gt;
1121</content:encoded>
1122 </item>
1123
1124
1125
1126
1127
1128 <item>
1129 <title>Parse RSS feeds with Lua</title>
1130 <link>https://mitjafelicijan.com/parse-rss-with-lua.html</link>
1131 <pubDate>Tue, 23 May 2023 12:00:00 &#43;0200</pubDate>
1132 <guid>https://mitjafelicijan.com/parse-rss-with-lua.html</guid>
1133 <description>Example of parsing RSS feeds with Lua.</description>
1134 <content:encoded>&lt;p&gt;Example of parsing RSS feeds with Lua. Before running the script install:&lt;/p&gt;
1135&lt;ul&gt;
1136&lt;li&gt;feedparser with &lt;code&gt;luarocks install feedparser&lt;/code&gt;&lt;/li&gt;
1137&lt;li&gt;luasocket with &lt;code&gt;luarocks install luasocket&lt;/code&gt;&lt;/li&gt;
1138&lt;/ul&gt;
1139&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;local&lt;/span&gt; http = require(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;socket.http&amp;#34;&lt;/span&gt;)
1140&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;local&lt;/span&gt; feedparser = require(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;feedparser&amp;#34;&lt;/span&gt;)
1141&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1142&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;local&lt;/span&gt; feed_url = &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;https://mitjafelicijan.com/index.xml&amp;#34;&lt;/span&gt;
1143&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1144&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;local&lt;/span&gt; response, status, _ = http.request(feed_url)
1145&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt; status == 200 &lt;span style=&#34;color:#00f&#34;&gt;then&lt;/span&gt;
1146&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;local&lt;/span&gt; parsed = feedparser.parse(response)
1147&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1148&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#008000&#34;&gt;-- Print out feed details.&lt;/span&gt;
1149&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; print(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&amp;gt; Title &amp;#34;&lt;/span&gt;, parsed.feed.title)
1150&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; print(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&amp;gt; Author &amp;#34;&lt;/span&gt;, parsed.feed.author)
1151&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; print(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&amp;gt; ID &amp;#34;&lt;/span&gt;, parsed.feed.id)
1152&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; print(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;&amp;gt; Entries &amp;#34;&lt;/span&gt;, #parsed.entries)
1153&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1154&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;for&lt;/span&gt; _, item &lt;span style=&#34;color:#00f&#34;&gt;in&lt;/span&gt; ipairs(parsed.entries) &lt;span style=&#34;color:#00f&#34;&gt;do&lt;/span&gt;
1155&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; print(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;GUID &amp;#34;&lt;/span&gt;, item.guid)
1156&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; print(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Title &amp;#34;&lt;/span&gt;, item.title)
1157&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; print(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Link &amp;#34;&lt;/span&gt;, item.link)
1158&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; print(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;Summary &amp;#34;&lt;/span&gt;, item.summary)
1159&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;end&lt;/span&gt;
1160&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;else&lt;/span&gt;
1161&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; print(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;! Request failed. Status:&amp;#34;&lt;/span&gt;, status)
1162&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;end&lt;/span&gt;
1163&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded>
1164 </item>
1165
1166
1167
1168 <item>
1169 <title>Extend Lua with custom C functions using Clang</title>
1170 <link>https://mitjafelicijan.com/extend-lua-with-custom-c.html</link>
1171 <pubDate>Tue, 23 May 2023 12:00:00 &#43;0200</pubDate>
1172 <guid>https://mitjafelicijan.com/extend-lua-with-custom-c.html</guid>
1173 <description>Here is a boilerplate for extending Lua with custom C functions.</description>
1174 <content:encoded>&lt;p&gt;Here is a boilerplate for extending Lua with custom C functions. This requires
1175Clang and Lua 5.1 to be installed. GCC can be used instead of Clang, but the
1176Makefile will need to be modified.&lt;/p&gt;
1177&lt;ul&gt;
1178&lt;li&gt;
1179&lt;p&gt;nativefunc.c&lt;/p&gt;
1180&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;&amp;lt;lua.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#00f&#34;&gt;
1181&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;#include&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;&amp;lt;lauxlib.h&amp;gt;&lt;/span&gt;&lt;span style=&#34;color:#00f&#34;&gt;
1182&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;&lt;/span&gt;
1183&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#2b91af&#34;&gt;int&lt;/span&gt; l_mult50(lua_State *L) {
1184&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#2b91af&#34;&gt;double&lt;/span&gt; number = luaL_checknumber(L, 1);
1185&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; lua_pushnumber(L, number * 50);
1186&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;return&lt;/span&gt; 1;
1187&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
1188&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1189&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#2b91af&#34;&gt;int&lt;/span&gt; luaopen_nativefunc(lua_State *L) {
1190&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;static&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;const&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;struct&lt;/span&gt; luaL_Reg nativeFuncLib[] = {{&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;mult50&amp;#34;&lt;/span&gt;, l_mult50}, {NULL, NULL}};
1191&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1192&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; luaL_register(L, &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;nativelib&amp;#34;&lt;/span&gt;, nativeFuncLib);
1193&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;return&lt;/span&gt; 1;
1194&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
1195&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
1196&lt;li&gt;
1197&lt;p&gt;main.lua&lt;/p&gt;
1198&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;require &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;nativefunc&amp;#34;&lt;/span&gt;
1199&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;print(nativelib.mult50(50))
1200&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
1201&lt;li&gt;
1202&lt;p&gt;Makefile&lt;/p&gt;
1203&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CC = clang
1204&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;CFLAGS =
1205&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;INCLUDES = &lt;span style=&#34;color:#a31515&#34;&gt;`&lt;/span&gt;pkg-config lua5.1 --cflags-only-I&lt;span style=&#34;color:#a31515&#34;&gt;`&lt;/span&gt;
1206&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1207&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;all:
1208&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;$(&lt;/span&gt;CC&lt;span style=&#34;color:#00f&#34;&gt;)&lt;/span&gt; -shared -o nativefunc.so -fPIC nativefunc.c &lt;span style=&#34;color:#00f&#34;&gt;$(&lt;/span&gt;CFLAGS&lt;span style=&#34;color:#00f&#34;&gt;)&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;$(&lt;/span&gt;INCLUDES&lt;span style=&#34;color:#00f&#34;&gt;)&lt;/span&gt;
1209&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1210&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;clean:
1211&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; rm *.so
1212&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
1213&lt;/ul&gt;
1214</content:encoded>
1215 </item>
1216
1217
1218
1219 <item>
1220 <title>Execute not blocking async shell command in C#</title>
1221 <link>https://mitjafelicijan.com/non-blocking-shell-exec-csharp.html</link>
1222 <pubDate>Mon, 22 May 2023 12:00:00 &#43;0200</pubDate>
1223 <guid>https://mitjafelicijan.com/non-blocking-shell-exec-csharp.html</guid>
1224 <description>Execute a shell command in async in C# while not blocking the UI thread.</description>
1225 <content:encoded>&lt;p&gt;Execute a shell command in async in C# while not blocking the UI thread.&lt;/p&gt;
1226&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;async&lt;/span&gt; Task executeCopyCommand()
1227&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
1228&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;await&lt;/span&gt; Task.Run(() =&amp;gt;
1229&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {
1230&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#2b91af&#34;&gt;var&lt;/span&gt; processStartInfo = &lt;span style=&#34;color:#00f&#34;&gt;new&lt;/span&gt; ProcessStartInfo(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;cmd&amp;#34;&lt;/span&gt;, &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;/c dir&amp;#34;&lt;/span&gt;)
1231&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {
1232&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; RedirectStandardOutput = &lt;span style=&#34;color:#00f&#34;&gt;true&lt;/span&gt;,
1233&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; UseShellExecute = &lt;span style=&#34;color:#00f&#34;&gt;false&lt;/span&gt;,
1234&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; CreateNoWindow = &lt;span style=&#34;color:#00f&#34;&gt;true&lt;/span&gt;
1235&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; };
1236&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1237&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#2b91af&#34;&gt;var&lt;/span&gt; process = &lt;span style=&#34;color:#00f&#34;&gt;new&lt;/span&gt; Process
1238&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; {
1239&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; StartInfo = processStartInfo
1240&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; };
1241&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1242&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; process.Start();
1243&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; process.WaitForExit();
1244&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; });
1245&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
1246&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Make sure that &lt;code&gt;async&lt;/code&gt; is present in the function definition and &lt;code&gt;await&lt;/code&gt; is used
1247in the method that calls &lt;code&gt;executeCopyCommand()&lt;/code&gt;.&lt;/p&gt;
1248&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#00f&#34;&gt;private&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;async&lt;/span&gt; &lt;span style=&#34;color:#00f&#34;&gt;void&lt;/span&gt; button_Click(&lt;span style=&#34;color:#2b91af&#34;&gt;object&lt;/span&gt; sender, EventArgs e)
1249&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{
1250&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt; &lt;span style=&#34;color:#00f&#34;&gt;await&lt;/span&gt; executeCopyCommand();
1251&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;}
1252&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded>
1253 </item>
1254
1255
1256
1257 <item>
1258 <title>Change permissions of matching files recursively</title>
1259 <link>https://mitjafelicijan.com/mass-set-permission.html</link>
1260 <pubDate>Tue, 16 May 2023 12:00:00 &#43;0200</pubDate>
1261 <guid>https://mitjafelicijan.com/mass-set-permission.html</guid>
1262 <description>Replace *.</description>
1263 <content:encoded>&lt;p&gt;Replace &lt;code&gt;*.xml&lt;/code&gt; with your pattern. This will remove executable bit from all
1264files matching the pattern. Change &lt;code&gt;&#43;&lt;/code&gt; to &lt;code&gt;-&lt;/code&gt; to add executable bit.&lt;/p&gt;
1265&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;find . -type f -name &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;*.xml&amp;#34;&lt;/span&gt; -exec chmod -x {} &#43;
1266&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded>
1267 </item>
1268
1269
1270
1271
1272
1273 <item>
1274 <title>Previews how man page written in Troff will look like</title>
1275 <link>https://mitjafelicijan.com/preview-troff-man-pages.html</link>
1276 <pubDate>Mon, 15 May 2023 12:00:00 &#43;0200</pubDate>
1277 <guid>https://mitjafelicijan.com/preview-troff-man-pages.html</guid>
1278 <description>Troff is used to write man pages and it is difficult to read it so this willpreview how it will look like when it is rendered.</description>
1279 <content:encoded>&lt;p&gt;Troff is used to write man pages and it is difficult to read it so this will
1280preview how it will look like when it is rendered.&lt;/p&gt;
1281&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# On Linux system.&lt;/span&gt;
1282&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;groff -man -Tascii filename
1283&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1284&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# On Plan9 system.&lt;/span&gt;
1285&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;man 1 filename
1286&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded>
1287 </item>
1288
1289
1290
1291 <item>
1292 <title>Convert all MKV files into other formats</title>
1293 <link>https://mitjafelicijan.com/convert-mkv.html</link>
1294 <pubDate>Sun, 14 May 2023 12:00:00 &#43;0200</pubDate>
1295 <guid>https://mitjafelicijan.com/convert-mkv.html</guid>
1296 <description>You will need ffmpeg installed on your system.</description>
1297 <content:encoded>&lt;p&gt;You will need &lt;code&gt;ffmpeg&lt;/code&gt; installed on your system. This will convert all MKV files
1298into WebM format.&lt;/p&gt;
1299&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# Convert all MKV files into WebM format.&lt;/span&gt;
1300&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;find ./ -name &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;*.mkv&amp;#39;&lt;/span&gt; -exec bash -c &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;ffmpeg -i &amp;#34;$0&amp;#34; -vcodec libvpx -acodec libvorbis -cpu-used 5 -threads 8 &amp;#34;${0%%.mp4}.webm&amp;#34;&amp;#39;&lt;/span&gt; {} &lt;span style=&#34;color:#a31515&#34;&gt;\;&lt;/span&gt;
1301&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# Convert all MKV files into MP4 format.&lt;/span&gt;
1302&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;find ./ -name &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;*.mkv&amp;#39;&lt;/span&gt; -exec bash -c &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;ffmpeg -i &amp;#34;$0&amp;#34; c:a copy -c:v copy -cpu-used 5 -threads 8 &amp;#34;${0%%.mp4}.mp4&amp;#34;&amp;#39;&lt;/span&gt; {} &lt;span style=&#34;color:#a31515&#34;&gt;\;&lt;/span&gt;
1303&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded>
1304 </item>
1305
1306
1307
1308 <item>
1309 <title>Download list of YouTube files</title>
1310 <link>https://mitjafelicijan.com/download-youtube-videos.html</link>
1311 <pubDate>Sat, 13 May 2023 12:00:00 &#43;0200</pubDate>
1312 <guid>https://mitjafelicijan.com/download-youtube-videos.html</guid>
1313 <description>If you need to download a list of YouTube videos and don&amp;#39;t want to download theactual YouTube list (which yt-dlp supports), you can use the following method.</description>
1314 <content:encoded>&lt;p&gt;If you need to download a list of YouTube videos and don&#39;t want to download the
1315actual YouTube list (which &lt;code&gt;yt-dlp&lt;/code&gt; supports), you can use the following method.&lt;/p&gt;
1316&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;// Used to get list of raw URL&amp;#39;s from YouTube&amp;#39;s video tab&amp;#39;.
1317&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;// Copy them into videos.txt.
1318&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;&lt;/span&gt;document.querySelectorAll(&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;#contents a.ytd-thumbnail.style-scope.ytd-thumbnail&amp;#39;&lt;/span&gt;).forEach(el =&amp;gt; console.log(el.href))
1319&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Download and install &lt;a href=&#34;https://github.com/yt-dlp/yt-dlp&#34;&gt;https://github.com/yt-dlp/yt-dlp&lt;/a&gt;.&lt;/p&gt;
1320&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# This will download all videos in videos.txt.&lt;/span&gt;
1321&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;yt-dlp --batch-file videos.txt -N &lt;span style=&#34;color:#a31515&#34;&gt;`&lt;/span&gt;nproc&lt;span style=&#34;color:#a31515&#34;&gt;`&lt;/span&gt; -f webm
1322&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded>
1323 </item>
1324
1325
1326
1327 <item>
1328 <title>Install Plan9port on Linux</title>
1329 <link>https://mitjafelicijan.com/install-plan9port-linux.html</link>
1330 <pubDate>Fri, 12 May 2023 12:00:00 &#43;0200</pubDate>
1331 <guid>https://mitjafelicijan.com/install-plan9port-linux.html</guid>
1332 <description>Install Plan9port on Linux.</description>
1333 <content:encoded>&lt;p&gt;Install Plan9port on Linux. This applies to
1334&lt;a href=&#34;https://9fans.github.io/plan9port/&#34;&gt;Plan9port&lt;/a&gt;. This is a port of many Plan 9
1335programs to Unix-like operating systems. Useful for programs like &lt;code&gt;9term&lt;/code&gt; and
1336&lt;code&gt;rc&lt;/code&gt;.&lt;/p&gt;
1337&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo apt-get install gcc libx11-dev libxt-dev libxext-dev libfontconfig1-dev
1338&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git clone https://github.com/9fans/plan9port $HOME/plan9
1339&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cd $HOME/plan9/plan9port
1340&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;./INSTALL -r $HOME/plan9
1341&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded>
1342 </item>
1343
1344
1345
1346 <item>
1347 <title>Fix bootloader not being written in Plan9</title>
1348 <link>https://mitjafelicijan.com/fix-plan9-bootloader.html</link>
1349 <pubDate>Thu, 11 May 2023 12:00:00 &#43;0200</pubDate>
1350 <guid>https://mitjafelicijan.com/fix-plan9-bootloader.html</guid>
1351 <description>If the bootloader is not being written to a disk when installing 9front on realharware try clearing first sector of the disk with the following command.</description>
1352 <content:encoded>&lt;p&gt;If the bootloader is not being written to a disk when installing 9front on real
1353harware try clearing first sector of the disk with the following command.&lt;/p&gt;
1354&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;dd &lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt;=/dev/zero of=/dev/sdX bs=512 count=1
1355&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1356&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# If command above doesn&amp;#39;t work try this one, wait couple of seconds and&lt;/span&gt;
1357&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# press delete key to stop the command.&lt;/span&gt;
1358&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cat &amp;lt;/dev/zero &amp;gt;/dev/sd*/data
1359&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded>
1360 </item>
1361
1362
1363
1364 <item>
1365 <title>Take a screenshot in Plan9</title>
1366 <link>https://mitjafelicijan.com/plan9-screenshot.html</link>
1367 <pubDate>Wed, 10 May 2023 12:00:00 &#43;0200</pubDate>
1368 <guid>https://mitjafelicijan.com/plan9-screenshot.html</guid>
1369 <description>Take a screenshot in Plan9.</description>
1370 <content:encoded>&lt;p&gt;Take a screenshot in Plan9. This applies to &lt;a href=&#34;https://9p.io/plan9/&#34;&gt;Plan9&lt;/a&gt; and
1371&lt;a href=&#34;https://9front.org/&#34;&gt;9front&lt;/a&gt;. This will take a screenshot of the screen and
1372output it to &lt;code&gt;/dev/screen&lt;/code&gt;. You can then use &lt;code&gt;topng&lt;/code&gt; to convert it to a png
1373image.&lt;/p&gt;
1374&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# Instant screenshot.&lt;/span&gt;
1375&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;cat /dev/screen | topng &amp;gt; screen.png
1376&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1377&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# Delayed screenshot (5 seconds).&lt;/span&gt;
1378&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sleep 5; cat /dev/screen | topng &amp;gt; screen.png
1379&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded>
1380 </item>
1381
1382
1383
1384 <item>
1385 <title>#cat-v on weechat configuration</title>
1386 <link>https://mitjafelicijan.com/catv-weechat-config.html</link>
1387 <pubDate>Tue, 09 May 2023 12:00:00 &#43;0200</pubDate>
1388 <guid>https://mitjafelicijan.com/catv-weechat-config.html</guid>
1389 <description>Set up weechat to connect to #cat-v on oftc.</description>
1390 <content:encoded>&lt;p&gt;Set up weechat to connect to #cat-v on oftc. This applies to
1391&lt;a href=&#34;https://weechat.org/&#34;&gt;weechat&lt;/a&gt; but should be similar for other irc clients.&lt;/p&gt;
1392&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# Install weechat and launch it and execute the following commands.&lt;/span&gt;
1393&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1394&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/server add oftc irc.oftc.net -tls
1395&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/set irc.server.oftc.autoconnect on
1396&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/set irc.server.oftc.autojoin &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;#cat-v&amp;#34;&lt;/span&gt;
1397&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;/set irc.server.oftc.nicks &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;nick1,nick2,nick3&amp;#34;&lt;/span&gt;
1398&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded>
1399 </item>
1400
1401
1402
1403 <item>
1404 <title>Write ISO to USB Key</title>
1405 <link>https://mitjafelicijan.com/write-iso-usb.html</link>
1406 <pubDate>Mon, 08 May 2023 12:00:00 &#43;0200</pubDate>
1407 <guid>https://mitjafelicijan.com/write-iso-usb.html</guid>
1408 <description>Write ISO to USB key.</description>
1409 <content:encoded>&lt;p&gt;Write ISO to USB key. Nothing fancy here.&lt;/p&gt;
1410&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;sudo dd &lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt;=iso_file.iso of=/dev/sdX bs=4M status=progress conv=fdatasync
1411&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded>
1412 </item>
1413
1414
1415
1416 <item>
1417 <title>Mount Plan9 over network</title>
1418 <link>https://mitjafelicijan.com/mount-plan9-over-network.html</link>
1419 <pubDate>Sun, 07 May 2023 12:00:00 &#43;0200</pubDate>
1420 <guid>https://mitjafelicijan.com/mount-plan9-over-network.html</guid>
1421 <description>First install libfuse with sudo apt install libfuse-dev.</description>
1422 <content:encoded>&lt;ul&gt;
1423&lt;li&gt;First install libfuse with sudo apt install libfuse-dev.&lt;/li&gt;
1424&lt;li&gt;Then clone &lt;a href=&#34;https://github.com/ftrvxmtrx/9pfs&#34;&gt;https://github.com/ftrvxmtrx/9pfs&lt;/a&gt; and compile it with make.&lt;/li&gt;
1425&lt;li&gt;Copy 9pfs to your path.&lt;/li&gt;
1426&lt;/ul&gt;
1427&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# On Plan9 side&lt;/span&gt;
1428&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;ip/ipconfig &lt;span style=&#34;color:#008000&#34;&gt;# enables network&lt;/span&gt;
1429&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;aux/listen1 -tv tcp!*!9999 /bin/exportfs -r tmp &lt;span style=&#34;color:#008000&#34;&gt;# export tmp folder&lt;/span&gt;
1430&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1431&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# On Linux side&lt;/span&gt;
1432&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;9pfs 172.18.0.1 -p 9999 local_folder &lt;span style=&#34;color:#008000&#34;&gt;# mount&lt;/span&gt;
1433&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;umount local_folder &lt;span style=&#34;color:#008000&#34;&gt;# unmount&lt;/span&gt;
1434&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded>
1435 </item>
1436
1437
1438
1439 <item>
1440 <title>Push to multiple origins at once in Git</title>
1441 <link>https://mitjafelicijan.com/git-push-multiple-origins.html</link>
1442 <pubDate>Sat, 06 May 2023 12:00:00 &#43;0200</pubDate>
1443 <guid>https://mitjafelicijan.com/git-push-multiple-origins.html</guid>
1444 <description>Sometimes you want to push to multiple origins at once.</description>
1445 <content:encoded>&lt;p&gt;Sometimes you want to push to multiple origins at once. This is useful if you
1446have a mirror of your repository on another server. You can do this by adding
1447multiple push urls to your git config. This is a shorthand for command above.&lt;/p&gt;
1448&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;git config --global alias.pushall &lt;span style=&#34;color:#a31515&#34;&gt;&amp;#39;!sh -c &amp;#34;git remote | xargs -L1 git push --all&amp;#34;&amp;#39;&lt;/span&gt;
1449&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded>
1450 </item>
1451
1452
1453
1454 <item>
1455 <title>Run 9front in Qemu</title>
1456 <link>https://mitjafelicijan.com/run-9front-in-qemu.html</link>
1457 <pubDate>Fri, 05 May 2023 12:00:00 &#43;0200</pubDate>
1458 <guid>https://mitjafelicijan.com/run-9front-in-qemu.html</guid>
1459 <description>Run 9front in Qemu.</description>
1460 <content:encoded>&lt;p&gt;Run 9front in Qemu. This applies to &lt;a href=&#34;https://9p.io/plan9/&#34;&gt;Plan9&lt;/a&gt; and
1461&lt;a href=&#34;https://9front.org/&#34;&gt;9front&lt;/a&gt;.&lt;/p&gt;
1462&lt;p&gt;Download from here &lt;a href=&#34;http://9front.org/iso/&#34;&gt;http://9front.org/iso/&lt;/a&gt;.&lt;/p&gt;
1463&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# Create a qcow2 image.&lt;/span&gt;
1464&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;qemu-img create -f qcow2 $HOME/VM/9front.qcow2.img 30G
1465&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1466&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#008000&#34;&gt;# Run the VM.&lt;/span&gt;
1467&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;qemu-system-x86_64 -cpu host -enable-kvm -m 1024 &lt;span style=&#34;color:#a31515&#34;&gt;\
1468&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&lt;/span&gt; -net nic,model=virtio,macaddr=52:54:00:00:EE:03 -net user &lt;span style=&#34;color:#a31515&#34;&gt;\
1469&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&lt;/span&gt; -device virtio-scsi-pci,id=scsi &lt;span style=&#34;color:#a31515&#34;&gt;\
1470&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&lt;/span&gt; -drive &lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt;=none,id=vd0,file=$HOME/VM/9front.qcow2.img &lt;span style=&#34;color:#a31515&#34;&gt;\
1471&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&lt;/span&gt; -device scsi-hd,drive=vd0 &lt;span style=&#34;color:#a31515&#34;&gt;\
1472&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&lt;/span&gt; -drive &lt;span style=&#34;color:#00f&#34;&gt;if&lt;/span&gt;=none,id=vd1,file=$HOME/VM/ISO/9front.386.iso &lt;span style=&#34;color:#a31515&#34;&gt;\
1473&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&lt;span style=&#34;color:#a31515&#34;&gt;&lt;/span&gt; -device scsi-cd,drive=vd1,bootindex=0
1474&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded>
1475 </item>
1476
1477
1478
1479 <item>
1480 <title>Cache busting in Hugo</title>
1481 <link>https://mitjafelicijan.com/cachebusting-in-hugo.html</link>
1482 <pubDate>Mon, 01 May 2023 12:00:00 &#43;0200</pubDate>
1483 <guid>https://mitjafelicijan.com/cachebusting-in-hugo.html</guid>
1484 <description>{{ $cachebuster := delimit (shuffle (split (md5 &amp;#34;6fab11c6669976d759d2992eff1dd5be&amp;#34;) &amp;#34;&amp;#34; )) &amp;#34;&amp;#34; }}&amp;lt;link rel=&amp;#34;stylesheet&amp;#34; href=&amp;#34;/style.</description>
1485 <content:encoded>&lt;pre tabindex=&#34;0&#34; style=&#34;background-color:#fff;&#34;&gt;&lt;code&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;{{ $cachebuster := delimit (shuffle (split (md5 &amp;#34;6fab11c6669976d759d2992eff1dd5be&amp;#34;) &amp;#34;&amp;#34; )) &amp;#34;&amp;#34; }}
1486&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;
1487&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&amp;lt;link rel=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;stylesheet&amp;#34;&lt;/span&gt; href=&lt;span style=&#34;color:#a31515&#34;&gt;&amp;#34;/style.css?v={{ $cachebuster }}&amp;#34;&lt;/span&gt;&amp;gt;
1488&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;This &lt;code&gt;6fab11c6669976d759d2992eff1dd5be&lt;/code&gt; can be random string you generate use.
1489You can use whatever you want.&lt;/p&gt;
1490</content:encoded>
1491 </item>
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568 </channel>
1569</rss>
diff --git a/public/online-radio-streaming-with-mpv-from-terminal.html b/public/online-radio-streaming-with-mpv-from-terminal.html
deleted file mode 100755
index c49b075..0000000
--- a/public/online-radio-streaming-with-mpv-from-terminal.html
+++ /dev/null
@@ -1,47 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Online radio streaming with MPV from terminal</title><meta name=description content="Recently I have been using my Thinkpad x220 more and there are some constraintsI have faced with it."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Online radio streaming with MPV from terminal</h1><p><cap>note</cap>, Jul 10, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>Recently I have been using my Thinkpad x220 more and there are some constraints
10I have faced with it. CPU is not as powerful as on my main machine and I really
11want to listen to some music while using the machine. Browsers really are bloat.<p>Check out this site <a href=https://streamurl.link/>https://streamurl.link/</a> and copy the stream url and then do
12<code>mpv streamlink</code>.</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
13a lock on a Linux NFS server, which turned
14out to be specific to NFS v3 (which I really should have seen coming,
15since it involved NLM and lockd). Finding the NFS v4 client that
16owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
17and Bradley Kuhn, are interacting on the OSI's license-discuss
18list where the're doing
19bad computer history and insisting that a guy Larry Rosen
20coincidentally interviewed for a book years ago is clearly the origin of
21somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
22i2c, plan9
23Another month, another file system.
24Well, if you can’t fix it in software, fix it in hardware (looking at
25you, bme680, we’re not
26done yet). The show must go on, as they say, and I would like my
27experiments to go on.
28So a “new” addition to the environmental sensor family connected to
29the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
30this mortal coil, we are endowed with self-awareness, agency, and free will.
31Each of the 8 billion members of this human race represents a unique person, a
32unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
33My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
341.0 has been released:
35wifi_da-1.0.sit
36(StuffIt 3 archive)
37SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
38This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
39classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
40In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
41Design Goals
42I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
43at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
44catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
45specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
46 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
47 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/parse-rss-with-lua.html b/public/parse-rss-with-lua.html
deleted file mode 100755
index eee2665..0000000
--- a/public/parse-rss-with-lua.html
+++ /dev/null
@@ -1,68 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Parse RSS feeds with Lua</title><meta name=description content="Example of parsing RSS feeds with Lua."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Parse RSS feeds with Lua</h1><p><cap>note</cap>, May 23, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>Example of parsing RSS feeds with Lua. Before running the script install:<ul><li>feedparser with <code>luarocks install feedparser</code><li>luasocket with <code>luarocks install luasocket</code></ul><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>local</span> http = require(<span style=color:#a31515>&#34;socket.http&#34;</span>)
10</span></span><span style=display:flex><span><span style=color:#00f>local</span> feedparser = require(<span style=color:#a31515>&#34;feedparser&#34;</span>)
11</span></span><span style=display:flex><span>
12</span></span><span style=display:flex><span><span style=color:#00f>local</span> feed_url = <span style=color:#a31515>&#34;https://mitjafelicijan.com/index.xml&#34;</span>
13</span></span><span style=display:flex><span>
14</span></span><span style=display:flex><span><span style=color:#00f>local</span> response, status, _ = http.request(feed_url)
15</span></span><span style=display:flex><span><span style=color:#00f>if</span> status == 200 <span style=color:#00f>then</span>
16</span></span><span style=display:flex><span> <span style=color:#00f>local</span> parsed = feedparser.parse(response)
17</span></span><span style=display:flex><span>
18</span></span><span style=display:flex><span> <span style=color:green>-- Print out feed details.</span>
19</span></span><span style=display:flex><span> print(<span style=color:#a31515>&#34;&gt; Title &#34;</span>, parsed.feed.title)
20</span></span><span style=display:flex><span> print(<span style=color:#a31515>&#34;&gt; Author &#34;</span>, parsed.feed.author)
21</span></span><span style=display:flex><span> print(<span style=color:#a31515>&#34;&gt; ID &#34;</span>, parsed.feed.id)
22</span></span><span style=display:flex><span> print(<span style=color:#a31515>&#34;&gt; Entries &#34;</span>, #parsed.entries)
23</span></span><span style=display:flex><span>
24</span></span><span style=display:flex><span> <span style=color:#00f>for</span> _, item <span style=color:#00f>in</span> ipairs(parsed.entries) <span style=color:#00f>do</span>
25</span></span><span style=display:flex><span> print(<span style=color:#a31515>&#34;GUID &#34;</span>, item.guid)
26</span></span><span style=display:flex><span> print(<span style=color:#a31515>&#34;Title &#34;</span>, item.title)
27</span></span><span style=display:flex><span> print(<span style=color:#a31515>&#34;Link &#34;</span>, item.link)
28</span></span><span style=display:flex><span> print(<span style=color:#a31515>&#34;Summary &#34;</span>, item.summary)
29</span></span><span style=display:flex><span> <span style=color:#00f>end</span>
30</span></span><span style=display:flex><span><span style=color:#00f>else</span>
31</span></span><span style=display:flex><span> print(<span style=color:#a31515>&#34;! Request failed. Status:&#34;</span>, status)
32</span></span><span style=display:flex><span><span style=color:#00f>end</span>
33</span></span></code></pre></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
34a lock on a Linux NFS server, which turned
35out to be specific to NFS v3 (which I really should have seen coming,
36since it involved NLM and lockd). Finding the NFS v4 client that
37owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
38and Bradley Kuhn, are interacting on the OSI's license-discuss
39list where the're doing
40bad computer history and insisting that a guy Larry Rosen
41coincidentally interviewed for a book years ago is clearly the origin of
42somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
43i2c, plan9
44Another month, another file system.
45Well, if you can’t fix it in software, fix it in hardware (looking at
46you, bme680, we’re not
47done yet). The show must go on, as they say, and I would like my
48experiments to go on.
49So a “new” addition to the environmental sensor family connected to
50the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
51this mortal coil, we are endowed with self-awareness, agency, and free will.
52Each of the 8 billion members of this human race represents a unique person, a
53unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
54My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
551.0 has been released:
56wifi_da-1.0.sit
57(StuffIt 3 archive)
58SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
59This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
60classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
61In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
62Design Goals
63I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
64at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
65catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
66specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
67 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
68 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/plan9-screenshot.html b/public/plan9-screenshot.html
deleted file mode 100755
index 4c4ceda..0000000
--- a/public/plan9-screenshot.html
+++ /dev/null
@@ -1,52 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Take a screenshot in Plan9</title><meta name=description content="Take a screenshot in Plan9."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Take a screenshot in Plan9</h1><p><cap>note</cap>, May 10, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>Take a screenshot in Plan9. This applies to <a href=https://9p.io/plan9/>Plan9</a> and
10<a href=https://9front.org/>9front</a>. This will take a screenshot of the screen and
11output it to <code>/dev/screen</code>. You can then use <code>topng</code> to convert it to a png
12image.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># Instant screenshot.</span>
13</span></span><span style=display:flex><span>cat /dev/screen | topng &gt; screen.png
14</span></span><span style=display:flex><span>
15</span></span><span style=display:flex><span><span style=color:green># Delayed screenshot (5 seconds).</span>
16</span></span><span style=display:flex><span>sleep 5; cat /dev/screen | topng &gt; screen.png
17</span></span></code></pre></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
18a lock on a Linux NFS server, which turned
19out to be specific to NFS v3 (which I really should have seen coming,
20since it involved NLM and lockd). Finding the NFS v4 client that
21owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
22and Bradley Kuhn, are interacting on the OSI's license-discuss
23list where the're doing
24bad computer history and insisting that a guy Larry Rosen
25coincidentally interviewed for a book years ago is clearly the origin of
26somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
27i2c, plan9
28Another month, another file system.
29Well, if you can’t fix it in software, fix it in hardware (looking at
30you, bme680, we’re not
31done yet). The show must go on, as they say, and I would like my
32experiments to go on.
33So a “new” addition to the environmental sensor family connected to
34the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
35this mortal coil, we are endowed with self-awareness, agency, and free will.
36Each of the 8 billion members of this human race represents a unique person, a
37unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
38My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
391.0 has been released:
40wifi_da-1.0.sit
41(StuffIt 3 archive)
42SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
43This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
44classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
45In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
46Design Goals
47I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
48at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
49catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
50specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
51 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
52 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/presentations-with-markdown.html b/public/presentations-with-markdown.html
deleted file mode 100755
index 3e0ebd9..0000000
--- a/public/presentations-with-markdown.html
+++ /dev/null
@@ -1,102 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Simple presentations with Markdown</title><meta name=description content="A simple way to make presentations without using desktop apps or using onlineservices is https://github."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Simple presentations with Markdown</h1><p><cap>note</cap>, Jun 21, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>A simple way to make presentations without using desktop apps or using online
10services is <a href=https://github.com/remarkjs/remark>https://github.com/remarkjs/remark</a>.<p>First create <code>index.html</code> and be sure you make changes to <code>config</code> variable.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>&lt;!DOCTYPE html&gt;</span>
11</span></span><span style=display:flex><span>&lt;html&gt;
12</span></span><span style=display:flex><span>
13</span></span><span style=display:flex><span>&lt;head&gt;
14</span></span><span style=display:flex><span> &lt;title&gt;&lt;/title&gt;
15</span></span><span style=display:flex><span> &lt;meta charset=<span style=color:#a31515>&#34;utf-8&#34;</span>&gt;
16</span></span><span style=display:flex><span> &lt;style&gt;
17</span></span><span style=display:flex><span> body {
18</span></span><span style=display:flex><span> <span style=color:#00f>font-family</span>: <span style=color:#a31515>&#39;SF Pro Display&#39;</span>;
19</span></span><span style=display:flex><span> }
20</span></span><span style=display:flex><span>
21</span></span><span style=display:flex><span> .<span style=color:#2b91af>remark-code</span>,
22</span></span><span style=display:flex><span> .<span style=color:#2b91af>remark-inline-code</span> {
23</span></span><span style=display:flex><span> <span style=color:#00f>font-family</span>: <span style=color:#a31515>&#39;SF Mono&#39;</span>;
24</span></span><span style=display:flex><span> <span style=color:#00f>font-size</span>: <span style=color:#00f>medium</span>;
25</span></span><span style=display:flex><span> <span style=color:#00f>background-color</span>: <span style=color:#00f>gainsboro</span>;
26</span></span><span style=display:flex><span> <span style=color:#00f>border-radius</span>: 5<span style=color:#2b91af>px</span>;
27</span></span><span style=display:flex><span> <span style=color:#00f>padding</span>: 0 5<span style=color:#2b91af>px</span>;
28</span></span><span style=display:flex><span> }
29</span></span><span style=display:flex><span> &lt;/style&gt;
30</span></span><span style=display:flex><span>&lt;/head&gt;
31</span></span><span style=display:flex><span>
32</span></span><span style=display:flex><span>&lt;body&gt;
33</span></span><span style=display:flex><span> &lt;textarea id=<span style=color:#a31515>&#34;source&#34;</span>&gt;&lt;/textarea&gt;
34</span></span><span style=display:flex><span> &lt;script src=<span style=color:#a31515>&#34;https://remarkjs.com/downloads/remark-latest.min.js&#34;</span>&gt;&lt;/script&gt;
35</span></span><span style=display:flex><span> &lt;script&gt;
36</span></span><span style=display:flex><span> <span style=color:#00f>const</span> config = {
37</span></span><span style=display:flex><span> title: <span style=color:#a31515>&#39;My presentation&#39;</span>,
38</span></span><span style=display:flex><span> file: <span style=color:#a31515>&#39;presentation.md&#39;</span>,
39</span></span><span style=display:flex><span> };
40</span></span><span style=display:flex><span>
41</span></span><span style=display:flex><span> document.title = config.title;
42</span></span><span style=display:flex><span> remark.create({ sourceUrl: config.file });
43</span></span><span style=display:flex><span> &lt;/script&gt;
44</span></span><span style=display:flex><span>&lt;/body&gt;
45</span></span><span style=display:flex><span>
46</span></span><span style=display:flex><span>&lt;/html&gt;
47</span></span></code></pre><p>Now the markdown file <code>presentation.md</code> with presenetation. <code>---</code> is used to
48separate slides. Other stuff is just pure markdown.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>class: center, middle
49</span></span><span style=display:flex><span>
50</span></span><span style=display:flex><span><span style=font-weight:700># Main title of the presentation
51</span></span></span><span style=display:flex><span><span style=font-weight:700></span>
52</span></span><span style=display:flex><span>---
53</span></span><span style=display:flex><span>
54</span></span><span style=display:flex><span><span style=font-weight:700># Fist slide
55</span></span></span><span style=display:flex><span><span style=font-weight:700></span>
56</span></span><span style=display:flex><span>Eveniet mollitia nemo architecto rerum aut iure iste. Sit nihil nobis libero iusto fugit nam laudantium ut. Dignissimos corrupti laudantium nisi.
57</span></span><span style=display:flex><span>
58</span></span><span style=display:flex><span><span style=color:#00f>-</span> Lorem ipsum dolor sit amet, consectetur adipiscing elit.
59</span></span><span style=display:flex><span><span style=color:#00f>-</span> Integer aliquet mauris a felis fringilla, ut congue massa finibus.
60</span></span><span style=display:flex><span>
61</span></span><span style=display:flex><span>---
62</span></span><span style=display:flex><span>
63</span></span><span style=display:flex><span><span style=font-weight:700># Slide two
64</span></span></span><span style=display:flex><span><span style=font-weight:700></span>
65</span></span><span style=display:flex><span><span style=color:#00f>-</span> Lorem ipsum dolor sit amet, consectetur adipiscing elit.
66</span></span><span style=display:flex><span><span style=color:#00f>-</span> Vestibulum eget leo ac dolor venenatis pulvinar.
67</span></span></code></pre></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
68a lock on a Linux NFS server, which turned
69out to be specific to NFS v3 (which I really should have seen coming,
70since it involved NLM and lockd). Finding the NFS v4 client that
71owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
72and Bradley Kuhn, are interacting on the OSI's license-discuss
73list where the're doing
74bad computer history and insisting that a guy Larry Rosen
75coincidentally interviewed for a book years ago is clearly the origin of
76somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
77i2c, plan9
78Another month, another file system.
79Well, if you can’t fix it in software, fix it in hardware (looking at
80you, bme680, we’re not
81done yet). The show must go on, as they say, and I would like my
82experiments to go on.
83So a “new” addition to the environmental sensor family connected to
84the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
85this mortal coil, we are endowed with self-awareness, agency, and free will.
86Each of the 8 billion members of this human race represents a unique person, a
87unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
88My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
891.0 has been released:
90wifi_da-1.0.sit
91(StuffIt 3 archive)
92SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
93This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
94classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
95In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
96Design Goals
97I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
98at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
99catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
100specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
101 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
102 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/preview-troff-man-pages.html b/public/preview-troff-man-pages.html
deleted file mode 100755
index a2b7bd7..0000000
--- a/public/preview-troff-man-pages.html
+++ /dev/null
@@ -1,50 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Previews how man page written in Troff will look like</title><meta name=description content="Troff is used to write man pages and it is difficult to read it so this willpreview how it will look like when it is rendered."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Previews how man page written in Troff will look like</h1><p><cap>note</cap>, May 15, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>Troff is used to write man pages and it is difficult to read it so this will
10preview how it will look like when it is rendered.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># On Linux system.</span>
11</span></span><span style=display:flex><span>groff -man -Tascii filename
12</span></span><span style=display:flex><span>
13</span></span><span style=display:flex><span><span style=color:green># On Plan9 system.</span>
14</span></span><span style=display:flex><span>man 1 filename
15</span></span></code></pre></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
16a lock on a Linux NFS server, which turned
17out to be specific to NFS v3 (which I really should have seen coming,
18since it involved NLM and lockd). Finding the NFS v4 client that
19owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
20and Bradley Kuhn, are interacting on the OSI's license-discuss
21list where the're doing
22bad computer history and insisting that a guy Larry Rosen
23coincidentally interviewed for a book years ago is clearly the origin of
24somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
25i2c, plan9
26Another month, another file system.
27Well, if you can’t fix it in software, fix it in hardware (looking at
28you, bme680, we’re not
29done yet). The show must go on, as they say, and I would like my
30experiments to go on.
31So a “new” addition to the environmental sensor family connected to
32the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
33this mortal coil, we are endowed with self-awareness, agency, and free will.
34Each of the 8 billion members of this human race represents a unique person, a
35unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
36My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
371.0 has been released:
38wifi_da-1.0.sit
39(StuffIt 3 archive)
40SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
41This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
42classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
43In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
44Design Goals
45I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
46at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
47catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
48specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
49 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
50 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/profiling-python-web-applications-with-visual-tools.html b/public/profiling-python-web-applications-with-visual-tools.html
deleted file mode 100755
index 6e3aa6c..0000000
--- a/public/profiling-python-web-applications-with-visual-tools.html
+++ /dev/null
@@ -1,176 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Profiling Python web applications with visual tools</title><meta name=description content="I have been profiling my software with KCachegrind for a long time now and I wasmissing this option when I am developing API&amp;#39;s or other web services."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Profiling Python web applications with visual tools</h1><p><cap>post</cap>, Apr 21, 2017 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>I have been profiling my software with KCachegrind for a long time now and I was
10missing this option when I am developing API's or other web services. I always
11knew that this is possible but never really took the time and dive into it.<p>Before we begin there are some requirements. We will need to:<ul><li>implement <a href=https://docs.python.org/2/library/profile.html#module-cProfile>cProfile</a> into our web app,<li>convert output to <a href=http://valgrind.org/docs/manual/cl-manual.html>callgrind</a> format with <a href=https://pypi.python.org/pypi/pyprof2calltree/>pyprof2calltree</a>,<li>visualize data with <a href=http://kcachegrind.sourceforge.net/html/Home.html>KCachegrind</a> or <a href=http://www.profilingviewer.com/>Profiling Viewer</a>.</ul><p>If you are using MacOS you should check out <a href=http://www.profilingviewer.com/>Profiling
12Viewer</a> or
13<a href=http://www.maccallgrind.com/>MacCallGrind</a>.<figure><img src=/posts/python-profiling/kcachegrind.png alt=KCachegrind></figure><p>We will be dividing this post into two main categories:<ul><li>writing simple web-service,<li>visualize profile of this web-service.</ul><h2 id=simple-web-service>Simple web-service</h2><p>Let's use virtualenv so we won't pollute our base system. If you don't have
14virtualenv installed on your system you can install it with pip command.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># let&#39;s install virtualenv globally</span>
15</span></span><span style=display:flex><span>$ sudo pip install virtualenv
16</span></span><span style=display:flex><span>
17</span></span><span style=display:flex><span><span style=color:green># let&#39;s also install pyprof2calltree globally</span>
18</span></span><span style=display:flex><span>$ sudo pip install pyprof2calltree
19</span></span><span style=display:flex><span>
20</span></span><span style=display:flex><span><span style=color:green># now we create project</span>
21</span></span><span style=display:flex><span>$ mkdir demo-project
22</span></span><span style=display:flex><span>$ cd demo-project/
23</span></span><span style=display:flex><span>
24</span></span><span style=display:flex><span><span style=color:green># now let&#39;s create folder where we will store profiles</span>
25</span></span><span style=display:flex><span>$ mkdir prof
26</span></span><span style=display:flex><span>
27</span></span><span style=display:flex><span><span style=color:green># now we create empty virtualenv in venv/ folder</span>
28</span></span><span style=display:flex><span>$ virtualenv --no-site-packages venv
29</span></span><span style=display:flex><span>
30</span></span><span style=display:flex><span><span style=color:green># we now need to activate virtualenv</span>
31</span></span><span style=display:flex><span>$ source venv/bin/activate
32</span></span><span style=display:flex><span>
33</span></span><span style=display:flex><span><span style=color:green># you can check if virtualenv was correctly initialized by</span>
34</span></span><span style=display:flex><span><span style=color:green># checking where your python interpreter is located</span>
35</span></span><span style=display:flex><span><span style=color:green># if command bellow points to your created directory and not some</span>
36</span></span><span style=display:flex><span><span style=color:green># system dir like /usr/bin/python then everything is fine</span>
37</span></span><span style=display:flex><span>$ which python
38</span></span><span style=display:flex><span>
39</span></span><span style=display:flex><span><span style=color:green># we can check now if all is good ➜ if ok couple of</span>
40</span></span><span style=display:flex><span><span style=color:green># lines will be displayed</span>
41</span></span><span style=display:flex><span>$ pip freeze
42</span></span><span style=display:flex><span><span style=color:green># appdirs==1.4.3</span>
43</span></span><span style=display:flex><span><span style=color:green># packaging==16.8</span>
44</span></span><span style=display:flex><span><span style=color:green># pyparsing==2.2.0</span>
45</span></span><span style=display:flex><span><span style=color:green># six==1.10.0</span>
46</span></span><span style=display:flex><span>
47</span></span><span style=display:flex><span><span style=color:green># now we are ready to install bottlepy ➜ web micro-framework</span>
48</span></span><span style=display:flex><span>$ pip install bottle
49</span></span><span style=display:flex><span>
50</span></span><span style=display:flex><span><span style=color:green># you can deactivate virtualenv but you will then go</span>
51</span></span><span style=display:flex><span><span style=color:green># under system domain ➜ for now don&#39;t deactivate</span>
52</span></span><span style=display:flex><span>$ deactivate
53</span></span></code></pre><p>We are now ready to write simple web service. Let's create file app.py and paste
54code bellow in this newly created file.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># -*- coding: utf-8 -*-</span>
55</span></span><span style=display:flex><span>
56</span></span><span style=display:flex><span><span style=color:#00f>import</span> bottle
57</span></span><span style=display:flex><span><span style=color:#00f>import</span> random
58</span></span><span style=display:flex><span><span style=color:#00f>import</span> cProfile
59</span></span><span style=display:flex><span>
60</span></span><span style=display:flex><span>app = bottle.Bottle()
61</span></span><span style=display:flex><span>
62</span></span><span style=display:flex><span><span style=color:green># this function is a decorator and encapsulates function</span>
63</span></span><span style=display:flex><span><span style=color:green># and performs profiling and then saves it to subfolder</span>
64</span></span><span style=display:flex><span><span style=color:green># prof/function-name.prof</span>
65</span></span><span style=display:flex><span><span style=color:green># in our example only awesome_random_number function will</span>
66</span></span><span style=display:flex><span><span style=color:green># be profiled because it has do_cprofile defined</span>
67</span></span><span style=display:flex><span><span style=color:#00f>def</span> do_cprofile(func):
68</span></span><span style=display:flex><span> <span style=color:#00f>def</span> profiled_func(*args, **kwargs):
69</span></span><span style=display:flex><span> profile = cProfile.Profile()
70</span></span><span style=display:flex><span> <span style=color:#00f>try</span>:
71</span></span><span style=display:flex><span> profile.enable()
72</span></span><span style=display:flex><span> result = func(*args, **kwargs)
73</span></span><span style=display:flex><span> profile.disable()
74</span></span><span style=display:flex><span> <span style=color:#00f>return</span> result
75</span></span><span style=display:flex><span> <span style=color:#00f>finally</span>:
76</span></span><span style=display:flex><span> profile.dump_stats(<span style=color:#a31515>&#34;prof/&#34;</span> + str(func.__name__) + <span style=color:#a31515>&#34;.prof&#34;</span>)
77</span></span><span style=display:flex><span> <span style=color:#00f>return</span> profiled_func
78</span></span><span style=display:flex><span>
79</span></span><span style=display:flex><span>
80</span></span><span style=display:flex><span><span style=color:green># we use profiling over specific function with including</span>
81</span></span><span style=display:flex><span><span style=color:green># @do_cprofile above function declaration</span>
82</span></span><span style=display:flex><span>@app.route(<span style=color:#a31515>&#34;/&#34;</span>)
83</span></span><span style=display:flex><span>@do_cprofile
84</span></span><span style=display:flex><span><span style=color:#00f>def</span> awesome_random_number():
85</span></span><span style=display:flex><span> awesome_random_number = random.randint(0, 100)
86</span></span><span style=display:flex><span> <span style=color:#00f>return</span> <span style=color:#a31515>&#34;awesome random number is &#34;</span> + str(awesome_random_number)
87</span></span><span style=display:flex><span>
88</span></span><span style=display:flex><span>@app.route(<span style=color:#a31515>&#34;/test&#34;</span>)
89</span></span><span style=display:flex><span><span style=color:#00f>def</span> test():
90</span></span><span style=display:flex><span> <span style=color:#00f>return</span> <span style=color:#a31515>&#34;dummy test&#34;</span>
91</span></span><span style=display:flex><span>
92</span></span><span style=display:flex><span><span style=color:#00f>if</span> __name__ == <span style=color:#a31515>&#39;__main__&#39;</span>:
93</span></span><span style=display:flex><span> bottle.run(
94</span></span><span style=display:flex><span> app = app,
95</span></span><span style=display:flex><span> host = <span style=color:#a31515>&#34;0.0.0.0&#34;</span>,
96</span></span><span style=display:flex><span> port = 4000
97</span></span><span style=display:flex><span> )
98</span></span><span style=display:flex><span>
99</span></span><span style=display:flex><span><span style=color:green># run with &#39;python app.py&#39;</span>
100</span></span><span style=display:flex><span><span style=color:green># open browser &#39;http://0.0.0.0:4000&#39;</span>
101</span></span></code></pre><p>When browser hits awesome_random_number() function profile is created in prof/
102subfolder.<h2 id=visualize-profile>Visualize profile</h2><p>Now let's create callgrind format from this cProfile output.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>$ cd prof/
103</span></span><span style=display:flex><span>$ pyprof2calltree -i awesome_random_number.prof
104</span></span><span style=display:flex><span><span style=color:green># this creates &#39;awesome_random_number.prof.log&#39; file in the same folder</span>
105</span></span></code></pre><p>This file can be opened with visualizing tools listed above. In this case we
106will be using Profilling Viewer under MacOS. You can open image in new tab. As
107you can see from this example there is hierarchy of execution order of your
108code.<figure><img src=/posts/python-profiling/profiling-viewer.png alt="Profilling Viewer"></figure><blockquote><p>Make sure you convert output of the cProfile output every time you want to
109refresh and take a look at your possible optimizations because cProfile updates
110.prof file every time browser hits the function.</blockquote><p>This is just a simple example but when you are developing real-life applications
111this can be very illuminating, especially to see which parts of your code are
112bottlenecks and need to be optimized.<h2 id=update-2017-04-22>Update 2017-04-22</h2><p>Reddit user <a href=https://www.reddit.com/user/mvt>mvt</a> also recommended this awesome
113web based profile visualizer <a href=https://jiffyclub.github.io/snakeviz/>SnakeViz</a>
114that directly takes output from
115<a href=https://docs.python.org/2/library/profile.html#module-cProfile>cProfile</a>
116module.<div class=reddit-embed data-embed-media=www.redditmedia.com data-embed-parent=false data-embed-live=false data-embed-uuid=583880c1-002e-41ed-a373-020a0ef2cff9 data-embed-created=2017-04-22T19:46:54.810Z><a href=https://www.reddit.com/r/Python/comments/66v373/profiling_python_web_applications_with_visual/dgljhsb/>Comment</a> from discussion <a href=https://www.reddit.com/r/Python/comments/66v373/profiling_python_web_applications_with_visual/>Profiling Python web applications with visual tools</a>.</div><script async src=https://www.redditstatic.com/comment-embed.js></script><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># let&#39;s install it globally as well</span>
117</span></span><span style=display:flex><span>$ sudo pip install snakeviz
118</span></span><span style=display:flex><span>
119</span></span><span style=display:flex><span><span style=color:green># now let&#39;s visualize</span>
120</span></span><span style=display:flex><span>$ cd prof/
121</span></span><span style=display:flex><span>$ snakeviz awesome_random_number.prof
122</span></span><span style=display:flex><span><span style=color:green># this automatically opens browser window and</span>
123</span></span><span style=display:flex><span><span style=color:green># shows visualized profile</span>
124</span></span></code></pre><figure><img src=/posts/python-profiling/snakeviz.png alt=SnakeViz></figure><p>Reddit user <a href=https://www.reddit.com/user/ccharles>ccharles</a> suggested a better
125way for installing pip software by targeting user level instead of using sudo.<div class=reddit-embed data-embed-media=www.redditmedia.com data-embed-parent=false data-embed-live=false data-embed-uuid=f4f0459e-684d-441e-bebe-eb49b2f0a31d data-embed-created=2017-04-22T19:46:10.874Z><a href=https://www.reddit.com/r/Python/comments/66v373/profiling_python_web_applications_with_visual/dglpzkx/>Comment</a> from discussion <a href=https://www.reddit.com/r/Python/comments/66v373/profiling_python_web_applications_with_visual/>Profiling Python web applications with visual tools</a>.</div><script async src=https://www.redditstatic.com/comment-embed.js></script><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># now we need to add this path to our $PATH variable</span>
126</span></span><span style=display:flex><span><span style=color:green># we do this my adding this line at the end of your</span>
127</span></span><span style=display:flex><span><span style=color:green># ~/.bashrc file</span>
128</span></span><span style=display:flex><span>PATH=$PATH:$HOME/.local/bin/
129</span></span><span style=display:flex><span>
130</span></span><span style=display:flex><span><span style=color:green># in order to use this new configuration you can close</span>
131</span></span><span style=display:flex><span><span style=color:green># and reopen terminal or reload .bashrc file</span>
132</span></span><span style=display:flex><span>$ source ~/.bashrc
133</span></span><span style=display:flex><span>
134</span></span><span style=display:flex><span><span style=color:green># now let&#39;s test if new directory is present in $PATH</span>
135</span></span><span style=display:flex><span>$ echo $PATH
136</span></span><span style=display:flex><span>
137</span></span><span style=display:flex><span><span style=color:green># now we can install on user level by adding --user</span>
138</span></span><span style=display:flex><span><span style=color:green># without use of sudo</span>
139</span></span><span style=display:flex><span>$ pip install snakeviz --user
140</span></span></code></pre><p>Or as suggested by <a href=https://www.reddit.com/user/mvt>mvt</a> you can
141use <a href=https://github.com/mitsuhiko/pipsi>pipsi</a>.</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
142a lock on a Linux NFS server, which turned
143out to be specific to NFS v3 (which I really should have seen coming,
144since it involved NLM and lockd). Finding the NFS v4 client that
145owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
146and Bradley Kuhn, are interacting on the OSI's license-discuss
147list where the're doing
148bad computer history and insisting that a guy Larry Rosen
149coincidentally interviewed for a book years ago is clearly the origin of
150somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
151i2c, plan9
152Another month, another file system.
153Well, if you can’t fix it in software, fix it in hardware (looking at
154you, bme680, we’re not
155done yet). The show must go on, as they say, and I would like my
156experiments to go on.
157So a “new” addition to the environmental sensor family connected to
158the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
159this mortal coil, we are endowed with self-awareness, agency, and free will.
160Each of the 8 billion members of this human race represents a unique person, a
161unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
162My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
1631.0 has been released:
164wifi_da-1.0.sit
165(StuffIt 3 archive)
166SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
167This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
168classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
169In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
170Design Goals
171I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
172at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
173catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
174specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
175 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
176 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/radio.pls b/public/radio.pls
deleted file mode 100755
index 77e6307..0000000
--- a/public/radio.pls
+++ /dev/null
@@ -1,38 +0,0 @@
1# Find stations: https://streamurl.link/
2
3[playlist]
4
5Title1=Metal
6File1=http://kathy.torontocast.com:2820/
7
8Title2=Technolovers Minimal
9File2=https://stream.technolovers.fm/minimal
10
11Title3=Indie Rock
12File3=http://s5.radio.co/s36d03408d/listen
13
14Title4=Montreal's Classic Rock
15File4=http://streams.justclassicrock.com:8000
16
17Title5=Raute Metal
18File5=https://metal-high.rautemusik.fm/?ref
19
20Title6=NCC 1701a Engine Noise
21File6=https://files.mitjafelicijan.com/haphazard/ncc-1701-a-engine-noise.ogg
22
23Title7=Funk & Soul
24File7=http://streams.80s80s.de/soul/mp3-192/
25
26Title8=80's Pop
27File8=http://streams.fluxfm.de/80er/mp3-320
28
29Title9=Roots Legacy Radio Dub
30File9=http://l.rootslegacy.fr/
31
32Title10=Ambiental
33File10=http://radio.stereoscenic.com/ama-h
34
35#Title6=
36#File6=
37
38Length1=-1
diff --git a/public/re-inventing-task-runner-that-i-actually-used-daily.html b/public/re-inventing-task-runner-that-i-actually-used-daily.html
deleted file mode 100755
index e8bbf1b..0000000
--- a/public/re-inventing-task-runner-that-i-actually-used-daily.html
+++ /dev/null
@@ -1,145 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Re-Inventing Task Runner That I Actually Used Daily</title><meta name=description content="Couple of months ago I had this brilliant idea of re-inventing the wheel bymaking an alternative for make."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Re-Inventing Task Runner That I Actually Used Daily</h1><p><cap>post</cap>, May 31, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>Couple of months ago I had this brilliant idea of re-inventing the wheel by
10making an alternative for make. And so I went. Boldly into the battle. And to my
11big surprise my attempt resulted in not a completely useless piece of software.<p>My initial requirements were quite simple but soon grow into something more
12ambitious. And looking back I should have stuck to the simple version. My
13laziness was on my side this time though. Because I haven’t implemented some of
14the features I now realise I really didn’t need them and they would bog the
15whole program and make it be something it was never meant to be.<p>My basic requirements were following:<ul><li>Syntax should be a tiny bit inspired by Rake and Rakefiles.<li>Should borrow the overall feel of a unit test experience.<li>Using something like Python would be a bit of an overkill.<li>The program must be statically compiled, so it can run on same architecture
16without libc, musl dependencies or things like that.<li>Install ruby for rake is a bit overkill and can not be done with certain
17really lightweight distributions like Alpine Linux. This tool would be usable
18on such lightweight systems for remote debugging.<li>I want to use it for more than just compiling things. I want to use it as an
19entry-point into a project, and I want this to help me indirectly document the
20project as well.<li>It should be an abstraction over bash shell or the default system shell.<ul><li>Each task essentially becomes its own shell instance.</ul><li>Must work on Linux and macOS systems.<li>By default, running <code>erd</code> list all the available tasks (when I use make, I
21usually put a disclaimer that you should check Makefile to see all available
22target).<li>Should support passing arguments when you run it from a shell.<li>Normal variable as the same as environmental variables. There is no
23distinction. Every variable is also essentially an environment variable and
24can be used by other programs.<li>State between tasks is not shared, and this makes this “pure” shell instances.<li>Should be single-threaded for the start and later expanded with <code>@spawn</code>
25command.<li>Variables behave like macros and are preprocessed before evaluation.<li>Should support something like <code>assure</code> that would check if programs like C
26compiler or Python (whatever the project requires) are installed on a machine.</ul><p>Quite a reasonable list of requirements. I do this things already in my
27Makefiles or/and Bash scripts. But I would like to avoid repeating myself every
28time I start working on something new.<p>So I started with the following syntax.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>@env on
29</span></span><span style=display:flex><span>
30</span></span><span style=display:flex><span><span style=color:green># Override the default shell.</span>
31</span></span><span style=display:flex><span>@shell <span style=color:#a31515>/bin/</span>bash
32</span></span><span style=display:flex><span>
33</span></span><span style=display:flex><span><span style=color:green># Assure that program is installed.</span>
34</span></span><span style=display:flex><span>@assure docker-compose pip python3
35</span></span><span style=display:flex><span>
36</span></span><span style=display:flex><span><span style=color:green># Load local dotenv files (these are then globally available).</span>
37</span></span><span style=display:flex><span>@dotenv .env
38</span></span><span style=display:flex><span>@dotenv .env.sample
39</span></span><span style=display:flex><span>@dotenv some_other_file
40</span></span><span style=display:flex><span>
41</span></span><span style=display:flex><span><span style=color:green># This are local variables but still accessible in tasks.</span>
42</span></span><span style=display:flex><span>@var HI = <span style=color:#a31515>&#34;hey&#34;</span>
43</span></span><span style=display:flex><span>@var TOKEN = <span style=color:#a31515>&#34;sometoken&#34;</span>
44</span></span><span style=display:flex><span>@var EMAIL = <span style=color:#a31515>&#34;m@m.com&#34;</span>
45</span></span><span style=display:flex><span>@var PASSWORD = <span style=color:#a31515>&#34;pass&#34;</span>
46</span></span><span style=display:flex><span>@var EDITOR = <span style=color:#a31515>&#34;vim&#34;</span>
47</span></span><span style=display:flex><span>
48</span></span><span style=display:flex><span>@task dev <span style=color:#a31515>&#34;Test chars .:&#39;}{]!//&#34;</span> does
49</span></span><span style=display:flex><span> echo <span style=color:#a31515>&#34;...&#34;</span> $HI
50</span></span><span style=display:flex><span><span style=color:#00f>end</span>
51</span></span><span style=display:flex><span>
52</span></span><span style=display:flex><span>@task clean <span style=color:#a31515>&#34;Cleans the obj files&#34;</span> does
53</span></span><span style=display:flex><span> rm .obj
54</span></span><span style=display:flex><span><span style=color:#00f>end</span>
55</span></span><span style=display:flex><span>
56</span></span><span style=display:flex><span>@task greet <span style=color:#a31515>&#34;Greets the user&#34;</span> does
57</span></span><span style=display:flex><span> echo <span style=color:#a31515>&#34;Hi user $TOKEN or $WINDOWID $EMAIL&#34;</span>
58</span></span><span style=display:flex><span><span style=color:#00f>end</span>
59</span></span><span style=display:flex><span>
60</span></span><span style=display:flex><span>@task stack <span style=color:#a31515>&#34;Starts Docker stack&#34;</span> does
61</span></span><span style=display:flex><span> docker-compose -f stack.yml up
62</span></span><span style=display:flex><span><span style=color:#00f>end</span>
63</span></span><span style=display:flex><span>
64</span></span><span style=display:flex><span>@task todo <span style=color:#a31515>&#34;Shows all todos in source files and count them&#34;</span> does
65</span></span><span style=display:flex><span> grep -ir <span style=color:#a31515>&#34;TODO|FIXME&#34;</span> . | wc -l
66</span></span><span style=display:flex><span><span style=color:#00f>end</span>
67</span></span><span style=display:flex><span>
68</span></span><span style=display:flex><span>@task test1 <span style=color:#a31515>&#34;For testing 1&#34;</span> does
69</span></span><span style=display:flex><span> unknown-command
70</span></span><span style=display:flex><span> echo <span style=color:#a31515>&#34;test1&#34;</span>
71</span></span><span style=display:flex><span> ls -lha
72</span></span><span style=display:flex><span><span style=color:#00f>end</span>
73</span></span><span style=display:flex><span>
74</span></span><span style=display:flex><span>@task test2 <span style=color:#a31515>&#34;For testing 2&#34;</span> does
75</span></span><span style=display:flex><span> echo <span style=color:#a31515>&#34;test1&#34;</span>
76</span></span><span style=display:flex><span> ls -lha
77</span></span><span style=display:flex><span> docker-compose -f samples/stack.yml up
78</span></span><span style=display:flex><span><span style=color:#00f>end</span>
79</span></span></code></pre><p>One thing that I really like about Errand. Yes, this is what it is called. And
80it is available at <a href=https://git.mitjafelicijan.com/errand.git/about/>https://git.mitjafelicijan.com/errand.git/about/</a>. Moving
81on. One thing that I really like is that a task is a persistent shell. By that I
82mean, that the whole task, even if it contains multiple command in one shell.
83In make each line in a target is that and you need to combine lines or add <code>\</code>
84at the end of the line.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># How you do this things in make.</span>
85</span></span><span style=display:flex><span>target:
86</span></span><span style=display:flex><span> source .venv/bin/activate <span style=color:#a31515>\
87</span></span></span><span style=display:flex><span><span style=color:#a31515></span> python script.py
88</span></span></code></pre><p>This solves this problem. Consider each task and what is being executed in that
89task a shell that will only close when all the tasks are completed.<p>By self-documenting I mean that if you are in a directory with <code>Errandfile</code> in,
90if you only type <code>erd</code> and press enter it should by default display all the
91possible targets. In make i was doing this by having a first target be something
92like <code>default</code> that echos the message “Check Makefile for all available target.”
93Because all of the tasks in Errand require a message I use that to display let’s
94call it table of contents.<p>Because I don’t use any external dependencies this whole thing can be statically
95compiled. So that also checked one of the boxes.<p>It works on Linux and on a Mac so that’s also a bonus. I don’t believe this
96would work on Windows machines because of the way that I use shell instances. By
97you could use something like Windows Subsystem for Linux and run it in
98there. That is a valid option.<p>To finish this essay off, how was it to use it in “real life”. I have to be
99honest. Some of the missing features still bother me. <code>@dotenv</code> directive is
100still missing and I need to implement this ASAP.<p>Another thing that needs to happen is support for streaming output. Currently
101commands like <code>docker-compose</code> that runs in foreground mode is not compatible
102with Errand. So commands that stream output are an issue. I need to revisit how
103I initiate shell and how I read stdout and stderr. But that shouldn’t be a
104problem.<p>I have been very satisfied with this thing. I am pleasantly surprised by how
105useful it is. I really wanted to test this in the wild before I commit to it. I
106have more abandoned project than Google and it’s bringing a massive shame to my
107family at this point. So I wanted to be sure that this is even useful. And it
108actually is. Quite surprised at myself.<p>I really need to package this now and write proper docs. And maybe rewrite
109tokeniser. Its atrocious right now. Site to behold! But that is an issue for
110another time.</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
111a lock on a Linux NFS server, which turned
112out to be specific to NFS v3 (which I really should have seen coming,
113since it involved NLM and lockd). Finding the NFS v4 client that
114owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
115and Bradley Kuhn, are interacting on the OSI's license-discuss
116list where the're doing
117bad computer history and insisting that a guy Larry Rosen
118coincidentally interviewed for a book years ago is clearly the origin of
119somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
120i2c, plan9
121Another month, another file system.
122Well, if you can’t fix it in software, fix it in hardware (looking at
123you, bme680, we’re not
124done yet). The show must go on, as they say, and I would like my
125experiments to go on.
126So a “new” addition to the environmental sensor family connected to
127the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
128this mortal coil, we are endowed with self-awareness, agency, and free will.
129Each of the 8 billion members of this human race represents a unique person, a
130unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
131My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
1321.0 has been released:
133wifi_da-1.0.sit
134(StuffIt 3 archive)
135SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
136This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
137classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
138In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
139Design Goals
140I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
141at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
142catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
143specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
144 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
145 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/rekindling-my-love-for-programming.html b/public/rekindling-my-love-for-programming.html
deleted file mode 100755
index 64b9b25..0000000
--- a/public/rekindling-my-love-for-programming.html
+++ /dev/null
@@ -1,85 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Rekindling my love for programming and enjoying the act of creating</title><meta name=description content="Programming can be a challenging and rewarding experience, but sometimes it&amp;#39;seasy to feel burnt out or disinterested."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Rekindling my love for programming and enjoying the act of creating</h1><p><cap>post</cap>, May 16, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>Programming can be a challenging and rewarding experience, but sometimes it's
10easy to feel burnt out or disinterested. I have lost the passion for coding over
11the past couple of months and it looked like I will never enjoy the coding as
12much as I did.<p>I was feeling burnt out with programming. I thought taking a break from it and
13focusing on other activities that I enjoy might be helpful. This way, I could
14come back to programming with a fresh perspective and renewed energy. I also
15thought about learning a new programming language or technology to keep things
16interesting and challenging.<p>However, what I didn't realize was that learning a new language or technology
17wasn't going to solve the underlying issue. I needed to take a step back and
18re-evaluate why I had lost my passion for programming in the first place. This
19involved taking a deep look into what I was doing that resulted in this rut.<p>Sometimes, it's easy to get caught up in the hype of new technologies or
20languages, and we can feel like we're missing out if we're not constantly
21learning and experimenting. However, it's important to remember that the latest
22and greatest isn't always the best fit for our projects or our
23interests. Instead of constantly chasing the next big thing, it can be helpful
24to focus on what truly interests us and what we're passionate about. This can
25help us stay motivated and engaged with our work, rather than feeling like we're
26just going through the motions.<p>I expressed that I had lost my passion for coding over the past couple of
27months, and I realized that the reason behind it was my tendency to spread
28myself too thin and not focus on completing interesting projects. In order to
29regain my passion for coding, I need to focus on projects that truly interest me
30and give me a sense of purpose and motivation.<p>Recently, I have been playing World of Warcraft more frequently and have become
31interested in developing addons for the game.<p>This quickly resulted in me creating three addons that improve the quality of
32life, and I subsequently developed a more useful add-on that encapsulates all
33the others I made.<p>I found it interesting that this action sparked a new interest in me.
34Additionally, I discovered the Lua language, which reminded me that coding
35should be fun rather than just a struggle with a language. It should be pure,
36unadulterated fun.<p>I wasn't fighting the syntax, nor was I focused on finding the most optimal
37solution. I simply created things without the pressure of making them the best
38they could possibly be.<p>This made me realize that I actually adore simple languages that get out of the
39way and let you express what you want to do. It forced me to rethink a lot about
40what I use and what I actually enjoy.<p>I have decided to stick to the basics. For a scripting language, I will use
41Lua. For networking, I will use Golang. And for any special needs, I will rely
42on C. I do not require Rust, Nim, or Zig. This selection is more than sufficient
43for my needs. I have to stay true to this simplicity. There is something to the
44Occam's Razor.<p>I've been struggling with a lack of creativity lately, but now I'm experiencing
45a real change. I realized I needed to take a step back and stop actively trying
46to address the issue. I needed to stop worrying and overthinking it. I simply
47needed some time. Looking back, I don't think I've taken any significant time
48off in the last 10 years.<p>Suddenly, I find myself with the energy and passion to complete multiple small
49projects. It doesn't feel like a chore at all. Who knew I needed WoW to
50kickstart everything. Inspiration really does come from the strangest places.</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
51a lock on a Linux NFS server, which turned
52out to be specific to NFS v3 (which I really should have seen coming,
53since it involved NLM and lockd). Finding the NFS v4 client that
54owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
55and Bradley Kuhn, are interacting on the OSI's license-discuss
56list where the're doing
57bad computer history and insisting that a guy Larry Rosen
58coincidentally interviewed for a book years ago is clearly the origin of
59somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
60i2c, plan9
61Another month, another file system.
62Well, if you can’t fix it in software, fix it in hardware (looking at
63you, bme680, we’re not
64done yet). The show must go on, as they say, and I would like my
65experiments to go on.
66So a “new” addition to the environmental sensor family connected to
67the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
68this mortal coil, we are endowed with self-awareness, agency, and free will.
69Each of the 8 billion members of this human race represents a unique person, a
70unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
71My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
721.0 has been released:
73wifi_da-1.0.sit
74(StuffIt 3 archive)
75SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
76This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
77classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
78In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
79Design Goals
80I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
81at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
82catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
83specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
84 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
85 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/remote-work.html b/public/remote-work.html
deleted file mode 100755
index 3cea514..0000000
--- a/public/remote-work.html
+++ /dev/null
@@ -1,78 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Remote work and how it affects the daily lives of people</title><meta name=description content="I have been working remotely for the past 5 years."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Remote work and how it affects the daily lives of people</h1><p><cap>post</cap>, May 5, 2020 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>I have been working remotely for the past 5 years. I love it. Love the freedom
10and make your schedule thingy.<h2 id=you-work-more-not-less>You work more not less</h2><p>I've heard from people things like: "Oh, you are so lucky, working from home,
11having all the free time you want". It was obvious they had no clue what means
12working remotely. They had this romantic idea of remote work. You can watch TV
13whenever you like, you can go outside for a picnic if you want and stuff like
14that.<p>This may be true if you work a day or two in a week from home. But if you go
15completely remote all these changes completely. I take some time to acclimate
16but then you start feeling the consequences of going fully remote. And it's not
17all rainbows and unicorns. Rather the opposite.<h2 id=feeling-lost>Feeling lost</h2><p>At first, I remembered I felt lost. I was not used to this kind of environment.
18It felt disoriented and a part of you that is used to procrastinate turns on.
19You start thinking of a workday as a whole day. And soon this idea of "I can do
20this later" starts creeping in. Well, I have the whole day ahead of me. I can do
21this a bit later.<h2 id=hyper-performance>Hyper-performance</h2><p>As a direct result, you become more focused on your work since you don't have
22all the interruptions common in the workplace. And you can quickly get used to
23this hyper-performance. But this mode requires also a lot of peace and quiet.<p>And here we come to the ugly parts of all this. <strong>People rarely have the
24self-control</strong> to not waste other people's time. It is paralyzing when people
25start calling you, sending you chat messages, etc. The thing is, that when I
26achieve this hyper-performance mode I am completely embroiled in the problem I
27am solving and this kind of interruptions mess with your head. I need an hour at
28least to get back in the zone. Sometimes not achieving the same focus the whole
29day.<p>I know that life is not how you want it to be and takes its route but from what
30I've learned this kind of interruptions can be avoided in 90% of the case easily
31just by closing any chat programs and putting your phone in a drawer.<h2 id=suggestion-to-all-the-new-remote-workers>Suggestion to all the new remote workers</h2><ul><li>Stop wasting other people's time. You don't bother people at their desks in
32the office either.<li>Do not replace daily chats in the hallways with instant messaging software.
33It will only interrupt people. Nothing good will come of it.<li>Set your working hours and try to not allow it to bleed outside these
34boundaries and maintain your routine.<li>Be prepared that hours will be longer regardless of your good intentions and
35your well thought of routine.<li>Try to be hyper-focused and do only one thing at the time. Multitasking is the
36enemy of progress.<li>Avoid long meetings and if possible eliminate them. Rather take time to write
37them out and allow others to respond in their own time. Meetings are usually a
38large waste of time and most of the people attending them are there just
39because the manager said so.<li>The software will not solve your problems. And throwing money at problems
40neither.<li>If you are in a managerial position don't supervise any single minute of
41workers. They are probably giving you more hours anyways. Track progress
42weekly not daily. You hired them and give them the benefit of the doubt that
43they will deliver what you agreed upon.</ul></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
44a lock on a Linux NFS server, which turned
45out to be specific to NFS v3 (which I really should have seen coming,
46since it involved NLM and lockd). Finding the NFS v4 client that
47owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
48and Bradley Kuhn, are interacting on the OSI's license-discuss
49list where the're doing
50bad computer history and insisting that a guy Larry Rosen
51coincidentally interviewed for a book years ago is clearly the origin of
52somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
53i2c, plan9
54Another month, another file system.
55Well, if you can’t fix it in software, fix it in hardware (looking at
56you, bme680, we’re not
57done yet). The show must go on, as they say, and I would like my
58experiments to go on.
59So a “new” addition to the environmental sensor family connected to
60the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
61this mortal coil, we are endowed with self-awareness, agency, and free will.
62Each of the 8 billion members of this human race represents a unique person, a
63unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
64My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
651.0 has been released:
66wifi_da-1.0.sit
67(StuffIt 3 archive)
68SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
69This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
70classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
71In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
72Design Goals
73I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
74at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
75catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
76specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
77 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
78 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/replacing-dropbox-in-favor-of-digitalocean-spaces.html b/public/replacing-dropbox-in-favor-of-digitalocean-spaces.html
deleted file mode 100755
index ff69f7c..0000000
--- a/public/replacing-dropbox-in-favor-of-digitalocean-spaces.html
+++ /dev/null
@@ -1,106 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Replacing Dropbox in favor of DigitalOcean spaces</title><meta name=description content="A few months ago I experimented with DigitalOcean spaces as my backup solutionthat could replace Dropboxeventually."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Replacing Dropbox in favor of DigitalOcean spaces</h1><p><cap>post</cap>, Jan 24, 2021 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>A few months ago I experimented with DigitalOcean spaces as my backup solution
10that could <a href=/digitalocean-spaces-to-sync-between-computers.html>replace Dropbox
11eventually</a>. That solution
12worked quite nicely, and I was amazed how smashing together a couple of existing
13solutions would work this fine.<p>I have been running that solution in the background for a couple of months now
14and kind of forgot about it. But recent developments around deplatforming and
15having us people hostages of technology and big companies speed up my goals to
16become less dependent on
17<a href=https://edition.cnn.com/2020/12/17/tech/google-antitrust-lawsuit/index.html>Google</a>,
18<a href=https://www.pcworld.com/article/2048680/dropbox-takes-a-peek-at-files.html>Dropbox</a>
19etc and take back some control.<p>I am not a conspiracy theory nut, but to be honest, what these companies are
20doing lately is out of control. It is a matter of principle at this point. I
21have almost completely degoogled my life all the way from ditching Gmail,
22YouTube and most of the services surrounding Google. And I must tell you, I feel
23so good. I haven't felt this way for a long time.<p><strong>Anyways. Let's get to the meat of things.</strong><p>Before you continue you should read my post about <a href=/digitalocean-spaces-to-sync-between-computers.html>syncing to
24Dropbox</a>.<blockquote><p>Also to note, I am using Linux on my machine with Gnome desktop environment.
25This should work on MacOS too. To use this on Windows I suggest using
26<a href=https://docs.microsoft.com/en-us/windows/wsl/install-win10>Subsystem for Linux</a>
27or <a href=https://www.cygwin.com/>Cygwin</a>.</blockquote><h2 id=folder-structure>Folder structure</h2><p>I liked structure from Dropbox. One folder where everything is located and
28synced. So, that's why adopted this also for my sync setup.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span>~</span>/Vault
29</span></span><span style=display:flex><span> <span>↳</span> backup
30</span></span><span style=display:flex><span> <span>↳</span> bin
31</span></span><span style=display:flex><span> <span>↳</span> documents
32</span></span><span style=display:flex><span> <span>↳</span> projects
33</span></span></code></pre><p>All of my code is located in <code>~/Vault/projects</code> folder. And most of the projects
34are Git repositories. I do not use this sync method for backup per see but in
35case I reinstall my machine I can easily recreate all the important folder
36structure with one quick command. No external drives needed that can fail etc.<h2 id=sync-script>Sync script</h2><p>My sync script is located in <code>~/Vault/bin/vault-backup.sh</code><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>#!/bin/bash
37</span></span></span><span style=display:flex><span><span style=color:#00f></span>
38</span></span><span style=display:flex><span><span style=color:green># dconf load /com/gexperts/Tilix/ &lt; tilix.dconf</span>
39</span></span><span style=display:flex><span><span style=color:green># 0 2 * * * sh ~/Vault/bin/vault-backup.sh</span>
40</span></span><span style=display:flex><span>
41</span></span><span style=display:flex><span>cd ~/Vault/backup/dotfiles
42</span></span><span style=display:flex><span>
43</span></span><span style=display:flex><span>MACHINE=<span style=color:#00f>$(</span>whoami<span style=color:#00f>)</span>@<span style=color:#00f>$(</span>hostname<span style=color:#00f>)</span>
44</span></span><span style=display:flex><span>mkdir -p $MACHINE
45</span></span><span style=display:flex><span>cd $MACHINE
46</span></span><span style=display:flex><span>
47</span></span><span style=display:flex><span>cp ~/.config/VSCodium/User/settings.json settings.json
48</span></span><span style=display:flex><span>cp ~/.s3cfg s3cfg
49</span></span><span style=display:flex><span>cp ~/.bash_extended bash_extended
50</span></span><span style=display:flex><span>cp ~/.ssh ssh -rf
51</span></span><span style=display:flex><span>
52</span></span><span style=display:flex><span>codium --list-extensions &gt; vscode-extension.txt
53</span></span><span style=display:flex><span>dconf dump /com/gexperts/Tilix/ &gt; tilix.dconf
54</span></span><span style=display:flex><span>
55</span></span><span style=display:flex><span>cd ~/Vault
56</span></span><span style=display:flex><span>s3cmd sync --delete-removed --exclude <span style=color:#a31515>&#39;node_modules/*&#39;</span> --exclude <span style=color:#a31515>&#39;.git/*&#39;</span> --exclude <span style=color:#a31515>&#39;.venv/*&#39;</span> ./ s3://bucket-name/backup/
57</span></span><span style=display:flex><span>
58</span></span><span style=display:flex><span>echo <span style=color:#a31515>`</span>date +<span style=color:#a31515>&#34;%D %T&#34;</span><span style=color:#a31515>`</span> &gt;&gt; ~/.vault.log
59</span></span><span style=display:flex><span>
60</span></span><span style=display:flex><span>notify-send <span style=color:#a31515>\
61</span></span></span><span style=display:flex><span><span style=color:#a31515></span> -u normal <span style=color:#a31515>\
62</span></span></span><span style=display:flex><span><span style=color:#a31515></span> -i /usr/share/icons/Adwaita/96x96/status/security-medium-symbolic.symbolic.png <span style=color:#a31515>\
63</span></span></span><span style=display:flex><span><span style=color:#a31515></span> <span style=color:#a31515>&#34;Vault sync succeded at `date +&#34;</span>%D %T<span style=color:#a31515>&#34;`&#34;</span>
64</span></span></code></pre><p>This script also backups some of the dotfiles I use and sends notification to
65Gnome notification center. It is a straightforward solution. Nothing special
66going on.<blockquote><p>One obvious benefit of this is that I can omit syncing Node's <code>node_modules</code>
67or Python's <code>.venv</code> and <code>.git</code> folders.</blockquote><p>You can use this script in a combination with <a href=https://en.wikipedia.org/wiki/Cron>Cron</a>.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>0 2 * * * sh ~/Vault/bin/vault-backup.sh
68</span></span></code></pre><p>When you start syncing your local stuff with a remote server you can review your
69items on DigitalOcean.<figure><img src=/posts/dropbox-sync/dropbox-spaces.png alt="Dropbox Spaces"></figure><p>I have been using this script now for quite some time, and it's working
70flawlessly. I also uninstalled Dropbox and stopped using it completely.<p>All I need to do is write a Bash script that does the reverse and downloads from
71remote server to local folder. This could be another post.</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
72a lock on a Linux NFS server, which turned
73out to be specific to NFS v3 (which I really should have seen coming,
74since it involved NLM and lockd). Finding the NFS v4 client that
75owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
76and Bradley Kuhn, are interacting on the OSI's license-discuss
77list where the're doing
78bad computer history and insisting that a guy Larry Rosen
79coincidentally interviewed for a book years ago is clearly the origin of
80somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
81i2c, plan9
82Another month, another file system.
83Well, if you can’t fix it in software, fix it in hardware (looking at
84you, bme680, we’re not
85done yet). The show must go on, as they say, and I would like my
86experiments to go on.
87So a “new” addition to the environmental sensor family connected to
88the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
89this mortal coil, we are endowed with self-awareness, agency, and free will.
90Each of the 8 billion members of this human race represents a unique person, a
91unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
92My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
931.0 has been released:
94wifi_da-1.0.sit
95(StuffIt 3 archive)
96SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
97This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
98classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
99In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
100Design Goals
101I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
102at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
103catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
104specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
105 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
106 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/robots.txt b/public/robots.txt
deleted file mode 100755
index c2a49f4..0000000
--- a/public/robots.txt
+++ /dev/null
@@ -1,2 +0,0 @@
1User-agent: *
2Allow: /
diff --git a/public/run-9front-in-qemu.html b/public/run-9front-in-qemu.html
deleted file mode 100755
index 2bab01c..0000000
--- a/public/run-9front-in-qemu.html
+++ /dev/null
@@ -1,56 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Run 9front in Qemu</title><meta name=description content="Run 9front in Qemu."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Run 9front in Qemu</h1><p><cap>note</cap>, May 5, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>Run 9front in Qemu. This applies to <a href=https://9p.io/plan9/>Plan9</a> and
10<a href=https://9front.org/>9front</a>.<p>Download from here <a href=http://9front.org/iso/>http://9front.org/iso/</a>.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># Create a qcow2 image.</span>
11</span></span><span style=display:flex><span>qemu-img create -f qcow2 $HOME/VM/9front.qcow2.img 30G
12</span></span><span style=display:flex><span>
13</span></span><span style=display:flex><span><span style=color:green># Run the VM.</span>
14</span></span><span style=display:flex><span>qemu-system-x86_64 -cpu host -enable-kvm -m 1024 <span style=color:#a31515>\
15</span></span></span><span style=display:flex><span><span style=color:#a31515></span> -net nic,model=virtio,macaddr=52:54:00:00:EE:03 -net user <span style=color:#a31515>\
16</span></span></span><span style=display:flex><span><span style=color:#a31515></span> -device virtio-scsi-pci,id=scsi <span style=color:#a31515>\
17</span></span></span><span style=display:flex><span><span style=color:#a31515></span> -drive <span style=color:#00f>if</span>=none,id=vd0,file=$HOME/VM/9front.qcow2.img <span style=color:#a31515>\
18</span></span></span><span style=display:flex><span><span style=color:#a31515></span> -device scsi-hd,drive=vd0 <span style=color:#a31515>\
19</span></span></span><span style=display:flex><span><span style=color:#a31515></span> -drive <span style=color:#00f>if</span>=none,id=vd1,file=$HOME/VM/ISO/9front.386.iso <span style=color:#a31515>\
20</span></span></span><span style=display:flex><span><span style=color:#a31515></span> -device scsi-cd,drive=vd1,bootindex=0
21</span></span></code></pre></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
22a lock on a Linux NFS server, which turned
23out to be specific to NFS v3 (which I really should have seen coming,
24since it involved NLM and lockd). Finding the NFS v4 client that
25owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
26and Bradley Kuhn, are interacting on the OSI's license-discuss
27list where the're doing
28bad computer history and insisting that a guy Larry Rosen
29coincidentally interviewed for a book years ago is clearly the origin of
30somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
31i2c, plan9
32Another month, another file system.
33Well, if you can’t fix it in software, fix it in hardware (looking at
34you, bme680, we’re not
35done yet). The show must go on, as they say, and I would like my
36experiments to go on.
37So a “new” addition to the environmental sensor family connected to
38the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
39this mortal coil, we are endowed with self-awareness, agency, and free will.
40Each of the 8 billion members of this human race represents a unique person, a
41unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
42My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
431.0 has been released:
44wifi_da-1.0.sit
45(StuffIt 3 archive)
46SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
47This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
48classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
49In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
50Design Goals
51I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
52at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
53catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
54specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
55 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
56 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/running-golang-application-as-pid1.html b/public/running-golang-application-as-pid1.html
deleted file mode 100755
index e276887..0000000
--- a/public/running-golang-application-as-pid1.html
+++ /dev/null
@@ -1,222 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Running Golang application as PID 1 with Linux kernel</title><meta name=description content="Unikernels, kernels, and alikeI have been reading a lot aboutunikernernels lately and found themvery intriguing."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Running Golang application as PID 1 with Linux kernel</h1><p><cap>post</cap>, Dec 25, 2021 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><h2 id=unikernels-kernels-and-alike>Unikernels, kernels, and alike</h2><p>I have been reading a lot about
10<a href=https://en.wikipedia.org/wiki/Unikernel>unikernernels</a> lately and found them
11very intriguing. When you push away all the marketing speak and look at the
12idea, it makes a lot of sense.<blockquote><p>A unikernel is a specialized, single address space machine image constructed
13by using library operating systems. (<a href=https://en.wikipedia.org/wiki/Unikernel>Wikipedia</a>)</blockquote><p>I really like the explanation from the article
14<a href="https://queue.acm.org/detail.cfm?id=2566628">Unikernels: Rise of the Virtual Library Operating System</a>.
15Really worth a read.<p>If we compare a normal operating system to a unikernel side by side, they would
16look something like this.<figure><img src=/posts/pid1/unikernels.webp alt="Virtual machines vs Containers vs Unikernels"></figure><p>From this image, we can see how the complexity significantly decreases with
17the use of Unikernels. This comes with a price, of course. Unikernels are hard
18to get running and require a lot of work since you don't have an actual proper
19kernel running in the background providing network access and drivers etc.<p>So as a half step to make the stack simpler, I started looking into using
20Linux kernel as a base and going from there. I came across this
21<a href="https://www.youtube.com/watch?v=Sk9TatW9ino">Youtube video talking about Building the Simplest Possible Linux System</a>
22by <a href=https://landley.net>Rob Landley</a> and apart from statically compiling the
23application to be run as PID1 there was really no other obstacles.<h2 id=what-is-pid-1>What is PID 1?</h2><p>PID 1 is the first process that Linux kernel starts after the boot process.
24It also has a couple of unique properties that are unique to it.<ul><li>When the process with PID 1 dies for any reason, all other processes are
25killed with KILL signal.<li>When any process having children dies for any reason, its children are
26re-parented to process with PID 1.<li>Many signals which have default action of Term do not have one for PID 1.<li>When the process with PID 1 dies for any reason, kernel panics, which
27result in system crash.</ul><p>PID 1 is considered as an Init application which takes care of running other
28and handling services like:<ul><li>sshd,<li>nginx,<li>pulseaudio,<li>etc.</ul><p>If you are on a Linux machine, you can check what your process is with PID 1
29by running the following.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>$ cat /proc/1/status
30</span></span><span style=display:flex><span>Name: systemd
31</span></span><span style=display:flex><span>Umask: 0000
32</span></span><span style=display:flex><span>State: S (sleeping)
33</span></span><span style=display:flex><span>Tgid: 1
34</span></span><span style=display:flex><span>Ngid: 0
35</span></span><span style=display:flex><span>Pid: 1
36</span></span><span style=display:flex><span>PPid: 0
37</span></span><span style=display:flex><span>...
38</span></span></code></pre><p>As we can see on my machine the process with id of 1 is <a href=https://systemd.io/>systemd</a>
39which is a software suite that provides an array of system components for Linux
40operating systems. If you look closely you can also see that the <code>PPid</code>
41(process id of the parent process) is <code>0</code> which additionally confirms that
42this process doesn't have a parent.<h2 id=so-why-even-run-application-as-pid-1-instead-of-just-using-a-container>So why even run application as PID 1 instead of just using a container?</h2><p>Containers are wonderful, but they come with a lot of baggage. And because they
43are in their nature layered, the images require quite a lot of space and also a
44lot of additional software to handle them. They are not as lightweight as they
45seem, and many popular images require 500 MB plus disk space.<p>The idea of running this as PID 1 would result in a significantly smaller footprint,
46as we will see later in the post.<blockquote><p>You could run a simple init system inside Docker container described more
47in this article <a href=https://blog.phusion.nl/2015/01/20/docker-and-the-pid-1-zombie-reaping-problem/>Docker and the PID 1 zombie reaping problem</a>.</blockquote><h2 id=the-master-plan>The master plan</h2><ol><li>Compile Linux kernel with the default definitions.<li>Prepare a Hello World application in Golang that is statically compiled.<li>Run it with <a href=https://www.qemu.org/>QEMU</a> and providing Golang application
48as init application / PID 1.</ol><p>For the sake of simplicity we will not be cross-compiling any of it and just
49use the 64bit version.<h2 id=compiling-linux-kernel>Compiling Linux kernel</h2><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>$ wget https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.15.7.tar.xz
50</span></span><span style=display:flex><span>$ tar xf linux-5.15.7.tar.xz
51</span></span><span style=display:flex><span>
52</span></span><span style=display:flex><span>$ cd linux-5.15.7
53</span></span><span style=display:flex><span>
54</span></span><span style=display:flex><span>$ make clean
55</span></span><span style=display:flex><span>
56</span></span><span style=display:flex><span><span style=color:green># read more about this https://stackoverflow.com/a/41886394</span>
57</span></span><span style=display:flex><span>$ make defconfig
58</span></span><span style=display:flex><span>
59</span></span><span style=display:flex><span>$ time make -j <span style=color:#a31515>`</span>nproc<span style=color:#a31515>`</span>
60</span></span><span style=display:flex><span>
61</span></span><span style=display:flex><span>$ cd ..
62</span></span></code></pre><p>At this point we have kernel image that is located in <code>arch/x86_64/boot/bzImage</code>.
63We will use this in QEMU later.<p>To make our lives a bit easier lets move the kernel image to another place.
64Lets create a folder <code>bin/</code> in the root of our project with <code>mkdir -p bin</code>.<p>At this point we can copy <code>bzImage</code> to <code>bin/</code> folder with
65<code>cp linux-5.15.7/arch/x86_64/boot/bzImage bin/bzImage</code>.<p>The folder structure of this experiment should look like this.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>pid1/
66</span></span><span style=display:flex><span> bin/
67</span></span><span style=display:flex><span> bzImage
68</span></span><span style=display:flex><span> linux-5.15.7/
69</span></span><span style=display:flex><span> linux-5.15.7.tar.xz
70</span></span></code></pre><h2 id=preparing-pid-1-application-in-golang>Preparing PID 1 application in Golang</h2><p>This step is relatively easy. The only thing we must have in mind that we will
71need to compile the binary as a static one.<p>Let's create <code>init.go</code> file in the root of the project.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>package</span> main
72</span></span><span style=display:flex><span>
73</span></span><span style=display:flex><span><span style=color:#00f>import</span> (
74</span></span><span style=display:flex><span> <span style=color:#a31515>&#34;fmt&#34;</span>
75</span></span><span style=display:flex><span> <span style=color:#a31515>&#34;time&#34;</span>
76</span></span><span style=display:flex><span>)
77</span></span><span style=display:flex><span>
78</span></span><span style=display:flex><span><span style=color:#00f>func</span> main() {
79</span></span><span style=display:flex><span> <span style=color:#00f>for</span> {
80</span></span><span style=display:flex><span> fmt.Println(<span style=color:#a31515>&#34;Hello from Golang&#34;</span>)
81</span></span><span style=display:flex><span> time.Sleep(1 * time.Second)
82</span></span><span style=display:flex><span> }
83</span></span><span style=display:flex><span>}
84</span></span></code></pre><p>If you notice, we have a forever loop in the main, with a simple sleep of 1
85second to not overwhelm the CPU. This is because PID 1 should never complete
86and/or exit. That would result in a kernel panic. Which is BAD!<p>There are two ways of compiling Golang application. Statically and dynamically.<p>To statically compile the binary, use the following command.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>$ go build -ldflags=<span style=color:#a31515>&#34;-extldflags=-static&#34;</span> init.go
87</span></span></code></pre><p>We can also check if the binary is statically compiled with:<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>$ file init
88</span></span><span style=display:flex><span>init: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), statically linked, Go BuildID=Ypu8Zw_4NBxm1Yxg2OYO/H5x721rQ9uTPiDVh-VqP/vZN7kXfGG1zhX_qdHMgH/9vBfmK81tFrygfOXDEOo, not stripped
89</span></span><span style=display:flex><span>
90</span></span><span style=display:flex><span>$ ldd init
91</span></span><span style=display:flex><span>not a dynamic executable
92</span></span></code></pre><p>At this point, we need to create <a href=https://www.linuxfromscratch.org/blfs/view/svn/postlfs/initramfs.html>initramfs</a>
93(abbreviated from "initial RAM file system", is the successor of initrd. It
94is a cpio archive of the initial file system that gets loaded into memory
95during the Linux startup process).<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>$ echo init | cpio -o --format=newc &gt; initramfs
96</span></span><span style=display:flex><span>$ mv initramfs bin/initramfs
97</span></span></code></pre><p>The projects at this stage should look like this.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>pid1/
98</span></span><span style=display:flex><span> bin/
99</span></span><span style=display:flex><span> bzImage
100</span></span><span style=display:flex><span> initramfs
101</span></span><span style=display:flex><span> linux-5.15.7/
102</span></span><span style=display:flex><span> linux-5.15.7.tar.xz
103</span></span><span style=display:flex><span> init.go
104</span></span></code></pre><h2 id=running-all-of-it-with-qemu>Running all of it with QEMU</h2><p><a href=https://www.qemu.org/>QEMU</a> is a free and open-source hypervisor. It emulates
105the machine's processor through dynamic binary translation and provides a set
106of different hardware and device models for the machine, enabling it to run a
107variety of guest operating systems.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>$ qemu-system-x86_64 -serial stdio -kernel bin/bzImage -initrd bin/initramfs -append <span style=color:#a31515>&#34;console=ttyS0&#34;</span> -m 128
108</span></span></code></pre><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>$ qemu-system-x86_64 -serial stdio -kernel bin/bzImage -initrd bin/initramfs -append <span style=color:#a31515>&#34;console=ttyS0&#34;</span> -m 128
109</span></span><span style=display:flex><span>[ 0.000000] Linux version 5.15.7 (m@khan) (gcc (GCC) 11.2.1 20211203 (Red Hat 11.2.1-7), GNU ld version 2.37-10.fc35) <span style=color:green>#7 SMP Mon Dec 13 10:23:25 CET 2021</span>
110</span></span><span style=display:flex><span>[ 0.000000] Command line: console=ttyS0
111</span></span><span style=display:flex><span>[ 0.000000] x86/fpu: x87 FPU will use FXSAVE
112</span></span><span style=display:flex><span>[ 0.000000] signal: max sigframe size: 1440
113</span></span><span style=display:flex><span>[ 0.000000] BIOS-provided physical RAM map:
114</span></span><span style=display:flex><span>[ 0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable
115</span></span><span style=display:flex><span>[ 0.000000] BIOS-e820: [mem 0x000000000009fc00-0x000000000009ffff] reserved
116</span></span><span style=display:flex><span>[ 0.000000] BIOS-e820: [mem 0x00000000000f0000-0x00000000000fffff] reserved
117</span></span><span style=display:flex><span>[ 0.000000] BIOS-e820: [mem 0x0000000000100000-0x0000000007fdffff] usable
118</span></span><span style=display:flex><span>[ 0.000000] BIOS-e820: [mem 0x0000000007fe0000-0x0000000007ffffff] reserved
119</span></span><span style=display:flex><span>[ 0.000000] BIOS-e820: [mem 0x00000000fffc0000-0x00000000ffffffff] reserved
120</span></span><span style=display:flex><span>[ 0.000000] NX (Execute Disable) protection: active
121</span></span><span style=display:flex><span>[ 0.000000] SMBIOS 2.8 present.
122</span></span><span style=display:flex><span>[ 0.000000] DMI: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-6.fc35 04/01/2014
123</span></span><span style=display:flex><span>[ 0.000000] tsc: Fast TSC calibration failed
124</span></span><span style=display:flex><span>...
125</span></span><span style=display:flex><span>[ 2.016106] ALSA device list:
126</span></span><span style=display:flex><span>[ 2.016329] No soundcards found.
127</span></span><span style=display:flex><span>[ 2.053176] Freeing unused kernel image (initmem) memory: 1368K
128</span></span><span style=display:flex><span>[ 2.056095] Write protecting the kernel read-only data: 20480k
129</span></span><span style=display:flex><span>[ 2.058248] Freeing unused kernel image (text/rodata gap) memory: 2032K
130</span></span><span style=display:flex><span>[ 2.058811] Freeing unused kernel image (rodata/data gap) memory: 500K
131</span></span><span style=display:flex><span>[ 2.059164] Run /init as init process
132</span></span><span style=display:flex><span>Hello from Golang
133</span></span><span style=display:flex><span>[ 2.386879] tsc: Refined TSC clocksource calibration: 3192.032 MHz
134</span></span><span style=display:flex><span>[ 2.387114] clocksource: tsc: mask: 0xffffffffffffffff max_cycles: 0x2e02e31fa14, max_idle_ns: 440795264947 ns
135</span></span><span style=display:flex><span>[ 2.387380] clocksource: Switched to clocksource tsc
136</span></span><span style=display:flex><span>[ 2.587895] input: ImExPS/2 Generic Explorer Mouse as /devices/platform/i8042/serio1/input/input3
137</span></span><span style=display:flex><span>Hello from Golang
138</span></span><span style=display:flex><span>Hello from Golang
139</span></span><span style=display:flex><span>Hello from Golang
140</span></span></code></pre><p>The whole <a href=/posts/pid1/qemu.log>log file here</a>.<h2 id=size-comparison>Size comparison</h2><p>The cool thing about this approach is that the Linux kernel and the application
141together only take around 12 MB, which is impressive as hell. And we need to
142also know that the size of bzImage (Linux kernel) could be greatly decreased
143by going into <code>make menuconfig</code> and removing a ton of features from the kernel,
144making the size even smaller. I managed to get kernel size down to 2 MB and
145still working properly.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>total 12M
146</span></span><span style=display:flex><span>-rw-r--r--. 1 m m 9.3M Dec 13 10:24 bzImage
147</span></span><span style=display:flex><span>-rw-r--r--. 1 m m 1.9M Dec 27 01:19 initramfs
148</span></span></code></pre><h2 id=creating-iso-image-and-running-it-with-gnome-boxes>Creating ISO image and running it with Gnome Boxes</h2><p>First we need to create proper folder structure with <code>mkdir -p iso/boot/grub</code>.<p>Then we need to download the <a href=https://github.com/littleosbook/littleosbook/raw/master/files/stage2_eltorito>grub binary</a>.
149You can read more about this program on <a href=https://github.com/littleosbook/littleosbook>https://github.com/littleosbook/littleosbook</a>.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>$ wget -O iso/boot/grub/stage2_eltorito https://github.com/littleosbook/littleosbook/raw/master/files/stage2_eltorito
150</span></span></code></pre><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>$ tree iso/boot/
151</span></span><span style=display:flex><span>iso/boot/
152</span></span><span style=display:flex><span>├── bzImage
153</span></span><span style=display:flex><span>├── grub
154</span></span><span style=display:flex><span>│   ├── menu.lst
155</span></span><span style=display:flex><span>│   └── stage2_eltorito
156</span></span><span style=display:flex><span>└── initramfs
157</span></span></code></pre><p>Let's copy files into proper folders.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>$ cp stage2_eltorito iso/boot/grub/
158</span></span><span style=display:flex><span>$ cp bin/bzImage iso/boot/
159</span></span><span style=display:flex><span>$ cp bin/initramfs iso/boot/
160</span></span></code></pre><p>Lets create a GRUB config file at <code>nano iso/boot/grub/menu.lst</code> with contents.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>default=<span style=color:#a31515>0</span>
161</span></span><span style=display:flex><span>timeout=<span style=color:#a31515>5</span>
162</span></span><span style=display:flex><span>
163</span></span><span style=display:flex><span>title GoAsPID1
164</span></span><span style=display:flex><span>kernel /boot/bzImage
165</span></span><span style=display:flex><span>initrd /boot/initramfs
166</span></span></code></pre><p>Let's create iso file by using genisoimage:<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>genisoimage -R <span style=color:#a31515>\
167</span></span></span><span style=display:flex><span><span style=color:#a31515></span> -b boot/grub/stage2_eltorito <span style=color:#a31515>\
168</span></span></span><span style=display:flex><span><span style=color:#a31515></span> -no-emul-boot <span style=color:#a31515>\
169</span></span></span><span style=display:flex><span><span style=color:#a31515></span> -boot-load-size 4 <span style=color:#a31515>\
170</span></span></span><span style=display:flex><span><span style=color:#a31515></span> -A os <span style=color:#a31515>\
171</span></span></span><span style=display:flex><span><span style=color:#a31515></span> -input-charset utf8 <span style=color:#a31515>\
172</span></span></span><span style=display:flex><span><span style=color:#a31515></span> -quiet <span style=color:#a31515>\
173</span></span></span><span style=display:flex><span><span style=color:#a31515></span> -boot-info-table <span style=color:#a31515>\
174</span></span></span><span style=display:flex><span><span style=color:#a31515></span> -o GoAsPID1.iso <span style=color:#a31515>\
175</span></span></span><span style=display:flex><span><span style=color:#a31515></span> iso
176</span></span></code></pre><p>This will produce <code>GoAsPID1.iso</code> which you can use with <a href=https://www.virtualbox.org/>Virtualbox</a>
177or <a href=https://apps.gnome.org/app/org.gnome.Boxes/>Gnome Boxes</a>.<p><video src=/posts/pid1/boxes.mp4 controls></video><h2 id=is-running-applications-as-pid-1-even-worth-it>Is running applications as PID 1 even worth it?</h2><p>Well, the answer to this is not as simple as one would think. Sometimes it is
178and sometimes it's not. For embedded systems and very specialized applications
179it is worth for sure. But in normal uses, I don't think so. It was an interesting
180exercise in compiling kernels and looking at the guts of the Linux kernel,
181but sticking to containers for most of the things is a better option in my
182opinion.<p>An interesting experiment would be creating an image that supports networking
183and could be deployed to AWS as an EC2 instance and observing how it fares.
184But in that case, we would need to write some sort of supervisor that would
185run on a separate EC2 that would check if other EC2 instances are running
186properly. Remember that if your application fails, kernel panics and the
187whole machine is inoperable in this case.</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
188a lock on a Linux NFS server, which turned
189out to be specific to NFS v3 (which I really should have seen coming,
190since it involved NLM and lockd). Finding the NFS v4 client that
191owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
192and Bradley Kuhn, are interacting on the OSI's license-discuss
193list where the're doing
194bad computer history and insisting that a guy Larry Rosen
195coincidentally interviewed for a book years ago is clearly the origin of
196somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
197i2c, plan9
198Another month, another file system.
199Well, if you can’t fix it in software, fix it in hardware (looking at
200you, bme680, we’re not
201done yet). The show must go on, as they say, and I would like my
202experiments to go on.
203So a “new” addition to the environmental sensor family connected to
204the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
205this mortal coil, we are endowed with self-awareness, agency, and free will.
206Each of the 8 billion members of this human race represents a unique person, a
207unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
208My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
2091.0 has been released:
210wifi_da-1.0.sit
211(StuffIt 3 archive)
212SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
213This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
214classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
215In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
216Design Goals
217I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
218at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
219catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
220specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
221 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
222 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/set-color-temperature-of-displays-on-i3.html b/public/set-color-temperature-of-displays-on-i3.html
deleted file mode 100755
index c04f9ff..0000000
--- a/public/set-color-temperature-of-displays-on-i3.html
+++ /dev/null
@@ -1,46 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Set color temperature of displays on i3</title><meta name=description content="I have been using Gnome&amp;#39;s night shift for a while now and I have been missingthis feature under i3wm."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Set color temperature of displays on i3</h1><p><cap>note</cap>, Jul 14, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>I have been using Gnome's night shift for a while now and I have been missing
10this feature under i3wm. This can be done with
11<a href=https://linux.die.net/man/1/redshift>redshift</a>.<ul><li>On Debian install with <code>sudo apt install redshift</code><li>And then manually set it with <code>redshift -O 3000</code><li>Reset the current settings with <code>redshift -x</code></ul></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
12a lock on a Linux NFS server, which turned
13out to be specific to NFS v3 (which I really should have seen coming,
14since it involved NLM and lockd). Finding the NFS v4 client that
15owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
16and Bradley Kuhn, are interacting on the OSI's license-discuss
17list where the're doing
18bad computer history and insisting that a guy Larry Rosen
19coincidentally interviewed for a book years ago is clearly the origin of
20somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
21i2c, plan9
22Another month, another file system.
23Well, if you can’t fix it in software, fix it in hardware (looking at
24you, bme680, we’re not
25done yet). The show must go on, as they say, and I would like my
26experiments to go on.
27So a “new” addition to the environmental sensor family connected to
28the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
29this mortal coil, we are endowed with self-awareness, agency, and free will.
30Each of the 8 billion members of this human race represents a unique person, a
31unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
32My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
331.0 has been released:
34wifi_da-1.0.sit
35(StuffIt 3 archive)
36SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
37This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
38classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
39In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
40Design Goals
41I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
42at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
43catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
44specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
45 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
46 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/simple-iot-application.html b/public/simple-iot-application.html
deleted file mode 100755
index b242397..0000000
--- a/public/simple-iot-application.html
+++ /dev/null
@@ -1,472 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Simple IOT application supported by real-time monitoring and data history</title><meta name=description content="Initial thoughtsI have been developing these kind of application for the better part of my last5 years and people keep asking me how to approach developing such applicationand I will give a try explaining it here."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Simple IOT application supported by real-time monitoring and data history</h1><p><cap>post</cap>, Aug 11, 2017 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><h2 id=initial-thoughts>Initial thoughts</h2><p>I have been developing these kind of application for the better part of my last
105 years and people keep asking me how to approach developing such application
11and I will give a try explaining it here.<p>IOT applications are really no different than any other kind of applications.
12We have data that needs to be collected and visualized in some form of tables or
13charts. The main difference here is that most of the times these data is
14collected by some kind of device foreign to developer that mainly operates in
15web domain. But fear not, it's not that different than writing some JavaScript.<p>There are many devices able to transmit data via wireless or wired network by
16default but for the sake of example we will be using commonly known Arduino with
17wireless module already on the board → <a href=https://store.arduino.cc/arduino-mkr1000>Arduino
18MKR1000</a>.<p>In order to make this little project as accessible to others as possible I will
19try to make it as inexpensive as possible. And by this I mean that I will avoid
20using hosted virtual servers and will be using my own laptop as a server. But
21you must buy Arduino MKR1000 to follow steps below. But if you would want to
22deploy this software I would suggest using
23<a href=https://www.digitalocean.com>DigitalOcean</a> → smallest VPS is only per month
24making this one of the most affordable option out there. Please notice that this
25software will not run on stock web hosting that only supports LAMP (Linux,
26Apache, MySQL, and PHP).<p>But before we begin please take notice that this is strictly experimental code
27and not well optimized and there are much better ways in handling some aspects
28of the application but that requires much deeper knowledge of technology that is
29not needed for an example like this.<p><strong>Development steps</strong><ol><li>Simple Python API that will receive and store incoming data.<li>Prototype C++ code that will read "sensor data" and transmit it to API.<li>Data visualization with charts → extends Python web application.</ol><p>Step 1. and 3. will share the same web application. One route will be dedicated
30to API and another to serving HTML with chart.<p>Schema below represents what we will try to achieve and how different parts
31correlates to each other.<figure><img src=/posts/iot-application/simple-iot-application-overview.svg alt=Overview></figure><h2 id=simple-python-api>Simple Python API</h2><p>I have always been a fan of simplicity so we will be using <a href=https://bottlepy.org/docs/dev/>Bottle: Python Web
32Framework</a>. It is a single file web framework
33that seriously simplifies working with routes, templating and has built-in web
34server that satisfies our need in this case.<p>First we need to install bottle package. This can be done by downloading
35<code>bottle.py</code> and placing it in the root of your application or by using pip
36software <code>pip install bottle --user</code>.<p>If you are using Linux or MacOS then Python is already installed. If you will
37try to test this on Windows please install <a href=https://www.python.org/downloads/windows/>Python for
38Windows</a>. There may be some problems
39with path when you will try to launch <code>python webapp.py</code> so please take care
40of this before you continue.<h3 id=basic-web-application>Basic web application</h3><p>Most basic bottle application is quite simple. Paste code below in
41<code>webapp.py</code> file and save.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># -*- coding: utf-8 -*-</span>
42</span></span><span style=display:flex><span>
43</span></span><span style=display:flex><span><span style=color:#00f>import</span> bottle
44</span></span><span style=display:flex><span>
45</span></span><span style=display:flex><span><span style=color:green># initializing bottle app</span>
46</span></span><span style=display:flex><span>app = bottle.Bottle()
47</span></span><span style=display:flex><span>
48</span></span><span style=display:flex><span><span style=color:green># triggered when / is accessed from browser</span>
49</span></span><span style=display:flex><span><span style=color:green># only accepts GET → no POST allowed</span>
50</span></span><span style=display:flex><span>@app.route(<span style=color:#a31515>&#34;/&#34;</span>, method=[<span style=color:#a31515>&#34;GET&#34;</span>])
51</span></span><span style=display:flex><span><span style=color:#00f>def</span> route_default():
52</span></span><span style=display:flex><span> <span style=color:#00f>return</span> <span style=color:#a31515>&#34;howdy from python&#34;</span>
53</span></span><span style=display:flex><span>
54</span></span><span style=display:flex><span><span style=color:green># starting server on http://0.0.0.0:5000</span>
55</span></span><span style=display:flex><span><span style=color:#00f>if</span> __name__ == <span style=color:#a31515>&#34;__main__&#34;</span>:
56</span></span><span style=display:flex><span> bottle.run(
57</span></span><span style=display:flex><span> app = app,
58</span></span><span style=display:flex><span> host = <span style=color:#a31515>&#34;0.0.0.0&#34;</span>,
59</span></span><span style=display:flex><span> port = 5000,
60</span></span><span style=display:flex><span> debug = <span style=color:#00f>True</span>,
61</span></span><span style=display:flex><span> reloader = <span style=color:#00f>True</span>,
62</span></span><span style=display:flex><span> catchall = <span style=color:#00f>True</span>,
63</span></span><span style=display:flex><span> )
64</span></span></code></pre><p>To run this simple application you should open command prompt or terminal on
65your machine and go to the folder containing your file and type <code>python webapp.py</code>. If everything goes ok then open your web browser and point it to
66<code>http://0.0.0.0:5000</code>.<p>If you would like change the port of your application (like port 80) and not use
67root to run your app this will present a problem. The TCP/IP port numbers below
681024 are privileged ports → this is a security feature. So in order of
69simplicity and security use a port number above 1024 like I have used port 5000.<p>If this fails at any time please fix it before you continue, because nothing
70below will work otherwise.<p>We use 0.0.0.0 as default host so that this app is available over your local
71network. If you find your local ip <code>ifconfig</code> and try accessing this site
72with your phone (if on same network/router as your machine) this should work as
73well (example of such ip <code>http://192.168.1.15:5000</code>). This is a must have
74because Arduino will be accessing this application to send it's data.<h3 id=web-application-security>Web application security</h3><p>There is a lot to be said about security and is a topic of many books. Of course
75all this can not be written here but to just establish some basic security → you
76should always use SSL with your application. Some fantastic free certificates
77are available by <a href=https://letsencrypt.org>Let's Encrypt - Free SSL/TLS
78Certificates</a>. With SSL certificate installed you
79should then make use of HTTP headers and send your "API key" via a header. If
80your key is send via header then this key is encrypted by SSL and send encrypted
81over the network. Never send your api keys by GET parameter like
82<code>http://example.com/?api_key=somekeyvalue</code>. The problem that this kind of
83sending presents is that this key is visible in logs and by network sniffers.<p>There is a fantastic article describing some aspects about security: <a href=https://www.keycdn.com/blog/web-application-security-best-practices/>11 Web
84Application Security Best
85Practices</a>. Please
86check it out.<h3 id=simple-api-for-writing-data-points>Simple API for writing data-points</h3><p>We will now be using boilerplate code from example above and extend it to be
87SQLite3 because it plays well with Python and can store quite large amount of
88able to write data received by API to local storage. For example use I will use
89data. I have been using it to collect gigabytes of data in a single database
90without any corruption or problems → your experience may vary.<p>To avoid learning SQLite I will be using <a href=https://dataset.readthedocs.io/en/latest/index.html>Dataset: databases for lazy
91people</a>. This package
92abstracts SQL and simplifies writing and reading data from database. You should
93install this package with pip software <code>pip install dataset --user</code>.<p>Because API will use POST method I will be testing if code works correctly by
94using <a href=https://chrome.google.com/webstore/detail/restlet-client-rest-api-t/aejoelaoggembcahagimdiliamlcdmfm>Restlet Client for Google
95Chrome</a>.
96This software also allows you to set headers → for basic security with API_KEY.<p>To quickly generate passwords or API keys I usually use this nifty website
97<a href=https://randomkeygen.com/>RandomKeygen</a>.<p>Copy and paste code below over your previous code in file <code>webapp.py</code>.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># -*- coding: utf-8 -*-</span>
98</span></span><span style=display:flex><span>
99</span></span><span style=display:flex><span><span style=color:#00f>import</span> time
100</span></span><span style=display:flex><span><span style=color:#00f>import</span> bottle
101</span></span><span style=display:flex><span><span style=color:#00f>import</span> random
102</span></span><span style=display:flex><span><span style=color:#00f>import</span> dataset
103</span></span><span style=display:flex><span>
104</span></span><span style=display:flex><span><span style=color:green># initializing bottle app</span>
105</span></span><span style=display:flex><span>app = bottle.Bottle()
106</span></span><span style=display:flex><span>
107</span></span><span style=display:flex><span><span style=color:green># connects to sqlite database</span>
108</span></span><span style=display:flex><span><span style=color:green># check_same_thread=False allows using it in multi-threaded mode</span>
109</span></span><span style=display:flex><span>app.config[<span style=color:#a31515>&#34;dsn&#34;</span>] = dataset.connect(<span style=color:#a31515>&#34;sqlite:///data.db?check_same_thread=False&#34;</span>)
110</span></span><span style=display:flex><span>
111</span></span><span style=display:flex><span><span style=color:green># api key that will be used in Arduino code</span>
112</span></span><span style=display:flex><span>app.config[<span style=color:#a31515>&#34;api_key&#34;</span>] = <span style=color:#a31515>&#34;JtF2aUE5SGHfVJBCG5SH&#34;</span>
113</span></span><span style=display:flex><span>
114</span></span><span style=display:flex><span><span style=color:green># triggered when /api is accessed from browser</span>
115</span></span><span style=display:flex><span><span style=color:green># only accepts POST → no GET allowed</span>
116</span></span><span style=display:flex><span>@app.route(<span style=color:#a31515>&#34;/api&#34;</span>, method=[<span style=color:#a31515>&#34;POST&#34;</span>])
117</span></span><span style=display:flex><span><span style=color:#00f>def</span> route_default():
118</span></span><span style=display:flex><span> status = 400
119</span></span><span style=display:flex><span> ts = int(time.time()) <span style=color:green># current timestamp</span>
120</span></span><span style=display:flex><span> value = bottle.request.body.read() <span style=color:green># data from device</span>
121</span></span><span style=display:flex><span> api_key = bottle.request.get_header(<span style=color:#a31515>&#34;Api_Key&#34;</span>) <span style=color:green># api key from header</span>
122</span></span><span style=display:flex><span>
123</span></span><span style=display:flex><span> <span style=color:green># outputs to console received data for debug reason</span>
124</span></span><span style=display:flex><span> print <span style=color:#a31515>&#34;&gt;&gt;&gt; </span><span style=color:#a31515>{}</span><span style=color:#a31515> :: </span><span style=color:#a31515>{}</span><span style=color:#a31515>&#34;</span>.format(value, api_key)
125</span></span><span style=display:flex><span>
126</span></span><span style=display:flex><span> <span style=color:green># if api_key is correct and value is present</span>
127</span></span><span style=display:flex><span> <span style=color:green># then writes attribute to point table</span>
128</span></span><span style=display:flex><span> <span style=color:#00f>if</span> api_key == app.config[<span style=color:#a31515>&#34;api_key&#34;</span>] <span style=color:#00f>and</span> value:
129</span></span><span style=display:flex><span> app.config[<span style=color:#a31515>&#34;dsn&#34;</span>][<span style=color:#a31515>&#34;point&#34;</span>].insert(dict(ts=ts, value=value))
130</span></span><span style=display:flex><span> status = 200
131</span></span><span style=display:flex><span>
132</span></span><span style=display:flex><span> <span style=color:green># we only need to return status</span>
133</span></span><span style=display:flex><span> <span style=color:#00f>return</span> bottle.HTTPResponse(status=status, body=<span style=color:#a31515>&#34;&#34;</span>)
134</span></span><span style=display:flex><span>
135</span></span><span style=display:flex><span><span style=color:green># starting server on http://0.0.0.0:5000</span>
136</span></span><span style=display:flex><span><span style=color:#00f>if</span> __name__ == <span style=color:#a31515>&#34;__main__&#34;</span>:
137</span></span><span style=display:flex><span> bottle.run(
138</span></span><span style=display:flex><span> app = app,
139</span></span><span style=display:flex><span> host = <span style=color:#a31515>&#34;0.0.0.0&#34;</span>,
140</span></span><span style=display:flex><span> port = 5000,
141</span></span><span style=display:flex><span> debug = <span style=color:#00f>True</span>,
142</span></span><span style=display:flex><span> reloader = <span style=color:#00f>True</span>,
143</span></span><span style=display:flex><span> catchall = <span style=color:#00f>True</span>,
144</span></span><span style=display:flex><span> )
145</span></span></code></pre><p>To run this simply go to folder containing python file and run <code>python webapp.py</code> from terminal. If everything goes ok you should have simple API
146available via POST method on /api route.<p>After testing the service with Restlet Client you should be able to view your
147data in a database file <code>data.db</code>.<figure><img src=/posts/iot-application/iot-rest-example.png alt="REST settings example"></figure><p>You can also check the contents of new database file by using desktop client
148for SQLite → <a href=http://sqlitebrowser.org/>DB Browser for SQLite</a>.<figure><img src=/posts/iot-application/iot-sqlite-db.png alt="SQLite database example"></figure><p>Table structure is as simple as it can be. We have ts (timestamp) and value
149(value from Arduino). As you can see timestamp is generated on API side. If you
150would happen to have atomic clock on Arduino it would be then better to generate
151and send timestamp with the value. This would be particularity useful if we
152would be collecting sensor data at a higher frequency and then sending this data
153in bulk to API.<p>If you will deploy this app with uWSGI and multi-threaded, use DSN (Data Source
154Name) url with <code>?check_same_thread=False</code>.<p>Ok, now that we have some sort of a working API with some basic security so
155unwanted people can not post data to your database can we proceed further and
156try to program Arduino to send data to API.<h2 id=sending-data-to-api-with-arduino-mkr1000>Sending data to API with Arduino MKR1000</h2><p>First of all you should have MKR1000 module and microUSB cable to proceed. If
157you have ever done any work with Arduino you should know that you also need
158<a href=https://www.arduino.cc/en/Main/Software>Arduino IDE</a>. On provided link you
159should be able to download and install IDE. Once that task is completed and you
160have successfully run blink example you should proceed to the next step.<p>In order to use wireless capabilities of MKR1000 you need to first install
161<a href=https://www.arduino.cc/en/Reference/WiFi101>WiFi101 library</a> in Arduino IDE.
162Please check before you install, you may already have it installed.<p>Code below is a working example that sends data to API. Before you try to test
163your code make sure you have run Python web application. Then change settings
164for wifi, api endpoint and api_key. If by some reason code bellow doesn't work
165for you please leave a comment and I'll try to help.<p>Once you have opened IDE and copied this code try to compile and upload it.
166Then open "Serial monitor" to see if any output is presented by Arduino.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>#include</span> <span style=color:#00f>&lt;WiFi101.h&gt;</span><span style=color:#00f>
167</span></span></span><span style=display:flex><span><span style=color:#00f></span>
168</span></span><span style=display:flex><span><span style=color:green>// wifi settings
169</span></span></span><span style=display:flex><span><span style=color:green></span><span style=color:#2b91af>char</span> ssid[] = <span style=color:#a31515>&#34;ssid-name&#34;</span>;
170</span></span><span style=display:flex><span><span style=color:#2b91af>char</span> pass[] = <span style=color:#a31515>&#34;ssid-password&#34;</span>;
171</span></span><span style=display:flex><span>
172</span></span><span style=display:flex><span><span style=color:green>// api server enpoint
173</span></span></span><span style=display:flex><span><span style=color:green></span><span style=color:#2b91af>char</span> server[] = <span style=color:#a31515>&#34;192.168.6.22&#34;</span>;
174</span></span><span style=display:flex><span><span style=color:#2b91af>int</span> port = 5000;
175</span></span><span style=display:flex><span>
176</span></span><span style=display:flex><span><span style=color:green>// api key that must be the same as the one in Python code
177</span></span></span><span style=display:flex><span><span style=color:green></span>String api_key = <span style=color:#a31515>&#34;JtF2aUE5SGHfVJBCG5SH&#34;</span>;
178</span></span><span style=display:flex><span>
179</span></span><span style=display:flex><span><span style=color:green>// frequency data is sent in ms - every 5 seconds
180</span></span></span><span style=display:flex><span><span style=color:green></span><span style=color:#2b91af>int</span> timeout = 1000 * 5;
181</span></span><span style=display:flex><span>
182</span></span><span style=display:flex><span><span style=color:#2b91af>int</span> status = WL_IDLE_STATUS;
183</span></span><span style=display:flex><span>
184</span></span><span style=display:flex><span><span style=color:#2b91af>void</span> setup() {
185</span></span><span style=display:flex><span>
186</span></span><span style=display:flex><span> <span style=color:green>// initialize serial and wait for port to open:
187</span></span></span><span style=display:flex><span><span style=color:green></span> Serial.begin(9600);
188</span></span><span style=display:flex><span> delay(1000);
189</span></span><span style=display:flex><span>
190</span></span><span style=display:flex><span> <span style=color:green>// check for the presence of the shield
191</span></span></span><span style=display:flex><span><span style=color:green></span> <span style=color:#00f>if</span> (WiFi.status() == WL_NO_SHIELD) {
192</span></span><span style=display:flex><span> Serial.println(<span style=color:#a31515>&#34;WiFi shield not present&#34;</span>);
193</span></span><span style=display:flex><span> <span style=color:#00f>while</span> (true);
194</span></span><span style=display:flex><span> }
195</span></span><span style=display:flex><span>
196</span></span><span style=display:flex><span> <span style=color:green>// attempt to connect to wifi network
197</span></span></span><span style=display:flex><span><span style=color:green></span> <span style=color:#00f>while</span> (status != WL_CONNECTED) {
198</span></span><span style=display:flex><span> Serial.print(<span style=color:#a31515>&#34;Attempting to connect to SSID: &#34;</span>);
199</span></span><span style=display:flex><span> Serial.println(ssid);
200</span></span><span style=display:flex><span> status = WiFi.begin(ssid, pass);
201</span></span><span style=display:flex><span> <span style=color:green>// wait 10 seconds for connection
202</span></span></span><span style=display:flex><span><span style=color:green></span> delay(10000);
203</span></span><span style=display:flex><span> }
204</span></span><span style=display:flex><span>
205</span></span><span style=display:flex><span> <span style=color:green>// output wifi status to serial monitor
206</span></span></span><span style=display:flex><span><span style=color:green></span> Serial.print(<span style=color:#a31515>&#34;SSID: &#34;</span>);
207</span></span><span style=display:flex><span> Serial.println(WiFi.SSID());
208</span></span><span style=display:flex><span>
209</span></span><span style=display:flex><span> IPAddress ip = WiFi.localIP();
210</span></span><span style=display:flex><span> Serial.print(<span style=color:#a31515>&#34;IP Address: &#34;</span>);
211</span></span><span style=display:flex><span> Serial.println(ip);
212</span></span><span style=display:flex><span>
213</span></span><span style=display:flex><span> <span style=color:#2b91af>long</span> rssi = WiFi.RSSI();
214</span></span><span style=display:flex><span> Serial.print(<span style=color:#a31515>&#34;signal strength (RSSI):&#34;</span>);
215</span></span><span style=display:flex><span> Serial.print(rssi);
216</span></span><span style=display:flex><span> Serial.println(<span style=color:#a31515>&#34; dBm&#34;</span>);
217</span></span><span style=display:flex><span>}
218</span></span><span style=display:flex><span>
219</span></span><span style=display:flex><span><span style=color:#2b91af>void</span> loop() {
220</span></span><span style=display:flex><span> WiFiClient client;
221</span></span><span style=display:flex><span>
222</span></span><span style=display:flex><span> <span style=color:#00f>if</span> (client.connect(server, port)) {
223</span></span><span style=display:flex><span>
224</span></span><span style=display:flex><span> <span style=color:green>// I use random number generator for this example
225</span></span></span><span style=display:flex><span><span style=color:green></span> <span style=color:green>// but you can use analog or digital inputs from arduino
226</span></span></span><span style=display:flex><span><span style=color:green></span> String content = String(random(1000));
227</span></span><span style=display:flex><span>
228</span></span><span style=display:flex><span> client.println(<span style=color:#a31515>&#34;POST /api HTTP/1.1&#34;</span>);
229</span></span><span style=display:flex><span> client.println(<span style=color:#a31515>&#34;Connection: close&#34;</span>);
230</span></span><span style=display:flex><span> client.println(<span style=color:#a31515>&#34;Api-Key: &#34;</span> + api_key);
231</span></span><span style=display:flex><span> client.println(<span style=color:#a31515>&#34;Content-Length: &#34;</span> + String(content.length()));
232</span></span><span style=display:flex><span> client.println();
233</span></span><span style=display:flex><span> client.println(content);
234</span></span><span style=display:flex><span>
235</span></span><span style=display:flex><span> delay(100);
236</span></span><span style=display:flex><span> client.stop();
237</span></span><span style=display:flex><span> Serial.println(<span style=color:#a31515>&#34;Data sent successfully ...&#34;</span>);
238</span></span><span style=display:flex><span>
239</span></span><span style=display:flex><span> } <span style=color:#00f>else</span> {
240</span></span><span style=display:flex><span> Serial.println(<span style=color:#a31515>&#34;Problem sending data ...&#34;</span>);
241</span></span><span style=display:flex><span> }
242</span></span><span style=display:flex><span>
243</span></span><span style=display:flex><span> <span style=color:green>// waits for x seconds and continue looping
244</span></span></span><span style=display:flex><span><span style=color:green></span> delay(timeout);
245</span></span><span style=display:flex><span>}
246</span></span></code></pre><p>As seen from example you can notice that Arduino is generating random integer
247between [ 0 .. 1000 ]. You can easily replace this with a temperature sensor or
248any other kind of sensor.<p>Now that we have API under the hood and Arduino is sending demo data we can now
249focus on data visualization.<h2 id=data-visualization>Data visualization</h2><p>Before we continue we should examine our project folder structure. Currently we
250only have two files in our project:<p><em>simple-iot-app/</em><ul><li><em>webapp.py</em><li><em>data.db</em></ul><p>We will now add HTML template that will contain CSS and JavaScript code inline
251for the simplicity reason. And for the bottle framework to be able to scan root
252application folder for templates we will add <code>bottle.TEMPLATE_PATH.insert(0, "./")</code> in <code>webapp.py</code>. By default bottle framework uses <code>views/</code>
253subfolder to store templates. This is not the ideal situation and if you will
254use bottle to develop web applications you should use native behavior and store
255templates in it's predefined folder. But for the sake of example we will
256over-ride this. Be careful to fully replace your code with new code that is
257provided below. Avoid partially replacing code in file :) Also new code for
258reading data-points is provided in Python example below.<p>First we add new route to our web application. It should be trigger when browser
259hits root of application <code>http://0.0.0.0:5000/</code>. This route will do nothing
260more than render <code>frontend.html</code> template. This is done by <code>return bottle.template("frontend.html")</code>. Check code below to further examine how
261exactly this is done.<p>Now we will expand <code>/api</code> route and use different methods to write or read
262data-points. For writing data-point we will use POST method and for reading
263points we will use GET method. GET method will return JSON object with latest
264readings and historical data.<p>There is a fantastic JavaScript library for plotting time-series charts called
265<a href=https://www.metricsgraphicsjs.org>MetricsGraphics.js</a> that is based on
266<a href=https://d3js.org/>D3.js</a> library for visualizing data.<p>Data schema required by MetricsGraphics.js → to achieve this we need to
267transform data from database into this format:<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>[
268</span></span><span style=display:flex><span> {
269</span></span><span style=display:flex><span> &#34;date&#34;: <span style=color:#a31515>&#34;2017-08-11 01:07:20&#34;</span>,
270</span></span><span style=display:flex><span> &#34;value&#34;: 933
271</span></span><span style=display:flex><span> },
272</span></span><span style=display:flex><span> {
273</span></span><span style=display:flex><span> &#34;date&#34;: <span style=color:#a31515>&#34;2017-08-11 01:07:30&#34;</span>,
274</span></span><span style=display:flex><span> &#34;value&#34;: 743
275</span></span><span style=display:flex><span> }
276</span></span><span style=display:flex><span>]
277</span></span></code></pre><p>Web application is now complete and we only need <code>frontend.html</code> that we
278will develop now. If you would try to start web app now and go to root app this
279will return error because we don't have frontend.html yet.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># -*- coding: utf-8 -*-</span>
280</span></span><span style=display:flex><span>
281</span></span><span style=display:flex><span><span style=color:#00f>import</span> time
282</span></span><span style=display:flex><span><span style=color:#00f>import</span> bottle
283</span></span><span style=display:flex><span><span style=color:#00f>import</span> json
284</span></span><span style=display:flex><span><span style=color:#00f>import</span> datetime
285</span></span><span style=display:flex><span><span style=color:#00f>import</span> random
286</span></span><span style=display:flex><span><span style=color:#00f>import</span> dataset
287</span></span><span style=display:flex><span>
288</span></span><span style=display:flex><span><span style=color:green># initializing bottle app</span>
289</span></span><span style=display:flex><span>app = bottle.Bottle()
290</span></span><span style=display:flex><span>
291</span></span><span style=display:flex><span><span style=color:green># adds root directory as template folder</span>
292</span></span><span style=display:flex><span>bottle.TEMPLATE_PATH.insert(0, <span style=color:#a31515>&#34;./&#34;</span>)
293</span></span><span style=display:flex><span>
294</span></span><span style=display:flex><span><span style=color:green># connects to sqlite database</span>
295</span></span><span style=display:flex><span><span style=color:green># check_same_thread=False allows using it in multi-threaded mode</span>
296</span></span><span style=display:flex><span>app.config[<span style=color:#a31515>&#34;db&#34;</span>] = dataset.connect(<span style=color:#a31515>&#34;sqlite:///data.db?check_same_thread=False&#34;</span>)
297</span></span><span style=display:flex><span>
298</span></span><span style=display:flex><span><span style=color:green># api key that will be used in Arduino code</span>
299</span></span><span style=display:flex><span>app.config[<span style=color:#a31515>&#34;api_key&#34;</span>] = <span style=color:#a31515>&#34;JtF2aUE5SGHfVJBCG5SH&#34;</span>
300</span></span><span style=display:flex><span>
301</span></span><span style=display:flex><span><span style=color:green># triggered when / is accessed from browser</span>
302</span></span><span style=display:flex><span><span style=color:green># only accepts GET → no POST allowed</span>
303</span></span><span style=display:flex><span>@app.route(<span style=color:#a31515>&#34;/&#34;</span>, method=[<span style=color:#a31515>&#34;GET&#34;</span>])
304</span></span><span style=display:flex><span><span style=color:#00f>def</span> route_default():
305</span></span><span style=display:flex><span> <span style=color:#00f>return</span> bottle.template(<span style=color:#a31515>&#34;frontend.html&#34;</span>)
306</span></span><span style=display:flex><span>
307</span></span><span style=display:flex><span><span style=color:green># triggered when /api is accessed from browser</span>
308</span></span><span style=display:flex><span><span style=color:green># accepts POST and GET</span>
309</span></span><span style=display:flex><span>@app.route(<span style=color:#a31515>&#34;/api&#34;</span>, method=[<span style=color:#a31515>&#34;GET&#34;</span>, <span style=color:#a31515>&#34;POST&#34;</span>])
310</span></span><span style=display:flex><span><span style=color:#00f>def</span> route_default():
311</span></span><span style=display:flex><span>
312</span></span><span style=display:flex><span> <span style=color:green># if method is POST then we write datapoint</span>
313</span></span><span style=display:flex><span> <span style=color:#00f>if</span> bottle.request.method == <span style=color:#a31515>&#34;POST&#34;</span>:
314</span></span><span style=display:flex><span> status = 400
315</span></span><span style=display:flex><span> ts = int(time.time()) <span style=color:green># current timestamp</span>
316</span></span><span style=display:flex><span> value = bottle.request.body.read() <span style=color:green># data from device</span>
317</span></span><span style=display:flex><span> api_key = bottle.request.get_header(<span style=color:#a31515>&#34;Api-Key&#34;</span>) <span style=color:green># api key from header</span>
318</span></span><span style=display:flex><span>
319</span></span><span style=display:flex><span> <span style=color:green># outputs to console recieved data for debug reason</span>
320</span></span><span style=display:flex><span> print <span style=color:#a31515>&#34;&gt;&gt;&gt; </span><span style=color:#a31515>{}</span><span style=color:#a31515> :: </span><span style=color:#a31515>{}</span><span style=color:#a31515>&#34;</span>.format(value, api_key)
321</span></span><span style=display:flex><span>
322</span></span><span style=display:flex><span> <span style=color:green># if api_key is correct and value is present</span>
323</span></span><span style=display:flex><span> <span style=color:green># then writes attribute to point table</span>
324</span></span><span style=display:flex><span> <span style=color:#00f>if</span> api_key == app.config[<span style=color:#a31515>&#34;api_key&#34;</span>] <span style=color:#00f>and</span> value:
325</span></span><span style=display:flex><span> app.config[<span style=color:#a31515>&#34;db&#34;</span>][<span style=color:#a31515>&#34;point&#34;</span>].insert(dict(ts=ts, value=value))
326</span></span><span style=display:flex><span> status = 200
327</span></span><span style=display:flex><span>
328</span></span><span style=display:flex><span> <span style=color:green># we only need to return status</span>
329</span></span><span style=display:flex><span> <span style=color:#00f>return</span> bottle.HTTPResponse(status=status, body=<span style=color:#a31515>&#34;&#34;</span>)
330</span></span><span style=display:flex><span>
331</span></span><span style=display:flex><span> <span style=color:green># if method is GET then we read datapoint</span>
332</span></span><span style=display:flex><span> <span style=color:#00f>else</span>:
333</span></span><span style=display:flex><span> response = []
334</span></span><span style=display:flex><span> datapoints = app.config[<span style=color:#a31515>&#34;db&#34;</span>][<span style=color:#a31515>&#34;point&#34;</span>].all()
335</span></span><span style=display:flex><span>
336</span></span><span style=display:flex><span> <span style=color:#00f>for</span> point <span style=color:#00f>in</span> datapoints:
337</span></span><span style=display:flex><span> response.append({
338</span></span><span style=display:flex><span> <span style=color:#a31515>&#34;date&#34;</span>: datetime.datetime.fromtimestamp(int(point[<span style=color:#a31515>&#34;ts&#34;</span>])).strftime(<span style=color:#a31515>&#34;%Y-%m-</span><span style=color:#a31515>%d</span><span style=color:#a31515> %H:%M:%S&#34;</span>),
339</span></span><span style=display:flex><span> <span style=color:#a31515>&#34;value&#34;</span>: point[<span style=color:#a31515>&#34;value&#34;</span>]
340</span></span><span style=display:flex><span> })
341</span></span><span style=display:flex><span>
342</span></span><span style=display:flex><span> bottle.response.content_type = <span style=color:#a31515>&#34;application/json&#34;</span>
343</span></span><span style=display:flex><span> <span style=color:#00f>return</span> json.dumps(response)
344</span></span><span style=display:flex><span>
345</span></span><span style=display:flex><span><span style=color:green># starting server on http://0.0.0.0:5000</span>
346</span></span><span style=display:flex><span><span style=color:#00f>if</span> __name__ == <span style=color:#a31515>&#34;__main__&#34;</span>:
347</span></span><span style=display:flex><span> bottle.run(
348</span></span><span style=display:flex><span> app = app,
349</span></span><span style=display:flex><span> host = <span style=color:#a31515>&#34;0.0.0.0&#34;</span>,
350</span></span><span style=display:flex><span> port = 5000,
351</span></span><span style=display:flex><span> debug = <span style=color:#00f>True</span>,
352</span></span><span style=display:flex><span> reloader = <span style=color:#00f>True</span>,
353</span></span><span style=display:flex><span> catchall = <span style=color:#00f>True</span>,
354</span></span><span style=display:flex><span> )
355</span></span></code></pre><p>And now finally we can implement <code>frontend.html</code>. Create file with this name
356and copy code below. When you are done you can start web application. Steps for
357this part are listed below the code.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>&lt;!DOCTYPE html&gt;</span>
358</span></span><span style=display:flex><span>&lt;html&gt;
359</span></span><span style=display:flex><span>
360</span></span><span style=display:flex><span> &lt;head&gt;
361</span></span><span style=display:flex><span> &lt;meta charset=<span style=color:#a31515>&#34;utf-8&#34;</span>&gt;
362</span></span><span style=display:flex><span> &lt;title&gt;Simple IOT application&lt;/title&gt;
363</span></span><span style=display:flex><span> &lt;/head&gt;
364</span></span><span style=display:flex><span>
365</span></span><span style=display:flex><span> &lt;body&gt;
366</span></span><span style=display:flex><span>
367</span></span><span style=display:flex><span> &lt;h1&gt;Simple IOT application&lt;/h1&gt;
368</span></span><span style=display:flex><span>
369</span></span><span style=display:flex><span> &lt;div class=<span style=color:#a31515>&#34;chart-placeholder&#34;</span>&gt;
370</span></span><span style=display:flex><span> &lt;div id=<span style=color:#a31515>&#34;chart&#34;</span>&gt;&lt;/div&gt;
371</span></span><span style=display:flex><span> &lt;/div&gt;
372</span></span><span style=display:flex><span>
373</span></span><span style=display:flex><span> <span style=color:green>&lt;!-- application main script --&gt;</span>
374</span></span><span style=display:flex><span> &lt;script src=<span style=color:#a31515>&#34;https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js&#34;</span>&gt;&lt;/script&gt;
375</span></span><span style=display:flex><span> &lt;script src=<span style=color:#a31515>&#34;https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js&#34;</span>&gt;&lt;/script&gt;
376</span></span><span style=display:flex><span> &lt;script src=<span style=color:#a31515>&#34;https://cdnjs.cloudflare.com/ajax/libs/metrics-graphics/2.11.0/metricsgraphics.min.js&#34;</span>&gt;&lt;/script&gt;
377</span></span><span style=display:flex><span> &lt;script&gt;
378</span></span><span style=display:flex><span> <span style=color:#00f>function</span> fetch_and_render() {
379</span></span><span style=display:flex><span> d3.json(<span style=color:#a31515>&#34;/api&#34;</span>, <span style=color:#00f>function</span>(data) {
380</span></span><span style=display:flex><span> data = MG.convert.date(data, <span style=color:#a31515>&#34;date&#34;</span>, <span style=color:#a31515>&#34;%Y-%m-%d %H:%M:%S&#34;</span>);
381</span></span><span style=display:flex><span> MG.data_graphic({
382</span></span><span style=display:flex><span> data: data,
383</span></span><span style=display:flex><span> chart_type: <span style=color:#a31515>&#34;line&#34;</span>,
384</span></span><span style=display:flex><span> full_width: <span style=color:#00f>true</span>,
385</span></span><span style=display:flex><span> height: 270,
386</span></span><span style=display:flex><span> target: document.getElementById(<span style=color:#a31515>&#34;chart&#34;</span>),
387</span></span><span style=display:flex><span> x_accessor: <span style=color:#a31515>&#34;date&#34;</span>,
388</span></span><span style=display:flex><span> y_accessor: <span style=color:#a31515>&#34;value&#34;</span>
389</span></span><span style=display:flex><span> });
390</span></span><span style=display:flex><span> });
391</span></span><span style=display:flex><span> }
392</span></span><span style=display:flex><span> window.onload = <span style=color:#00f>function</span>() {
393</span></span><span style=display:flex><span> <span style=color:green>// initial call for rendering
394</span></span></span><span style=display:flex><span><span style=color:green></span> fetch_and_render();
395</span></span><span style=display:flex><span>
396</span></span><span style=display:flex><span> <span style=color:green>// updates chart every 5 seconds
397</span></span></span><span style=display:flex><span><span style=color:green></span> setInterval(<span style=color:#00f>function</span>() {
398</span></span><span style=display:flex><span> fetch_and_render();
399</span></span><span style=display:flex><span> }, 5000);
400</span></span><span style=display:flex><span> }
401</span></span><span style=display:flex><span> &lt;/script&gt;
402</span></span><span style=display:flex><span>
403</span></span><span style=display:flex><span> <span style=color:green>&lt;!-- application styles --&gt;</span>
404</span></span><span style=display:flex><span> &lt;style&gt;
405</span></span><span style=display:flex><span> body {
406</span></span><span style=display:flex><span> <span style=color:#00f>font</span>: 13<span style=color:#2b91af>px</span> <span style=color:#00f>sans-serif</span>;
407</span></span><span style=display:flex><span> <span style=color:#00f>padding</span>: 20<span style=color:#2b91af>px</span> 50<span style=color:#2b91af>px</span>;
408</span></span><span style=display:flex><span> }
409</span></span><span style=display:flex><span> .<span style=color:#2b91af>chart-placeholder</span> {
410</span></span><span style=display:flex><span> <span style=color:#00f>border</span>: 2<span style=color:#2b91af>px</span> <span style=color:#00f>solid</span> #ccc;
411</span></span><span style=display:flex><span> <span style=color:#00f>width</span>: 100<span style=color:#2b91af>%</span>;
412</span></span><span style=display:flex><span> <span style=color:#00f>user-select</span>: <span style=color:#00f>none</span>;
413</span></span><span style=display:flex><span> }
414</span></span><span style=display:flex><span> <span style=color:green>/* chart styles */</span>
415</span></span><span style=display:flex><span> .<span style=color:#2b91af>mg-line1-color</span> {
416</span></span><span style=display:flex><span> stroke: <span style=color:#00f>red</span>;
417</span></span><span style=display:flex><span> stroke-width: 2;
418</span></span><span style=display:flex><span> }
419</span></span><span style=display:flex><span> .<span style=color:#2b91af>mg-main-area</span>, .<span style=color:#2b91af>mg-main-line</span> {
420</span></span><span style=display:flex><span> fill: #fff;
421</span></span><span style=display:flex><span> }
422</span></span><span style=display:flex><span> .<span style=color:#2b91af>mg-x-axis</span> line, .<span style=color:#2b91af>mg-y-axis</span> line {
423</span></span><span style=display:flex><span> stroke: #b3b2b2;
424</span></span><span style=display:flex><span> stroke-width: 1<span style=color:#2b91af>px</span>;
425</span></span><span style=display:flex><span> }
426</span></span><span style=display:flex><span> &lt;/style&gt;
427</span></span><span style=display:flex><span>
428</span></span><span style=display:flex><span> &lt;/body&gt;
429</span></span><span style=display:flex><span>
430</span></span><span style=display:flex><span>&lt;/html&gt;
431</span></span></code></pre><p>Now the folder structure should look like:<p><em>simple-iot-app/</em><ul><li><em>webapp.py</em><li><em>data.db</em><li><em>frontend.html</em></ul><p>Ok, lets now start application and start feeding it data.<ol><li><code>python webapp.py</code><li>connect Arduino MKR1000 to power source<li>open browser and go to <code>http://0.0.0.0:5000</code></ol><p>If everything goes well you should be seeing new data-points rendered on chart
432every 5 seconds.<p>If you navigate to <code>http://0.0.0.0:5000</code> you should see rendered chart as
433shown on picture below.<figure><img src=/posts/iot-application/iot-app-output.png alt="Application output"></figure><p>Complete application with all the code is available for
434<a href=/posts/iot-application/simple-iot-application.zip>download</a>.<h2 id=conclusion>Conclusion</h2><p>I hope this clarifies some aspects of IOT application development. Of course
435this is a minimal example and is far from what can be done in real life with
436some further dive into other technologies.<p>If you would like to continue exploring IOT world here are some interesting
437resources for you to examine:<ul><li><a href=https://www.allaboutcircuits.com/projects/reading-sensors-with-an-arduino/>Reading Sensors with an Arduino</a><li><a href=http://www.hivemq.com/blog/how-to-get-started-with-mqtt>MQTT 101 – How to Get Started with the lightweight IoT Protocol</a><li><a href=https://www.html5rocks.com/en/tutorials/eventsource/basics/>Stream Updates with Server-Sent Events</a><li><a href=http://www.tutorialspoint.com/internet_of_things/>Internet of Things (IoT) Tutorials</a></ul><p>Any comment or additional ideas are welcomed in comments below.</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
438a lock on a Linux NFS server, which turned
439out to be specific to NFS v3 (which I really should have seen coming,
440since it involved NLM and lockd). Finding the NFS v4 client that
441owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
442and Bradley Kuhn, are interacting on the OSI's license-discuss
443list where the're doing
444bad computer history and insisting that a guy Larry Rosen
445coincidentally interviewed for a book years ago is clearly the origin of
446somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
447i2c, plan9
448Another month, another file system.
449Well, if you can’t fix it in software, fix it in hardware (looking at
450you, bme680, we’re not
451done yet). The show must go on, as they say, and I would like my
452experiments to go on.
453So a “new” addition to the environmental sensor family connected to
454the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
455this mortal coil, we are endowed with self-awareness, agency, and free will.
456Each of the 8 billion members of this human race represents a unique person, a
457unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
458My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
4591.0 has been released:
460wifi_da-1.0.sit
461(StuffIt 3 archive)
462SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
463This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
464classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
465In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
466Design Goals
467I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
468at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
469catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
470specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
471 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
472 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/simple-server-sent-events-based-pubsub-server.html b/public/simple-server-sent-events-based-pubsub-server.html
deleted file mode 100755
index 9d316b5..0000000
--- a/public/simple-server-sent-events-based-pubsub-server.html
+++ /dev/null
@@ -1,343 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Simple Server-Sent Events based PubSub Server</title><meta name=description content="Before we continue ."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Simple Server-Sent Events based PubSub Server</h1><p><cap>post</cap>, Mar 22, 2020 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><h2 id=before-we-continue->Before we continue ...</h2><p>Publisher Subscriber model is nothing new and there are many amazing solutions
10out there, so writing a new one would be a waste of time if other solutions
11wouldn't have quite complex install procedures and weren't so hard to maintain.
12But to be fair, comparing this simple server with something like
13<a href=https://kafka.apache.org/>Kafka</a> or <a href=https://www.rabbitmq.com/>RabbitMQ</a> is
14laughable at the least. Those solutions are enterprise grade and have many
15mechanisms there to ensure messages aren't lost and much more. Regardless of
16these drawbacks, this method has been tested on a large website and worked until
17now without any problems. So now, that we got that cleared up, let's continue.<p><em><strong>Wiki definition:</strong> Publish/subscribe messaging, or pub/sub messaging, is a
18form of asynchronous service-to-service communication used in serverless and
19microservices architectures. In a pub/sub model, any message published to a
20topic is immediately received by all the subscribers to the topic.</em><h2 id=general-goals>General goals</h2><ul><li>provide a simple server that relays messages to all the connected clients,<li>messages can be posted on specific topics,<li>messages get sent via <a href=https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events>Server-Sent
21Events</a>
22to all the subscribers.</ul><h2 id=how-exactly-does-the-pubsub-model-work>How exactly does the pub/sub model work?</h2><p>The easiest way to explain this is with diagram bellow. Basic function is
23simple. We have subscribers that receive messages, and we have publishers that
24create and post messages. Similar model is also well know pattern that works on
25a premise of consumers and producers, and they take similar roles.<figure><img src=/posts/simple-pubsub-server/pubsub-overview.png alt="How PubSub works"></figure><p><strong>These are some naive characteristics we want to achieve:</strong><ul><li>producer is publishing messages to subscribe topic,<li>consumer is receiving messages from subscribed topic,<li>servers is also known as Broker,<li>broker does not store messages or tracks success,<li>broker uses
26<a href=https://en.wikipedia.org/wiki/FIFO_(computing_and_electronics)>FIFO</a> method
27for delivering messages,<li>if consumer wants to receive messages from a topic, producer and consumer
28topics must match,<li>consumer can subscribe to multiple topics,<li>producer can publish to multiple topics,<li>each message has a messageId.</ul><p><strong>Known drawbacks:</strong><ul><li>messages will not be stored in a persistent queue or unreceived messages like
29<a href=https://en.wikipedia.org/wiki/Dead_letter_queue>DeadLetterQueue</a> so old
30messages could be lost on server restart,<li><a href=https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events>Server-Sent
31Events</a>
32opens a long-running connection between the client and the server so make sure
33if your setup is load balanced that the load balancer in this case can have
34long opened connection,<li>no system moderation due to the dynamic nature of creating queues.</ul><h2 id=server-sent-events>Server-Sent Events</h2><p>Read more about it on <a href=https://html.spec.whatwg.org/multipage/server-sent-events.html>official specification
35page</a>.<h3 id=current-browser-support>Current browser support</h3><figure><img src=/posts/simple-pubsub-server/caniuse.png alt="Browser support"></figure><p>Check
36<a href="https://caniuse.com/#feat=eventsource">https://caniuse.com/#feat=eventsource</a>
37for latest information about browser support.<h3 id=known-issues>Known issues</h3><ul><li>Firefox 52 and below do not support EventSource in web/shared workers<li>In Firefox prior to version 36 server-sent events do not reconnect
38automatically in case of a connection interrupt (bug)<li>Reportedly, CORS in EventSource is currently supported in Firefox 10+, Opera
3912+, Chrome 26+, Safari 7.0+.<li>Antivirus software may block the event streaming data chunks.</ul><p>Source: <a href="https://caniuse.com/#feat=eventsource">https://caniuse.com/#feat=eventsource</a><h3 id=message-format>Message format</h3><p>The simplest message that can be sent is only with data attribute:<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>data: this is a simple message
40</span></span><span style=display:flex><span>&lt;blank line&gt;
41</span></span></code></pre><p>You can send message IDs to be used if the connection is dropped:<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>id: 33
42</span></span><span style=display:flex><span>data: this is line one
43</span></span><span style=display:flex><span>data: this is line two
44</span></span><span style=display:flex><span>&lt;blank line&gt;
45</span></span></code></pre><p>And you can specify your own event types (the above messages will all trigger
46the message event):<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>id: 36
47</span></span><span style=display:flex><span>event: price
48</span></span><span style=display:flex><span>data: 103.34
49</span></span><span style=display:flex><span>&lt;blank line&gt;
50</span></span></code></pre><h3 id=server-requirements>Server requirements</h3><p>The important thing is how you send headers and which headers are sent by the
51server that triggers browser to threat response as a EventStream.<p>Headers responsible for this are:<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>Content-Type: text/event-stream
52</span></span><span style=display:flex><span>Cache-Control: no-cache
53</span></span><span style=display:flex><span>Connection: keep-alive
54</span></span></code></pre><h3 id=debugging-with-google-chrome>Debugging with Google Chrome</h3><p>Google Chrome provides build-in debugging and exploration tool for <a href=https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events>Server-Sent
55Events</a>
56which is quite nice and available from Developer Tools under Network tab.<blockquote><p>You can debug only client side events that get received and not the server
57ones. For debugging server events add <code>console.log</code> to <code>server.js</code> code and
58print out events.</blockquote><figure><img src=/posts/simple-pubsub-server/chrome-debugging.png alt="Google Chrome Developer Tools EventStream"></figure><h2 id=server-implementation>Server implementation</h2><p>For the sake of this example we will use <a href=https://nodejs.org/en/>Node.js</a> with
59<a href=https://expressjs.com>Express</a> as our router since this is the easiest way to
60get started and we will use already written SSE library for node
61<a href=https://www.npmjs.com/package/sse-pubsub>sse-pubsub</a> so we don't reinvent the
62wheel.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>npm init --yes
63</span></span><span style=display:flex><span>
64</span></span><span style=display:flex><span>npm install express
65</span></span><span style=display:flex><span>npm install body-parser
66</span></span><span style=display:flex><span>npm install sse-pubsub
67</span></span></code></pre><p>Basic implementation of a server (<code>server.js</code>):<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>const</span> express = require(<span style=color:#a31515>&#39;express&#39;</span>);
68</span></span><span style=display:flex><span><span style=color:#00f>const</span> bodyParser = require(<span style=color:#a31515>&#39;body-parser&#39;</span>);
69</span></span><span style=display:flex><span><span style=color:#00f>const</span> SSETopic = require(<span style=color:#a31515>&#39;sse-pubsub&#39;</span>);
70</span></span><span style=display:flex><span>
71</span></span><span style=display:flex><span><span style=color:#00f>const</span> app = express();
72</span></span><span style=display:flex><span><span style=color:#00f>const</span> port = process.env.PORT || 4000;
73</span></span><span style=display:flex><span>
74</span></span><span style=display:flex><span><span style=color:green>// topics container
75</span></span></span><span style=display:flex><span><span style=color:green></span><span style=color:#00f>const</span> sseTopics = {};
76</span></span><span style=display:flex><span>
77</span></span><span style=display:flex><span>app.use(bodyParser.json());
78</span></span><span style=display:flex><span>
79</span></span><span style=display:flex><span><span style=color:green>// open for all cors
80</span></span></span><span style=display:flex><span><span style=color:green></span>app.all(<span style=color:#a31515>&#39;*&#39;</span>, (req, res, next) =&gt; {
81</span></span><span style=display:flex><span> res.header(<span style=color:#a31515>&#39;Access-Control-Allow-Origin&#39;</span>, <span style=color:#a31515>&#39;*&#39;</span>);
82</span></span><span style=display:flex><span> res.header(<span style=color:#a31515>&#39;Access-Control-Allow-Headers&#39;</span>, <span style=color:#a31515>&#39;X-Requested-With, Content-Type&#39;</span>);
83</span></span><span style=display:flex><span> next();
84</span></span><span style=display:flex><span>});
85</span></span><span style=display:flex><span>
86</span></span><span style=display:flex><span><span style=color:green>// preflight request error fix
87</span></span></span><span style=display:flex><span><span style=color:green></span>app.options(<span style=color:#a31515>&#39;*&#39;</span>, <span style=color:#00f>async</span> (req, res) =&gt; {
88</span></span><span style=display:flex><span> res.header(<span style=color:#a31515>&#39;Access-Control-Allow-Origin&#39;</span>, <span style=color:#a31515>&#39;*&#39;</span>);
89</span></span><span style=display:flex><span> res.header(<span style=color:#a31515>&#39;Access-Control-Allow-Headers&#39;</span>, <span style=color:#a31515>&#39;X-Requested-With, Content-Type&#39;</span>);
90</span></span><span style=display:flex><span> res.send(<span style=color:#a31515>&#39;OK&#39;</span>);
91</span></span><span style=display:flex><span>});
92</span></span><span style=display:flex><span>
93</span></span><span style=display:flex><span><span style=color:green>// serve the event streams
94</span></span></span><span style=display:flex><span><span style=color:green></span>app.get(<span style=color:#a31515>&#39;/stream/:topic&#39;</span>, <span style=color:#00f>async</span> (req, res, next) =&gt; {
95</span></span><span style=display:flex><span> <span style=color:#00f>const</span> topic = req.params.topic;
96</span></span><span style=display:flex><span>
97</span></span><span style=display:flex><span> <span style=color:#00f>if</span> (!(topic <span style=color:#00f>in</span> sseTopics)) {
98</span></span><span style=display:flex><span> sseTopics[topic] = <span style=color:#00f>new</span> SSETopic({
99</span></span><span style=display:flex><span> pingInterval: 0,
100</span></span><span style=display:flex><span> maxStreamDuration: 15000,
101</span></span><span style=display:flex><span> });
102</span></span><span style=display:flex><span> }
103</span></span><span style=display:flex><span>
104</span></span><span style=display:flex><span> <span style=color:green>// subscribing client to topic
105</span></span></span><span style=display:flex><span><span style=color:green></span> sseTopics[topic].subscribe(req, res);
106</span></span><span style=display:flex><span>});
107</span></span><span style=display:flex><span>
108</span></span><span style=display:flex><span><span style=color:green>// accepts new messages into topic
109</span></span></span><span style=display:flex><span><span style=color:green></span>app.post(<span style=color:#a31515>&#39;/publish&#39;</span>, <span style=color:#00f>async</span> (req, res) =&gt; {
110</span></span><span style=display:flex><span> <span style=color:#00f>let</span> body = req.body;
111</span></span><span style=display:flex><span> <span style=color:#00f>let</span> status = 200;
112</span></span><span style=display:flex><span>
113</span></span><span style=display:flex><span> console.log(<span style=color:#a31515>&#39;Incoming message:&#39;</span>, req.body);
114</span></span><span style=display:flex><span>
115</span></span><span style=display:flex><span> <span style=color:#00f>if</span> (
116</span></span><span style=display:flex><span> body.hasOwnProperty(<span style=color:#a31515>&#39;topic&#39;</span>) &amp;&amp;
117</span></span><span style=display:flex><span> body.hasOwnProperty(<span style=color:#a31515>&#39;event&#39;</span>) &amp;&amp;
118</span></span><span style=display:flex><span> body.hasOwnProperty(<span style=color:#a31515>&#39;message&#39;</span>)
119</span></span><span style=display:flex><span> ) {
120</span></span><span style=display:flex><span> <span style=color:#00f>const</span> topic = req.body.topic;
121</span></span><span style=display:flex><span> <span style=color:#00f>const</span> event = req.body.event;
122</span></span><span style=display:flex><span> <span style=color:#00f>const</span> message = req.body.message;
123</span></span><span style=display:flex><span>
124</span></span><span style=display:flex><span> <span style=color:#00f>if</span> (topic <span style=color:#00f>in</span> sseTopics) {
125</span></span><span style=display:flex><span> <span style=color:green>// sends message to all the subscribers
126</span></span></span><span style=display:flex><span><span style=color:green></span> sseTopics[topic].publish(message, event);
127</span></span><span style=display:flex><span> }
128</span></span><span style=display:flex><span> } <span style=color:#00f>else</span> {
129</span></span><span style=display:flex><span> status = 400;
130</span></span><span style=display:flex><span> }
131</span></span><span style=display:flex><span>
132</span></span><span style=display:flex><span> res.status(status).send({
133</span></span><span style=display:flex><span> status,
134</span></span><span style=display:flex><span> });
135</span></span><span style=display:flex><span>});
136</span></span><span style=display:flex><span>
137</span></span><span style=display:flex><span><span style=color:green>// returns JSON object of all opened topics
138</span></span></span><span style=display:flex><span><span style=color:green></span>app.get(<span style=color:#a31515>&#39;/status&#39;</span>, <span style=color:#00f>async</span> (req, res) =&gt; {
139</span></span><span style=display:flex><span> res.send(sseTopics);
140</span></span><span style=display:flex><span>});
141</span></span><span style=display:flex><span>
142</span></span><span style=display:flex><span><span style=color:green>// health-check endpoint
143</span></span></span><span style=display:flex><span><span style=color:green></span>app.get(<span style=color:#a31515>&#39;/&#39;</span>, <span style=color:#00f>async</span> (req, res) =&gt; {
144</span></span><span style=display:flex><span> res.send(<span style=color:#a31515>&#39;OK&#39;</span>);
145</span></span><span style=display:flex><span>});
146</span></span><span style=display:flex><span>
147</span></span><span style=display:flex><span><span style=color:green>// return a 404 if no routes match
148</span></span></span><span style=display:flex><span><span style=color:green></span>app.use((req, res, next) =&gt; {
149</span></span><span style=display:flex><span> res.set(<span style=color:#a31515>&#39;Cache-Control&#39;</span>, <span style=color:#a31515>&#39;private, no-store&#39;</span>);
150</span></span><span style=display:flex><span> res.status(404).end(<span style=color:#a31515>&#39;Not found&#39;</span>);
151</span></span><span style=display:flex><span>});
152</span></span><span style=display:flex><span>
153</span></span><span style=display:flex><span><span style=color:green>// starts the server
154</span></span></span><span style=display:flex><span><span style=color:green></span>app.listen(port, () =&gt; {
155</span></span><span style=display:flex><span> console.log(<span style=color:#a31515>`PubSub server running on http://localhost:</span><span style=color:#a31515>${</span>port<span style=color:#a31515>}</span><span style=color:#a31515>`</span>);
156</span></span><span style=display:flex><span>});
157</span></span></code></pre><h3 id=our-custom-message-format>Our custom message format</h3><p>Each message posted on a server must be in a specific format that out server
158accepts. Having structure like this allows us to have multiple separated type of
159events on each topic.<p>With this we can separate streams and only receive events that belong to the
160topic.<p>One example would be, that we have index page and we want to receive messages
161about new upvotes or new subscribers but we don't want to follow events for
162other pages. This reduces clutter and overall network. And structure is much
163nicer and maintanable.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>{
164</span></span><span style=display:flex><span> &#34;topic&#34;: <span style=color:#a31515>&#34;sample-topic&#34;</span>,
165</span></span><span style=display:flex><span> &#34;event&#34;: <span style=color:#a31515>&#34;sample-event&#34;</span>,
166</span></span><span style=display:flex><span> &#34;message&#34;: { &#34;name&#34;: <span style=color:#a31515>&#34;John&#34;</span> }
167</span></span><span style=display:flex><span>}
168</span></span></code></pre><h2 id=publisher-and-subscriber-clients>Publisher and subscriber clients</h2><h3 id=publisher-and-subscriber-in-action>Publisher and subscriber in action</h3><p><video src=/posts/simple-pubsub-server/clients.m4v controls></video><p>You can download <a href=../simple-pubsub-server/sse-pubsub-server.zip>the code</a> and
169follow along.<h3 id=publisher>Publisher</h3><p>As talked about above publisher is the one that send messages to the
170broker/server. Message inside the payload can be whatever you want (string,
171object, array). I would however personally avoid send large chunks of data like
172blobs and such.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>&lt;!DOCTYPE html&gt;</span>
173</span></span><span style=display:flex><span>&lt;html lang=<span style=color:#a31515>&#34;en&#34;</span>&gt;
174</span></span><span style=display:flex><span>
175</span></span><span style=display:flex><span> &lt;head&gt;
176</span></span><span style=display:flex><span> &lt;meta charset=<span style=color:#a31515>&#34;UTF-8&#34;</span>&gt;
177</span></span><span style=display:flex><span> &lt;meta name=<span style=color:#a31515>&#34;viewport&#34;</span> content=<span style=color:#a31515>&#34;width=device-width, initial-scale=1.0&#34;</span>&gt;
178</span></span><span style=display:flex><span> &lt;title&gt;Publisher&lt;/title&gt;
179</span></span><span style=display:flex><span> &lt;/head&gt;
180</span></span><span style=display:flex><span>
181</span></span><span style=display:flex><span> &lt;body&gt;
182</span></span><span style=display:flex><span>
183</span></span><span style=display:flex><span> &lt;h1&gt;Publisher&lt;/h1&gt;
184</span></span><span style=display:flex><span>
185</span></span><span style=display:flex><span> &lt;fieldset&gt;
186</span></span><span style=display:flex><span> &lt;p&gt;
187</span></span><span style=display:flex><span> &lt;label&gt;Server:&lt;/label&gt;
188</span></span><span style=display:flex><span> &lt;input type=<span style=color:#a31515>&#34;text&#34;</span> id=<span style=color:#a31515>&#34;server&#34;</span> value=<span style=color:#a31515>&#34;http://localhost:4000&#34;</span>&gt;
189</span></span><span style=display:flex><span> &lt;/p&gt;
190</span></span><span style=display:flex><span> &lt;p&gt;
191</span></span><span style=display:flex><span> &lt;label&gt;Topic:&lt;/label&gt;
192</span></span><span style=display:flex><span> &lt;input type=<span style=color:#a31515>&#34;text&#34;</span> id=<span style=color:#a31515>&#34;topic&#34;</span> value=<span style=color:#a31515>&#34;sample-topic&#34;</span>&gt;
193</span></span><span style=display:flex><span> &lt;/p&gt;
194</span></span><span style=display:flex><span> &lt;p&gt;
195</span></span><span style=display:flex><span> &lt;label&gt;Event:&lt;/label&gt;
196</span></span><span style=display:flex><span> &lt;input type=<span style=color:#a31515>&#34;text&#34;</span> id=<span style=color:#a31515>&#34;event&#34;</span> value=<span style=color:#a31515>&#34;sample-event&#34;</span>&gt;
197</span></span><span style=display:flex><span> &lt;/p&gt;
198</span></span><span style=display:flex><span> &lt;p&gt;
199</span></span><span style=display:flex><span> &lt;label&gt;Message:&lt;/label&gt;
200</span></span><span style=display:flex><span> &lt;input type=<span style=color:#a31515>&#34;text&#34;</span> id=<span style=color:#a31515>&#34;message&#34;</span> value=<span style=color:#a31515>&#39;{&#34;name&#34;: &#34;John&#34;}&#39;</span>&gt;
201</span></span><span style=display:flex><span> &lt;/p&gt;
202</span></span><span style=display:flex><span> &lt;p&gt;
203</span></span><span style=display:flex><span> &lt;button type=<span style=color:#a31515>&#34;button&#34;</span> id=<span style=color:#a31515>&#34;button&#34;</span>&gt;Publish message to topic&lt;/button&gt;
204</span></span><span style=display:flex><span> &lt;/p&gt;
205</span></span><span style=display:flex><span> &lt;/fieldset&gt;
206</span></span><span style=display:flex><span>
207</span></span><span style=display:flex><span> &lt;script&gt;
208</span></span><span style=display:flex><span>
209</span></span><span style=display:flex><span> <span style=color:#00f>const</span> button = document.querySelector(<span style=color:#a31515>&#39;#button&#39;</span>);
210</span></span><span style=display:flex><span> <span style=color:#00f>const</span> server = document.querySelector(<span style=color:#a31515>&#39;#server&#39;</span>);
211</span></span><span style=display:flex><span> <span style=color:#00f>const</span> topic = document.querySelector(<span style=color:#a31515>&#39;#topic&#39;</span>);
212</span></span><span style=display:flex><span> <span style=color:#00f>const</span> event = document.querySelector(<span style=color:#a31515>&#39;#event&#39;</span>);
213</span></span><span style=display:flex><span> <span style=color:#00f>const</span> message = document.querySelector(<span style=color:#a31515>&#39;#message&#39;</span>);
214</span></span><span style=display:flex><span>
215</span></span><span style=display:flex><span> button.addEventListener(<span style=color:#a31515>&#39;click&#39;</span>, <span style=color:#00f>async</span> (evt) =&gt; {
216</span></span><span style=display:flex><span> <span style=color:#00f>const</span> req = <span style=color:#00f>await</span> fetch(<span style=color:#a31515>`</span><span style=color:#a31515>${</span>server.value<span style=color:#a31515>}</span><span style=color:#a31515>/publish`</span>, {
217</span></span><span style=display:flex><span> method: <span style=color:#a31515>&#39;post&#39;</span>,
218</span></span><span style=display:flex><span> headers: {
219</span></span><span style=display:flex><span> <span style=color:#a31515>&#39;Accept&#39;</span>: <span style=color:#a31515>&#39;application/json&#39;</span>,
220</span></span><span style=display:flex><span> <span style=color:#a31515>&#39;Content-Type&#39;</span>: <span style=color:#a31515>&#39;application/json&#39;</span>,
221</span></span><span style=display:flex><span> },
222</span></span><span style=display:flex><span> body: JSON.stringify({
223</span></span><span style=display:flex><span> topic: topic.value,
224</span></span><span style=display:flex><span> event: event.value,
225</span></span><span style=display:flex><span> message: JSON.parse(message.value),
226</span></span><span style=display:flex><span> }),
227</span></span><span style=display:flex><span> });
228</span></span><span style=display:flex><span>
229</span></span><span style=display:flex><span> <span style=color:#00f>const</span> res = <span style=color:#00f>await</span> req.json();
230</span></span><span style=display:flex><span> console.log(res);
231</span></span><span style=display:flex><span> });
232</span></span><span style=display:flex><span>
233</span></span><span style=display:flex><span> &lt;/script&gt;
234</span></span><span style=display:flex><span>
235</span></span><span style=display:flex><span> &lt;/body&gt;
236</span></span><span style=display:flex><span>
237</span></span><span style=display:flex><span>&lt;/html&gt;
238</span></span></code></pre><h3 id=subscriber>Subscriber</h3><p>Subscriber is responsible for receiving new messages that come from server via
239publisher. The code bellow is very rudimentary but works and follows the
240implementation guidelines for EventSource.<p>You can use either Developer Tools Console to see incoming messages or you can
241defer to Debugging with Google Chrome section above to see all EventStream
242messages.<blockquote><p>Don't be alarmed if the subscriber gets disconnected from the server every so
243often. The code we have here resets connection every 15s but it automatically
244get reconnected and fetches all messages up to last received message id. This
245setting can be adjusted in <code>server.js</code> file; search for the
246<code>maxStreamDuration</code> variable.</blockquote><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>&lt;!DOCTYPE html&gt;</span>
247</span></span><span style=display:flex><span>&lt;html lang=<span style=color:#a31515>&#34;en&#34;</span>&gt;
248</span></span><span style=display:flex><span>
249</span></span><span style=display:flex><span> &lt;head&gt;
250</span></span><span style=display:flex><span> &lt;meta charset=<span style=color:#a31515>&#34;UTF-8&#34;</span>&gt;
251</span></span><span style=display:flex><span> &lt;meta name=<span style=color:#a31515>&#34;viewport&#34;</span> content=<span style=color:#a31515>&#34;width=device-width, initial-scale=1.0&#34;</span>&gt;
252</span></span><span style=display:flex><span> &lt;title&gt;Subscriber&lt;/title&gt;
253</span></span><span style=display:flex><span> &lt;link rel=<span style=color:#a31515>&#34;stylesheet&#34;</span> href=<span style=color:#a31515>&#34;style.css&#34;</span>&gt;
254</span></span><span style=display:flex><span> &lt;/head&gt;
255</span></span><span style=display:flex><span>
256</span></span><span style=display:flex><span> &lt;body&gt;
257</span></span><span style=display:flex><span>
258</span></span><span style=display:flex><span> &lt;h1&gt;Subscriber&lt;/h1&gt;
259</span></span><span style=display:flex><span>
260</span></span><span style=display:flex><span> &lt;fieldset&gt;
261</span></span><span style=display:flex><span> &lt;p&gt;
262</span></span><span style=display:flex><span> &lt;label&gt;Server:&lt;/label&gt;
263</span></span><span style=display:flex><span> &lt;input type=<span style=color:#a31515>&#34;text&#34;</span> id=<span style=color:#a31515>&#34;server&#34;</span> value=<span style=color:#a31515>&#34;http://localhost:4000&#34;</span>&gt;
264</span></span><span style=display:flex><span> &lt;/p&gt;
265</span></span><span style=display:flex><span> &lt;p&gt;
266</span></span><span style=display:flex><span> &lt;label&gt;Topic:&lt;/label&gt;
267</span></span><span style=display:flex><span> &lt;input type=<span style=color:#a31515>&#34;text&#34;</span> id=<span style=color:#a31515>&#34;topic&#34;</span> value=<span style=color:#a31515>&#34;sample-topic&#34;</span>&gt;
268</span></span><span style=display:flex><span> &lt;/p&gt;
269</span></span><span style=display:flex><span> &lt;p&gt;
270</span></span><span style=display:flex><span> &lt;label&gt;Event:&lt;/label&gt;
271</span></span><span style=display:flex><span> &lt;input type=<span style=color:#a31515>&#34;text&#34;</span> id=<span style=color:#a31515>&#34;event&#34;</span> value=<span style=color:#a31515>&#34;sample-event&#34;</span>&gt;
272</span></span><span style=display:flex><span> &lt;/p&gt;
273</span></span><span style=display:flex><span> &lt;p&gt;
274</span></span><span style=display:flex><span> &lt;button type=<span style=color:#a31515>&#34;button&#34;</span> id=<span style=color:#a31515>&#34;button&#34;</span>&gt;Subscribe to topic&lt;/button&gt;
275</span></span><span style=display:flex><span> &lt;/p&gt;
276</span></span><span style=display:flex><span> &lt;/fieldset&gt;
277</span></span><span style=display:flex><span>
278</span></span><span style=display:flex><span> &lt;script&gt;
279</span></span><span style=display:flex><span>
280</span></span><span style=display:flex><span> <span style=color:#00f>const</span> button = document.querySelector(<span style=color:#a31515>&#39;#button&#39;</span>);
281</span></span><span style=display:flex><span> <span style=color:#00f>const</span> server = document.querySelector(<span style=color:#a31515>&#39;#server&#39;</span>);
282</span></span><span style=display:flex><span> <span style=color:#00f>const</span> topic = document.querySelector(<span style=color:#a31515>&#39;#topic&#39;</span>);
283</span></span><span style=display:flex><span> <span style=color:#00f>const</span> event = document.querySelector(<span style=color:#a31515>&#39;#event&#39;</span>);
284</span></span><span style=display:flex><span>
285</span></span><span style=display:flex><span> button.addEventListener(<span style=color:#a31515>&#39;click&#39;</span>, <span style=color:#00f>async</span> (evt) =&gt; {
286</span></span><span style=display:flex><span>
287</span></span><span style=display:flex><span> <span style=color:#00f>let</span> es = <span style=color:#00f>new</span> EventSource(<span style=color:#a31515>`</span><span style=color:#a31515>${</span>server.value<span style=color:#a31515>}</span><span style=color:#a31515>/stream/</span><span style=color:#a31515>${</span>topic.value<span style=color:#a31515>}</span><span style=color:#a31515>`</span>);
288</span></span><span style=display:flex><span>
289</span></span><span style=display:flex><span> es.addEventListener(event.value, <span style=color:#00f>function</span> (evt) {
290</span></span><span style=display:flex><span> console.log(<span style=color:#a31515>`incoming message`</span>, JSON.parse(evt.data));
291</span></span><span style=display:flex><span> });
292</span></span><span style=display:flex><span>
293</span></span><span style=display:flex><span> es.addEventListener(<span style=color:#a31515>&#39;open&#39;</span>, <span style=color:#00f>function</span> (evt) {
294</span></span><span style=display:flex><span> console.log(<span style=color:#a31515>&#39;connected&#39;</span>, evt);
295</span></span><span style=display:flex><span> });
296</span></span><span style=display:flex><span>
297</span></span><span style=display:flex><span> es.addEventListener(<span style=color:#a31515>&#39;error&#39;</span>, <span style=color:#00f>function</span> (evt) {
298</span></span><span style=display:flex><span> console.log(<span style=color:#a31515>&#39;error&#39;</span>, evt);
299</span></span><span style=display:flex><span> });
300</span></span><span style=display:flex><span>
301</span></span><span style=display:flex><span> });
302</span></span><span style=display:flex><span>
303</span></span><span style=display:flex><span> &lt;/script&gt;
304</span></span><span style=display:flex><span>
305</span></span><span style=display:flex><span> &lt;/body&gt;
306</span></span><span style=display:flex><span>
307</span></span><span style=display:flex><span>&lt;/html&gt;
308</span></span></code></pre><h2 id=reading-further>Reading further</h2><ul><li><a href=https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events>Using server-sent events</a><li><a href=https://www.smashingmagazine.com/2018/02/sse-websockets-data-flow-http2/>Using SSE Instead Of WebSockets For Unidirectional Data Flow Over HTTP/2</a><li><a href=https://apifriends.com/api-streaming/server-sent-events/>What is Server-Sent Events?</a><li><a href=https://tools.ietf.org/id/draft-xie-bidirectional-messaging-01.html>An HTTP/2 extension for bidirectional messaging communication</a><li><a href=https://developers.google.com/web/fundamentals/performance/http2>Introduction to HTTP/2</a><li><a href=https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API>The WebSocket API (WebSockets)</a></ul></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
309a lock on a Linux NFS server, which turned
310out to be specific to NFS v3 (which I really should have seen coming,
311since it involved NLM and lockd). Finding the NFS v4 client that
312owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
313and Bradley Kuhn, are interacting on the OSI's license-discuss
314list where the're doing
315bad computer history and insisting that a guy Larry Rosen
316coincidentally interviewed for a book years ago is clearly the origin of
317somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
318i2c, plan9
319Another month, another file system.
320Well, if you can’t fix it in software, fix it in hardware (looking at
321you, bme680, we’re not
322done yet). The show must go on, as they say, and I would like my
323experiments to go on.
324So a “new” addition to the environmental sensor family connected to
325the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
326this mortal coil, we are endowed with self-awareness, agency, and free will.
327Each of the 8 billion members of this human race represents a unique person, a
328unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
329My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
3301.0 has been released:
331wifi_da-1.0.sit
332(StuffIt 3 archive)
333SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
334This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
335classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
336In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
337Design Goals
338I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
339at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
340catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
341specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
342 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
343 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/simple-world-clock-with-eiink-display-and-raspberry-pi-zero.html b/public/simple-world-clock-with-eiink-display-and-raspberry-pi-zero.html
deleted file mode 100755
index 25b97cc..0000000
--- a/public/simple-world-clock-with-eiink-display-and-raspberry-pi-zero.html
+++ /dev/null
@@ -1,104 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Simple world clock with eInk display and Raspberry Pi Zero</title><meta name=description content="Our team is spread across the world, from the USA all the way to Australia, sohaving some sort of world clock makes sense."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Simple world clock with eInk display and Raspberry Pi Zero</h1><p><cap>post</cap>, Jun 26, 2021 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>Our team is spread across the world, from the USA all the way to Australia, so
10having some sort of world clock makes sense.<p>Currently, I am using an extension for Gnome called <a href=https://extensions.gnome.org/extension/2657/timezones-extension/>Timezone
11extension</a>,
12and it serves the purpose quite well.<p>But I also have a bunch of electronics that I bought through the time, and I am
13not using any of them, and it's time to stop hording this stuff and use it in a
14project.<p>A while ago I bought a small eInk display <a href="https://shop.pimoroni.com/products/inky-phat?variant=12549254217811">Inky
15pHAT</a> and I
16have a bunch of <a href=https://www.raspberrypi.org/products/raspberry-pi-zero/>Raspberry Pi's
17Zero</a> lying around that
18I really need to use.<figure><img src=/posts/world-clock/hardware.jpg alt="Inky pHAT, Raspberry Pi Zero"></figure><p>Since the Inky <a href="https://shop.pimoroni.com/products/inky-phat?variant=12549254217811">Inky
19pHAT</a> is
20essentially a HAT, it can easily be added on top of the <a href=https://www.raspberrypi.org/products/raspberry-pi-zero/>Raspberry Pi
21Zero</a>.<p>First, I installed the necessary software on Raspberry Pi with <code>pip3 install inky</code>.<p>And then I created a file <code>clock.py</code> in home directory <code>/home/pi</code>.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green>#!/usr/bin/env python</span>
22</span></span><span style=display:flex><span><span style=color:green># -*- coding: utf-8 -*-</span>
23</span></span><span style=display:flex><span>
24</span></span><span style=display:flex><span><span style=color:#00f>import</span> sys
25</span></span><span style=display:flex><span><span style=color:#00f>import</span> os
26</span></span><span style=display:flex><span><span style=color:#00f>from</span> inky.auto <span style=color:#00f>import</span> auto
27</span></span><span style=display:flex><span><span style=color:#00f>from</span> PIL <span style=color:#00f>import</span> Image, ImageFont, ImageDraw
28</span></span><span style=display:flex><span><span style=color:#00f>from</span> font_fredoka_one <span style=color:#00f>import</span> FredokaOne
29</span></span><span style=display:flex><span>
30</span></span><span style=display:flex><span>clocks = [
31</span></span><span style=display:flex><span> <span style=color:#a31515>&#39;America/New_York&#39;</span>,
32</span></span><span style=display:flex><span> <span style=color:#a31515>&#39;Europe/Ljubljana&#39;</span>,
33</span></span><span style=display:flex><span> <span style=color:#a31515>&#39;Australia/Brisbane&#39;</span>,
34</span></span><span style=display:flex><span>]
35</span></span><span style=display:flex><span>
36</span></span><span style=display:flex><span>board = auto()
37</span></span><span style=display:flex><span>board.set_border(board.WHITE)
38</span></span><span style=display:flex><span>board.rotation = 90
39</span></span><span style=display:flex><span>
40</span></span><span style=display:flex><span>img = Image.new(<span style=color:#a31515>&#39;P&#39;</span>, (board.WIDTH, board.HEIGHT))
41</span></span><span style=display:flex><span>draw = ImageDraw.Draw(img)
42</span></span><span style=display:flex><span>
43</span></span><span style=display:flex><span>big_font = ImageFont.truetype(FredokaOne, 18)
44</span></span><span style=display:flex><span>small_font = ImageFont.truetype(FredokaOne, 13)
45</span></span><span style=display:flex><span>
46</span></span><span style=display:flex><span>x = board.WIDTH / 3
47</span></span><span style=display:flex><span>y = board.HEIGHT / 3
48</span></span><span style=display:flex><span>
49</span></span><span style=display:flex><span>idx = 1
50</span></span><span style=display:flex><span><span style=color:#00f>for</span> clock <span style=color:#00f>in</span> clocks:
51</span></span><span style=display:flex><span> ctime = os.popen(<span style=color:#a31515>&#39;TZ=&#34;</span><span style=color:#a31515>{}</span><span style=color:#a31515>&#34; date +&#34;</span><span style=color:#a31515>%a</span><span style=color:#a31515>,%H:%M&#34;&#39;</span>.format(clock))
52</span></span><span style=display:flex><span> ctime = ctime.read().strip().split(<span style=color:#a31515>&#39;,&#39;</span>)
53</span></span><span style=display:flex><span> city = clock.split(<span style=color:#a31515>&#39;/&#39;</span>)[1].replace(<span style=color:#a31515>&#39;_&#39;</span>, <span style=color:#a31515>&#39; &#39;</span>)
54</span></span><span style=display:flex><span>
55</span></span><span style=display:flex><span> draw.text((15, (idx*y)-y+10), city, fill=board.BLACK, font=small_font)
56</span></span><span style=display:flex><span> draw.text((110, (idx*y)-y+7), str(ctime[0]), fill=board.BLACK, font=big_font)
57</span></span><span style=display:flex><span> draw.text((155, (idx*y)-y+7), str(ctime[1]), fill=board.BLACK, font=big_font)
58</span></span><span style=display:flex><span>
59</span></span><span style=display:flex><span> idx += 1
60</span></span><span style=display:flex><span>
61</span></span><span style=display:flex><span>board.set_image(img)
62</span></span><span style=display:flex><span>board.show()
63</span></span></code></pre><p>And because eInk displays are rather slow to refresh and the clock requires
64refreshing only once a minute, this can be done through cronjob.<p>Before we add this job to cron we need to make <code>clock.py</code> executable with <code>chmod +x clock.py</code>.<p>Then we add a cronjob with <code>crontab -e</code>.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>* * * * * /home/pi/clock.py
65</span></span></code></pre><p>So, we end up with a result like this.<figure><img src=/posts/world-clock/world-clock.jpg alt="World Clock"></figure><p>And for the enclosure that can be 3D printed, but I haven't yet something like
66this can be used.</p><iframe id=vs_iframe src="https://www.viewstl.com/?embedded&url=https%3A%2F%2Fmitjafelicijan.com%2Fposts%2Fworld-clock%2Fenclosure.stl&color=gray&bgcolor=white&edges=no&orientation=front&noborder=no" style=border:0;margin:0;width:100%;height:400px></iframe><p>You can download my <a href=/posts/world-clock/enclosure.stl>STL file for the enclosure
67here</a>, but make sure that dimensions make
68sense and also opening for USB port should be added or just use a drill and some
69hot glue to make it stick in the enclosure.</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
70a lock on a Linux NFS server, which turned
71out to be specific to NFS v3 (which I really should have seen coming,
72since it involved NLM and lockd). Finding the NFS v4 client that
73owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
74and Bradley Kuhn, are interacting on the OSI's license-discuss
75list where the're doing
76bad computer history and insisting that a guy Larry Rosen
77coincidentally interviewed for a book years ago is clearly the origin of
78somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
79i2c, plan9
80Another month, another file system.
81Well, if you can’t fix it in software, fix it in hardware (looking at
82you, bme680, we’re not
83done yet). The show must go on, as they say, and I would like my
84experiments to go on.
85So a “new” addition to the environmental sensor family connected to
86the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
87this mortal coil, we are endowed with self-awareness, agency, and free will.
88Each of the 8 billion members of this human race represents a unique person, a
89unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
90My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
911.0 has been released:
92wifi_da-1.0.sit
93(StuffIt 3 archive)
94SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
95This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
96classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
97In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
98Design Goals
99I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
100at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
101catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
102specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
103 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
104 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/simplifying-and-reducing-clutter.html b/public/simplifying-and-reducing-clutter.html
deleted file mode 100755
index 411043a..0000000
--- a/public/simplifying-and-reducing-clutter.html
+++ /dev/null
@@ -1,80 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Simplifying and reducing clutter in my life and work</title><meta name=description content="I recently moved my main working machine back from Hachintosh to Linux."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Simplifying and reducing clutter in my life and work</h1><p><cap>post</cap>, Oct 14, 2019 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>I recently moved my main working machine back from Hachintosh to Linux. Well the
10experiment was interesting and I have done some great work on macOS but it was
11time to move back.<p>I actually really missed Linux. The simplicity of <code>apt-get</code> or just the amount
12of software that exists for Linux should be a no-brainer. I spent most of my
13time on macOS finding solutions to make things work. Using
14<a href=https://brew.sh/>Brew</a> was just a horrible experience and far from package
15managers of Linux. At least they managed to get that <code>sudo</code> debacle sorted.<p>Not all was bad. macOS in general was a perfectly good environment. Things like
16Docker and tooling like this worked without any hiccups. My normal tools like
17coding IDE worked flawlessly and the whole look and feel is just superb. I have
18been using MacBook Air for couple of years so I was used to the system but never
19as a daily driver.<p>One of the things I did after I installed Linux back on my machine was cleaning
20up my Dropbox folder. I have everything on Dropbox. Even projects folder. I
21write code for living so my whole life revolves around couple of megs of code
22(with assets). So it's not like I have huge files on my machine. I don't have
23movies or music or pictures on my PC. All of that stuff is in cloud. I use
24Google music and I have Netflix account which is more than enough for me.<p>I also went and deleted some of the repositories on my Github account. I have
25deleted more code than deployed. People find this strange but for me deleting
26something feels so cathartic and also forces me to write better code next time
27around when I am faced with similar problem. That was a huge relief if I am
28being totally honest.<p>Next step was to do something with my webpage. I have been using some scripts I
29wrote a while ago to generate static pages from markdown source posts. I kept on
30adding and adding stuff on top of it and it became a source of a
31frustration. And this is just a simple blog and I was using gulp and npm.
32Anyways after couple of hours of searching and testing static generators I found
33an interesting one
34<a href=https://github.com/piranha/gostatic>https://github.com/piranha/gostatic</a> and I
35just decided to use this one. It was the only one that had a simple templating
36engine, not that I really need one. But others had this convoluted way of trying
37to solve everything and at the end just required quite bigger learning curve I
38was ready to go with. So I deleted couple of old posts, simplified HTML, trashed
39most of the CSS and went with
40<a href=https://motherfuckingwebsite.com/>https://motherfuckingwebsite.com/</a>
41aesthetics. Yeah, the previous site was more visually stimulating but all I
42really care is the content at this point. And Times New Roman font is kind of
43awesome.<p>I stopped working on most of the projects in the past couple of months because
44the overhead was just too insane. There comes a point when you stretch yourself
45too much and then you stop progressing and with that comes dissatisfaction.<p>So that's about it. Moving forward minimal style.</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
46a lock on a Linux NFS server, which turned
47out to be specific to NFS v3 (which I really should have seen coming,
48since it involved NLM and lockd). Finding the NFS v4 client that
49owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
50and Bradley Kuhn, are interacting on the OSI's license-discuss
51list where the're doing
52bad computer history and insisting that a guy Larry Rosen
53coincidentally interviewed for a book years ago is clearly the origin of
54somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
55i2c, plan9
56Another month, another file system.
57Well, if you can’t fix it in software, fix it in hardware (looking at
58you, bme680, we’re not
59done yet). The show must go on, as they say, and I would like my
60experiments to go on.
61So a “new” addition to the environmental sensor family connected to
62the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
63this mortal coil, we are endowed with self-awareness, agency, and free will.
64Each of the 8 billion members of this human race represents a unique person, a
65unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
66My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
671.0 has been released:
68wifi_da-1.0.sit
69(StuffIt 3 archive)
70SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
71This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
72classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
73In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
74Design Goals
75I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
76at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
77catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
78specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
79 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
80 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/sitemap.xml b/public/sitemap.xml
deleted file mode 100755
index 37366d7..0000000
--- a/public/sitemap.xml
+++ /dev/null
@@ -1,418 +0,0 @@
1<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml">
2
3 <url>
4 <loc>https://mitjafelicijan.com/compile-drawterm-on-fedora-38.html</loc>
5 <lastmod>2023-09-25T09:04:28+00:00</lastmod>
6 </url>
7
8 <url>
9 <loc>https://mitjafelicijan.com/aws-eb-pyyaml-fix.html</loc>
10 <lastmod>2023-09-18T07:27:29+00:00</lastmod>
11 </url>
12
13 <url>
14 <loc>https://mitjafelicijan.com/floods-in-slovenia.html</loc>
15 <lastmod>2023-08-05T07:06:50+00:00</lastmod>
16 </url>
17
18 <url>
19 <loc>https://mitjafelicijan.com/make-b-w-svg-charts-with-matplotlib.html</loc>
20 <lastmod>2023-08-01T17:04:10+00:00</lastmod>
21 </url>
22
23 <url>
24 <loc>https://mitjafelicijan.com/set-color-temperature-of-displays-on-i3.html</loc>
25 <lastmod>2023-07-14T09:19:31+00:00</lastmod>
26 </url>
27
28 <url>
29 <loc>https://mitjafelicijan.com/fix-screen-tearing-on-debian-12-xorg-and-i3.html</loc>
30 <lastmod>2023-07-10T04:21:48+00:00</lastmod>
31 </url>
32
33 <url>
34 <loc>https://mitjafelicijan.com/online-radio-streaming-with-mpv-from-terminal.html</loc>
35 <lastmod>2023-07-10T03:34:45+00:00</lastmod>
36 </url>
37
38 <url>
39 <loc>https://mitjafelicijan.com/who-knows-what-the-world-will-look-like-tomorrow.html</loc>
40 <lastmod>2023-07-08T18:49:07+00:00</lastmod>
41 </url>
42
43 <url>
44 <loc>https://mitjafelicijan.com/bringing-all-of-my-projects-together-under-one-umbrella.html</loc>
45 <lastmod>2023-07-01T18:49:07+00:00</lastmod>
46 </url>
47
48 <url>
49 <loc>https://mitjafelicijan.com/60s-ibm-computers-commercial.html</loc>
50 <lastmod>2023-06-29T22:13:45+00:00</lastmod>
51 </url>
52
53 <url>
54 <loc>https://mitjafelicijan.com/10gui-10-finger-multitouch-user-interface.html</loc>
55 <lastmod>2023-06-29T14:51:39+00:00</lastmod>
56 </url>
57
58 <url>
59 <loc>https://mitjafelicijan.com/alacritty-open-links-with-modifier.html</loc>
60 <lastmod>2023-06-25T17:17:16+00:00</lastmod>
61 </url>
62
63 <url>
64 <loc>https://mitjafelicijan.com/development-environments-with-nix.html</loc>
65 <lastmod>2023-06-25T16:38:10+00:00</lastmod>
66 </url>
67
68 <url>
69 <loc>https://mitjafelicijan.com/making-cgit-look-nicer.html</loc>
70 <lastmod>2023-06-24T13:33:58+00:00</lastmod>
71 </url>
72
73 <url>
74 <loc>https://mitjafelicijan.com/presentations-with-markdown.html</loc>
75 <lastmod>2023-06-21T08:54:48+00:00</lastmod>
76 </url>
77
78 <url>
79 <loc>https://mitjafelicijan.com/bulk-make-thumbnails.html</loc>
80 <lastmod>2023-06-04T20:46:56+00:00</lastmod>
81 </url>
82
83 <url>
84 <loc>https://mitjafelicijan.com/ewd-manuscripts-ebook.html</loc>
85 <lastmod>2023-06-01T22:47:56+00:00</lastmod>
86 </url>
87
88 <url>
89 <loc>https://mitjafelicijan.com/re-inventing-task-runner-that-i-actually-used-daily.html</loc>
90 <lastmod>2023-05-31T12:21:10+00:00</lastmod>
91 </url>
92
93 <url>
94 <loc>https://mitjafelicijan.com/extending-dte-editor.html</loc>
95 <lastmod>2023-05-31T08:12:45+00:00</lastmod>
96 </url>
97
98 <url>
99 <loc>https://mitjafelicijan.com/grep-to-less-maintain-colors.html</loc>
100 <lastmod>2023-05-29T21:27:07+00:00</lastmod>
101 </url>
102
103 <url>
104 <loc>https://mitjafelicijan.com/easy-time-took-in-bash.html</loc>
105 <lastmod>2023-05-28T17:53:20+00:00</lastmod>
106 </url>
107
108 <url>
109 <loc>https://mitjafelicijan.com/dcss-on-4k-display.html</loc>
110 <lastmod>2023-05-27T19:35:11+00:00</lastmod>
111 </url>
112
113 <url>
114 <loc>https://mitjafelicijan.com/drawing-pixels-in-plan9.html</loc>
115 <lastmod>2023-05-27T17:41:33+00:00</lastmod>
116 </url>
117
118 <url>
119 <loc>https://mitjafelicijan.com/cronjobs-github-with-actions.html</loc>
120 <lastmod>2023-05-27T00:35:36+00:00</lastmod>
121 </url>
122
123 <url>
124 <loc>https://mitjafelicijan.com/dcss-new-player-guide.html</loc>
125 <lastmod>2023-05-25T22:00:00+00:00</lastmod>
126 </url>
127
128 <url>
129 <loc>https://mitjafelicijan.com/xterm-color-palette.html</loc>
130 <lastmod>2023-05-25T12:00:00+00:00</lastmod>
131 </url>
132
133 <url>
134 <loc>https://mitjafelicijan.com/tmux-sane-defaults.html</loc>
135 <lastmod>2023-05-25T12:00:00+00:00</lastmod>
136 </url>
137
138 <url>
139 <loc>https://mitjafelicijan.com/fresh-9front-desktop.html</loc>
140 <lastmod>2023-05-24T12:00:00+00:00</lastmod>
141 </url>
142
143 <url>
144 <loc>https://mitjafelicijan.com/i-was-wrong-about-git-workflows.html</loc>
145 <lastmod>2023-05-23T12:00:00+00:00</lastmod>
146 </url>
147
148 <url>
149 <loc>https://mitjafelicijan.com/parse-rss-with-lua.html</loc>
150 <lastmod>2023-05-23T12:00:00+00:00</lastmod>
151 </url>
152
153 <url>
154 <loc>https://mitjafelicijan.com/extend-lua-with-custom-c.html</loc>
155 <lastmod>2023-05-23T12:00:00+00:00</lastmod>
156 </url>
157
158 <url>
159 <loc>https://mitjafelicijan.com/non-blocking-shell-exec-csharp.html</loc>
160 <lastmod>2023-05-22T12:00:00+00:00</lastmod>
161 </url>
162
163 <url>
164 <loc>https://mitjafelicijan.com/mass-set-permission.html</loc>
165 <lastmod>2023-05-16T12:00:00+00:00</lastmod>
166 </url>
167
168 <url>
169 <loc>https://mitjafelicijan.com/rekindling-my-love-for-programming.html</loc>
170 <lastmod>2023-05-16T12:00:00+00:00</lastmod>
171 </url>
172
173 <url>
174 <loc>https://mitjafelicijan.com/preview-troff-man-pages.html</loc>
175 <lastmod>2023-05-15T12:00:00+00:00</lastmod>
176 </url>
177
178 <url>
179 <loc>https://mitjafelicijan.com/convert-mkv.html</loc>
180 <lastmod>2023-05-14T12:00:00+00:00</lastmod>
181 </url>
182
183 <url>
184 <loc>https://mitjafelicijan.com/download-youtube-videos.html</loc>
185 <lastmod>2023-05-13T12:00:00+00:00</lastmod>
186 </url>
187
188 <url>
189 <loc>https://mitjafelicijan.com/install-plan9port-linux.html</loc>
190 <lastmod>2023-05-12T12:00:00+00:00</lastmod>
191 </url>
192
193 <url>
194 <loc>https://mitjafelicijan.com/fix-plan9-bootloader.html</loc>
195 <lastmod>2023-05-11T12:00:00+00:00</lastmod>
196 </url>
197
198 <url>
199 <loc>https://mitjafelicijan.com/plan9-screenshot.html</loc>
200 <lastmod>2023-05-10T12:00:00+00:00</lastmod>
201 </url>
202
203 <url>
204 <loc>https://mitjafelicijan.com/catv-weechat-config.html</loc>
205 <lastmod>2023-05-09T12:00:00+00:00</lastmod>
206 </url>
207
208 <url>
209 <loc>https://mitjafelicijan.com/write-iso-usb.html</loc>
210 <lastmod>2023-05-08T12:00:00+00:00</lastmod>
211 </url>
212
213 <url>
214 <loc>https://mitjafelicijan.com/mount-plan9-over-network.html</loc>
215 <lastmod>2023-05-07T12:00:00+00:00</lastmod>
216 </url>
217
218 <url>
219 <loc>https://mitjafelicijan.com/git-push-multiple-origins.html</loc>
220 <lastmod>2023-05-06T12:00:00+00:00</lastmod>
221 </url>
222
223 <url>
224 <loc>https://mitjafelicijan.com/run-9front-in-qemu.html</loc>
225 <lastmod>2023-05-05T12:00:00+00:00</lastmod>
226 </url>
227
228 <url>
229 <loc>https://mitjafelicijan.com/cachebusting-in-hugo.html</loc>
230 <lastmod>2023-05-01T12:00:00+00:00</lastmod>
231 </url>
232
233 <url>
234 <loc>https://mitjafelicijan.com/trying-to-build-a-new-kind-of-terminal-emulator.html</loc>
235 <lastmod>2023-01-26T12:00:00+00:00</lastmod>
236 </url>
237
238 <url>
239 <loc>https://mitjafelicijan.com/that-sound-that-machine-makes-when-struggling.html</loc>
240 <lastmod>2022-10-16T12:00:00+00:00</lastmod>
241 </url>
242
243 <url>
244 <loc>https://mitjafelicijan.com/state-of-web-technologies-and-web-development-in-year-2022.html</loc>
245 <lastmod>2022-10-06T12:00:00+00:00</lastmod>
246 </url>
247
248 <url>
249 <loc>https://mitjafelicijan.com/vault.html</loc>
250 <lastmod>2022-08-27T12:00:00+00:00</lastmod>
251 </url>
252
253 <url>
254 <loc>https://mitjafelicijan.com/curriculum-vitae.html</loc>
255 <lastmod>2022-08-27T12:00:00+00:00</lastmod>
256 </url>
257
258 <url>
259 <loc>https://mitjafelicijan.com/aerial-photography-of-algae-spotted-on-river-sava.html</loc>
260 <lastmod>2022-08-13T12:00:00+00:00</lastmod>
261 </url>
262
263 <url>
264 <loc>https://mitjafelicijan.com/what-would-dna-sound-if-synthesized.html</loc>
265 <lastmod>2022-07-05T12:00:00+00:00</lastmod>
266 </url>
267
268 <url>
269 <loc>https://mitjafelicijan.com/tying-out-helix-code-editor.html</loc>
270 <lastmod>2022-06-30T12:00:00+00:00</lastmod>
271 </url>
272
273 <url>
274 <loc>https://mitjafelicijan.com/wap-mobile-web-before-the-web.html</loc>
275 <lastmod>2021-12-30T12:00:00+00:00</lastmod>
276 </url>
277
278 <url>
279 <loc>https://mitjafelicijan.com/running-golang-application-as-pid1.html</loc>
280 <lastmod>2021-12-25T12:00:00+00:00</lastmod>
281 </url>
282
283 <url>
284 <loc>https://mitjafelicijan.com/debian-based-riced-up-distribution-for-developers-and-devops-folks.html</loc>
285 <lastmod>2021-12-03T12:00:00+00:00</lastmod>
286 </url>
287
288 <url>
289 <loc>https://mitjafelicijan.com/linux-cheatsheet.html</loc>
290 <lastmod>2021-08-01T12:00:00+00:00</lastmod>
291 </url>
292
293 <url>
294 <loc>https://mitjafelicijan.com/from-internet-consumer-to-full-hominum-again.html</loc>
295 <lastmod>2021-07-30T12:00:00+00:00</lastmod>
296 </url>
297
298 <url>
299 <loc>https://mitjafelicijan.com/simple-world-clock-with-eiink-display-and-raspberry-pi-zero.html</loc>
300 <lastmod>2021-06-26T12:00:00+00:00</lastmod>
301 </url>
302
303 <url>
304 <loc>https://mitjafelicijan.com/using-goaccess-with-nginx-to-replace-google-analytics.html</loc>
305 <lastmod>2021-01-25T12:00:00+00:00</lastmod>
306 </url>
307
308 <url>
309 <loc>https://mitjafelicijan.com/replacing-dropbox-in-favor-of-digitalocean-spaces.html</loc>
310 <lastmod>2021-01-24T12:00:00+00:00</lastmod>
311 </url>
312
313 <url>
314 <loc>https://mitjafelicijan.com/digitalocean-spaces-to-sync-between-computers.html</loc>
315 <lastmod>2020-09-09T12:00:00+00:00</lastmod>
316 </url>
317
318 <url>
319 <loc>https://mitjafelicijan.com/bind-warning-on-login-in-ubuntu.html</loc>
320 <lastmod>2020-09-08T12:00:00+00:00</lastmod>
321 </url>
322
323 <url>
324 <loc>https://mitjafelicijan.com/esp8266-and-micropython-guide.html</loc>
325 <lastmod>2020-09-06T12:00:00+00:00</lastmod>
326 </url>
327
328 <url>
329 <loc>https://mitjafelicijan.com/disable-mouse-wake-from-suspend-with-systemd-service.html</loc>
330 <lastmod>2020-08-15T12:00:00+00:00</lastmod>
331 </url>
332
333 <url>
334 <loc>https://mitjafelicijan.com/remote-work.html</loc>
335 <lastmod>2020-05-05T12:00:00+00:00</lastmod>
336 </url>
337
338 <url>
339 <loc>https://mitjafelicijan.com/my-love-and-hate-relationship-with-nodejs.html</loc>
340 <lastmod>2020-03-30T12:00:00+00:00</lastmod>
341 </url>
342
343 <url>
344 <loc>https://mitjafelicijan.com/the-strange-case-of-elasticsearch-allocation-failure.html</loc>
345 <lastmod>2020-03-29T12:00:00+00:00</lastmod>
346 </url>
347
348 <url>
349 <loc>https://mitjafelicijan.com/create-placeholder-images-with-sharp.html</loc>
350 <lastmod>2020-03-27T12:00:00+00:00</lastmod>
351 </url>
352
353 <url>
354 <loc>https://mitjafelicijan.com/simple-server-sent-events-based-pubsub-server.html</loc>
355 <lastmod>2020-03-22T12:00:00+00:00</lastmod>
356 </url>
357
358 <url>
359 <loc>https://mitjafelicijan.com/using-sentiment-analysis-for-clickbait-detection-in-rss-feeds.html</loc>
360 <lastmod>2019-10-19T12:00:00+00:00</lastmod>
361 </url>
362
363 <url>
364 <loc>https://mitjafelicijan.com/simplifying-and-reducing-clutter.html</loc>
365 <lastmod>2019-10-14T12:00:00+00:00</lastmod>
366 </url>
367
368 <url>
369 <loc>https://mitjafelicijan.com/encoding-binary-data-into-dna-sequence.html</loc>
370 <lastmod>2019-01-03T12:00:00+00:00</lastmod>
371 </url>
372
373 <url>
374 <loc>https://mitjafelicijan.com/using-digitalocean-spaces-object-storage-with-fuse.html</loc>
375 <lastmod>2018-01-16T12:00:00+00:00</lastmod>
376 </url>
377
378 <url>
379 <loc>https://mitjafelicijan.com/simple-iot-application.html</loc>
380 <lastmod>2017-08-11T12:00:00+00:00</lastmod>
381 </url>
382
383 <url>
384 <loc>https://mitjafelicijan.com/profiling-python-web-applications-with-visual-tools.html</loc>
385 <lastmod>2017-04-21T12:00:00+00:00</lastmod>
386 </url>
387
388 <url>
389 <loc>https://mitjafelicijan.com/what-i-ve-learned-developing-ad-server.html</loc>
390 <lastmod>2017-04-17T12:00:00+00:00</lastmod>
391 </url>
392
393 <url>
394 <loc>https://mitjafelicijan.com/golang-profiling-simplified.html</loc>
395 <lastmod>2017-03-07T12:00:00+00:00</lastmod>
396 </url>
397
398 <url>
399 <loc>https://mitjafelicijan.com/software-development-pitfalls.html</loc>
400 <lastmod>2015-11-10T12:00:00+00:00</lastmod>
401 </url>
402
403 <url>
404 <loc>https://mitjafelicijan.com/wireless-sensor-networks.html</loc>
405 <lastmod>2013-10-24T12:00:00+00:00</lastmod>
406 </url>
407
408 <url>
409 <loc>https://mitjafelicijan.com/led-technology-not-so-eco.html</loc>
410 <lastmod>2012-03-09T12:00:00+00:00</lastmod>
411 </url>
412
413 <url>
414 <loc>https://mitjafelicijan.com/most-likely-to-succeed-in-year-of-2011.html</loc>
415 <lastmod>2011-01-13T12:00:00+00:00</lastmod>
416 </url>
417
418</urlset>
diff --git a/public/software-development-pitfalls.html b/public/software-development-pitfalls.html
deleted file mode 100755
index d3d53e4..0000000
--- a/public/software-development-pitfalls.html
+++ /dev/null
@@ -1,152 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Software development and my favorite pitfalls</title><meta name=description content="Over the years I had the privilege to work on some very excited projects both insoftware development field and also in electronics field and every experiencetaught me some invaluable lessons about how NOT TO approach development."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Software development and my favorite pitfalls</h1><p><cap>post</cap>, Nov 10, 2015 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>Over the years I had the privilege to work on some very excited projects both in
10software development field and also in electronics field and every experience
11taught me some invaluable lessons about how NOT TO approach development. And
12through this post I will try to point out some absurd, outdated techniques I
13find the most annoying and damaging during a development cycle. There will be
14swearing because this topic really gets on my nerves and I never coherently
15tried to explain them in writing. So if I get heated up, please bear with me.<p>As new methods of project management are emerging, underlying processes still
16stay old and outdated. This is mainly because we as people are unable to
17completely shift away from these approaches.<p>I was always struggling with communication, and many times that cost me a
18relationship or two because I was not on the ball all the time. Through every
19experience, I became more convinced that I am the problem and never ever doubted
20that the problem may be that communication never evolved a single step from
21emails. And if you think for a second, not many things have changed around this
22topic. We just have different representations of email (message boards, chats,
23project management tools). And I believe this is the real issue we are facing
24now.<p>There are many articles written about hyper connectivity and the effects that
25are a direct result of it. But mainstream does nothing towards it. We are just
26putting out fires, and we do nothing to prevent it. I am certain this will be a
27major source of grief in coming years. And what we all can do to avoid this is
28to change our mindset and experiment on our communication skills, development
29approaches. We need to maximize possible output that a person can give. And to
30achieve this we need to listen to them, encourage them. I know that not
31everybody is a naturally born leader, but with enough practice and encouragement
32they also can become active participants in leadership.<p>There are many talks now about methodologies such as Scrum, Kanban, Cleanroom
33and they all fucking piss me of :). These are all boxes that imprison people and
34take away their freedom of thought. This is a straightforward mindfuck /
35amputation of creativity.<p>Let me list a couple of things that I find really destructive and bad for a
36project and in a long run company.<h2 id=ping-emails>Ping emails</h2><p>Ping emails are emails you have to write as soon as you receive an email. Its
37sole purpose is to inform the sender that you received their email, and you are
38working on it. Its result is only to calm down the sender that their task is
39being dealt with. It’s intent basically is, I did my job by sending you this
40email, so I am on clear grounds. I categorize this email as fuck you email.
41This is one of the most irritating types of emails I need to write. This is the
42ultimate control freak show you can experience, and it gives the sender a false
43feeling of control. Newsflash: We do not live in 1982 where there was a
44possibility that email never reached the destination. I really hate this from
45the bottom of my heart.<p>They should be like: “Yes, I am fucking alive, and I am at your service my
46leash!”. I guess if I would reply like this, I wouldn’t have to write any more
47of this kind of messages.<h2 id=everybody-is-a-project-manager>Everybody is a project manager</h2><p>Well, this is a tough one. I noticed that as soon as you let people to give
48their suggestions, you are basically screwed. There is a truth in the saying:
49“Give low expectations and deliver little more than you promised.”.<p>People tend to take a role of a manager as soon as they are presented with an
50opportunity. And by getting angry at them, you only provoke yourself. They are
51not at fault. You just need to tell them they are only giving suggestions and
52not tasks at the beginning and everything will be alright. But if you give them
53a feeling that they are in control, you will have immense problems explaining
54why their features are not in current release.<p>Project mission must be always leading project requirements and any deviation
55from it will result in major project butchering. And by this, I mean that the
56project will get its own path, and you will be left with half done software that
57helps nobody. Clear mission goals and clean execution will allow you to develop
58software will clear intent.<h2 id=we-are-never-wrong>We are never wrong</h2><p>I find this type of arrogance the worst. We must always conduct ourselves that
59we are infallible and cannot make mistakes. As soon as a procedure or process is
60established, there is no room for changes or improvements. This is the most
61idiotic thing someone can say of think. I think that processes need to involve
62and change over time. This is imperative and need to have in your organization
63if you want to improve and develop company. We all need to grow balls and change
64everything in order to adapt to current situations. Being a prisoner of
65predefined processes kills creativity.<p>I am constantly trying new software for project managing and communication. I
66believe every team has its own dynamic, and it needs to be discovered
67organically and naturally through many experiments. By putting the team in a
68box, you are amputating their creativity and therefore minimizing their
69potential. But if you talk to an executive, you will mainly find archetypical
70thinking and a strong need to compartmentalize everything from business
71processes to resource management. And this type of management that often
72displays micromanagement techniques only works for short periods (couple of
73years) and then employees either leave the company or become basically retarded
74drones on autopilot.<h2 id=micromanaging>Micromanaging</h2><p>This basically implies that everybody on the team is an idiot who needs to have
75a to-do list that they cannot write themselves. How about spoon-feeding the team
76at launch because besides the team leader, everybody must be a retarded idiot at
77best?<p>I prefer milestones as they give developers much more freedom and creativity in
78developing and not waste their time checking some bizarre to-do list that was
79not even thought through. Projects constantly change throughout the development
80cycle, and all you are left at the end is a list of unchecked tasks and the
81wrath of management why they are not completed. Best WTF moment!<h2 id=human-contact--no-need-for-it>Human contact — no need for it!</h2><p>We are vigorously trying to eliminate physical contact by replacing short
82meetings with software, with no regards that we are not machines. Many times a
83simple 5-min meeting at morning can solve most of the problems. In rapid
84development, short bursts of man to man communication is possibly the best way
85to go.<p>We now have all this software available, and all what we get out of it is a
86giant clusterfuck. An obstacle and not a solution. So, why we still use them?<h2 id=mvp-is-killing-innovation>MVP is killing innovation</h2><p>Many will disagree with me on this one, but I stand strong by this statement.
87What I noticed in my experience that all this buzz words around us only mislead
88and capture us in a circle of solving issues that already have a solution, but
89we are unable to see it without using some fancy word for it.<p>The toughest thing to do for a developer is to minimize requirements. Well, this
90is though only for bad developers. Yes, I said it. There are many types of
91developers out there. And those unable to minimize feature scope are the ones
92you don’t need on your team. Their only goal is to solve problems that exist
93only in their heads. And then you have to argue with them, and waste energy on
94them, instead of developing your awesome product. They are a cancer and I
95suggest you cut them off.<p>MVP as an idea is great, but sadly people don’t understand underlying
96philosophy, and they spent too much time focusing and fixating on something that
97every sane person with normal IQ will understand without some made up
98acronym. And the result is a lot of talking and barely no execution.<p>Well, MVP is not directly killing innovation, but stupid people do when they try
99to understand it.<h2 id=pressure-wasteland>Pressure wasteland</h2><p>You must never allow to be pressured into confirming a deadline if you are not
100confident. We often feel a need that we are in service of others, which is true
101to some extent. But it is also true that others are in service to us to some
102extent. And we forget this all the time. We are all pressured all the time to
103make decisions just to calm other people down. And when they leave your office
104you experience WTF moment :) How the hell did they manage to fuck me up again?<p>People need to realize that the more pressure you put on somebody, the less they
105will be able to do. So 5-min update email requests will only resolve in mental
106breakdown and inability to work that day. Constant poking is probably the only
107thing I lose my mind instantly. For all you that are doing this: “Stop bothering
108us with your insecurities and let us do our job. We will do it quicker and
109better without you breathing down our necks.”<p>If this happens to me, I end up with no energy at the end. Don’t you get it?
110You will get much more from and out of me if you ask me like a human person and
111not your personal butler. On a long run, you are destroying your relationships
112and nobody would want to work with you. Your schizophrenic approach will damage
113only you in a long run. Nobody is anybody’s property.<h2 id=conclusion>Conclusion</h2><p>I am guilty of many things described in this post. And I find it hard sometimes
114to acknowledge this. And I lie to myself and try vigorously to find some
115explanation why I do these things. There is always space for growth. And maybe
116you will also find some of yourself in this post and realize what needs to
117change for you to evolve.</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
118a lock on a Linux NFS server, which turned
119out to be specific to NFS v3 (which I really should have seen coming,
120since it involved NLM and lockd). Finding the NFS v4 client that
121owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
122and Bradley Kuhn, are interacting on the OSI's license-discuss
123list where the're doing
124bad computer history and insisting that a guy Larry Rosen
125coincidentally interviewed for a book years ago is clearly the origin of
126somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
127i2c, plan9
128Another month, another file system.
129Well, if you can’t fix it in software, fix it in hardware (looking at
130you, bme680, we’re not
131done yet). The show must go on, as they say, and I would like my
132experiments to go on.
133So a “new” addition to the environmental sensor family connected to
134the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
135this mortal coil, we are endowed with self-awareness, agency, and free will.
136Each of the 8 billion members of this human race represents a unique person, a
137unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
138My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
1391.0 has been released:
140wifi_da-1.0.sit
141(StuffIt 3 archive)
142SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
143This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
144classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
145In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
146Design Goals
147I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
148at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
149catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
150specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
151 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
152 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/state-of-web-technologies-and-web-development-in-year-2022.html b/public/state-of-web-technologies-and-web-development-in-year-2022.html
deleted file mode 100755
index 2d9e622..0000000
--- a/public/state-of-web-technologies-and-web-development-in-year-2022.html
+++ /dev/null
@@ -1,220 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>State of Web Technologies and Web development in year 2022</title><meta name=description content="Initial thoughtsThis post is a critique on the current state of web development."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>State of Web Technologies and Web development in year 2022</h1><p><cap>post</cap>, Oct 6, 2022 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><h2 id=initial-thoughts>Initial thoughts</h2><p><em>This post is a critique on the current state of web development. It is an
10opinionated post! I will learn more about this in the future, and probably
11slightly change my mind about some of the things I criticize.</em><p>I have started working on a hobby project about two weeks ago, and I wanted to
12use that situation as a learning one. Trying new things, new technologies, new
13tools. I always considered myself to be an adventurous person when it comes to
14technology. I never shy away from trying new languages, new operating systems
15etc. Likewise, I find the whole experience satisfying, and it tickles that part
16of my brain that finds discovery the highest of the mountains to climb.<p>What I always wanted to make was a coding game, that you would play in a browser
17(just to eliminate building binaries for each operating system) where you would
18level up your character and go into these scriptable battles. You know, RPG
19elements.<p>So, the natural way to go would be some sort of SPA (single page application)
20with basic routing and some state management. Nothing crazy.<blockquote><p><strong>Before we move on</strong>, I have to be transparent. Take my views on this with
21a grain of salt. I have only scratched the surface with these technologies,
22and my knowledge is full of gaps. This is my experience using some of these
23products for the first time or in a limited capacity.</blockquote><p>Having this out of the way, I got myself a fresh pot of coffee and down the
24rabbit hole I went.<h2 id=giving-react-js-a-spin>Giving React JS a spin</h2><p>I first tried <a href=https://reactjs.org/>React JS</a>. I kind of like it. Furthermore,
25I have worked with libraries like this in the past and also wrote a couple of
26them (nothing compared to that level), but I had the basic understanding of what
27was going on. I rolled up a project quickly and had basic things done in a
28matter of two hours, which was impressive.<p>I prefer using <a href=https://tailwindcss.com/>Tailwind CSS</a> for my styling
29pleasures, and integrating that was also a painless experience. It was actually
30nice to see that some things got better with time. In about 2 minutes I got
31Tailwind working, and I was able to use classes at my disposal. All that
32<code>postcss</code> stuff was taken care of by adding a couple of things in config files
33(all described really well in their documentation).<p>It is not that different from Vue which I have had more encounters with in the
34past People will probably call me a lunatic for saying this. But you know, it is
35the truth. Same same, but different. I still believe that using libraries like
36this is beneficial. I am not a JavaScript purist. They all have their quirks,
37but at the end of the day, I truly believe it’s worth it.<h2 id=bundlers-and-transpilers>Bundlers and Transpilers</h2><p>I still reject calling <a href=https://www.typescriptlang.org/>Typescript</a> to
38<a href=https://www.javascript.com/>JavaScript</a> conversion a "compilation process". I
39call them <a href=https://devopedia.org/transpiler>transpilers</a>, and I don’t care! 😈<p>The first one that I ever used was <a href=https://webpack.js.org/>webpack</a>, and it
40was an absolute horrific experience. Saying this, it is an absolutely fantastic
41tool. I felt more like a config editor than actually a programmer. To be fair,
42I am a huge fan of <a href=https://www.gnu.org/software/make/>make</a>, and you can do as
43you wish with this information. I like my build systems simple.<p>Also, isn’t it interesting that we need something like
44<a href=https://babeljs.io/>Babel</a> to make JavaScript code work in a browser that has
45only one client side scripting available, which is by no accident also
46JavaScript. Why? I know why it’s needed, but seriously, why.<p>I haven’t used Babel for years now. Or if I did, it was packaged together by
47some other bundler thingy. Which does not make things better, but at least I
48didn’t need to worry about it.<p>I really don’t like complicated build systems. I really don’t like abstracting
49code and making things appear magical. The older I get, the more I appreciate
50clear and clean, expressive code. No one-liners, if possible.<p>But I have to give props to <a href=https://vitejs.dev/>Vite</a>! This was one of the
51best developer experiences I have ever had. Granted, it still has magical
52properties. And yes, it still is a bundler and abstracts things to the nth
53degree. But at least it didn’t force me to configure 700 lines of JSON. And I
54know that this makes me a hypocrite. You can’t have it all. Nonetheless, my
55reasoning here is, if using bundlers is inevitable, then at least they should
56provide an excellent developer experience.<p>I also noticed that now the catch-all phrase is “blazingly fast” and “lightning
57fast” and “next generation” and stuff like that. I mean, yeah, tools should get
58faster with time. But saying that starting a project now takes 2 seconds instead
59of 20 seconds is something that is a break it or make it kind of a deal is
60ridiculous. I don’t mind waiting a couple of seconds every couple of days. I
61also don’t create 700 projects every day, and also who does? This argument has
62no bite. All I want is a decent reload time (~100ms is more than good enough for
63me) and that is it.<p>You don’t need to sell me benefits if I only get them when I start a fresh
64project, and then try to convince me that this is somehow changing the fate of
65the universe. First of all, it is not. And second, if this is your only argument
66for your tool, I would advise you to maybe re-focus your efforts to something
67else. Vite says that startup times are really fast. And if that would be the
68only thing differentiating it from other tools, I would ignore it. But it has
69some really compelling features like <a href=https://www.geeksforgeeks.org/reactjs-hot-module-replacement/>Hot Module
70Replacement</a> that
71really works well. It was a joy to use.<p>So, I will be definitely using Vite in the future.<h2 id=jam-stack-mach-stack-no-snack>Jam Stack, Mach Stack no snack</h2><p>Let's get a couple of the acronyms out of the way, so we all know what we are
72talking about:<ul><li>Jam Stack - JavaScript, API and Markup<li>Mach Stack - Microservices, API-first, Cloud-Native SaaS, Headless</ul><p>It is so hard to follow all these new trendy things happening around you, that
73it makes you have a massive <strong>FOMO</strong> all the time. But on the other hand, you
74also don’t want to be that old fart that doesn’t move with the times and still
75writes his trusty jQuery code while listening to Blink 182 All the small things
76on full blast. It’s a good song, don’t get me wrong, but there are other songs
77out there.<p>I have to admit. <a href=https://vercel.com/>Vercel</a> is really cool! Love the
78simplicity of the service. You could compare it to
79<a href=https://www.netlify.com/>Netlify</a>. I haven’t tried Netlify extensively, but
80from a couple of experimental deployments I still prefer Vercel. It is much more
81streamlined, but maybe this is bias in me. I really like Vercel’s Analytics,
82which give you a <a href=https://web.dev/vitals/>Core Web Vitals report</a> in their
83admin console. Kind of cool, I’m not going to lie.<p>This whole idea about frontend and backend merging into <a href=https://www.debugbear.com/blog/server-side-rendering>SSR (server-side
84rendering)</a> looks so good
85on paper. It almost doesn’t come with any major flaws.<p>But when it comes to the actual implementation, there is much to be desired.
86I’m going to lump <a href=https://nextjs.org/>Next.js</a> and
87<a href=https://nuxtjs.org/>Nuxt.js</a> together because they are essentially the same
88thing, just a different library.<p>Now comes the reality. Mixing backend and frontend in this manner creates this
89weird mental model where you kind of rely on magical properties of these
90libraries. You relinquish control over to them for better developer experience.
91But is that really true? Initially, I was so stoked about it. However, the more
92I used them, the more I felt uncomfortable. I felt dirty, actually. Maybe this
93is because I come from old ways of doing things where you control every step of
94request, and allowing something to hijack it feels like blasphemy.<p>More than that, some pretty significant technical issues arose from this. How do
95you do JWT token authentication? You put it in <code>api</code> folder and then do some
96fetching and storing into local state management. But doing this also requires
97some tinkering with await/async stuff on the React/Vue side of things. And then
98you need to write middleware for it. And the more I look at it, the more I see
99that this whole thing was not meant to be used like this, and it all feels and
100looks like a huge hack.<p>The issue I have with this is that they over-promise and under-deliver. They
101want to be an all-in-one replacement for everything, and they don’t deliver on
102this promise. And how could they?! We have to be fair. It is an impossible task.<p>They sell you <a href=https://www.geeksforgeeks.org/overview-of-noops/>NoOps</a>, but
103when you need to accomplish something a little bit more out of the scope of
104Hello World, you have to make hacky decisions to make it work. And having a
105deployment strategy that relies on many moving parts is never a good idea.
106Abstracting too much is usually a sign of bad architecture.<p>Lately, this has become a huge trend that will for sure bite us in the future.
107And let’s not get it twisted. By doing this, PaaS providers like
108<a href=https://aws.amazon.com/>AWS</a>, <a href=https://cloud.google.com/>GCS</a>, etc. obscure
109their billing, and you end up paying more than you really should. And even if
110that is not an issue, it comes down to the principle of things. AWS is known for
111having multiple “currencies“ inside their projects like write operations, read
112operations, etc. which add up, and it creates this impossible to track billing
113scheme. It all behaves suspiciously like a pay-to-win game you could find on
114mobile phones that scams you out of your money.<p>And as far as I am concerned, the most important thing was me not coding the
115functionalities for the game I want to make. I was battling libraries and cloud
116providers. How to deploy, what settings are relevant. Bad documentation or
117multiple versions of achieving the same thing. You are getting bombarded by all
118this information, and you don’t really have any control over it.
119Production-ready code becomes a joke, essentially. Especially if you tend to
120work on that project for a prolonged period of time.<p>All of these options end up creating a fatigue. What to choose, what not to
121choose. Unnecessary worrying about if the stack will still be deemed worthy in
122six months. There is elegance in simplicity.<blockquote><p>JavaScript UI frameworks and libraries work in cycles. Every six months or
123so, a new one pops up, claiming that it has revolutionized UI development.
124Thousands of developers adopt it into their new projects, blog posts are
125written, Stack Overflow questions are asked and answered, and then a newer
126(and even more revolutionary) framework pops up to usurp the throne.
127— Ian Allen</blockquote><p>And this jab at these libraries and cloud providers is not done out of malice.
128It is a real concern that I have about them. In my life, I have seen
129technologies come and go, but the basics always stick around. So surrendering
130all the power you have to a library or a cloud provider is in my opinion a
131stupid move.<h2 id=tailwind-css-still-rocks>Tailwind CSS still rocks!</h2><p>You know, many people say negative things about Tailwind. And after a lot of
132deliberation, I came to the conclusion that Tailwind is good for two types of
133developers. Tailwind is good for a complete noob or a senior developer. A
134complete noob doesn’t really care about inner workings of CSS, and a senior
135developer also doesn’t care about CSS. Well, at least, not anymore. And
136developers in between usually have the biggest issues with it. Not always of
137course, but in a lot of cases.<p>I like the creature comforts of Tailwind. Being utility first would make me
138argue that it is actually more similar to <a href=https://sass-lang.com/>Sass</a> or
139<a href=https://lesscss.org/>Less</a> than something like Bootstrap. Not technically, but
140ideologically. After I started using it, I never looked back. I use it every
141time I need to do something web related.<p>Writing CSS for general things feels like going several steps back. Instead of
142focusing on what you are actually trying to achieve, you focus on notations like
143<a href=https://en.bem.info/methodology/css/>BEM</a>, code structuring, optimizing HTML
144size. Just doing things that make 0.1% difference. You know that saying: Early
145optimization is the root of all evil. Exactly that.<p>I am also not saying that Tailwind is the cure for everything. Sometimes custom
146CSS is necessary. But from what I found out in using it for almost two years in
147a production environment (on a site getting quite a lot of traffic and
148constantly being changed), I can say without any reservations that Tailwind
149saved our asses countless times. We would be rewriting CSS all the time without
150it. And I don’t really think writing CSS is the best way to spend my time.<p>I have also noticed that people who criticize Tailwind the most never actually
151used it in a real project that has a long lifetime with plenty of changes that
152will happen in the future.<p>But you know, whatever floats your boat!<h2 id=code-maintainability>Code maintainability</h2><p>Somehow, people also stopped talking about maintenance. If you constantly try to
153catch the latest and greatest train, you are by that logic always trying new
154things. Which is a good thing if you want to learn about technologies and try
155them. But for the production environment, you have to have a stable stack that
156doesn’t change every 6 months.<p>You can lock dependencies for sure. Nevertheless, the hype train moves along
157anyway. And the mindset this breeds goes against locking the code. This
158bleeding-edge rolling release cycle is not helping. That is why enterprise
159solutions usually look down on these popular stacks and only do bare minimum to
160appear hip and cool.<p>With that said, I still think that progress is good, but should be taken with a
161grain of salt. If your project is something that should be built once and then
162rarely updated, going with the latest stack is a possible way to go. But, if you
163are working on a project that lasts for years, you should probably approach it
164with some level of caution. Web development is often times too volatile.<h2 id=web-development-has-a-marketing-issue>Web development has a marketing issue</h2><p>I noticed that almost every project now has this marketing spin put on it.
165Everything is blazingly fast now. I get it, they are competing for your
166attention, but what happened to just being truthful and not inflating reality.<p>And in order to appeal to mass market, they leave things out of their marketing
167materials. These open-source projects are now behaving more and more like
168companies do. Which is a scary thought on its self.<p>And we are also seeing a rise in a concept of building a company in the open,
169which is a good thing, don't get me wrong. But when it is using open-source to
170lure people and then lock them in their ecosystem, there is where I have issues
171with it.<p>This might be because I have been using GNU/Linux for 20 years now and have been
172so beholden for my success to open-source that I see issues when open-source is
173being used to trick people into a false sense of security that these projects
174are built in the spirit of open-source. Because there is a difference. They are
175NOT! They have a really specific goal in mind. And the open-source is being used
176as a delivery system. Which is in my opinion disgusting!<h2 id=conclusion>Conclusion</h2><p>I will end my post with this. Web development is running now in circles. People
177are discovering <a href=https://www.tutorialspoint.com/remote-procedure-call-rpc>RPC</a>
178now and this is the now the next big thing. <a href=https://graphql.org/>GraphQL</a> is
179so passé. And I am so tired of it all. Of blazingly fast libraries, of all these
180new technologies that are actually just a remake of old ones. Of just the
181general spirit of the web. I will just use what I already know. Which worked 10
182years ago and will work 10 years after this. I will adopt a couple of little
183tools like Vite. But I will not waste my time on this anymore.<p>It was a good exercise to get in touch with what’s new now. Nothing really
184changed that much. FOMO is now cured! Now I have to get my ass back to actually
185code and make the project that I wanted to make in the first place.</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
186a lock on a Linux NFS server, which turned
187out to be specific to NFS v3 (which I really should have seen coming,
188since it involved NLM and lockd). Finding the NFS v4 client that
189owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
190and Bradley Kuhn, are interacting on the OSI's license-discuss
191list where the're doing
192bad computer history and insisting that a guy Larry Rosen
193coincidentally interviewed for a book years ago is clearly the origin of
194somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
195i2c, plan9
196Another month, another file system.
197Well, if you can’t fix it in software, fix it in hardware (looking at
198you, bme680, we’re not
199done yet). The show must go on, as they say, and I would like my
200experiments to go on.
201So a “new” addition to the environmental sensor family connected to
202the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
203this mortal coil, we are endowed with self-awareness, agency, and free will.
204Each of the 8 billion members of this human race represents a unique person, a
205unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
206My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
2071.0 has been released:
208wifi_da-1.0.sit
209(StuffIt 3 archive)
210SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
211This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
212classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
213In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
214Design Goals
215I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
216at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
217catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
218specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
219 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
220 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/that-sound-that-machine-makes-when-struggling.html b/public/that-sound-that-machine-makes-when-struggling.html
deleted file mode 100755
index 5e1389d..0000000
--- a/public/that-sound-that-machine-makes-when-struggling.html
+++ /dev/null
@@ -1,64 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Microsoundtrack — That sound that machine makes when struggling</title><meta name=description content="A couple of months ago, I got an idea about micro soundtracks."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Microsoundtrack — That sound that machine makes when struggling</h1><p><cap>post</cap>, Oct 16, 2022 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>A couple of months ago, I got an idea about micro soundtracks. In this concept,
10you are the observer, director, and audience in this tiny movies.<p>What you do is to attempt to imagine what would be happening around you based on
11a title of the song and let the song help you fill the void in your story.<p>I made these songs is Logic Pro X. Every year or so I do this kind of thing and
12make a couple of songs similar to this. But this is the first time I am posting
13about it.<p>You can listen to the whole set on
14<a href="https://www.youtube.com/watch?v=_5oXBhSmF3c">Youtube</a> or scroll down the page
15and there are embedded players for each song.<h2 id=a-bunch-of-inter-dimensional-people-with-loud-clocks>A bunch of inter-dimensional people with loud clocks</h2><p>A group of inter-dimensional people are going up and down the elevator with you
16while having loud clocks around their necks. Each clock ticks on a different
17frequency. A lot of other sounds are getting drawn into your dimension,
18resulting in a strange merging of dimensions.</p><iframe style=border:0;width:100%;height:42px src="https://bandcamp.com/EmbeddedPlayer/album=3913808801/size=small/bgcol=ffffff/linkcol=0687f5/track=1349272965/transparent=true/" seamless title=Bandcamp><a href=https://mitjafelicijan.bandcamp.com/album/that-sound-that-machine-makes-when-struggling>That sound that machine makes when struggling by Mitja Felicijan</a></iframe><h2 id=two-black-holes-conversing-about-the-weather>Two black holes conversing about the weather</h2><p>You are a traveler in a spaceship flying very close to two colliding black holes
19having a discussion about the weather while tearing each other apart. During all
20this your ship is getting pulled into the event horizon of both black holes,
21putting a lot of strain on your spaceship.</p><iframe style=border:0;width:100%;height:42px src="https://bandcamp.com/EmbeddedPlayer/album=3913808801/size=small/bgcol=ffffff/linkcol=0687f5/track=1756714200/transparent=true/" seamless title=Bandcamp><a href=https://mitjafelicijan.bandcamp.com/album/that-sound-that-machine-makes-when-struggling>That sound that machine makes when struggling by Mitja Felicijan</a></iframe><h2 id=a-planet-where-every-organism-is-a-plant>A planet where every organism is a plant</h2><p>You land on a planet where every living organism is a plant and among those
22plants some of them are highly intelligent, and you were asked to make first
23contact with the native species. Your visit takes place in a giant cave where
24you are meeting these plants, and they are talking to you.</p><iframe style=border:0;width:100%;height:42px src="https://bandcamp.com/EmbeddedPlayer/album=3913808801/size=small/bgcol=ffffff/linkcol=0687f5/track=3710973979/transparent=true/" seamless title=Bandcamp><a href=https://mitjafelicijan.bandcamp.com/album/that-sound-that-machine-makes-when-struggling>That sound that machine makes when struggling by Mitja Felicijan</a></iframe><h2 id=bio-implants-having-a-fit-and-reprogramming-your-brain>Bio implants having a fit and reprogramming your brain</h2><p>In a distant future where everybody has bio implants, you have just received
25your first one, which happens to be a brain implant. Something goes wrong, and
26your implant is starting to misbehave, and you are experiencing brain
27malfunctions. You are on the streets at night a couple of hours after your
28procedure. You can feel your sanity breaking down.</p><iframe style=border:0;width:100%;height:42px src="https://bandcamp.com/EmbeddedPlayer/album=3913808801/size=small/bgcol=ffffff/linkcol=0687f5/track=1157430581/transparent=true/" seamless title=Bandcamp><a href=https://mitjafelicijan.bandcamp.com/album/that-sound-that-machine-makes-when-struggling>That sound that machine makes when struggling by Mitja Felicijan</a></iframe><h2 id=cow-animation>Cow animation</h2><p>I also made this little cow animation. Go into full screen to see the effects in
29more details.<p><video src=/posts/microsoundtrack/cow.m4v controls loop></video></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
30a lock on a Linux NFS server, which turned
31out to be specific to NFS v3 (which I really should have seen coming,
32since it involved NLM and lockd). Finding the NFS v4 client that
33owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
34and Bradley Kuhn, are interacting on the OSI's license-discuss
35list where the're doing
36bad computer history and insisting that a guy Larry Rosen
37coincidentally interviewed for a book years ago is clearly the origin of
38somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
39i2c, plan9
40Another month, another file system.
41Well, if you can’t fix it in software, fix it in hardware (looking at
42you, bme680, we’re not
43done yet). The show must go on, as they say, and I would like my
44experiments to go on.
45So a “new” addition to the environmental sensor family connected to
46the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
47this mortal coil, we are endowed with self-awareness, agency, and free will.
48Each of the 8 billion members of this human race represents a unique person, a
49unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
50My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
511.0 has been released:
52wifi_da-1.0.sit
53(StuffIt 3 archive)
54SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
55This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
56classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
57In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
58Design Goals
59I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
60at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
61catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
62specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
63 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
64 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/the-strange-case-of-elasticsearch-allocation-failure.html b/public/the-strange-case-of-elasticsearch-allocation-failure.html
deleted file mode 100755
index 5c380a4..0000000
--- a/public/the-strange-case-of-elasticsearch-allocation-failure.html
+++ /dev/null
@@ -1,97 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>The strange case of Elasticsearch allocation failure</title><meta name=description content="I&amp;#39;ve been using Elasticsearch in production for 5 years now and never had asingle problem with it."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>The strange case of Elasticsearch allocation failure</h1><p><cap>post</cap>, Mar 29, 2020 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>I've been using Elasticsearch in production for 5 years now and never had a
10single problem with it. Hell, never even known there could be a problem. Just
11worked. All this time. The first node that I deployed is still being used in
12production, never updated, upgraded, touched in anyway.<p>All this bliss came to an abrupt end this Friday when I got notification that
13Elasticsearch cluster went warm. Well, warm is not that bad right? Wrong!
14Quickly after that I got another email which sent chills down my spine. Cluster
15is now red. RED! Now, shit really hit the fan!<p>I tried googling what could be the problem and after executing allocation
16function noticed that some shards were unassigned and 5 attempts were already
17made (which is BTW to my luck the maximum) and that meant I am basically fucked.
18They also applied that one should wait for cluster to re-balance itself. So, I
19waited. One hour, two hours, several hours. Nothing, still RED.<p>The strangest thing about it all was, that queries were still being fulfilled.
20Data was coming out. On the outside it looked like nothing was wrong but
21everybody that would look at the cluster would know immediately that something
22was very very wrong and we were living on borrowed time here.<blockquote><p><strong>Please, DO NOT do what I did.</strong> Seriously! Please ask someone on official
23forums or if you know an expert please consult him. There could be million of
24reasons and these solution fit my problem. Maybe in your case it would
25disastrous. I had all the data backed up and even if I would fail spectacularly
26I would be able to restore the data. It would be a huge pain and I would loose
27couple of days but I had a plan B.</blockquote><p>Executing allocation and told me what the problem was but no clear solution yet.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>GET /_cat/allocation?format=json
28</span></span></code></pre><p>I got a message that <code>ALLOCATION_FAILED</code> with additional info <code>failed to create shard, failure ioexception[failed to obtain in-memory shard lock]</code>. Well
29splendid! I must also say that our cluster is capable more than enough to handle
30the traffic. Also JVM memory pressure never was an issue. So what happened
31really then?<p>I tried also re-routing failed ones with no success due to AWS restrictions on
32having managed Elasticsearch cluster (they lock some of the functions).<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>POST /_cluster/reroute?retry_failed=true
33</span></span></code></pre><p>I got a message that significantly reduced my options.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>{
34</span></span><span style=display:flex><span> &#34;Message&#34;: <span style=color:#a31515>&#34;Your request: &#39;/_cluster/reroute&#39; is not allowed.&#34;</span>
35</span></span><span style=display:flex><span>}
36</span></span></code></pre><p>After that I went on a hunt again. I won't bother you with all the details
37because hours/days went by until I was finally able to re-index the problematic
38index and hoped for the best. Until that moment even re-indexing was giving me
39errors.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>POST _reindex
40</span></span><span style=display:flex><span>{
41</span></span><span style=display:flex><span> &#34;source&#34;: {
42</span></span><span style=display:flex><span> &#34;index&#34;: <span style=color:#a31515>&#34;myindex&#34;</span>
43</span></span><span style=display:flex><span> },
44</span></span><span style=display:flex><span> &#34;dest&#34;: {
45</span></span><span style=display:flex><span> &#34;index&#34;: <span style=color:#a31515>&#34;myindex-new&#34;</span>
46</span></span><span style=display:flex><span> }
47</span></span><span style=display:flex><span>}
48</span></span></code></pre><p>I needed to do this multiple times to get all the documents re-indexed. Then I
49dropped the original one with the following command.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>DELETE /myindex
50</span></span></code></pre><p>And re-indexed again new one in the original one (well by name only).<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>POST _reindex
51</span></span><span style=display:flex><span>{
52</span></span><span style=display:flex><span> &#34;source&#34;: {
53</span></span><span style=display:flex><span> &#34;index&#34;: <span style=color:#a31515>&#34;myindex-new&#34;</span>
54</span></span><span style=display:flex><span> },
55</span></span><span style=display:flex><span> &#34;dest&#34;: {
56</span></span><span style=display:flex><span> &#34;index&#34;: <span style=color:#a31515>&#34;myindex&#34;</span>
57</span></span><span style=display:flex><span> }
58</span></span><span style=display:flex><span>}
59</span></span></code></pre><p>On the surface it looks like all is working but I have a long road in front of
60me to get all the things working again. Cluster now shows that it is in Green
61mode but I am also getting a notification that the cluster has processing status
62which could mean million of things.<p>Godspeed!</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
63a lock on a Linux NFS server, which turned
64out to be specific to NFS v3 (which I really should have seen coming,
65since it involved NLM and lockd). Finding the NFS v4 client that
66owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
67and Bradley Kuhn, are interacting on the OSI's license-discuss
68list where the're doing
69bad computer history and insisting that a guy Larry Rosen
70coincidentally interviewed for a book years ago is clearly the origin of
71somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
72i2c, plan9
73Another month, another file system.
74Well, if you can’t fix it in software, fix it in hardware (looking at
75you, bme680, we’re not
76done yet). The show must go on, as they say, and I would like my
77experiments to go on.
78So a “new” addition to the environmental sensor family connected to
79the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
80this mortal coil, we are endowed with self-awareness, agency, and free will.
81Each of the 8 billion members of this human race represents a unique person, a
82unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
83My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
841.0 has been released:
85wifi_da-1.0.sit
86(StuffIt 3 archive)
87SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
88This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
89classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
90In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
91Design Goals
92I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
93at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
94catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
95specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
96 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
97 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/tmux-sane-defaults.html b/public/tmux-sane-defaults.html
deleted file mode 100755
index 52627ac..0000000
--- a/public/tmux-sane-defaults.html
+++ /dev/null
@@ -1,69 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Sane defaults for tmux with more visible statusbar</title><meta name=description content="# Remap prefix from &amp;#39;C-b&amp;#39; to &amp;#39;M-a&amp;#39;."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Sane defaults for tmux with more visible statusbar</h1><p><cap>note</cap>, May 25, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><pre><code class=language-conf># Remap prefix from 'C-b' to 'M-a'.
10unbind C-b
11set-option -g prefix M-a
12bind-key M-a send-prefix
13
14# Split panes using | and -.
15bind | split-window -h
16bind - split-window -v
17unbind '&quot;'
18unbind %
19
20# Start counting windows with 1.
21set-option -g allow-rename on
22set -g base-index 1
23setw -g pane-base-index 1
24
25# Statusbar: purple bg and white fg.
26set -g status-bg '#480b8e'
27set -g status-fg '#ffffff'
28
29# Active window: black bg and white fg.
30set -g window-status-current-format &quot;#[fg=#ffffff]#[bg=#111111]#[fg=#ffffff]#[bg=#111111] #I:#W #[fg=#ffffff]#[bg=#111111]&quot;
31
32# Disable mouse mode (tmux 2.1 and above).
33set -g mouse off
34</code></pre></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
35a lock on a Linux NFS server, which turned
36out to be specific to NFS v3 (which I really should have seen coming,
37since it involved NLM and lockd). Finding the NFS v4 client that
38owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
39and Bradley Kuhn, are interacting on the OSI's license-discuss
40list where the're doing
41bad computer history and insisting that a guy Larry Rosen
42coincidentally interviewed for a book years ago is clearly the origin of
43somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
44i2c, plan9
45Another month, another file system.
46Well, if you can’t fix it in software, fix it in hardware (looking at
47you, bme680, we’re not
48done yet). The show must go on, as they say, and I would like my
49experiments to go on.
50So a “new” addition to the environmental sensor family connected to
51the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
52this mortal coil, we are endowed with self-awareness, agency, and free will.
53Each of the 8 billion members of this human race represents a unique person, a
54unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
55My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
561.0 has been released:
57wifi_da-1.0.sit
58(StuffIt 3 archive)
59SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
60This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
61classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
62In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
63Design Goals
64I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
65at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
66catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
67specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
68 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
69 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/trying-to-build-a-new-kind-of-terminal-emulator.html b/public/trying-to-build-a-new-kind-of-terminal-emulator.html
deleted file mode 100755
index 6b42a0f..0000000
--- a/public/trying-to-build-a-new-kind-of-terminal-emulator.html
+++ /dev/null
@@ -1,224 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Trying to build a New kind of terminal emulator for the modern age</title><meta name=description content="Over the past few weeks, I have been really thinking about terminal emulators,how we interact with computers, the separation of text-based programs and GUIones."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Trying to build a New kind of terminal emulator for the modern age</h1><p><cap>post</cap>, Jan 26, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>Over the past few weeks, I have been really thinking about terminal emulators,
10how we interact with computers, the separation of text-based programs and GUI
11ones. To be perfectly honest, I got pissed off one evening when I was cleaning
12up files on my computer. Normally, I go into console and do <code>ncdu</code> and check
13where the junk is. Then I start deleting stuff. Without any discrimination,
14usually. But when it comes to screenshots, I have learned that it's good to keep
15them somewhere near if I need to refer to something that I was doing. I am an
16avid screenshot taker. So at that point I checked Pictures folder and also did a
17basic search <code>find . -type f -name "*.jpg"</code> for all the JPEG files in my home
18directory and immediately got pissed off. Why can’t I see thumbnails in my
19terminal? I know why, but why in the year of 2022 this is still a problem. I am
20used to traversing my disk via terminal. I am faster, and I am more comfortable
21this way. But when it comes to visualization, I then need to revert to GUI
22applications and again find the same file to see it. I know that programs like
23<code>feh</code> and <code>sxiv</code> are available, but I would just like to see the preview. Like
24<a href=https://jupyter.org/>Jupyter notebook</a> or something similar. Just having it
25inline. Part of a result.<p>It also didn’t help that I was spending some time with the <a href=https://plan9.io/plan9/>Plan
269</a> Operating system. More specifically
27<a href=http://9front.org/>9FRONT</a>. The way that <a href=http://acme.cat-v.org/>ACME editor</a>
28handles text editing is just wonderful. Different and fresh somehow, even though
29it’s super old.<p>So, I went on a lookout for an interesting way of visualizing results of some
30query. I found these applications to be outstanding examples of how not to be a
31captive of a predetermined way of doing things.<ul><li><a href=https://www.wolfram.com/mathematica/>Wolfram Mathematica</a><li><a href=https://jupyter.org/>Jupyter notebooks</a><li><a href=http://www.9front.org>Plan 9 / 9FRONT</a><li><a href=https://templeos.org/>Temple OS</a><li><a href=https://www.gnu.org/software/emacs/>Emacs</a></ul><p>My idea is not as out there as ACME is, but it is a spin on the terminal
32emulators. I like the modes that Vi/Vim provides you with. I like the way the
33Emacs does its own <code>M-x</code> <code>M-c</code>. Furthermore, I really like how Mathematica and
34Jupyter present the data in a free flowing form. And I love how Temple OS is
35basically a C interpreter on some level.<blockquote><p><strong>Note:</strong> This is part 1 of the journey. Nowhere finished yet. I am just
36tinkering with this at the moment. This whole thing can easily spectacularly
37fail.</blockquote><p>So I started. I knew that I wanted to have the couple of modes, but I didn’t
38like the repetition of keystrokes, so the only option was to have some sort of
39toggle and indicate to the user that they are in a special mode. Like Vi does
40for Normal and Visual mode.<p>These modes would for the first version be:<ul><li><em>Preview mode</em> (toggle with Ctrl + P)<ul><li>When this mode would be enabled, the <code>ls</code> command would try to find images
41from the results and display thumbnails from them in the terminal itself.
42No ASCII art. Proper images. In a grid!</ul><li><em>Detach mode</em> (toggle with Ctrl + D)<ul><li>When this mode would be enabled, every command would open a new window
43and execute that command in it. This would be useful for starting <code>htop</code>
44in a separate window.</ul></ul><p>The reason for having these modes togglable is to not ask for previews every
45time. You enable a mode and until you disable it, it behaves that way. Purely
46out of ergonomic reasons.<p>I would like to treat every terminal I open as a session mentally. When I start
47using the terminal, I start digging deeper into the issue I am trying to
48resolve. And while I am doing this, I would like to open detached windows
49etc. A lot of these things can be done easily with something like
50<a href=https://i3wm.org/>i3</a>, but also that pull you out of the context of what you
51were doing. I would like to orchestrate everything from one single point.<p>In planning for this project, I knew that I would need to use a language like C
52and a library such as <a href=https://www.libsdl.org/>SDL2</a> in order to achieve the
53desired results. I had considered other options, but ultimately determined that
54<a href=https://www.libsdl.org/>SDL2</a> was the best fit based on its capabilities and
55reputation in the programming community.<p>At first, I thought the idea of a hardware accelerated terminal was a bit of a
56joke. It seemed like such a niche and unnecessary feature, especially given the
57fact that terminal emulators have been around for decades and have always relied
58on software rendering. But to be fair, <a href=https://alacritty.org/>Alacritty</a> is
59doing the same thing. Well, they are doing a remarkable job at it.<p>So, I embarked on a journey. Everything has to start somewhere. For me, it
60started with creating a window! It has to start somewhere. 🙂<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green>// Oh, Hi Mark!
61</span></span></span><span style=display:flex><span><span style=color:green>// Create the window, obviously.
62</span></span></span><span style=display:flex><span><span style=color:green></span>SDL_Window *window = SDL_CreateWindow(
63</span></span><span style=display:flex><span> WINDOW_TITLE, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
64</span></span><span style=display:flex><span> WINDOW_WIDTH, WINDOW_HEIGHT,
65</span></span><span style=display:flex><span> SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
66</span></span></code></pre><p>I continued like this to get some text displayed on the screen.<p>I noted that
67<a href=https://wiki.libsdl.org/SDL_ttf/TTF_RenderText_Solid><code>TTF_RenderText_Solid</code></a>
68rendered text really poorly. There were no antialiasing at all. In my wisdom, I
69never checked the documentation. Well, that was a fail. To uneducated like me:
70<code>TTF_RenderText_Solid</code> renders Latin1 text at fast quality to a new 8-bit
71surface. So, that's why the texts looked like shit. No wonder.<p>Remarks on <code>TTF_RenderText_Solid</code>: This function will allocate a new 8-bit,
72palettized surface. The surface's 0 pixel will be the colorkey, giving a
73transparent background. The 1 pixel will be set to the text color.<p>After I replaced it with
74<a href=https://wiki.libsdl.org/SDL_ttf/TTF_RenderText_LCD><code>TTF_RenderText_LCD</code></a> which
75renders Latin1 text at LCD subpixel quality to a new ARGB surface, the text
76started looking good. Really make sure you read the documentation. It’s actually
77good. As a side note, you can find all the documentation regarding <a href=https://wiki.libsdl.org/>SDL2 on
78their Wiki</a>.<p>After that was done, I started working on displaying other things like <code>Preview</code>
79and <code>Detach</code> modes. This wasn’t really that hard. In SDL2 you can check all the
80available events with <code>while (SDL_PollEvent(&amp;event) > 0)</code> and have a bunch of
81switch statements to determine which key is currently being pressed. More about
82keys, <a href=https://documentation.help/SDL/sdlkey.html>SDLKey</a> and mroe about
83pooling the events on
84<a href=https://documentation.help/SDL/sdlpollevent.html>SDL_PollEvent</a>.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>while</span> (SDL_PollEvent(&amp;event) &gt; 0)
85</span></span><span style=display:flex><span>{
86</span></span><span style=display:flex><span> <span style=color:#00f>switch</span> (event.type)
87</span></span><span style=display:flex><span> {
88</span></span><span style=display:flex><span> <span style=color:#00f>case</span> SDL_QUIT:
89</span></span><span style=display:flex><span> running = false;
90</span></span><span style=display:flex><span> <span style=color:#00f>break</span>;
91</span></span><span style=display:flex><span>
92</span></span><span style=display:flex><span> <span style=color:#00f>case</span> SDL_TEXTINPUT:
93</span></span><span style=display:flex><span> <span style=color:#00f>if</span> (!meta_key_pressed)
94</span></span><span style=display:flex><span> {
95</span></span><span style=display:flex><span> strncat(input_prompt_text, event.text.text, 1);
96</span></span><span style=display:flex><span> update_input_prompt = true;
97</span></span><span style=display:flex><span> }
98</span></span><span style=display:flex><span> <span style=color:#00f>break</span>;
99</span></span><span style=display:flex><span> }
100</span></span><span style=display:flex><span>}
101</span></span></code></pre><p>After that was somewhat working correctly, I started creating a struct that
102would hold all the commands and results and I call them Cells. Yes, I stole that
103naming idea from Jupyter.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>typedef</span> <span style=color:#00f>struct</span>
104</span></span><span style=display:flex><span>{
105</span></span><span style=display:flex><span> <span style=color:#2b91af>char</span> *command;
106</span></span><span style=display:flex><span> <span style=color:#2b91af>char</span> *result;
107</span></span><span style=display:flex><span> SDL_Surface *surface;
108</span></span><span style=display:flex><span> SDL_Texture *texture;
109</span></span><span style=display:flex><span> SDL_Rect rect;
110</span></span><span style=display:flex><span>} Cell;
111</span></span></code></pre><p>I am at a place now where I am starting to implement scrolling. This will for
112sure be fun to code. Memory management in C is super easy. 😂<p>I have also added a simple <a href=https://en.wikipedia.org/wiki/INI_file>INI file like
113configuration</a> support. It is done in an
114<a href=https://github.com/nothings/stb/blob/master/docs/stb_howto.txt>STB style of
115header</a> and maps
116to specific options supported by the terminal. It is not universal, and the code
117below demonstrates how I will use it in the future.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>#ifndef CONFIG_H
118</span></span></span><span style=display:flex><span><span style=color:#00f>#define CONFIG_H
119</span></span></span><span style=display:flex><span><span style=color:#00f></span>
120</span></span><span style=display:flex><span><span style=color:green>/*
121</span></span></span><span style=display:flex><span><span style=color:green># This is a comment
122</span></span></span><span style=display:flex><span><span style=color:green>
123</span></span></span><span style=display:flex><span><span style=color:green># This is the first configuration option
124</span></span></span><span style=display:flex><span><span style=color:green>dettach=value11111
125</span></span></span><span style=display:flex><span><span style=color:green>
126</span></span></span><span style=display:flex><span><span style=color:green># This is the second configuration option
127</span></span></span><span style=display:flex><span><span style=color:green>preview=value22222
128</span></span></span><span style=display:flex><span><span style=color:green>
129</span></span></span><span style=display:flex><span><span style=color:green># This is the third configuration option
130</span></span></span><span style=display:flex><span><span style=color:green>debug=value33333
131</span></span></span><span style=display:flex><span><span style=color:green>*/</span>
132</span></span><span style=display:flex><span>
133</span></span><span style=display:flex><span><span style=color:green>// Define a struct to hold the configuration options
134</span></span></span><span style=display:flex><span><span style=color:green></span><span style=color:#00f>typedef</span> <span style=color:#00f>struct</span>
135</span></span><span style=display:flex><span>{
136</span></span><span style=display:flex><span> <span style=color:#2b91af>char</span> dettach[256];
137</span></span><span style=display:flex><span> <span style=color:#2b91af>char</span> preview[256];
138</span></span><span style=display:flex><span> <span style=color:#2b91af>char</span> debug[256];
139</span></span><span style=display:flex><span>} Config;
140</span></span><span style=display:flex><span>
141</span></span><span style=display:flex><span><span style=color:green>// Read the configuration file and return the options as a struct
142</span></span></span><span style=display:flex><span><span style=color:green></span><span style=color:#00f>extern</span> Config read_config_file(<span style=color:#00f>const</span> <span style=color:#2b91af>char</span> *filename)
143</span></span><span style=display:flex><span>{
144</span></span><span style=display:flex><span> <span style=color:green>// Create a struct to hold the configuration options
145</span></span></span><span style=display:flex><span><span style=color:green></span> Config config = {0};
146</span></span><span style=display:flex><span>
147</span></span><span style=display:flex><span> <span style=color:green>// Open the configuration file
148</span></span></span><span style=display:flex><span><span style=color:green></span> FILE *file = fopen(filename, <span style=color:#a31515>&#34;r&#34;</span>);
149</span></span><span style=display:flex><span>
150</span></span><span style=display:flex><span> <span style=color:green>// Read each line from the file
151</span></span></span><span style=display:flex><span><span style=color:green></span> <span style=color:#2b91af>char</span> line[256];
152</span></span><span style=display:flex><span> <span style=color:#00f>while</span> (fgets(line, <span style=color:#00f>sizeof</span>(line), file))
153</span></span><span style=display:flex><span> {
154</span></span><span style=display:flex><span> <span style=color:green>// Check if this line is a comment or empty
155</span></span></span><span style=display:flex><span><span style=color:green></span> <span style=color:#00f>if</span> (line[0] == <span style=color:#a31515>&#39;#&#39;</span> || line[0] == <span style=color:#a31515>&#39;\n&#39;</span>)
156</span></span><span style=display:flex><span> <span style=color:#00f>continue</span>;
157</span></span><span style=display:flex><span>
158</span></span><span style=display:flex><span> <span style=color:green>// Parse the line to get the option and value
159</span></span></span><span style=display:flex><span><span style=color:green></span> <span style=color:#2b91af>char</span> option[128], value[128];
160</span></span><span style=display:flex><span> <span style=color:#00f>if</span> (sscanf(line, <span style=color:#a31515>&#34;%[^=]=%s&#34;</span>, option, value) != 2)
161</span></span><span style=display:flex><span> <span style=color:#00f>continue</span>;
162</span></span><span style=display:flex><span>
163</span></span><span style=display:flex><span> <span style=color:green>// Set the value of the appropriate option in the config struct
164</span></span></span><span style=display:flex><span><span style=color:green></span> <span style=color:#00f>if</span> (strcmp(option, <span style=color:#a31515>&#34;dettach&#34;</span>) == 0)
165</span></span><span style=display:flex><span> {
166</span></span><span style=display:flex><span> strncpy(config.option1, value, <span style=color:#00f>sizeof</span>(config.option1));
167</span></span><span style=display:flex><span> }
168</span></span><span style=display:flex><span> <span style=color:#00f>else</span> <span style=color:#00f>if</span> (strcmp(option, <span style=color:#a31515>&#34;preview&#34;</span>) == 0)
169</span></span><span style=display:flex><span> {
170</span></span><span style=display:flex><span> strncpy(config.option2, value, <span style=color:#00f>sizeof</span>(config.option2));
171</span></span><span style=display:flex><span> }
172</span></span><span style=display:flex><span> <span style=color:#00f>else</span> <span style=color:#00f>if</span> (strcmp(option, <span style=color:#a31515>&#34;debug&#34;</span>) == 0)
173</span></span><span style=display:flex><span> {
174</span></span><span style=display:flex><span> strncpy(config.option3, value, <span style=color:#00f>sizeof</span>(config.option3));
175</span></span><span style=display:flex><span> }
176</span></span><span style=display:flex><span> }
177</span></span><span style=display:flex><span>
178</span></span><span style=display:flex><span> <span style=color:green>// Close the configuration file
179</span></span></span><span style=display:flex><span><span style=color:green></span> fclose(file);
180</span></span><span style=display:flex><span>
181</span></span><span style=display:flex><span> <span style=color:green>// Return the configuration options
182</span></span></span><span style=display:flex><span><span style=color:green></span> <span style=color:#00f>return</span> config;
183</span></span><span style=display:flex><span>}
184</span></span><span style=display:flex><span>
185</span></span><span style=display:flex><span><span style=color:#00f>#endif
186</span></span></span></code></pre><p>This is as far as I managed to get for now. I have a daily job and this
187prohibits me to work on these things full time. But I should probably get back
188and finish this. At least have a simple version working out, so I can start
189testing it on my machines. Fingers crossed. 🕵️‍♂️</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
190a lock on a Linux NFS server, which turned
191out to be specific to NFS v3 (which I really should have seen coming,
192since it involved NLM and lockd). Finding the NFS v4 client that
193owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
194and Bradley Kuhn, are interacting on the OSI's license-discuss
195list where the're doing
196bad computer history and insisting that a guy Larry Rosen
197coincidentally interviewed for a book years ago is clearly the origin of
198somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
199i2c, plan9
200Another month, another file system.
201Well, if you can’t fix it in software, fix it in hardware (looking at
202you, bme680, we’re not
203done yet). The show must go on, as they say, and I would like my
204experiments to go on.
205So a “new” addition to the environmental sensor family connected to
206the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
207this mortal coil, we are endowed with self-awareness, agency, and free will.
208Each of the 8 billion members of this human race represents a unique person, a
209unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
210My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
2111.0 has been released:
212wifi_da-1.0.sit
213(StuffIt 3 archive)
214SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
215This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
216classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
217In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
218Design Goals
219I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
220at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
221catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
222specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
223 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
224 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/tying-out-helix-code-editor.html b/public/tying-out-helix-code-editor.html
deleted file mode 100755
index 309833e..0000000
--- a/public/tying-out-helix-code-editor.html
+++ /dev/null
@@ -1,67 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Trying out Helix code editor as my main editor</title><meta name=description content="I have been searching for a lightweight code editor for quite some time."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Trying out Helix code editor as my main editor</h1><p><cap>post</cap>, Jun 30, 2022 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>I have been searching for a lightweight code editor for quite some time. One of
10the main reasons was that I wanted something that doesn't burn through CPU and
11RAM usage is not through the roof. I have been mostly using Visual Studio Code.
12It's been an outstanding editor. I have no quarrel with it at all. It's just
13time to spice life up with something new.<p>I have been on this search for a couple of years. I have tried Vim, Neovim,
14Emacs, Doom Emacs, Micro and couple more. Among most of them, I liked Micro and
15Doom Emacs the most. Micro editor was a little too basic for me. And Doom Emacs
16was a bit too hardcore. This does not reflect on any of the editors. It's just
17my personal preference.<blockquote><p>I tried Helix Editor about a year ago. But I didn't pay attention to it.
18Tried it and saw it's similar to Vi and just said no. I was premature to
19dismiss it.</blockquote><p>One of the things I actually miss is line wrapping for certain files. When
20writing Markdown, line wrapping would be very helpful. Editing such a document
21is frustrating to say the least. Some of the Markdown to HTML converters don't
22take kindly of new lines between sentences. Not paragraphs, sentences. And I use
23Markdown to write this blog you are reading.<p>But other than this, I have been extremely satisfied by it. It's been a pleasant
24surprise. There have been zero issues with the editor.<p>One thing to do before you are able to use autocompletion and make use Language
25Server support is to install the language server with NPM.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>npm install -g typescript typescript-language-server
26</span></span></code></pre><p>I am still getting used to the keyboard shortcuts and getting better. What Helix
27does really well is packing in sane defaults and even though because currently
28there is no plugin support I haven't found any need for them. It has all that
29you would need. It goes to extreme measures to show a user what is going on with
30popups that show you what the keyboard shortcuts are.<p>And it comes us packed with many
31<a href=https://github.com/helix-editor/helix/wiki/Themes>really good themes</a>.<figure><img src=/posts/helix-editor/editor.png alt=Editor></figure><p>It's still young but has this mature feeling to it. It has sane defaults and
32mimics Vim (works a bit differently, but the overall idea is similar).</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
33a lock on a Linux NFS server, which turned
34out to be specific to NFS v3 (which I really should have seen coming,
35since it involved NLM and lockd). Finding the NFS v4 client that
36owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
37and Bradley Kuhn, are interacting on the OSI's license-discuss
38list where the're doing
39bad computer history and insisting that a guy Larry Rosen
40coincidentally interviewed for a book years ago is clearly the origin of
41somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
42i2c, plan9
43Another month, another file system.
44Well, if you can’t fix it in software, fix it in hardware (looking at
45you, bme680, we’re not
46done yet). The show must go on, as they say, and I would like my
47experiments to go on.
48So a “new” addition to the environmental sensor family connected to
49the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
50this mortal coil, we are endowed with self-awareness, agency, and free will.
51Each of the 8 billion members of this human race represents a unique person, a
52unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
53My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
541.0 has been released:
55wifi_da-1.0.sit
56(StuffIt 3 archive)
57SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
58This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
59classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
60In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
61Design Goals
62I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
63at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
64catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
65specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
66 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
67 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/using-digitalocean-spaces-object-storage-with-fuse.html b/public/using-digitalocean-spaces-object-storage-with-fuse.html
deleted file mode 100755
index 4f700e0..0000000
--- a/public/using-digitalocean-spaces-object-storage-with-fuse.html
+++ /dev/null
@@ -1,280 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Using DigitalOcean Spaces Object Storage with FUSE</title><meta name=description content="Couple of months ago DigitalOcean introduced newproduct calledSpaces whichis Object Storage very similar to Amazon&amp;#39;s S3."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Using DigitalOcean Spaces Object Storage with FUSE</h1><p><cap>post</cap>, Jan 16, 2018 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>Couple of months ago <a href=https://www.digitalocean.com>DigitalOcean</a> introduced new
10product called
11<a href=https://blog.digitalocean.com/introducing-spaces-object-storage/>Spaces</a> which
12is Object Storage very similar to Amazon's S3. This really peaked my interest,
13because this was something I was missing and even the thought of going over the
14internet for such functionality was in no interest to me. Also in fashion with
15their previous pricing this also is very cheap and pricing page is a no-brainer
16compared to AWS or GCE. <a href=https://www.digitalocean.com/pricing/>Prices are clearly and precisely defined and
17outlined</a>. You must love them for that
18:)<h2 id=initial-requirements>Initial requirements</h2><ul><li>Is it possible to use them as a mounted drive with FUSE? (tl;dr YES)<li>Will the performance degrade over time and over different sizes of objects?
19(tl;dr NO&amp;YES)<li>Can storage be mounted on multiple machines at the same time and be writable?
20(tl;dr YES)</ul><blockquote><p>Let me be clear. This scripts I use are made just for benchmarking and are not
21intended to be used in real-life situations. Besides that, I am looking into
22using this approaches but adding caching service in front of it and then
23dumping everything as an object to storage. This could potentially be some
24interesting post of itself. But in case you would need real-time data without
25eventual consistency please take this scripts as they are: not usable in such
26situations.</blockquote><h2 id=is-it-possible-to-use-them-as-a-mounted-drive-with-fuse>Is it possible to use them as a mounted drive with FUSE?</h2><p>Well, actually they can be used in such manor. Because they are similar to <a href=https://aws.amazon.com/s3/>AWS
27S3</a> many tools are available and you can find many
28articles and <a href="https://stackoverflow.com/search?q=s3+fuse">Stackoverflow items</a>.<p>To make this work you will need DigitalOcean account. If you don't have one you
29will not be able to test this code. But if you have an account then you go and
30<a href="https://cloud.digitalocean.com/droplets/new?size=s-1vcpu-1gb&amp;region=ams3&amp;distro=debian&amp;distroImage=debian-9-x64&amp;options=private_networking,install_agent">create new
31Droplet</a>.
32If you click on this link you will already have preselected Debian 9 with
33smallest VM option.<ul><li>Please be sure to add you SSH key, because we will login to this machine
34remotely.<li>If you change your region please remember which one you choose because we will
35need this information when we try to mount space to our machine.</ul><p>Instuctions on how to use SSH keys and how to setup them are available in
36article <a href=https://www.digitalocean.com/community/tutorials/how-to-use-ssh-keys-with-digitalocean-droplets>How To Use SSH Keys with DigitalOcean
37Droplets</a>.<figure><img src=/posts/do-fuse/fuse-droplets.png alt="DigitalOcean Droplets"></figure><p>After we created Droplet it's time to create new Space. This is done by clicking
38on a button <a href=https://cloud.digitalocean.com/spaces/new>Create</a> (right top
39corner) and selecting Spaces. Choose pronounceable <code>Unique name</code> because we
40will use it in examples below. You can either choose Private or Public, it
41doesn't matter in our case. And you can always change that in the future.<p>When you have created new Space we should <a href=https://cloud.digitalocean.com/settings/api/tokens>generate Access
42key</a>. This link will guide
43to the page when you can generate this key. After you create new one, please
44save provided Key and Secret because Secret will not be shown again.<figure><img src=/posts/do-fuse/fuse-spaces.png alt="DigitalOcean Spaces"></figure><p>Now that we have new Space and Access key we should SSH into our machine.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># replace IP with the ip of your newly created droplet</span>
45</span></span><span style=display:flex><span>ssh root@IP
46</span></span><span style=display:flex><span>
47</span></span><span style=display:flex><span><span style=color:green># this will install utilities for mounting storage objects as FUSE</span>
48</span></span><span style=display:flex><span>apt install s3fs
49</span></span><span style=display:flex><span>
50</span></span><span style=display:flex><span><span style=color:green># we now need to provide credentials (access key we created earlier)</span>
51</span></span><span style=display:flex><span><span style=color:green># replace KEY and SECRET with your own credentials but leave the colon between them</span>
52</span></span><span style=display:flex><span><span style=color:green># we also need to set proper permissions</span>
53</span></span><span style=display:flex><span>echo <span style=color:#a31515>&#34;KEY:SECRET&#34;</span> &gt; .passwd-s3fs
54</span></span><span style=display:flex><span>chmod 600 .passwd-s3fs
55</span></span><span style=display:flex><span>
56</span></span><span style=display:flex><span><span style=color:green># now we mount space to our machine</span>
57</span></span><span style=display:flex><span><span style=color:green># replace UNIQUE-NAME with the name you choose earlier</span>
58</span></span><span style=display:flex><span><span style=color:green># if you choose different region for your space be careful about -ourl option (ams3)</span>
59</span></span><span style=display:flex><span>s3fs UNIQUE-NAME /mnt/ -ourl=https://ams3.digitaloceanspaces.com -ouse_cache=/tmp
60</span></span><span style=display:flex><span>
61</span></span><span style=display:flex><span><span style=color:green># now we try to create a file</span>
62</span></span><span style=display:flex><span><span style=color:green># once you mount it may take a couple of seconds to retrieve data</span>
63</span></span><span style=display:flex><span>echo <span style=color:#a31515>&#34;Hello cruel world&#34;</span> &gt; /mnt/hello.txt
64</span></span></code></pre><p>After all this you can return to your browser and go to <a href=https://cloud.digitalocean.com/spaces>DigitalOcean
65Spaces</a> and click on your created
66space. If file hello.txt is present you have successfully mounted space to your
67machine and wrote data to it.<p>I choose the same region for my Droplet and my Space but you don't have to. You
68can have different regions. What this actually does to performance I don't know.<p>Additional information on FUSE:<ul><li><a href=https://github.com/s3fs-fuse/s3fs-fuse>Github project page for s3fs</a><li><a href=https://en.wikipedia.org/wiki/Filesystem_in_Userspace>FUSE - Filesystem in Userspace</a></ul><h2 id=will-the-performance-degrade-over-time-and-over-different-sizes-of-objects>Will the performance degrade over time and over different sizes of objects?</h2><p>For this task I didn't want to just read and write text files or uploading
69images. I actually wanted to figure out if using something like SQlite is viable
70in this case.<h3 id=measurement-experiment-1-file-copy>Measurement experiment 1: File copy</h3><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># first we create some dummy files at different sizes</span>
71</span></span><span style=display:flex><span>dd <span style=color:#00f>if</span>=/dev/zero of=10KB.dat bs=1024 count=10 <span style=color:green>#10KB</span>
72</span></span><span style=display:flex><span>dd <span style=color:#00f>if</span>=/dev/zero of=100KB.dat bs=1024 count=100 <span style=color:green>#100KB</span>
73</span></span><span style=display:flex><span>dd <span style=color:#00f>if</span>=/dev/zero of=1MB.dat bs=1024 count=1024 <span style=color:green>#1MB</span>
74</span></span><span style=display:flex><span>dd <span style=color:#00f>if</span>=/dev/zero of=10MB.dat bs=1024 count=10240 <span style=color:green>#10MB</span>
75</span></span><span style=display:flex><span>
76</span></span><span style=display:flex><span><span style=color:green># now we set time command to only return real</span>
77</span></span><span style=display:flex><span>TIMEFORMAT=%R
78</span></span><span style=display:flex><span>
79</span></span><span style=display:flex><span><span style=color:green># now lets test it</span>
80</span></span><span style=display:flex><span>(time cp 10KB.dat /mnt/) |&amp; tee -a 10KB.results.txt
81</span></span><span style=display:flex><span>
82</span></span><span style=display:flex><span><span style=color:green># and now we automate</span>
83</span></span><span style=display:flex><span><span style=color:green># this will perform the same operation 100 times</span>
84</span></span><span style=display:flex><span><span style=color:green># this will output results into separated files based on objecty size</span>
85</span></span><span style=display:flex><span>n=0; <span style=color:#00f>while</span> (( n++ &lt; 100 )); <span style=color:#00f>do</span> (time cp 10KB.dat /mnt/10KB.$n.dat) |&amp; tee -a 10KB.results.txt; <span style=color:#00f>done</span>
86</span></span><span style=display:flex><span>n=0; <span style=color:#00f>while</span> (( n++ &lt; 100 )); <span style=color:#00f>do</span> (time cp 100KB.dat /mnt/100KB.$n.dat) |&amp; tee -a 100KB.results.txt; <span style=color:#00f>done</span>
87</span></span><span style=display:flex><span>n=0; <span style=color:#00f>while</span> (( n++ &lt; 100 )); <span style=color:#00f>do</span> (time cp 1MB.dat /mnt/1MB.$n.dat) |&amp; tee -a 1MB.results.txt; <span style=color:#00f>done</span>
88</span></span><span style=display:flex><span>n=0; <span style=color:#00f>while</span> (( n++ &lt; 100 )); <span style=color:#00f>do</span> (time cp 10MB.dat /mnt/10MB.$n.dat) |&amp; tee -a 10MB.results.txt; <span style=color:#00f>done</span>
89</span></span></code></pre><p>Files of size 100MB were not successfully transferred and ended up displaying
90error (cp: failed to close '/mnt/100MB.1.dat': Operation not permitted).<p>As I suspected, object size is not really that important. Sadly I don't have the
91time to test performance over periods of time. But if some of you would do it
92please send me your data. I would be interested in seeing results.<p><strong>Here are plotted results</strong><p>You can download <a href=/posts/do-fuse/copy-benchmarks.tsv>raw result here</a>.
93Measurements are in seconds.</p><script src=//cdn.plot.ly/plotly-latest.min.js></script><div id=copy-benchmarks></div><script>
94(function(){
95 var request = new XMLHttpRequest();
96 request.open("GET", "/posts/do-fuse/copy-benchmarks.tsv", true);
97 request.onload = function() {
98 if (request.status >= 200 && request.status < 400) {
99 var payload = request.responseText.trim();
100 var tsv = payload.split("\n");
101 for (var i=0; i<tsv.length; i++) { tsv[i] = tsv[i].split("\t"); }
102 var traces = [];
103 var headers = tsv[0];
104 tsv.shift();
105 Array.prototype.forEach.call(headers, function(el, idx) {
106 var x = [];
107 var y = [];
108 for (var j=0; j<tsv.length; j++) {
109 x.push(j);
110 y.push(parseFloat(tsv[j][idx].replace(",", ".")));
111 }
112 traces.push({ x: x, y: y, type: "scatter", name: el, line: { width: 1, shape: "spline" } });
113 });
114 var copy = Plotly.newPlot("copy-benchmarks", traces, { legend: {"orientation": "h"}, height: 400, margin: { l: 40, r: 0, b: 20, t: 30, pad: 0 }, yaxis: { title: "execution time in seconds", titlefont: { size: 12 } }, xaxis: { title: "fn(i)", titlefont: { size: 12 } } });
115 } else { }
116 };
117 request.onerror = function() { };
118 request.send(null);
119})();
120</script><p>As far as these tests show, performance is quite stable and can be predicted
121which is fantastic. But this is a small test and spans only over couple of
122hours. So you should not completely trust them.<h3 id=measurement-experiment-2-sqlite-performanse>Measurement experiment 2: SQLite performanse</h3><p>I was unable to use database file directly from mounted drive so this is a no-go
123as I suspected. So I executed code below on a local disk just to get some
124benchmarks. I inserted 1000 records with DROPTABLE, CREATETABLE, INSERTMANY,
125FETCHALL, COMMIT for 1000 times to generate statistics. As you can see
126performance of SQLite is quite amazing. You could then potentially just copy
127file to mounted drive and be done with it.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>import</span> time
128</span></span><span style=display:flex><span><span style=color:#00f>import</span> sqlite3
129</span></span><span style=display:flex><span><span style=color:#00f>import</span> sys
130</span></span><span style=display:flex><span>
131</span></span><span style=display:flex><span><span style=color:#00f>if</span> len(sys.argv) &lt; 3:
132</span></span><span style=display:flex><span> print(<span style=color:#a31515>&#34;usage: python sqlite-benchmark.py DB_PATH NUM_RECORDS REPEAT&#34;</span>)
133</span></span><span style=display:flex><span> exit()
134</span></span><span style=display:flex><span>
135</span></span><span style=display:flex><span><span style=color:#00f>def</span> data_iter(x):
136</span></span><span style=display:flex><span> <span style=color:#00f>for</span> i <span style=color:#00f>in</span> range(x):
137</span></span><span style=display:flex><span> <span style=color:#00f>yield</span> <span style=color:#a31515>&#34;m&#34;</span> + str(i), <span style=color:#a31515>&#34;f&#34;</span> + str(i*i)
138</span></span><span style=display:flex><span>
139</span></span><span style=display:flex><span>header_line = <span style=color:#a31515>&#34;</span><span style=color:#a31515>%s</span><span style=color:#a31515>\t</span><span style=color:#a31515>%s</span><span style=color:#a31515>\t</span><span style=color:#a31515>%s</span><span style=color:#a31515>\t</span><span style=color:#a31515>%s</span><span style=color:#a31515>\t</span><span style=color:#a31515>%s</span><span style=color:#a31515>\n</span><span style=color:#a31515>&#34;</span> % (<span style=color:#a31515>&#34;DROPTABLE&#34;</span>, <span style=color:#a31515>&#34;CREATETABLE&#34;</span>, <span style=color:#a31515>&#34;INSERTMANY&#34;</span>, <span style=color:#a31515>&#34;FETCHALL&#34;</span>, <span style=color:#a31515>&#34;COMMIT&#34;</span>)
140</span></span><span style=display:flex><span><span style=color:#00f>with</span> open(<span style=color:#a31515>&#34;sqlite-benchmarks.tsv&#34;</span>, <span style=color:#a31515>&#34;w&#34;</span>) <span style=color:#00f>as</span> fp:
141</span></span><span style=display:flex><span> fp.write(header_line)
142</span></span><span style=display:flex><span>
143</span></span><span style=display:flex><span>start_time = time.time()
144</span></span><span style=display:flex><span>conn = sqlite3.connect(sys.argv[1])
145</span></span><span style=display:flex><span>c = conn.cursor()
146</span></span><span style=display:flex><span>end_time = time.time()
147</span></span><span style=display:flex><span>result_time = CONNECT = end_time - start_time
148</span></span><span style=display:flex><span>print(<span style=color:#a31515>&#34;CONNECT: </span><span style=color:#a31515>%g</span><span style=color:#a31515> seconds&#34;</span> % (result_time))
149</span></span><span style=display:flex><span>
150</span></span><span style=display:flex><span>start_time = time.time()
151</span></span><span style=display:flex><span>c.execute(<span style=color:#a31515>&#34;PRAGMA journal_mode=WAL&#34;</span>)
152</span></span><span style=display:flex><span>c.execute(<span style=color:#a31515>&#34;PRAGMA temp_store=MEMORY&#34;</span>)
153</span></span><span style=display:flex><span>c.execute(<span style=color:#a31515>&#34;PRAGMA synchronous=OFF&#34;</span>)
154</span></span><span style=display:flex><span>result_time = PRAGMA = end_time - start_time
155</span></span><span style=display:flex><span>print(<span style=color:#a31515>&#34;PRAGMA: </span><span style=color:#a31515>%g</span><span style=color:#a31515> seconds&#34;</span> % (result_time))
156</span></span><span style=display:flex><span>
157</span></span><span style=display:flex><span><span style=color:#00f>for</span> i <span style=color:#00f>in</span> range(int(sys.argv[3])):
158</span></span><span style=display:flex><span> print(<span style=color:#a31515>&#34;#</span><span style=color:#a31515>%i</span><span style=color:#a31515>&#34;</span> % (i))
159</span></span><span style=display:flex><span>
160</span></span><span style=display:flex><span> start_time = time.time()
161</span></span><span style=display:flex><span> c.execute(<span style=color:#a31515>&#34;drop table if exists test&#34;</span>)
162</span></span><span style=display:flex><span> end_time = time.time()
163</span></span><span style=display:flex><span> result_time = DROPTABLE = end_time - start_time
164</span></span><span style=display:flex><span> print(<span style=color:#a31515>&#34;DROPTABLE: </span><span style=color:#a31515>%g</span><span style=color:#a31515> seconds&#34;</span> % (result_time))
165</span></span><span style=display:flex><span>
166</span></span><span style=display:flex><span> start_time = time.time()
167</span></span><span style=display:flex><span> c.execute(<span style=color:#a31515>&#34;create table if not exists test(a,b)&#34;</span>)
168</span></span><span style=display:flex><span> end_time = time.time()
169</span></span><span style=display:flex><span> result_time = CREATETABLE = end_time - start_time
170</span></span><span style=display:flex><span> print(<span style=color:#a31515>&#34;CREATETABLE: </span><span style=color:#a31515>%g</span><span style=color:#a31515> seconds&#34;</span> % (result_time))
171</span></span><span style=display:flex><span>
172</span></span><span style=display:flex><span> start_time = time.time()
173</span></span><span style=display:flex><span> c.executemany(<span style=color:#a31515>&#34;INSERT INTO test VALUES (?, ?)&#34;</span>, data_iter(int(sys.argv[2])))
174</span></span><span style=display:flex><span> end_time = time.time()
175</span></span><span style=display:flex><span> result_time = INSERTMANY = end_time - start_time
176</span></span><span style=display:flex><span> print(<span style=color:#a31515>&#34;INSERTMANY: </span><span style=color:#a31515>%g</span><span style=color:#a31515> seconds&#34;</span> % (result_time))
177</span></span><span style=display:flex><span>
178</span></span><span style=display:flex><span> start_time = time.time()
179</span></span><span style=display:flex><span> c.execute(<span style=color:#a31515>&#34;select count(*) from test&#34;</span>)
180</span></span><span style=display:flex><span> res = c.fetchall()
181</span></span><span style=display:flex><span> end_time = time.time()
182</span></span><span style=display:flex><span> result_time = FETCHALL = end_time - start_time
183</span></span><span style=display:flex><span> print(<span style=color:#a31515>&#34;FETCHALL: </span><span style=color:#a31515>%g</span><span style=color:#a31515> seconds&#34;</span> % (result_time))
184</span></span><span style=display:flex><span>
185</span></span><span style=display:flex><span> start_time = time.time()
186</span></span><span style=display:flex><span> conn.commit()
187</span></span><span style=display:flex><span> end_time = time.time()
188</span></span><span style=display:flex><span> result_time = COMMIT = end_time - start_time
189</span></span><span style=display:flex><span> print(<span style=color:#a31515>&#34;COMMIT: </span><span style=color:#a31515>%g</span><span style=color:#a31515> seconds&#34;</span> % (result_time))
190</span></span><span style=display:flex><span>
191</span></span><span style=display:flex><span> print
192</span></span><span style=display:flex><span> log_line = <span style=color:#a31515>&#34;</span><span style=color:#a31515>%f</span><span style=color:#a31515>\t</span><span style=color:#a31515>%f</span><span style=color:#a31515>\t</span><span style=color:#a31515>%f</span><span style=color:#a31515>\t</span><span style=color:#a31515>%f</span><span style=color:#a31515>\t</span><span style=color:#a31515>%f</span><span style=color:#a31515>\n</span><span style=color:#a31515>&#34;</span> % (DROPTABLE, CREATETABLE, INSERTMANY, FETCHALL, COMMIT)
193</span></span><span style=display:flex><span> <span style=color:#00f>with</span> open(<span style=color:#a31515>&#34;sqlite-benchmarks.tsv&#34;</span>, <span style=color:#a31515>&#34;a&#34;</span>) <span style=color:#00f>as</span> fp:
194</span></span><span style=display:flex><span> fp.write(log_line)
195</span></span><span style=display:flex><span>
196</span></span><span style=display:flex><span>start_time = time.time()
197</span></span><span style=display:flex><span>conn.close()
198</span></span><span style=display:flex><span>end_time = time.time()
199</span></span><span style=display:flex><span>result_time = CLOSE = end_time - start_time
200</span></span><span style=display:flex><span>print(<span style=color:#a31515>&#34;CLOSE: </span><span style=color:#a31515>%g</span><span style=color:#a31515> seconds&#34;</span> % (result_time))
201</span></span></code></pre><p>You can download <a href=/posts/do-fuse/sqlite-benchmarks.tsv>raw result here</a>. And
202again, these results are done on a local block storage and do not represent
203capabilities of object storage. With my current approach and state of the test
204code these can not be done. I would need to make Python code much more robust
205and check locking etc.<div id=sqlite-benchmarks></div><script>
206(function(){
207 var request = new XMLHttpRequest();
208 request.open("GET", "/posts/do-fuse/sqlite-benchmarks.tsv", true);
209 request.onload = function() {
210 if (request.status >= 200 && request.status < 400) {
211 var payload = request.responseText.trim();
212 var tsv = payload.split("\n");
213 for (var i=0; i<tsv.length; i++) { tsv[i] = tsv[i].split("\t"); }
214 var traces = [];
215 var headers = tsv[0];
216 tsv.shift();
217 Array.prototype.forEach.call(headers, function(el, idx) {
218 var x = [];
219 var y = [];
220 for (var j=0; j<tsv.length; j++) {
221 x.push(j);
222 y.push(parseFloat(tsv[j][idx].replace(",", ".")));
223 }
224 traces.push({ x: x, y: y, type: "scatter", name: el, line: { width: 1, shape: "spline" } });
225 });
226 var sqlite = Plotly.newPlot("sqlite-benchmarks", traces, { legend: {"orientation": "h"}, height: 400, margin: { l: 50, r: 0, b: 20, t: 30, pad: 0 }, yaxis: { title: "execution time in seconds", titlefont: { size: 12 } } });
227 } else { }
228 };
229 request.onerror = function() { };
230 request.send(null);
231})();
232</script><h2 id=can-storage-be-mounted-on-multiple-machines-at-the-same-time-and-be-writable>Can storage be mounted on multiple machines at the same time and be writable?</h2><p>Well, this one didn't take long to test. And the answer is <strong>YES</strong>. I mounted
233space on both machines and measured same performance on both machines. But
234because file is downloaded before write and then uploaded on complete there
235could potentially be problems is another process is trying to access the same
236file.<h2 id=observations-and-conslusion>Observations and conslusion</h2><p>Using Spaces in this way makes it easier to access and manage files. But besides
237that you would need to write additional code to make this one play nice with you
238applications.<p>Nevertheless, this was extremely simple to setup and use and this is just
239another excellent product in DigitalOcean product line. I found this exercise
240very valuable and am thinking about implementing some sort of mechanism for
241SQLite, so data can be stored on Spaces and accessed by many VM's. For a project
242where data doesn't need to be accessible in real-time and can have couple of
243minutes old data this would be very interesting. If any of you find this
244proposal interesting please write in a comment box below or shoot me an email
245and I will keep you posted.</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
246a lock on a Linux NFS server, which turned
247out to be specific to NFS v3 (which I really should have seen coming,
248since it involved NLM and lockd). Finding the NFS v4 client that
249owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
250and Bradley Kuhn, are interacting on the OSI's license-discuss
251list where the're doing
252bad computer history and insisting that a guy Larry Rosen
253coincidentally interviewed for a book years ago is clearly the origin of
254somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
255i2c, plan9
256Another month, another file system.
257Well, if you can’t fix it in software, fix it in hardware (looking at
258you, bme680, we’re not
259done yet). The show must go on, as they say, and I would like my
260experiments to go on.
261So a “new” addition to the environmental sensor family connected to
262the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
263this mortal coil, we are endowed with self-awareness, agency, and free will.
264Each of the 8 billion members of this human race represents a unique person, a
265unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
266My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
2671.0 has been released:
268wifi_da-1.0.sit
269(StuffIt 3 archive)
270SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
271This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
272classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
273In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
274Design Goals
275I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
276at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
277catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
278specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
279 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
280 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/using-goaccess-with-nginx-to-replace-google-analytics.html b/public/using-goaccess-with-nginx-to-replace-google-analytics.html
deleted file mode 100755
index 08ceb9d..0000000
--- a/public/using-goaccess-with-nginx-to-replace-google-analytics.html
+++ /dev/null
@@ -1,129 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Using GoAccess with Nginx to replace Google Analytics</title><meta name=description content="IntroductionI know!"><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Using GoAccess with Nginx to replace Google Analytics</h1><p><cap>post</cap>, Jan 25, 2021 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><h2 id=introduction>Introduction</h2><p>I know! You cannot simply replace Google Analytics with parsing access logs and
10displaying a couple of charts. But to be honest, I actually never used Google
11Analytics to the fullest extent and was usually interested in seeing page hits
12and which pages were visited most often.<p>I recently moved my blog from Firebase to a VPS and also decided to remove
13Google Analytics tracking code from the site since its quite malicious and
14tracks users across other pages also and is creating a profile of a user, and
15I've had it. But I also need some insight of what is happening on a server and
16which content is being read the most etc.<p>I have looked at many existing solutions like:<ul><li><a href=https://umami.is/>Umami</a><li><a href=https://github.com/sheshbabu/freshlytics>Freshlytics</a><li><a href=https://matomo.org/>Matomo</a></ul><p>But the more I looked at them the more I noticed that I am replacing one evil
17with another one. Don't get me wrong. Some of these solutions are absolutely
18fantastic but would require installation of databases and something like PHP or
19Node. And I was not ready to put those things on my fresh server. Also having
20Docker installed is out of the question.<h2 id=opting-for-log-parsing>Opting for log parsing</h2><p>So, I defaulted to parsing already existing logs and generating HTML reports
21from this data.<p>I found this amazing software <a href=https://goaccess.io/>GoAccess</a> which provides
22all the functionalities I need, and it's a single binary. Written in Go.<p>GoAccess can be used in two different modes.<figure><img src=/posts/goaccess/goaccess-dash-term.png alt="GoAccess Terminal"></figure><p><em>Running in a terminal</em><figure><img src=/posts/goaccess/goaccess-dash-html.png alt="GoAccess HTML"></figure><p><em>Running in a browser</em><p>I, however, need this to run in a browser. So, the second option is the way to
23go. The Idea is to periodically run cronjob and export this report into a folder
24that gets then server by Nginx behind a Basic authentication.<h2 id=getting-nginx-ready>Getting Nginx ready</h2><p>I choose Ubuntu on <a href=https://www.digitalocean.com/>DigitalOcean</a>. First I
25installed <a href=https://nginx.org/en/>Nginx</a>, and
26<a href=https://letsencrypt.org/getting-started/>Letsencrypt</a> certbot and all the
27necessary dependencies.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># log in as root user</span>
28</span></span><span style=display:flex><span>sudo su -
29</span></span><span style=display:flex><span>
30</span></span><span style=display:flex><span><span style=color:green># first let&#39;s update the system</span>
31</span></span><span style=display:flex><span>apt update &amp;&amp; apt upgrade -y
32</span></span><span style=display:flex><span>
33</span></span><span style=display:flex><span><span style=color:green># let&#39;s install</span>
34</span></span><span style=display:flex><span>apt install nginx certbot python3-certbot-nginx apache2-utils
35</span></span></code></pre><p>After all this is installed we can create a new configuration for a statistics.
36Stats will be available at <code>stats.domain.com</code>.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># creates directory where html will be hosted</span>
37</span></span><span style=display:flex><span>mkdir -p /var/www/html/stats.domain.com
38</span></span><span style=display:flex><span>
39</span></span><span style=display:flex><span>cp /etc/nginx/sites-available/default /etc/nginx/sites-available/stats.domain.com
40</span></span><span style=display:flex><span>nano /etc/nginx/sites-available/stats.domain.com
41</span></span></code></pre><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>server</span> {
42</span></span><span style=display:flex><span> <span style=color:#00f>root</span> <span style=color:#a31515>/var/www/html/stats.domain.com</span>;
43</span></span><span style=display:flex><span> <span style=color:#00f>server_name</span> <span style=color:#a31515>stats.domain.com</span>;
44</span></span><span style=display:flex><span>
45</span></span><span style=display:flex><span> <span style=color:#00f>index</span> <span style=color:#a31515>index.html</span>;
46</span></span><span style=display:flex><span> <span style=color:#00f>location</span> <span style=color:#a31515>/</span> {
47</span></span><span style=display:flex><span> <span style=color:#00f>try_files</span> $uri $uri/ =404;
48</span></span><span style=display:flex><span> }
49</span></span><span style=display:flex><span>}
50</span></span></code></pre><p>Now we check if the configuration is ok. We can do this with <code>nginx -t</code>. If all
51is ok, we can restart Nginx with <code>service nginx restart</code>.<p>After all that you should add A record for this domain that points to IP of a
52droplet.<p>Before enabling SSL you should test if DNS records have propagated with <code>curl stats.domain.com</code>.<p>Now, it's time to provision TLS certificate. To achieve this, you execute
53command <code>certbot --nginx</code>. Follow the wizard and when you are asked about
54redirection always choose 2 (always redirect to HTTPS).<p>When this is done you can visit <a href=https://stats.domain.com>https://stats.domain.com</a> and you should get 404
55not found error which is correct.<h2 id=getting-goaccess-ready>Getting GoAccess ready</h2><p>If you are using Debian like system GoAccess should be available in repository.
56Otherwise refer to the official website.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>apt install goaccess
57</span></span></code></pre><p>To enable Geo location we also need one additiona thing.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>cd /var/www/html/stats.stats.com
58</span></span><span style=display:flex><span>wget https://github.com/P3TERX/GeoLite.mmdb/raw/download/GeoLite2-City.mmdb
59</span></span></code></pre><p>Now we create a shell script that will be executed every 10 minutes.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>nano /var/www/html/stats.domain.com/generate-stats.sh
60</span></span></code></pre><p>Contents of this file should look like this.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>#!/bin/sh
61</span></span></span><span style=display:flex><span><span style=color:#00f></span>
62</span></span><span style=display:flex><span>zcat -f /var/log/nginx/access.log* &gt; /var/log/nginx/access-all.log
63</span></span><span style=display:flex><span>
64</span></span><span style=display:flex><span>goaccess <span style=color:#a31515>\
65</span></span></span><span style=display:flex><span><span style=color:#a31515></span> --log-file=/var/log/nginx/access-all.log <span style=color:#a31515>\
66</span></span></span><span style=display:flex><span><span style=color:#a31515></span> --log-format=COMBINED <span style=color:#a31515>\
67</span></span></span><span style=display:flex><span><span style=color:#a31515></span> --exclude-ip=0.0.0.0 <span style=color:#a31515>\
68</span></span></span><span style=display:flex><span><span style=color:#a31515></span> --geoip-database=/var/www/html/stats.domain.com/GeoLite2-City.mmdb <span style=color:#a31515>\
69</span></span></span><span style=display:flex><span><span style=color:#a31515></span> --ignore-crawlers <span style=color:#a31515>\
70</span></span></span><span style=display:flex><span><span style=color:#a31515></span> --real-os <span style=color:#a31515>\
71</span></span></span><span style=display:flex><span><span style=color:#a31515></span> --output=/var/www/html/stats.domain.com/index.html
72</span></span><span style=display:flex><span>
73</span></span><span style=display:flex><span>rm /var/log/nginx/access-all.log
74</span></span></code></pre><p>Because after a while nginx creates multiple files with access logs we use
75<a href=https://linux.die.net/man/1/zcat><code>zcat</code></a> to extract Gziped contents and create
76a file that has all the access logs. After this file is used we delete it.<p>If you want to exclude your home IP's result look at the <code>--exclude-ip</code> option
77in script and instead of <code>0.0.0.0</code> add your own home IP address. You can find
78your home IP by executing <code>curl ifconfig.me</code> from your local machine and NOT
79from the droplet.<p>Test the script by executing <code>sh /var/www/html/stats.domain.com/generate-stats.sh</code> and then checking
80<code>https://stats.domain.com</code>. If you can see stats instead of 404 than you are
81set.<p>It's time to add this script to cron with <code>cron -e</code>.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>*/10 * * * * sh /<span style=color:#00f>var</span>/www/html/stats.domain.com/generate-stats.sh
82</span></span></code></pre><h2 id=securing-with-basic-authentication>Securing with Basic authentication</h2><p>You probably don't want stats to be publicly available, so we should create a
83user and a password for Basic authentication.<p>First we create a password for a user <code>stats</code> with <code>htpasswd -c /etc/nginx/.htpasswd stats</code>.<p>Now we update config file with <code>nano /etc/nginx/sites-available/stats.domain.com</code>. You probably noticed that the
84file looks a bit different from before. This is because <code>certbot</code> added
85additional rules for SSL.<p>Your location portion the config file should now look like. You should add
86<code>auth_basic</code> and <code>auth_basic_user_file</code> lines to the file.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>location</span> <span style=color:#a31515>/</span> {
87</span></span><span style=display:flex><span> <span style=color:#00f>try_files</span> $uri $uri/ =404;
88</span></span><span style=display:flex><span> <span style=color:#00f>auth_basic</span> <span style=color:#a31515>&#34;Private</span> <span style=color:#a31515>Property&#34;</span>;
89</span></span><span style=display:flex><span> <span style=color:#00f>auth_basic_user_file</span> <span style=color:#a31515>/etc/nginx/.htpasswd</span>;
90</span></span><span style=display:flex><span>}
91</span></span></code></pre><p>Test if config is still ok with <code>nginx -t</code> and if it is you can restart Nginx
92with <code>service nginx restart</code>.<p>If you now visit <code>https://stats.domain.com</code> you should be prompted for username
93and password. If not, try reopening your browser.<p>That is all. You now have analytics for your server that gets refreshed every 10
94minutes.</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
95a lock on a Linux NFS server, which turned
96out to be specific to NFS v3 (which I really should have seen coming,
97since it involved NLM and lockd). Finding the NFS v4 client that
98owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
99and Bradley Kuhn, are interacting on the OSI's license-discuss
100list where the're doing
101bad computer history and insisting that a guy Larry Rosen
102coincidentally interviewed for a book years ago is clearly the origin of
103somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
104i2c, plan9
105Another month, another file system.
106Well, if you can’t fix it in software, fix it in hardware (looking at
107you, bme680, we’re not
108done yet). The show must go on, as they say, and I would like my
109experiments to go on.
110So a “new” addition to the environmental sensor family connected to
111the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
112this mortal coil, we are endowed with self-awareness, agency, and free will.
113Each of the 8 billion members of this human race represents a unique person, a
114unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
115My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
1161.0 has been released:
117wifi_da-1.0.sit
118(StuffIt 3 archive)
119SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
120This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
121classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
122In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
123Design Goals
124I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
125at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
126catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
127specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
128 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
129 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/using-sentiment-analysis-for-clickbait-detection-in-rss-feeds.html b/public/using-sentiment-analysis-for-clickbait-detection-in-rss-feeds.html
deleted file mode 100755
index 7a70590..0000000
--- a/public/using-sentiment-analysis-for-clickbait-detection-in-rss-feeds.html
+++ /dev/null
@@ -1,88 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Using sentiment analysis for clickbait detection in RSS feeds</title><meta name=description content="Initial thoughtsOne of the things that interested me for a while now is if major wellestablished news sites use click bait titles to drive additional traffic totheir sites and generate additional impressions."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Using sentiment analysis for clickbait detection in RSS feeds</h1><p><cap>post</cap>, Oct 19, 2019 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><h2 id=initial-thoughts>Initial thoughts</h2><p>One of the things that interested me for a while now is if major well
10established news sites use click bait titles to drive additional traffic to
11their sites and generate additional impressions.<p>Goal is to see how article titles and actual content of article differ from each
12other and see if titles are clickbaited.<h2 id=preparing-and-cleaning-data>Preparing and cleaning data</h2><p>For this example I opted to just use RSS feed from a new website and decided to
13go with <a href=https://www.theguardian.com>The Guardian</a> World news. While this gets
14us limited data (~40) articles and also description (actual content) is trimmed
15this really doesn't reflect the actual article contents.<p>To get better content I could use web scraping and use RSS as link list and
16fetch contents directly from website, but for this simple example this will
17suffice.<p>There are couple of requirements we need to install before we continue:<ul><li><code>pip3 install feedparser</code> (parses RSS feed from url)<li><code>pip3 install vaderSentiment</code> (does sentiment polarity analysis)<li><code>pip3 install matplotlib</code> (plots chart of results)</ul><p>So first we need to fetch RSS data and sanitize HTML content from description.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>import</span> re
18</span></span><span style=display:flex><span><span style=color:#00f>import</span> feedparser
19</span></span><span style=display:flex><span>
20</span></span><span style=display:flex><span>feed_url = <span style=color:#a31515>&#34;https://www.theguardian.com/world/rss&#34;</span>
21</span></span><span style=display:flex><span>feed = feedparser.parse(feed_url)
22</span></span><span style=display:flex><span>
23</span></span><span style=display:flex><span><span style=color:green># sanitize html</span>
24</span></span><span style=display:flex><span><span style=color:#00f>for</span> item <span style=color:#00f>in</span> feed.entries:
25</span></span><span style=display:flex><span> item.description = re.sub(<span style=color:#a31515>&#39;&lt;[^&lt;]+?&gt;&#39;</span>, <span style=color:#a31515>&#39;&#39;</span>, item.description)
26</span></span></code></pre><h2 id=perform-sentiment-analysis>Perform sentiment analysis</h2><p>Since we now have cleaned up data in our <code>feed.entries</code> object we can start with
27performing sentiment analysis.<p>There are many sentiment analysis libraries available that range from rule-based
28sentiment analysis up to machine learning supported analysis. To keep things
29simple I decided to use rule-based analysis library
30<a href=https://github.com/cjhutto/vaderSentiment>vaderSentiment</a> from
31<a href=https://github.com/cjhutto>C.J. Hutto</a>. Really nice library and quite easy to
32use.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>from</span> vaderSentiment.vaderSentiment <span style=color:#00f>import</span> SentimentIntensityAnalyzer
33</span></span><span style=display:flex><span>analyser = SentimentIntensityAnalyzer()
34</span></span><span style=display:flex><span>
35</span></span><span style=display:flex><span>sentiment_results = []
36</span></span><span style=display:flex><span><span style=color:#00f>for</span> item <span style=color:#00f>in</span> feed.entries:
37</span></span><span style=display:flex><span> sentiment_title = analyser.polarity_scores(item.title)
38</span></span><span style=display:flex><span> sentiment_description = analyser.polarity_scores(item.description)
39</span></span><span style=display:flex><span> sentiment_results.append([sentiment_title[<span style=color:#a31515>&#39;compound&#39;</span>], sentiment_description[<span style=color:#a31515>&#39;compound&#39;</span>]])
40</span></span></code></pre><p>Now that we have this data in a shape that is compatible with matplotlib we can
41plot results to see the difference between title and description sentiment of an
42article.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>import</span> matplotlib.pyplot <span style=color:#00f>as</span> plt
43</span></span><span style=display:flex><span>
44</span></span><span style=display:flex><span>plt.rcParams[<span style=color:#a31515>&#39;figure.figsize&#39;</span>] = (15, 3)
45</span></span><span style=display:flex><span>plt.plot(sentiment_results, drawstyle=<span style=color:#a31515>&#39;steps&#39;</span>)
46</span></span><span style=display:flex><span>plt.title(<span style=color:#a31515>&#39;Sentiment analysis relationship between title and description (Guardian World News)&#39;</span>)
47</span></span><span style=display:flex><span>plt.legend([<span style=color:#a31515>&#39;title&#39;</span>, <span style=color:#a31515>&#39;description&#39;</span>])
48</span></span><span style=display:flex><span>plt.show()
49</span></span></code></pre><h2 id=results-and-assets>Results and assets</h2><ol><li>Because of the small sample size further conclusions are impossible to make.<li>Rule-based approach may not be the best way of doing this. By using deep
50learning we would be able to get better insights.<li><strong>Next step would be to</strong> periodically fetch RSS items and store them over a
51longer period of time and then perform analysis again and use either machine
52learning or deep learning on top of it.</ol><figure><img src=/posts/sentiment-analysis/guardian-sa-title-desc-relationship.png alt="Relationship between title and description"></figure><p>Figure above displays difference between title and description sentiment for
53specific RSS feed item. 1 means positive and -1 means negative sentiment.<p><a href=/posts/sentiment-analysis/sentiment-analysis.ipynb>» Download Jupyter Notebook</a><h2 id=going-further>Going further</h2><ul><li><a href=https://github.com/bswiss/news_mood>Twitter Sentiment Analysis by Bryan Schwierzke</a><li><a href=https://github.com/thisandagain/sentiment>AFINN-based sentiment analysis for Node.js by Andrew Sliwinski</a><li><a href=https://github.com/adeshpande3/LSTM-Sentiment-Analysis>Sentiment Analysis with LSTMs in Tensorflow by Adit Deshpande</a><li><a href=https://github.com/abdulfatir/twitter-sentiment-analysis>Sentiment analysis on tweets using Naive Bayes, SVM, CNN, LSTM, etc. by Abdul Fatir</a></ul></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
54a lock on a Linux NFS server, which turned
55out to be specific to NFS v3 (which I really should have seen coming,
56since it involved NLM and lockd). Finding the NFS v4 client that
57owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
58and Bradley Kuhn, are interacting on the OSI's license-discuss
59list where the're doing
60bad computer history and insisting that a guy Larry Rosen
61coincidentally interviewed for a book years ago is clearly the origin of
62somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
63i2c, plan9
64Another month, another file system.
65Well, if you can’t fix it in software, fix it in hardware (looking at
66you, bme680, we’re not
67done yet). The show must go on, as they say, and I would like my
68experiments to go on.
69So a “new” addition to the environmental sensor family connected to
70the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
71this mortal coil, we are endowed with self-awareness, agency, and free will.
72Each of the 8 billion members of this human race represents a unique person, a
73unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
74My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
751.0 has been released:
76wifi_da-1.0.sit
77(StuffIt 3 archive)
78SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
79This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
80classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
81In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
82Design Goals
83I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
84at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
85catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
86specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
87 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
88 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/vault.html b/public/vault.html
deleted file mode 100755
index b9e7b4c..0000000
--- a/public/vault.html
+++ /dev/null
@@ -1,45 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Personal vault</title><meta name=description content="Hi traveler!"><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><div><h1>Personal vault</h1><div><p><strong>Hi traveler!</strong><p>This is a repository of interesting things I have gathered over time and it also
10stores binaries etc of my personal projects.<p>Be kind, this server is bandwidth limited.<p><em>Good luck!</em><hr><ul><li>audiobooks<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/audiobooks/h-g-wells-the-time-machine.ogg>h-g-wells-the-time-machine.ogg</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/audiobooks/philip-francis-nowlan-armageddon-2419-a-d.mp3>philip-francis-nowlan-armageddon-2419-a-d.mp3</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/audiobooks/philip-francis-nowlan-the-airlords-of-han.mp3>philip-francis-nowlan-the-airlords-of-han.mp3</a></ul><li>books<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/books/Civilized%20to%20Death.pdf>Civilized to Death.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/books/Common%20Sense.pdf>Common Sense.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/books/History%20of%20UNIX%20programs,%20sycalls,%20etc.pdf>History of UNIX programs, sycalls, etc.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/books/The%20Maiden%20Who%20Travels%20The%20Planet.pdf>The Maiden Who Travels The Planet.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/books/The%20UNIX-HATERS%20Handbook.pdf>The UNIX-HATERS Handbook.pdf</a></ul><li>essays<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/essays/Bumbleton.pdf>Bumbleton.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/essays/Bumbleton.tex>Bumbleton.tex</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/essays/Lorna%20the%20geologist.pdf>Lorna the geologist.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/essays/Lorna%20the%20geologist.tex>Lorna the geologist.tex</a></ul><li>haphazard<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/acme.pdf>acme.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/antfarm.jpg>antfarm.jpg</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/ape.pdf>ape.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/asciitable.txt>asciitable.txt</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/bakingonagrill.jpg>bakingonagrill.jpg</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/carules.png>carules.png</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/ccompiler.pdf>ccompiler.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/cellularintro.pdf>cellularintro.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/changeresolution.txt>changeresolution.txt</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/cord.h>cord.h</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/dunescrescent.mp4>dunescrescent.mp4</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/elisp.pdf>elisp.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/ewd-manuscripts.epub>ewd-manuscripts.epub</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/ewd-manuscripts.mobi>ewd-manuscripts.mobi</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/ewd831.pdf>ewd831.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/graphca.pdf>graphca.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/inspectorclay.jpg>inspectorclay.jpg</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/kaczynski2.pdf>kaczynski2.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/marionette.gif>marionette.gif</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/mk.pdf>mk.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/ncc-1701-a-engine-noise.ogg>ncc-1701-a-engine-noise.ogg</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/ownership-check-for-c.pdf>ownership-check-for-c.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/p9assembler.pdf>p9assembler.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/p9fileserver.pdf>p9fileserver.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/p9mkfiles.pdf>p9mkfiles.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/p9whub.go>p9whub.go</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/plan9.pdf>plan9.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/plantsystems.jpg>plantsystems.jpg</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/rcshell.pdf>rcshell.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/rule126.png>rule126.png</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/runonqemu.txt>runonqemu.txt</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/shred.go>shred.go</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/simulator.go>simulator.go</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/standard-ml.pdf>standard-ml.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/staticserver.txt>staticserver.txt</a></ul><li>papers<ul><li>affective-computing<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/affective-computing/Theories-Methods-and-Current-Research-on-Emotions.pdf>Theories-Methods-and-Current-Research-on-Emotions.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/affective-computing/affective-computing.pdf>affective-computing.pdf</a></ul><li>api_design<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/api_design/api-design.pdf>api-design.pdf</a></ul><li>artificial-intelligence<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/artificial-intelligence/3-bayesian-network-inference-algorithm.pdf>3-bayesian-network-inference-algorithm.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/artificial-intelligence/efficient-selectivity-and-backup-operators-in-monte-carlo-tree-search.pdf>efficient-selectivity-and-backup-operators-in-monte-carlo-tree-search.pdf</a></ul><li>audio-comp-sci<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/audio-comp-sci/an-ethnographic-and-technological-study-of-breakbeats.pdf>an-ethnographic-and-technological-study-of-breakbeats.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/audio-comp-sci/essentia.pdf>essentia.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/audio-comp-sci/marsyas.pdf>marsyas.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/audio-comp-sci/real-time-chord-detection.pdf>real-time-chord-detection.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/audio-comp-sci/shazam-audio-search-algorithm.pdf>shazam-audio-search-algorithm.pdf</a></ul><li>caching<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/caching/2q-a-low-overhead-high-performance-buffer-management-replacement-algorithm.pdf>2q-a-low-overhead-high-performance-buffer-management-replacement-algorithm.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/caching/a-constant-algorithm-for-implementing-the-lfu-cache-eviction-scheme.pdf>a-constant-algorithm-for-implementing-the-lfu-cache-eviction-scheme.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/caching/a-program-optimization-for-automatic-database-result-caching.pdf>a-program-optimization-for-automatic-database-result-caching.pdf</a></ul><li>comp-sci-fundamentals-and-history<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/comp-sci-fundamentals-and-history/axiomatic-basis-computer-programming.pdf>axiomatic-basis-computer-programming.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/comp-sci-fundamentals-and-history/early-lisp-history-1956-1959-herbert-stoyan-html-rendering.pdf>early-lisp-history-1956-1959-herbert-stoyan-html-rendering.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/comp-sci-fundamentals-and-history/hints-for-computer-system-design.pdf>hints-for-computer-system-design.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/comp-sci-fundamentals-and-history/recursive-functions-of-symbolic-expressions-and-their-computation-by-machine-parti.pdf>recursive-functions-of-symbolic-expressions-and-their-computation-by-machine-parti.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/comp-sci-fundamentals-and-history/story-of-squeak-a-practical-smalltalk-written-in-itself.pdf>story-of-squeak-a-practical-smalltalk-written-in-itself.pdf</a></ul><li>computational-creativity<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/computational-creativity/mexica-a-computer-model-of-a-cognitive-account-of-creativing-writing.pdf>mexica-a-computer-model-of-a-cognitive-account-of-creativing-writing.pdf</a></ul><li>computer-education<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/computer-education/framework-for-automated-generation-of-questions-across-formal-domains.pdf>framework-for-automated-generation-of-questions-across-formal-domains.pdf</a></ul><li>computer-graphics<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/computer-graphics/digital_video_stabilization_and_rolling_shutter_correction_using_gyroscopes.pdf>digital_video_stabilization_and_rolling_shutter_correction_using_gyroscopes.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/computer-graphics/imaging_vector_fields_using_line_integral_convolution.pdf>imaging_vector_fields_using_line_integral_convolution.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/computer-graphics/pushpull++.pdf>pushpull++.pdf</a></ul><li>cryptography<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/cryptography/communication-theory-of-secrecy-systems.pdf>communication-theory-of-secrecy-systems.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/cryptography/ntru-prime.pdf>ntru-prime.pdf</a></ul><li>data-compression<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/data-compression/Error-Controlled_Lossy_Compression_Optimized_for_High_Compression_Ratios_of_Scientific_Datasets.pdf>Error-Controlled_Lossy_Compression_Optimized_for_High_Compression_Ratios_of_Scientific_Datasets.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/data-compression/Significantly_Improving_Lossy_Compression_for_Scientific_Data_Sets_Based_on_Multidimensional_Prediction_and_Error-Controlled_Quantization.pdf>Significantly_Improving_Lossy_Compression_for_Scientific_Data_Sets_Based_on_Multidimensional_Prediction_and_Error-Controlled_Quantization.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/data-compression/data-compression.pdf>data-compression.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/data-compression/fast_error_bounded_Lossy_hpc_data_compression_with_sz.pdf>fast_error_bounded_Lossy_hpc_data_compression_with_sz.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/data-compression/fixed-rate_compressed_floating_point_arrays.pdf>fixed-rate_compressed_floating_point_arrays.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/data-compression/fpc_a_high_speed_compressor_for_double_precision_floating_point_data.pdf>fpc_a_high_speed_compressor_for_double_precision_floating_point_data.pdf</a></ul><li>data-fusion<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/data-fusion/a-new-approach-to-linear-filtering-and-prediction-problems.pdf>a-new-approach-to-linear-filtering-and-prediction-problems.pdf</a></ul><li>data-replication<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/data-replication/a-comprehensive-study-of-convergent-and-communative-replicated-data-types.pdf>a-comprehensive-study-of-convergent-and-communative-replicated-data-types.pdf</a></ul><li>data-science<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/data-science/tidy_data.pdf>tidy_data.pdf</a></ul><li>data-structures<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/data-structures/b-trees-write-optimization.pdf>b-trees-write-optimization.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/data-structures/epidemic-broadcast-trees.pdf>epidemic-broadcast-trees.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/data-structures/ideal-hash-trees.pdf>ideal-hash-trees.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/data-structures/lca-revisited.pdf>lca-revisited.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/data-structures/level-ancestor-simplified.pdf>level-ancestor-simplified.pdf</a></ul><li>datastores<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/datastores/bigtable-a-distributed-storage-system-for-structured-data.pdf>bigtable-a-distributed-storage-system-for-structured-data.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/datastores/database-metatheory--asking-the-big-queries.pdf>database-metatheory--asking-the-big-queries.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/datastores/dynamo-amazons-highly-available-key-value-store.pdf>dynamo-amazons-highly-available-key-value-store.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/datastores/elle-inferring-isolation-anomalies-from-experimental-observations.pdf>elle-inferring-isolation-anomalies-from-experimental-observations.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/datastores/flat-datacenter-storage.pdf>flat-datacenter-storage.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/datastores/freenet-a-distributed-anonymous-information-and-retrieval-system.pdf>freenet-a-distributed-anonymous-information-and-retrieval-system.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/datastores/megastore-providing-scalable-highly-available-storage-for-interactive-services.pdf>megastore-providing-scalable-highly-available-storage-for-interactive-services.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/datastores/network-challenges-of-data-recovery-in-erasure-coded-distributed-storage-systems.pdf>network-challenges-of-data-recovery-in-erasure-coded-distributed-storage-systems.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/datastores/rados-a-scalable-reliable-storage-service-for-petabyte-scale-storage-clusters.pdf>rados-a-scalable-reliable-storage-service-for-petabyte-scale-storage-clusters.pdf</a><li><a href="https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/datastores/spanner-google's-globally-distributed-database.pdf">spanner-google's-globally-distributed-database.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/datastores/spartan-a-distributed-array-framework-with-smart-tiling.pdf>spartan-a-distributed-array-framework-with-smart-tiling.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/datastores/stasis-flexible-transactional-storage.pdf>stasis-flexible-transactional-storage.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/datastores/tao-facebook-distributed-datastore.pdf>tao-facebook-distributed-datastore.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/datastores/the-google-file-system.pdf>the-google-file-system.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/datastores/transactional-storage-for-geo-replicated-systems.pdf>transactional-storage-for-geo-replicated-systems.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/datastores/warp-multi-key-transactions-for-key-value-stores.pdf>warp-multi-key-transactions-for-key-value-stores.pdf</a></ul><li>design<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/design/out-of-the-tar-pit.pdf>out-of-the-tar-pit.pdf</a></ul><li>digital-currency<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/digital-currency/bitcoin.pdf>bitcoin.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/digital-currency/peercoin.pdf>peercoin.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/digital-currency/primecoin.pdf>primecoin.pdf</a></ul><li>distributed-systems<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/a-history-of-the-virtual-synchrony-replication-model.pdf>a-history-of-the-virtual-synchrony-replication-model.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/a-hundred-impossibility-proofs-for-distributed-computing.pdf>a-hundred-impossibility-proofs-for-distributed-computing.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/a-note-on-distributed-computing.pdf>a-note-on-distributed-computing.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/a-response-to-cheriton-and-skeens-criticism-of-causal-and-totally-ordered-communication.pdf>a-response-to-cheriton-and-skeens-criticism-of-causal-and-totally-ordered-communication.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/a-universal-modular-actor-formalism-for-artificial-intelligence.pdf>a-universal-modular-actor-formalism-for-artificial-intelligence.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/a-versatile-scheme-for-routing-highly-variable-traffic-in-service-overlays-and-ip.pdf>a-versatile-scheme-for-routing-highly-variable-traffic-in-service-overlays-and-ip.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/beehive-lookup-performance-for-power-law-query-distributions-in-peer-to-peer-overlays.pdf>beehive-lookup-performance-for-power-law-query-distributions-in-peer-to-peer-overlays.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/brewers-conjecture.pdf>brewers-conjecture.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/byzantine-chain-replication.pdf>byzantine-chain-replication.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/byzantine-fault-tolerant-distributed-commit-protocol.pdf>byzantine-fault-tolerant-distributed-commit-protocol.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/chain-replication-for-supporting-high-throughput-and-availability.pdf>chain-replication-for-supporting-high-throughput-and-availability.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/commodifying-replicated-state-machines-with-openreplica.pdf>commodifying-replicated-state-machines-with-openreplica.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/consensus-in-presence-of-partial-synchrony.pdf>consensus-in-presence-of-partial-synchrony.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/consistent-global-states-of-distributed-systems-fundamental-concepts-and-mechanisms.pdf>consistent-global-states-of-distributed-systems-fundamental-concepts-and-mechanisms.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/consistent-hashing-and-random-trees.pdf>consistent-hashing-and-random-trees.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/copysets-reducing-the-frequency-of-data-loss-in-cloud-storage.pdf>copysets-reducing-the-frequency-of-data-loss-in-cloud-storage.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/dapper-a-large-scale-distributed-tracing-infrastructure.pdf>dapper-a-large-scale-distributed-tracing-infrastructure.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/distributed-snapshots-determining-global-states-of-distributed-systems.pdf>distributed-snapshots-determining-global-states-of-distributed-systems.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/eluding-carnivores-file-sharing-with-strong-anonymity.pdf>eluding-carnivores-file-sharing-with-strong-anonymity.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/end-to-end-arguments-in-system-design.pdf>end-to-end-arguments-in-system-design.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/epidemic-algorithms-for-replicated-database-maintenance.pdf>epidemic-algorithms-for-replicated-database-maintenance.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/harvest-yield-and-scalable-tolerant-systems.pdf>harvest-yield-and-scalable-tolerant-systems.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/herbivore-a-scalable-and-efficient-protocol-for-anonymous.pdf>herbivore-a-scalable-and-efficient-protocol-for-anonymous.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/high-level-specifications--lessons-from-industry.pdf>high-level-specifications--lessons-from-industry.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/how-the-hidden-hand-shapes-the-market-for-software-reliability.pdf>how-the-hidden-hand-shapes-the-market-for-software-reliability.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/implementing-the-omega-failure-detector-in-crash-recovery-failure-model.pdf>implementing-the-omega-failure-detector-in-crash-recovery-failure-model.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/impossibility-of-consensus-with-one-faulty-process.pdf>impossibility-of-consensus-with-one-faulty-process.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/in-search-of-an-understandable-consensus-algorithm.pdf>in-search-of-an-understandable-consensus-algorithm.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/ironFleet-proving-practical-distributed-systems-correct.pdf>ironFleet-proving-practical-distributed-systems-correct.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/join-calculus.pdf>join-calculus.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/kelips-building-an-efficient-and-stable-p2p-dht-through-increased-memory-and-background-overhead.pdf>kelips-building-an-efficient-and-stable-p2p-dht-through-increased-memory-and-background-overhead.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/large-scale-incremental-processing-using-distributed-transactions-and-notifications.pdf>large-scale-incremental-processing-using-distributed-transactions-and-notifications.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/life-beyond-distributed-transactions-an-apostates-opinion.pdf>life-beyond-distributed-transactions-an-apostates-opinion.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/mapreduce-simplified-data-processing-on-large-clusters.pdf>mapreduce-simplified-data-processing-on-large-clusters.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/mesos-a-platform-for-fine-grained-resource-sharing-in-the-data-center.pdf>mesos-a-platform-for-fine-grained-resource-sharing-in-the-data-center.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/oblivious-routing-of-highly-variable-traffic-in-service-overlays-and-ip-backbones.pdf>oblivious-routing-of-highly-variable-traffic-in-service-overlays-and-ip-backbones.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/on-proof-and-progress-in-mathematics.pdf>on-proof-and-progress-in-mathematics.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/p5-a-protocal-for-scalable-anonymous-communication.pdf>p5-a-protocal-for-scalable-anonymous-communication.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/pastry-scalable-decentralized-object-location-and-routing-for-large-scale-peer-to-peer-systems.pdf>pastry-scalable-decentralized-object-location-and-routing-for-large-scale-peer-to-peer-systems.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/paxos-made-moderately-complex.pdf>paxos-made-moderately-complex.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/paxos-made-simple.pdf>paxos-made-simple.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/self-stabilizing-systems-in-spite-of-distributed-control.pdf>self-stabilizing-systems-in-spite-of-distributed-control.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/sift-design-and-analysis-of-a-fault-tolerant-computer-for-aircraft-contro.pdf>sift-design-and-analysis-of-a-fault-tolerant-computer-for-aircraft-contro.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/signal-&-collect-graph-algorithms-for-the-(semantic)-web.pdf>signal-&-collect-graph-algorithms-for-the-(semantic)-web.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/simple-testing-can-prevent-most-critical-failures.pdf>simple-testing-can-prevent-most-critical-failures.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/solution-of-a-problem-in-concurrent-programming-control.pdf>solution-of-a-problem-in-concurrent-programming-control.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/sparse-partitions.pdf>sparse-partitions.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/stronger-semantics-for-low-latency-geo-replicated-storage.pdf>stronger-semantics-for-low-latency-geo-replicated-storage.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/the-akamai-network.pdf>the-akamai-network.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/the-chubby-lock-service-for-loosely-coupled-distributed-systems.pdf>the-chubby-lock-service-for-loosely-coupled-distributed-systems.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/the-dining-cryptographers-problem.pdf>the-dining-cryptographers-problem.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/tiered-replication-a-cost-effective-alternative-to-full-cluster-geo-replication.pdf>tiered-replication-a-cost-effective-alternative-to-full-cluster-geo-replication.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/tor-the-second-generation-onion-router.pdf>tor-the-second-generation-onion-router.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/towards-a-cloud-computing-research-agenda.pdf>towards-a-cloud-computing-research-agenda.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/understanding-the-limitations-of-causally-and-totally-ordered-communication.pdf>understanding-the-limitations-of-causally-and-totally-ordered-communication.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/viewing-control-structures-as-patterns-of-passing-messages.pdf>viewing-control-structures-as-patterns-of-passing-messages.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/zab-high-performance-broadcast-for-primary-backup-systems.pdf>zab-high-performance-broadcast-for-primary-backup-systems.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/distributed-systems/zookeeper-wait-free-coordination-for-internet-scale-systems.pdf>zookeeper-wait-free-coordination-for-internet-scale-systems.pdf</a></ul><li>economics<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/economics/online-ad-auctions.pdf>online-ad-auctions.pdf</a></ul><li>experimental-algorithmics<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/experimental-algorithmics/a-theoreticians-guide-to-the-experimental-analysis-of-algorithms.pdf>a-theoreticians-guide-to-the-experimental-analysis-of-algorithms.pdf</a></ul><li>faults-and-verification<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/faults-and-verification/epitaxis-a-system-for-syntactic-and-semantic-software-queries.pdf>epitaxis-a-system-for-syntactic-and-semantic-software-queries.pdf</a></ul><li>gamification<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/gamification/gamification-in-education-what-how-why-bother.pdf>gamification-in-education-what-how-why-bother.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/gamification/why-students-engage-in-gaming-the-system-behavior-in-interactive-learning-environments.pdf>why-students-engage-in-gaming-the-system-behavior-in-interactive-learning-environments.pdf</a></ul><li>garbage-collection<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/garbage-collection/incremental_mature_garbage_collection_using_the_train_algorithm.pdf>incremental_mature_garbage_collection_using_the_train_algorithm.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/garbage-collection/parallel_generational_copying_garbage_collection_with_a_block_structured_heap.pdf>parallel_generational_copying_garbage_collection_with_a_block_structured_heap.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/garbage-collection/the_lisp_ii_garbage_collector.pdf>the_lisp_ii_garbage_collector.pdf</a></ul><li>information-retrieval<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/information-retrieval/authoritative-sources-in-a-hyperlinked-environment.pdf>authoritative-sources-in-a-hyperlinked-environment.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/information-retrieval/graph_of_word_and_tw_idf.pdf>graph_of_word_and_tw_idf.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/information-retrieval/okapi-at-trec3.pdf>okapi-at-trec3.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/information-retrieval/the-pagerank-citation-ranking-bringing-order-to-the-web.pdf>the-pagerank-citation-ranking-bringing-order-to-the-web.pdf</a></ul><li>information-theory<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/information-theory/a-mathematical-theory-of-communication-1948.pdf>a-mathematical-theory-of-communication-1948.pdf</a></ul><li>languages-paradigms<ul><li>functional_programming<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-paradigms/functional_programming/concatenative-programming-an-overlooked-paradigm.pdf>concatenative-programming-an-overlooked-paradigm.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-paradigms/functional_programming/equal-rights-for-functional-objects.pdf>equal-rights-for-functional-objects.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-paradigms/functional_programming/functional-programming-with-bananas-lenses-envelops-and-barbed-wire.pdf>functional-programming-with-bananas-lenses-envelops-and-barbed-wire.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-paradigms/functional_programming/optimal-purely-functional-priority-queues.pdf>optimal-purely-functional-priority-queues.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-paradigms/functional_programming/organizing-programs-without-classes.pdf>organizing-programs-without-classes.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-paradigms/functional_programming/purely-functional-data-structures.pdf>purely-functional-data-structures.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-paradigms/functional_programming/why-functional-programming-matters.pdf>why-functional-programming-matters.pdf</a></ul><li>functional_reactive_programming<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-paradigms/functional_reactive_programming/a-survey-of-functional-reactive-programming.pdf>a-survey-of-functional-reactive-programming.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-paradigms/functional_reactive_programming/deprecating-the%20observer-pattern.pdf>deprecating-the observer-pattern.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-paradigms/functional_reactive_programming/frp-in-plt-scheme.pdf>frp-in-plt-scheme.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-paradigms/functional_reactive_programming/functional-reactive-animation.pdf>functional-reactive-animation.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-paradigms/functional_reactive_programming/ray-integrating-rx-and-async-for-direct-style-reactive-streams.pdf>ray-integrating-rx-and-async-for-direct-style-reactive-streams.pdf</a></ul><li>new_paradigms<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-paradigms/new_paradigms/cognitive-computing-programming-paradigm-corelet-language.pdf>cognitive-computing-programming-paradigm-corelet-language.pdf</a></ul></ul><li>languages-theory<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-theory/composable-and-compilable-macros-you-want-it-when.pdf>composable-and-compilable-macros-you-want-it-when.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-theory/fundamental-concepts-in-programming-languages.pdf>fundamental-concepts-in-programming-languages.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-theory/on-understanding-types-data-abstraction-polymorphism.pdf>on-understanding-types-data-abstraction-polymorphism.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-theory/predicate-dispatching.pdf>predicate-dispatching.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-theory/principal-type-schemes-for-functional-programs.pdf>principal-type-schemes-for-functional-programs.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-theory/programming-languages-application-and-interpretation.pdf>programming-languages-application-and-interpretation.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-theory/propositions-as-types.pdf>propositions-as-types.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-theory/the-derivative-of-a-regular-type-one-hole-contexts.pdf>the-derivative-of-a-regular-type-one-hole-contexts.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages-theory/theory-in-programming-practice.pdf>theory-in-programming-practice.pdf</a></ul><li>languages<ul><li>clojure<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages/clojure/a-practical-optional-type-system-for-clojure.pdf>a-practical-optional-type-system-for-clojure.pdf</a></ul><li>haskell<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages/haskell/a-poor-mans-concurrency-monad.pdf>a-poor-mans-concurrency-monad.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages/haskell/making-a-fast-curry-push-enter-versus-eval-apply-for-higher-order-languages.pdf>making-a-fast-curry-push-enter-versus-eval-apply-for-higher-order-languages.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages/haskell/tackling-the-awkward-squad-monadic-input-output-concurrency-exceptions-and-foreign-language-calls-in-haskell.pdf>tackling-the-awkward-squad-monadic-input-output-concurrency-exceptions-and-foreign-language-calls-in-haskell.pdf</a></ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages/scp91-felleisen.ps.gz>scp91-felleisen.ps.gz</a><li>smalltalk<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages/smalltalk/Design-Principles-Behind-Smalltalk.pdf>Design-Principles-Behind-Smalltalk.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/languages/smalltalk/The-Early-History-Of-Smalltalk.pdf>The-Early-History-Of-Smalltalk.pdf</a></ul></ul><li>logic-and-programming<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/logic-and-programming/event-calculus.txt>event-calculus.txt</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/logic-and-programming/on-the-meanings-of-the-logical-constants.pdf>on-the-meanings-of-the-logical-constants.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/logic-and-programming/representing-game-dialogue-as-expressions-in-first-order-logic.pdf>representing-game-dialogue-as-expressions-in-first-order-logic.pdf</a></ul><li>machine-learning<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/machine-learning/General-self-similarity--an-overview.pdf>General-self-similarity--an-overview.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/machine-learning/Understanding-Deep-Convolutional-Networks.pdf>Understanding-Deep-Convolutional-Networks.pdf</a><li>dimensionality_reduction<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/machine-learning/dimensionality_reduction/a-sparse-johnson-lindenstrauss-transform.pdf>a-sparse-johnson-lindenstrauss-transform.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/machine-learning/dimensionality_reduction/toward-a-unified-theory-of-sparse-dimensionality-reduction-in-euclidean-space.pdf>toward-a-unified-theory-of-sparse-dimensionality-reduction-in-euclidean-space.pdf</a></ul></ul><li>mathematics<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/mathematics/from-dominoes-to-hexagons.pdf>from-dominoes-to-hexagons.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/mathematics/graph-isomorphism-and-representation-theory.pdf>graph-isomorphism-and-representation-theory.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/mathematics/intro-to-tropical-algebraic-geometry.pdf>intro-to-tropical-algebraic-geometry.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/mathematics/tilings.pdf>tilings.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/mathematics/transcendence-of-pi.pdf>transcendence-of-pi.pdf</a></ul><li>memory-management<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/memory-management/making-lockless-synchronization-fast.pdf>making-lockless-synchronization-fast.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/memory-management/scatteralloc-massively-parallel-dynamic-memory-allocation-for-the-gpu.pdf>scatteralloc-massively-parallel-dynamic-memory-allocation-for-the-gpu.pdf</a></ul><li>non-blocking-algorithms<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/non-blocking-algorithms/a-wait-free-queue-as-fast-as-fetch-and-add.pdf>a-wait-free-queue-as-fast-as-fetch-and-add.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/non-blocking-algorithms/a-wait-free-stack.pdf>a-wait-free-stack.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/non-blocking-algorithms/efficient-lock-free-b+trees.pdf>efficient-lock-free-b+trees.pdf</a></ul><li>operating-systems<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/operating-systems/jails-confining-the-omnipotent-root..pdf>jails-confining-the-omnipotent-root..pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/operating-systems/solaris-zones-operating-system-support-for-consolidating-commercial-workloads.pdf>solaris-zones-operating-system-support-for-consolidating-commercial-workloads.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/operating-systems/therac.pdf>therac.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/operating-systems/unix-time-sharing-system.pdf>unix-time-sharing-system.pdf</a></ul><li>pattern-matching<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/pattern-matching/aho-corasick-string-matching.pdf>aho-corasick-string-matching.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/pattern-matching/compiling-pattern-matching-to-good-decision-trees.pdf>compiling-pattern-matching-to-good-decision-trees.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/pattern-matching/extensible-pattern-matching-extensible-language.pdf>extensible-pattern-matching-extensible-language.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/pattern-matching/warnings-for-pattern-matching.pdf>warnings-for-pattern-matching.pdf</a></ul><li>physics<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/physics/buridans-principle.pdf>buridans-principle.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/physics/on-the-attraction-of-two-perfectly-conducting-plates.pdf>on-the-attraction-of-two-perfectly-conducting-plates.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/physics/on-the-electrodynamics-of-moving-bodies.pdf>on-the-electrodynamics-of-moving-bodies.pdf</a></ul><li>processes<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/processes/communicating-sequential-processes-paper.pdf>communicating-sequential-processes-paper.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/processes/communicating-sequential-processes.pdf>communicating-sequential-processes.pdf</a></ul><li>quantum-computing<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/quantum-computing/advance_in_quantum_machine_learning.pdf>advance_in_quantum_machine_learning.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/quantum-computing/grovers_algorithm.pdf>grovers_algorithm.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/quantum-computing/shors_algorithm.pdf>shors_algorithm.pdf</a></ul><li>security<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/security/ids-evasion-ptacek-newsham.pdf>ids-evasion-ptacek-newsham.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/security/macaroons-cookies-with-contextual-caveats.pdf>macaroons-cookies-with-contextual-caveats.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/security/sok-eternal-war-in-memory.pdf>sok-eternal-war-in-memory.pdf</a></ul><li>software-engineering-orgs<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/software-engineering-orgs/common-ground-and-coordination-in-joint-activity.pdf>common-ground-and-coordination-in-joint-activity.pdf</a></ul><li>sports-analytics<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/sports-analytics/2014-ssac-pointwise-predicting-points-and-valuing-decisions-in-real-time.pdf>2014-ssac-pointwise-predicting-points-and-valuing-decisions-in-real-time.pdf</a></ul><li>sublinear-algorithms<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/sublinear-algorithms/1985-Flajolet-Probabilistic-counting.pdf>1985-Flajolet-Probabilistic-counting.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/sublinear-algorithms/An-Elementary-Proof-of-a-Theorem-of-Johnson-and-Lindenstrauss.pdf>An-Elementary-Proof-of-a-Theorem-of-Johnson-and-Lindenstrauss.pdf</a></ul><li>systematic-review<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/systematic-review/systematic-review-in-software-engineering.pdf>systematic-review-in-software-engineering.pdf</a></ul><li>time-series<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/time-series/operators-on-inhomogeneous-time-series.pdf>operators-on-inhomogeneous-time-series.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/time-series/ts-asap.pdf>ts-asap.pdf</a></ul><li>virtual-machines<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/virtual-machines/kvm-linux-virtual-machines-monitor.pdf>kvm-linux-virtual-machines-monitor.pdf</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/papers/virtual-machines/live-migration-of-virtual-machines.pdf>live-migration-of-virtual-machines.pdf</a></ul></ul><li>public-projects<ul><li>alternator<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/alternator/alternator-1.0.0-linux-amd64.md>alternator-1.0.0-linux-amd64.md</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/alternator/alternator-1.0.0-linux-amd64.tar.gz>alternator-1.0.0-linux-amd64.tar.gz</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/alternator/alternator-1.0.0-linux-arm64.md>alternator-1.0.0-linux-arm64.md</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/alternator/alternator-1.0.0-linux-arm64.tar.gz>alternator-1.0.0-linux-arm64.tar.gz</a></ul><li>errand<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/errand/errand-0.1.0-darwin-arm64.md5>errand-0.1.0-darwin-arm64.md5</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/errand/errand-0.1.0-darwin-arm64.tar.gz>errand-0.1.0-darwin-arm64.tar.gz</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/errand/errand-0.1.0-linux-amd64.md5>errand-0.1.0-linux-amd64.md5</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/errand/errand-0.1.0-linux-amd64.tar.gz>errand-0.1.0-linux-amd64.tar.gz</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/errand/errand-0.1.0-linux-arm64.md5>errand-0.1.0-linux-arm64.md5</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/errand/errand-0.1.0-linux-arm64.tar.gz>errand-0.1.0-linux-arm64.tar.gz</a></ul><li>jbmafp<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/jbmafp/jbmafp-v0.1.tar.xz>jbmafp-v0.1.tar.xz</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/jbmafp/jbmafp-v0.1.zip>jbmafp-v0.1.zip</a></ul><li>simpleapi<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/simpleapi/sapi-0.1.0-darwin-amd64.md5>sapi-0.1.0-darwin-amd64.md5</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/simpleapi/sapi-0.1.0-darwin-amd64.tar.gz>sapi-0.1.0-darwin-amd64.tar.gz</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/simpleapi/sapi-0.1.0-darwin-arm64.md5>sapi-0.1.0-darwin-arm64.md5</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/simpleapi/sapi-0.1.0-darwin-arm64.tar.gz>sapi-0.1.0-darwin-arm64.tar.gz</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/simpleapi/sapi-0.1.0-linux-amd64.md5>sapi-0.1.0-linux-amd64.md5</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/simpleapi/sapi-0.1.0-linux-amd64.tar.gz>sapi-0.1.0-linux-amd64.tar.gz</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/simpleapi/sapi-0.1.0-linux-arm64.md5>sapi-0.1.0-linux-arm64.md5</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/public-projects/simpleapi/sapi-0.1.0-linux-arm64.tar.gz>sapi-0.1.0-linux-arm64.tar.gz</a></ul></ul><li>video<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/Building%20the%20Simplest%20Possible%20Linux%20System%20-%20Rob%20Landley.webm>Building the Simplest Possible Linux System - Rob Landley.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/Go%20webserver,%20HTMX%20Integration,%20Template%20Fragments.webm>Go webserver, HTMX Integration, Template Fragments.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/Toybox%20vs%20BusyBox%20-%20Rob%20Landley,%20hobbyist.webm>Toybox vs BusyBox - Rob Landley, hobbyist.webm</a><li>plan9-videos<ul><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/9Front%20Basic%20Install.webm>9Front Basic Install.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/9Front%20on%20the%20Desktop;%20IRC,%20web,%20and%20video%20in%20plan9%20terminals.webm>9Front on the Desktop; IRC, web, and video in plan9 terminals.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/A%20Quick%20Intro%20to%20C%20Programming,%20for%20Plan%209%20and%209%20Front.mp4>A Quick Intro to C Programming, for Plan 9 and 9 Front.mp4</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Adding%20to%20the%20Grid;%20Listening%20to%20CO2%20Levels%20and%20Speaking%20to%20Light%20Bulbs%20with%20Plan9.webm>Adding to the Grid; Listening to CO2 Levels and Speaking to Light Bulbs with Plan9.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Alternative%209Front%20Partition%20Schemes.webm>Alternative 9Front Partition Schemes.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Auth%20&%20File%20Server%20Setup,%20using%209Front.mp4>Auth & File Server Setup, using 9Front.mp4</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Bonus%20Pipe%20Video;%20funny%20things%20you%20can%20do%20locally%20with%20named%20pipes%20in%209Front.webm>Bonus Pipe Video; funny things you can do locally with named pipes in 9Front.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Booting%20a%20Terminal%20off%20a%20USB%20drive,%20New%20User%20set%20up,%20and%20Disaster%20recover,%20for%20Plan9%20using%209Front.webm>Booting a Terminal off a USB drive, New User set up, and Disaster recover, for Plan9 using 9Front.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Building%20a%20Better%20Grid%20with%209Front.mp4>Building a Better Grid with 9Front.mp4</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Consorting%20With%20Daemons!%20Running%209Front%20in%20bhyve%20on%20FreeBSD.webm>Consorting With Daemons! Running 9Front in bhyve on FreeBSD.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Doing%20Custom%20Work.%20Basic%20Configuration%20Files%20in%20Plan9%20%E2%A7%B8%209Front.webm>Doing Custom Work. Basic Configuration Files in Plan9 ⧸ 9Front.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Drivers%20Part%202;%20Doing%20some%20initial%20reads%20and%20writes%20to%20a%20USB%20device%20in%209Front.mp4>Drivers Part 2; Doing some initial reads and writes to a USB device in 9Front.mp4</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Getting%209%20Front%20to%20run%20on%20an%20Arm%20SBC,%20featuring%20the%20Pine%20A64%20LTS.webm>Getting 9 Front to run on an Arm SBC, featuring the Pine A64 LTS.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Getting%20Plan9%20and%20Linux%20to%20play%20(audio)%20together%20&%20Bonus%20Rant!.webm>Getting Plan9 and Linux to play (audio) together & Bonus Rant!.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Grave%20Robbing%20my%20way%20out%20of%20The%20Global%20Chip%20Shortage,%20feat;%209Front.webm>Grave Robbing my way out of The Global Chip Shortage, feat; 9Front.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Hot%20Time%20with%209Front%20on%20Arm.webm>Hot Time with 9Front on Arm.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Intro%20to%20USB%20drivers%20for%20Plan9%20and%209Front.webm>Intro to USB drivers for Plan9 and 9Front.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Introduction%20to%20Grids;%20or,%20what%20can%20I%20do%20with%20all%20these%20Plan9%20machines?.webm>Introduction to Grids; or, what can I do with all these Plan9 machines?.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Introduction%20to%20getting%20around.%20The%20User%20Interface%20of%20Plan9%20%E2%A7%B8%209Front.webm>Introduction to getting around. The User Interface of Plan9 ⧸ 9Front.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/MIPS%20Rides%20Again;%20my%20presentation%20for%20the%20International%20Workshop%20on%20Plan%209.webm>MIPS Rides Again; my presentation for the International Workshop on Plan 9.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Making%20New%20Namespaces%20in%20Plan9%20with%20auth%E2%A7%B8newns.webm>Making New Namespaces in Plan9 with auth⧸newns.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Making%20Your%20Server%20Do%20More;%20Hosting%20services%20on%20your%20Plan9%20server.webm>Making Your Server Do More; Hosting services on your Plan9 server.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Making%20a%20sythetic%20filesystem:%20making%20fake%20files%20for%20fun%20and%20profit%20on%20Plan9%20and%209Front.webm>Making a sythetic filesystem: making fake files for fun and profit on Plan9 and 9Front.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Meanwhile,%20In%20the%20Laboratory;%20finishing%20house%20chores%20and%20starting%20computer%20projects.webm>Meanwhile, In the Laboratory; finishing house chores and starting computer projects.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/PXE%20Boot%209Front.webm>PXE Boot 9Front.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Plan9%20File%20Server,%20pt.%201;%20Installing%209Front.mp4>Plan9 File Server, pt. 1; Installing 9Front.mp4</a><li><a href="https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Plan9's%20rio,%20and%20how%20to%20modify%20it.webm">Plan9's rio, and how to modify it.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Plan9,%20gpsfs%20&%20Raspberry%20Pi;%20Using%209Front%20to%20get%20the%20most%20out%20of%20Soviet%20Technology.mp4>Plan9, gpsfs & Raspberry Pi; Using 9Front to get the most out of Soviet Technology.mp4</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Planning%20a%20Plan9%20Ethernet%20switch%20filesystem,%20feat:%20a%20stream%20of%20consciousness.webm>Planning a Plan9 Ethernet switch filesystem, feat: a stream of consciousness.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Raspberry%20Pi%20Plan9%20Server;%20Using%20a%20Pi%20and%209Front%20to%20serve%20up%20sensor%20data.webm>Raspberry Pi Plan9 Server; Using a Pi and 9Front to serve up sensor data.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Raspberry%20Pi%20on%20your%20Plan9%20Network,%20featuring%209Front%20on%20a%20Pi%203B.webm>Raspberry Pi on your Plan9 Network, featuring 9Front on a Pi 3B.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Reading%20from%20a%20USB%20Device%20with%209Front.webm>Reading from a USB Device with 9Front.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Show%20and%20Tell;%20some%20stuff%20to%20throw%209Front%20at.webm>Show and Tell; some stuff to throw 9Front at.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Some%20Useful%20Tools%20in%20Plan9.%20Mouse%20Chording,%20VT,%20and%20Acme.mp4>Some Useful Tools in Plan9. Mouse Chording, VT, and Acme.mp4</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Still%20poking%20around%20a%20USB%20Device%20with%209Front.webm>Still poking around a USB Device with 9Front.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Using%20Bridges%20and%20Network%20Aliasing%20in%20Plan9%20&%209Front.webm>Using Bridges and Network Aliasing in Plan9 & 9Front.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Using%20Drawterm%20to%20access%20your%20Plan9%20server.webm>Using Drawterm to access your Plan9 server.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Using%20Listen1%20on%20Plan9%20to%20Debug%20Networking%20Code.webm>Using Listen1 on Plan9 to Debug Networking Code.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Using%20vmx;%20Running%20Linux%20Mint%20in%20a%20virtual%20machine%20on%209Front.webm>Using vmx; Running Linux Mint in a virtual machine on 9Front.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/When%20Tech%20Bubbles%20Burst%20&%20Other%20Strange%20Tales.webm>When Tech Bubbles Burst & Other Strange Tales.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Where%20to%20Find%20Kernel%20Code%20in%209front%20and%20Plan9.webm>Where to Find Kernel Code in 9front and Plan9.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Why%20is%20Plan9%20like%20this?%20An%20intermediate%20guide%20to%20namespaces%20with%20rio.webm>Why is Plan9 like this? An intermediate guide to namespaces with rio.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Why%20is%20Plan9%20like%20this?%20An%20introduction%20to%20Namespaces.webm>Why is Plan9 like this? An introduction to Namespaces.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Working%20with%20Kernels;%20Modifying%20and%20Installing%20a%20Kernel%20in%209Front.mp4>Working with Kernels; Modifying and Installing a Kernel in 9Front.mp4</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/Writing%20Plan9%20Kernels;%209Front%20on%20the%20MT7688.webm>Writing Plan9 Kernels; 9Front on the MT7688.webm</a><li><a href=https://mitjafelicijan.fra1.digitaloceanspaces.com/video/plan9-videos/wizfs:%20A%209Front%20file%20server%20for%20Wiz%20light%20bulbs.webm>wizfs: A 9Front file server for Wiz light bulbs.webm</a></ul></ul></ul></div></div></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
11a lock on a Linux NFS server, which turned
12out to be specific to NFS v3 (which I really should have seen coming,
13since it involved NLM and lockd). Finding the NFS v4 client that
14owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
15and Bradley Kuhn, are interacting on the OSI's license-discuss
16list where the're doing
17bad computer history and insisting that a guy Larry Rosen
18coincidentally interviewed for a book years ago is clearly the origin of
19somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
20i2c, plan9
21Another month, another file system.
22Well, if you can’t fix it in software, fix it in hardware (looking at
23you, bme680, we’re not
24done yet). The show must go on, as they say, and I would like my
25experiments to go on.
26So a “new” addition to the environmental sensor family connected to
27the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
28this mortal coil, we are endowed with self-awareness, agency, and free will.
29Each of the 8 billion members of this human race represents a unique person, a
30unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
31My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
321.0 has been released:
33wifi_da-1.0.sit
34(StuffIt 3 archive)
35SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
36This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
37classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
38In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
39Design Goals
40I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
41at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
42catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
43specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
44 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
45 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/wap-mobile-web-before-the-web.html b/public/wap-mobile-web-before-the-web.html
deleted file mode 100755
index e4030a2..0000000
--- a/public/wap-mobile-web-before-the-web.html
+++ /dev/null
@@ -1,153 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Wireless Application Protocol and the mobile web before the web</title><meta name=description content="A little stroll down the history laneAbout two weeks ago, I watched this outstanding documentary on YouTubeSpringboard: the secret history of the first realsmartphone about the history ofsmartphones and phones in general."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Wireless Application Protocol and the mobile web before the web</h1><p><cap>post</cap>, Dec 30, 2021 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><h2 id=a-little-stroll-down-the-history-lane>A little stroll down the history lane</h2><p>About two weeks ago, I watched this outstanding documentary on YouTube
10<a href="https://www.youtube.com/watch?v=b9_Vh9h3Ohw">Springboard: the secret history of the first real
11smartphone</a> about the history of
12smartphones and phones in general. It brought back so many memories. I never had
13an actual smartphone before the Android. The closest to smartphone was <a href=https://www.gsmarena.com/sony_ericsson_p1-1982.php>Sony
14Ericsson P1</a>. A fantastic
15phone and I broke it in Prague after a party and that was one of those rare
16occasions where I was actually mad at myself. But nevertheless, after that
17phone, the next one was an Android one.<p>Before that, I only owned normal phones from Nokia and Siemens etc. Nothing
18special, actually. These are the phones we are talking about. Before 2007.
19Apple and Android phones didn't exist yet.<p>These phones were rocking:<ul><li>No selfie cameras.<li>~2 inch displays.<li>~120 MHz beast CPU's.<li>144p main cameras.<li>But they had a headphone jack.</ul><p>Let's take a look at these beauties.<figure><img src=/posts/wap/phones.gif alt="Old phones"></figure><h2 id=wap---wireless-application-protocol>WAP - Wireless Application Protocol</h2><p>Not that one! We are talking about Wireless Application Protocol and not Cardi
20B's song 😃<p>WAP stands for Wireless Application Protocol. It is a protocol designed for
21micro-browsers, and it enables the access of internet in the mobile devices. It
22uses the mark-up language WML (Wireless Markup Language and not HTML), WML is
23defined as XML 1.0 application. Furthermore, it enables creating web
24applications for mobile devices. In 1998, WAP Forum was founded by Ericson,
25Motorola, Nokia and Unwired Planet whose aim was to standardize the various
26wireless technologies via protocols.
27<a href=https://www.geeksforgeeks.org/wireless-application-protocol/>(source)</a><p>WAP protocol was resulted by the joint efforts of the various members of WAP
28Forum. In 2002, WAP forum was merged with various other forums of the industry,
29resulting in the formation of Open Mobile Alliance (OMA).
30<a href=https://www.geeksforgeeks.org/wireless-application-protocol/>(source)</a><p>These were some wild times. Devices had tiny screens and data transmission rates
31were abominable. But they were capable of rendering WML (Wireless Markup
32Language). This was very similar to HTML, actually. It is a markup language,
33after all.<p>These pages could be served by <a href=https://apache.org/>Apache</a> and could be
34generated by CGI scripts on the backend. The only difference was the limited
35markup language.<h2 id=wml---wireless-markup-language>WML - Wireless Markup Language</h2><p>Just like web browsers use HTML for content structure, older mobile device
36browsers use WML - if you need to support really old mobile phones using WML
37browsers, you will need to know about it. WML is XML-based (an XML vocabulary
38just like XHTML and MathML, but not HTML) and does not use the same metaphor as
39HTML. HTML is a single document with some metadata packed away in the head, and
40a body encapsulating the visible page. With WML, the metaphor does not envisage
41a page, but rather a deck of cards. A WML file might have several pages or cards
42contained within it.
43<a href=https://www.w3.org/wiki/Introduction_to_mobile_web>(source)</a><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>&lt;?xml version=&#34;1.0&#34;?&gt;</span>
44</span></span><span style=display:flex><span><span style=color:#00f>&lt;!DOCTYPE wml PUBLIC &#34;-//WAPFORUM//DTD WML 1.1//EN&#34; &#34;http://www.wapforum.org/DTD/wml_1.1.xml&#34;&gt;</span>
45</span></span><span style=display:flex><span>&lt;wml&gt;
46</span></span><span style=display:flex><span> &lt;card id=<span style=color:#a31515>&#34;home&#34;</span> title=<span style=color:#a31515>&#34;Example Homepage&#34;</span>&gt;
47</span></span><span style=display:flex><span> &lt;p&gt;Welcome to the Example homepage&lt;/p&gt;
48</span></span><span style=display:flex><span> &lt;/card&gt;
49</span></span><span style=display:flex><span>&lt;/wml&gt;
50</span></span></code></pre><p>There is an amazing tutorial on <a href=https://www.tutorialspoint.com/wml/index.htm>Tutorialpoint about
51WML</a>.<h2 id=converting-digg-to-wml>Converting Digg to WML</h2><p>This task is completely useless and not really feasible nowadays, but I had to
52give it a try for old-time sake. Since the data is already there in a form of
53RSS feed, I could take this feed and parse it and create a WML version of the
54homepage.<p>We will need:<ul><li>Python3 + Pip<li>ImageMagick<li>feedparser and mako templating</ul><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># for fedora 35</span>
55</span></span><span style=display:flex><span>sudo dnf install ImageMagick python3-pip
56</span></span><span style=display:flex><span>
57</span></span><span style=display:flex><span><span style=color:green># tempalting engine for python</span>
58</span></span><span style=display:flex><span>pip install mako --user
59</span></span><span style=display:flex><span>
60</span></span><span style=display:flex><span><span style=color:green># for parsing rss feeds</span>
61</span></span><span style=display:flex><span>pip install feedparser --user
62</span></span></code></pre><p>Project folder structure should look like the following.<pre><code>12:43:53 m@khan wap → tree -L 1
63.
64├── generate.py
65└── template.wml
66
67</code></pre><p>After that, I created a small template for the homepage.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>&lt;?xml version=&#34;1.0&#34;?&gt;</span>
68</span></span><span style=display:flex><span><span style=color:#00f>&lt;!DOCTYPE wml PUBLIC &#34;-//WAPFORUM//DTD WML 1.2//EN&#34; &#34;http://www.wapforum.org/DTD/wml_1.2.xml&#34;&gt;</span>
69</span></span><span style=display:flex><span>
70</span></span><span style=display:flex><span>&lt;wml&gt;
71</span></span><span style=display:flex><span>
72</span></span><span style=display:flex><span> &lt;card title=<span style=color:#a31515>&#34;Digg - What the Internet is talking about right now&#34;</span>&gt;
73</span></span><span style=display:flex><span>
74</span></span><span style=display:flex><span> % for item in entries:
75</span></span><span style=display:flex><span> &lt;p&gt;&lt;img src=<span style=color:#a31515>&#34;/images/${item.id}.jpg&#34;</span> width=<span style=color:#a31515>&#34;175&#34;</span> height=<span style=color:#a31515>&#34;95&#34;</span> alt=<span style=color:#a31515>&#34;${item.title}&#34;</span> /&gt;&lt;/p&gt;
76</span></span><span style=display:flex><span> &lt;p&gt;&lt;small&gt;${item.kicker}&lt;/small&gt;&lt;/p&gt;
77</span></span><span style=display:flex><span> &lt;p&gt;&lt;big&gt;&lt;b&gt;${item.title}&lt;/b&gt;&lt;/big&gt;&lt;/p&gt;
78</span></span><span style=display:flex><span> &lt;p&gt;${item.description}&lt;/p&gt;
79</span></span><span style=display:flex><span> % endfor
80</span></span><span style=display:flex><span>
81</span></span><span style=display:flex><span> &lt;/card&gt;
82</span></span><span style=display:flex><span>
83</span></span><span style=display:flex><span>&lt;/wml&gt;
84</span></span></code></pre><p>And the parser that parses RSS feed looks like this.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>import</span> os
85</span></span><span style=display:flex><span><span style=color:#00f>import</span> feedparser
86</span></span><span style=display:flex><span><span style=color:#00f>from</span> mako.template <span style=color:#00f>import</span> Template
87</span></span><span style=display:flex><span>
88</span></span><span style=display:flex><span>os.system(<span style=color:#a31515>&#39;mkdir -p www/images&#39;</span>)
89</span></span><span style=display:flex><span>
90</span></span><span style=display:flex><span>template = Template(filename=<span style=color:#a31515>&#39;template.wml&#39;</span>)
91</span></span><span style=display:flex><span>
92</span></span><span style=display:flex><span>feed = feedparser.parse(<span style=color:#a31515>&#39;https://digg.com/rss/top.xml&#39;</span>)
93</span></span><span style=display:flex><span>
94</span></span><span style=display:flex><span>entries = feed.entries[:15]
95</span></span><span style=display:flex><span>
96</span></span><span style=display:flex><span><span style=color:#00f>for</span> entry <span style=color:#00f>in</span> entries:
97</span></span><span style=display:flex><span> print(<span style=color:#a31515>&#39;Processing image with id </span><span style=color:#a31515>{}</span><span style=color:#a31515>&#39;</span>.format(entry.id))
98</span></span><span style=display:flex><span> os.system(<span style=color:#a31515>&#39;wget -q -O www/images/</span><span style=color:#a31515>{}</span><span style=color:#a31515>.jpg &#34;</span><span style=color:#a31515>{}</span><span style=color:#a31515>&#34;&#39;</span>.format(entry.id, entry.links[1].href))
99</span></span><span style=display:flex><span> os.system(<span style=color:#a31515>&#39;convert www/images/</span><span style=color:#a31515>{}</span><span style=color:#a31515>.jpg -type Grayscale -resize 175x -depth 3 -quality 30 www/images/</span><span style=color:#a31515>{}</span><span style=color:#a31515>.jpg&#39;</span>.format(entry.id, entry.id))
100</span></span><span style=display:flex><span>
101</span></span><span style=display:flex><span>html = template.render(entries = entries)
102</span></span><span style=display:flex><span>
103</span></span><span style=display:flex><span><span style=color:#00f>with</span> open(<span style=color:#a31515>&#39;www/index.wml&#39;</span>, <span style=color:#a31515>&#39;w+&#39;</span>) <span style=color:#00f>as</span> fp:
104</span></span><span style=display:flex><span> fp.write(html)
105</span></span></code></pre><p>This script will create a folder <code>www</code> and in the folder <code>www/images</code> for
106storing resized images.<blockquote><p>Be sure you don't use SSL and use just normal HTTP for serving the content.
107These old phones will have problems with TLS 1.3 etc.</blockquote><p>If you look at the python file, I convert all the images into tiny B&amp;W images.
108They should be WBMP (Wireless BitMaP) but I choose JPEGs for this, and it seems
109to work properly.<p>Because I currently don't have a phone old enough to test it on, I used an
110emulator. And it was really hard to find one. I found <a href=http://wap-proof.sharewarejunction.com/>WAP
111Proof</a> on shareware junction, and it
112did the job well enough. I will try to find and actual device to test it on.<p><video src=/posts/wap/emulator.mp4 controls></video><p>If you are using Nginx to serve the contents, add a directive to the hosts file
113that will automatically server <code>index.wml</code> file.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>server</span> {
114</span></span><span style=display:flex><span> <span style=color:#00f>index</span> <span style=color:#a31515>index.wml</span> <span style=color:#a31515>index.html</span> <span style=color:#a31515>index.htm</span> <span style=color:#a31515>index.nginx-debian.html</span>;
115</span></span><span style=display:flex><span>}
116</span></span></code></pre><h2 id=conclusion>Conclusion</h2><p>Well, this was pointless, but very fun! I hope you enjoyed it as much as I did.
117I will try to find an old phone to test it on. If you have any questions, feel
118free to ask in the comments.</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
119a lock on a Linux NFS server, which turned
120out to be specific to NFS v3 (which I really should have seen coming,
121since it involved NLM and lockd). Finding the NFS v4 client that
122owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
123and Bradley Kuhn, are interacting on the OSI's license-discuss
124list where the're doing
125bad computer history and insisting that a guy Larry Rosen
126coincidentally interviewed for a book years ago is clearly the origin of
127somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
128i2c, plan9
129Another month, another file system.
130Well, if you can’t fix it in software, fix it in hardware (looking at
131you, bme680, we’re not
132done yet). The show must go on, as they say, and I would like my
133experiments to go on.
134So a “new” addition to the environmental sensor family connected to
135the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
136this mortal coil, we are endowed with self-awareness, agency, and free will.
137Each of the 8 billion members of this human race represents a unique person, a
138unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
139My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
1401.0 has been released:
141wifi_da-1.0.sit
142(StuffIt 3 archive)
143SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
144This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
145classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
146In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
147Design Goals
148I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
149at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
150catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
151specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
152 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
153 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/what-i-ve-learned-developing-ad-server.html b/public/what-i-ve-learned-developing-ad-server.html
deleted file mode 100755
index 03ae36b..0000000
--- a/public/what-i-ve-learned-developing-ad-server.html
+++ /dev/null
@@ -1,159 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>What I've learned developing ad server</title><meta name=description content="For the past year and half I have been developing native advertising server thatcontextually matches ads and displays them in different template forms onvariety of websites."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>What I've learned developing ad server</h1><p><cap>post</cap>, Apr 17, 2017 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>For the past year and half I have been developing native advertising server that
10contextually matches ads and displays them in different template forms on
11variety of websites. This project grew from serving thousands of ads per day to
12millions.<p>The system is made from couple of core components:<ul><li>API for serving ads,<li>Utils - cronjobs and queue management tools,<li>Dashboard UI.</ul><p>Initial release was using <a href=https://www.mongodb.com/>MongoDB</a> for full-text
13search but was later replaced by <a href=https://www.elastic.co/>Elasticsearch</a> for
14better CPU utilization and better search performance. This provided us with many
15amazing functionalities of <a href=https://www.elastic.co/>Elasticsearch</a>. You should
16check it out if you do any search related operations.<p>Because the premise of the server is to provide native ad experience, they are
17rendered on the client side via simple templating engine. This ensures that ads
18can be displayed number of different ways based on the visual style of the
19page. And this makes JavaScript client library quite complex.<p>So now that you know basic information about the product lets get into the
20lessons we learned.<h2 id=aggregate-everything>Aggregate everything</h2><p>After beta version was released everything (impressions, clicks, etc) was
21written in nanosecond resolution in the database. At that time we were using
22<a href=https://www.postgresql.org/>PostgreSQL</a> and database quickly grew way above
23200GB in disk space. And that was problematic. Statistics took disturbingly long
24time to aggregate. Also using indexes on stats table in database was no help
25after we reached 500 million datapoints.<blockquote><p>There is a marketing product information and there is real life experience.
26And the tend to be quite the opposite.</blockquote><p>This was the reason that now everything is aggregated on daily basis and this
27data is then fed to Elastic in form of daily summary. With this we achieved we
28can now track many more dimensions such as zone, channel and platform
29information. And with this information we can now adapt occurrences of ads on
30specific places more precisely.<p>We have also adapted <a href=https://redis.io/>Redis</a> as a full-time citizen in our
31stack. Because Redis also stores information on a local disk we have some sort
32of backup if server would accidentally suffer some failure.<p>All the real-time statistics for ad serving and redirecting is presented as
33counters in Redis instance and daily extracted and pushed to Elastic.<h2 id=measure-everything>Measure everything</h2><p>The thing about software is that we really don't know how well it is performing
34under load until such load is presented. When testing locally everything is fine
35but when on production things tend to fall apart.<p>As a solution for this we are measuring everything we can. Function execution
36time (by encapsulating functions with timers), server performance (cpu, memory,
37disk, etc), Nginx and <a href=https://uwsgi-docs.readthedocs.io/>uWSGI</a> performance.
38We sacrifice a bit of performance for the sake of this information. And we store
39all this information for later analysis.<p><strong>Example of function execution time</strong><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>{
40</span></span><span style=display:flex><span> &#34;get_final_filtered_ads&#34;: {
41</span></span><span style=display:flex><span> &#34;counter&#34;: 1931250,
42</span></span><span style=display:flex><span> &#34;avg&#34;: 0.0066143431,
43</span></span><span style=display:flex><span> &#34;elapsed&#34;: 12773.9500310003
44</span></span><span style=display:flex><span> },
45</span></span><span style=display:flex><span> &#34;store_keywords_statistics&#34;: {
46</span></span><span style=display:flex><span> &#34;counter&#34;: 1931011,
47</span></span><span style=display:flex><span> &#34;avg&#34;: 0.0004605267,
48</span></span><span style=display:flex><span> &#34;elapsed&#34;: 889.2821669996
49</span></span><span style=display:flex><span> },
50</span></span><span style=display:flex><span> &#34;match_by_context&#34;: {
51</span></span><span style=display:flex><span> &#34;counter&#34;: 1931011,
52</span></span><span style=display:flex><span> &#34;avg&#34;: 0.0055960716,
53</span></span><span style=display:flex><span> &#34;elapsed&#34;: 10806.0758889999
54</span></span><span style=display:flex><span> },
55</span></span><span style=display:flex><span> &#34;match_by_high_performance&#34;: {
56</span></span><span style=display:flex><span> &#34;counter&#34;: 262,
57</span></span><span style=display:flex><span> &#34;avg&#34;: 0.0152770229,
58</span></span><span style=display:flex><span> &#34;elapsed&#34;: 4.00258
59</span></span><span style=display:flex><span> },
60</span></span><span style=display:flex><span> &#34;store_impression_stats&#34;: {
61</span></span><span style=display:flex><span> &#34;counter&#34;: 1931250,
62</span></span><span style=display:flex><span> &#34;avg&#34;: 0.0006189991,
63</span></span><span style=display:flex><span> &#34;elapsed&#34;: 1195.4419869999
64</span></span><span style=display:flex><span> }
65</span></span><span style=display:flex><span>}
66</span></span></code></pre><p>We have also started profiling with <a href=https://pymotw.com/2/profile/>cProfile</a>
67and then visualizing with <a href=http://kcachegrind.sourceforge.net/>KCachegrind</a>.
68This provides much more detailed look into code execution.<h2 id=cache-control-is-your-friend>Cache control is your friend</h2><p>Because we use Javascript library for rendering ads we rely on this script
69extensively and when in need we need to be able to change behavior of the script
70quickly.<p>In our case we can not simply replace javascript url in html code. It usually
71takes a day or two for the guys who maintain sites to change code or add
72?ver=xxx attribute. And this makes rapid deployment and testing very difficult
73and time consuming. There is a limitation of how much you can test locally.<p>We are now in the process of integrating <a href=https://www.google.com/analytics/tag-manager/>Google Tag
74Manager</a> but couple of websites
75are developed on ASP.net platform that have some problems with tag manager. With
76a solution below we are certain that we are serving latest version of the
77script.<p>And it only takes one mistake and users have the script cached and in case of
78caching it for 1 year you probably know where the problem is.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># nginx ➜ /etc/nginx/sites-available/default
79</span></span></span><span style=display:flex><span><span style=color:green></span><span style=color:#00f>location</span> <span style=color:#a31515>/static/</span> {
80</span></span><span style=display:flex><span> <span style=color:#00f>alias</span> <span style=color:#a31515>/path-to-static-content/</span>;
81</span></span><span style=display:flex><span> <span style=color:#00f>autoindex</span> off;
82</span></span><span style=display:flex><span> <span style=color:#00f>charset</span> <span style=color:#a31515>utf-8</span>;
83</span></span><span style=display:flex><span> <span style=color:#00f>gzip</span> on;
84</span></span><span style=display:flex><span> <span style=color:#00f>gzip_types</span> <span style=color:#a31515>text/plain</span> <span style=color:#a31515>application/javascript</span> <span style=color:#a31515>application/x-javascript</span> <span style=color:#a31515>text/javascript</span> <span style=color:#a31515>text/xml</span> <span style=color:#a31515>text/css</span>;
85</span></span><span style=display:flex><span> <span style=color:#00f>location</span> ~<span style=color:#a31515>*</span> <span style=color:#a31515>\.(ico|gif|jpeg|jpg|png|woff|ttf|otf|svg|woff2|eot)</span>$ {
86</span></span><span style=display:flex><span> <span style=color:#00f>expires</span> <span style=color:#a31515>1y</span>;
87</span></span><span style=display:flex><span> <span style=color:#00f>add_header</span> <span style=color:#a31515>Pragma</span> <span style=color:#a31515>public</span>;
88</span></span><span style=display:flex><span> <span style=color:#00f>add_header</span> <span style=color:#a31515>Cache-Control</span> <span style=color:#a31515>&#34;public&#34;</span>;
89</span></span><span style=display:flex><span> }
90</span></span><span style=display:flex><span> <span style=color:#00f>location</span> ~<span style=color:#a31515>*</span> <span style=color:#a31515>\.(css|js|txt)</span>$ {
91</span></span><span style=display:flex><span> <span style=color:#00f>expires</span> <span style=color:#a31515>3600s</span>;
92</span></span><span style=display:flex><span> <span style=color:#00f>add_header</span> <span style=color:#a31515>Pragma</span> <span style=color:#a31515>public</span>;
93</span></span><span style=display:flex><span> <span style=color:#00f>add_header</span> <span style=color:#a31515>Cache-Control</span> <span style=color:#a31515>&#34;public,</span> <span style=color:#a31515>must-revalidate&#34;</span>;
94</span></span><span style=display:flex><span> }
95</span></span><span style=display:flex><span>}
96</span></span></code></pre><p>Also be careful when redirecting to url in your python code. We noticed that if
97we didn't precisely setup cache control and expire headers in response we didn't
98get the request on the server and therefore couldn't measure clicks. So when
99redirecting do as follows and there will be no problems.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:green># python ➜ bottlepy web micro-framework</span>
100</span></span><span style=display:flex><span>response = bottle.HTTPResponse(status=302)
101</span></span><span style=display:flex><span>response.set_header(<span style=color:#a31515>&#34;Cache-Control&#34;</span>, <span style=color:#a31515>&#34;no-store, no-cache, must-revalidate&#34;</span>)
102</span></span><span style=display:flex><span>response.set_header(<span style=color:#a31515>&#34;Expires&#34;</span>, <span style=color:#a31515>&#34;Thu, 01 Jan 1970 00:00:00 GMT&#34;</span>)
103</span></span><span style=display:flex><span>response.set_header(<span style=color:#a31515>&#34;Location&#34;</span>, url)
104</span></span><span style=display:flex><span><span style=color:#00f>return</span> response
105</span></span></code></pre><blockquote><p>Cache control in browsers is quite aggressive and you need to be precise to
106avoid future problems. We learned that lesson the hard way.</blockquote><h2 id=learn-nginx>Learn NGINX</h2><p>When deciding on a web server we went with Nginx as a reverse proxy for our
107applications. We adapted micro-service oriented architecture early in the
108project to ensure when we scale we can easily add additional servers to our
109cluster. And Nginx was crucial to perform load balancing and static content
110delivery.<p>At first our config file was quite simple and later grew larger. After patching
111and adding new settings I sat down and learned more about the guts of Nginx.
112This proved to be very useful and we were able to squeeze much more out of our
113setup. So I advise you to take your time and read through the
114<a href=https://nginx.org/en/docs/>documentation</a>. This saved us a lot of headache.
115Googling for solutions only goes so far.<h2 id=use-redismemcached>Use Redis/Memcached</h2><p>As explained above we are using caching basically for everything. It is the
116corner stone of our services. At first we were very careful about the quantity
117of things we stored in <a href=https://redis.io/>Redis</a>. But we later found out that
118the memory footprint is very low even when storing large amount of data in it.<p>So we gradually increased our usage to caching whole HTML outputs of dashboard.
119This improved our performance in order of magnitude. And by using native TTL
120support this goes hand in hand with our needs.<p>The reason why we choose <a href=https://redis.io/>Redis</a> over
121<a href=https://memcached.org/>Memcached</a> was the nature of scalability of Redis out
122of the box. But all this can be achieved with Memcached.<h2 id=conclusion>Conclusion</h2><p>There are a lot more details that could have been written and every single topic
123in here deserves it's own post but you probably got the idea about the problems
124we faced.</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
125a lock on a Linux NFS server, which turned
126out to be specific to NFS v3 (which I really should have seen coming,
127since it involved NLM and lockd). Finding the NFS v4 client that
128owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
129and Bradley Kuhn, are interacting on the OSI's license-discuss
130list where the're doing
131bad computer history and insisting that a guy Larry Rosen
132coincidentally interviewed for a book years ago is clearly the origin of
133somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
134i2c, plan9
135Another month, another file system.
136Well, if you can’t fix it in software, fix it in hardware (looking at
137you, bme680, we’re not
138done yet). The show must go on, as they say, and I would like my
139experiments to go on.
140So a “new” addition to the environmental sensor family connected to
141the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
142this mortal coil, we are endowed with self-awareness, agency, and free will.
143Each of the 8 billion members of this human race represents a unique person, a
144unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
145My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
1461.0 has been released:
147wifi_da-1.0.sit
148(StuffIt 3 archive)
149SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
150This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
151classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
152In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
153Design Goals
154I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
155at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
156catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
157specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
158 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
159 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/what-would-dna-sound-if-synthesized.html b/public/what-would-dna-sound-if-synthesized.html
deleted file mode 100755
index fa5188f..0000000
--- a/public/what-would-dna-sound-if-synthesized.html
+++ /dev/null
@@ -1,237 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>What would DNA sound if synthesized to an audio file</title><meta name=description content="IntroductionLately, I have been thinking a lot about the nature of life, what are thefoundation blocks of life and things like that."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>What would DNA sound if synthesized to an audio file</h1><p><cap>post</cap>, Jul 5, 2022 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><h2 id=introduction>Introduction</h2><p>Lately, I have been thinking a lot about the nature of life, what are the
10foundation blocks of life and things like that. It's remarkable how complex and
11on the other hand simple the creation is when you look at it. The miracle of
12life keeps us grounded when our imagination goes wild. If the DNA are the blocks
13of life, you could consider them to be an API nature provided us to better
14understand all of this chaos masquerading as order.<p>I have been reading a lot about superintelligence and our somehow misguided path
15to create general artificial intelligence. What would the building blocks or our
16creation look like? Is the compression really the ultimate storage of
17information? Will our creation also ponder this questions when creating new
18worlds for themselves, or will we just disappear into the vastness of
19possibilities? It is a little offensive that we are playing God whilst being
20completely ignorant of our own reality. Who knows! Like many other
21breakthroughs, this one will also come at a cost not known to us when it finally
22happens.<p>To keep things a bit lighter, I decided to convert some popular DNA sequences
23into an audio files for us to listen to. I am not the first one, nor I will be
24the last one to do this. But it is an interesting exercise in better
25understanding the relationship between art and science. Maybe listening to DNA
26instead of parsing it will find a way into better understanding, or at least
27enjoying the creation and cryptic nature of life.<h2 id=dna-encoding-and-primer-example>DNA encoding and primer example</h2><p>I have been exploring DNA in the past in my post from about 3 years ago in
28<a href=/encoding-binary-data-into-dna-sequence.html>Encoding binary data into DNA
29sequence</a> where I have been
30converting all sorts of data into DNA sequences.<p>This will be a similar exercise but instead of converting to DNA, I will be
31generating tones from Nucleotides.<table><thead><tr><th>Nucleotides<th>Note<th>Frequency<tbody><tr><td><strong>A</strong> (Adenine)<td>A<td>440 Hz<tr><td><strong>C</strong> (Cytosine)<td>C<td>783.99 Hz<tr><td><strong>G</strong> (Guanine)<td>G<td>523.25 Hz<tr><td><strong>T</strong> (Thymine)<td>D<td>587.33 Hz</table><p>Since we do not have T in equal-tempered scale, I choose D to represent T note.<p>You can check <a href=https://pages.mtu.edu/~suits/notefreqs.html>Frequencies for equal-tempered scale, A4 = 440
32Hz</a>. For this tuning, we also
33choose <code>Speed of Sound = 345 m/s = 1130 ft/s = 770 miles/hr</code>.<p>Now that we have this out of the way, we can also brush up on the DNA sequencing
34a bit. This is a famous quote I also used for the encoding tests, and it goes
35like this.<blockquote><p>How wonderful that we have met with a paradox. Now we have some hope of
36making progress.
37― Niels Bohr</blockquote><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>&gt;SEQ1
38</span></span><span style=display:flex><span>GACAGCTTGTGTACAAGTGTGCTTGCTCGCGAGCGGGTACGCGCGTGGGCTAACAAGTGA
39</span></span><span style=display:flex><span>GCCAGCAGGTGAACAAGTGTGCGGACAAGCCAGCAGGTGCGCGGACAAGCTGGCGGGTGA
40</span></span><span style=display:flex><span>ACAAGTGTGCCGGTGAGCCAACAAGCAGACAAGTAAGCAGGTACGCAGGCGAGCTTGTCA
41</span></span><span style=display:flex><span>ACTCACAAGATCGCTTGTGTACAAGTGTGCGGACAAGCCAGCAGGTGCGCGGACAAGTAT
42</span></span><span style=display:flex><span>GCTTGCTGGCGGACAAGCCAGCTTGTAAGCGGACAAGCTTGCGCACAAGCTGGCAGGCCT
43</span></span><span style=display:flex><span>GCCGGCTCGCGTACAAATTCACAAGTAAGTACGCTTGCGTGTACGCGGGTATGTATACTC
44</span></span><span style=display:flex><span>AACCTCACCAAACGGGACAAGATCGCCGGCGGGCTAGTATACAAGAACGCTTGCCAGTAC
45</span></span><span style=display:flex><span>AACC
46</span></span></code></pre><p>This is what we gonna work with to get things rolling forward, when creating
47parser and waveform generator.<h2 id=parsing-dna-data>Parsing DNA data</h2><p>This step is rather simple one. All we need to do is parse input DNA sequence in
48<a href=https://en.wikipedia.org/wiki/FASTA_format>FASTA format</a> well known in
49<a href=https://en.wikipedia.org/wiki/Bioinformatics>Bioinformatics</a> to extract single
50Nucleotides that will be converted into separate tones based on equal-tempered
51scale explained above.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>nucleotide_tone_map = {
52</span></span><span style=display:flex><span> <span style=color:#a31515>&#39;A&#39;</span>: 440,
53</span></span><span style=display:flex><span> <span style=color:#a31515>&#39;C&#39;</span>: 523.25,
54</span></span><span style=display:flex><span> <span style=color:#a31515>&#39;G&#39;</span>: 783.99,
55</span></span><span style=display:flex><span> <span style=color:#a31515>&#39;T&#39;</span>: 587.33, <span style=color:green># converted to D</span>
56</span></span><span style=display:flex><span>}
57</span></span><span style=display:flex><span>
58</span></span><span style=display:flex><span><span style=color:#00f>def</span> split(word):
59</span></span><span style=display:flex><span> <span style=color:#00f>return</span> [char <span style=color:#00f>for</span> char <span style=color:#00f>in</span> word]
60</span></span><span style=display:flex><span>
61</span></span><span style=display:flex><span><span style=color:#00f>def</span> generate_from_dna_sequence(sequence):
62</span></span><span style=display:flex><span> <span style=color:#00f>for</span> nucleotide <span style=color:#00f>in</span> split(sequence):
63</span></span><span style=display:flex><span> print(nucleotide, nucleotide_tone_map[nucleotide])
64</span></span></code></pre><h2 id=generating-sine-wave>Generating sine wave</h2><p>Because we are essentially creating a long stream of notes we will be appending
65sine notes to a global array we will later use for creating a WAV file out of
66it.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>import</span> math
67</span></span><span style=display:flex><span>
68</span></span><span style=display:flex><span><span style=color:#00f>def</span> append_sinewave(freq=440.0, duration_milliseconds=500, volume=1.0):
69</span></span><span style=display:flex><span> <span style=color:#00f>global</span> audio
70</span></span><span style=display:flex><span>
71</span></span><span style=display:flex><span> num_samples = duration_milliseconds * (sample_rate / 1000.0)
72</span></span><span style=display:flex><span>
73</span></span><span style=display:flex><span> <span style=color:#00f>for</span> x <span style=color:#00f>in</span> range(int(num_samples)):
74</span></span><span style=display:flex><span> audio.append(volume * math.sin(2 * math.pi * freq * (x / sample_rate)))
75</span></span><span style=display:flex><span>
76</span></span><span style=display:flex><span> <span style=color:#00f>return</span>
77</span></span></code></pre><p>The sine wave generated here is the standard beep. If you want something more
78aggressive, you could try a square or saw tooth waveform.<h2 id=generating-a-wav-file-from-accumulated-sine-waves>Generating a WAV file from accumulated sine waves</h2><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>import</span> wave
79</span></span><span style=display:flex><span><span style=color:#00f>import</span> struct
80</span></span><span style=display:flex><span>
81</span></span><span style=display:flex><span><span style=color:#00f>def</span> save_wav(file_name):
82</span></span><span style=display:flex><span> wav_file = wave.open(file_name, <span style=color:#a31515>&#39;w&#39;</span>)
83</span></span><span style=display:flex><span> nchannels = 1
84</span></span><span style=display:flex><span> sampwidth = 2
85</span></span><span style=display:flex><span>
86</span></span><span style=display:flex><span> nframes = len(audio)
87</span></span><span style=display:flex><span> comptype = <span style=color:#a31515>&#39;NONE&#39;</span>
88</span></span><span style=display:flex><span> compname = <span style=color:#a31515>&#39;not compressed&#39;</span>
89</span></span><span style=display:flex><span> wav_file.setparams((nchannels, sampwidth, sample_rate, nframes, comptype, compname))
90</span></span><span style=display:flex><span>
91</span></span><span style=display:flex><span> <span style=color:#00f>for</span> sample <span style=color:#00f>in</span> audio:
92</span></span><span style=display:flex><span> wav_file.writeframes(struct.pack(<span style=color:#a31515>&#39;h&#39;</span>, int(sample * 32767.0)))
93</span></span><span style=display:flex><span>
94</span></span><span style=display:flex><span> wav_file.close()
95</span></span></code></pre><p>44100 is the industry standard sample rate - CD quality. If you need to save on
96file size, you can adjust it downwards. The standard for low quality is, 8000 or
978kHz.<p>WAV files here are using short, 16 bit, signed integers for the sample size.
98So, we multiply the floating-point data we have by 32767, the maximum value for
99a short integer.<blockquote><p>It is theoretically possible to use the floating point -1.0 to 1.0 data
100directly in a WAV file, but not obvious how to do that using the wave module
101in Python.</blockquote><h2 id=generating-spectograms>Generating Spectograms</h2><p>I have tried two methods of doing this and both were just fine. I however opted
102out to use the <a href=https://linux.die.net/man/1/sox>SoX - Sound eXchange, the Swiss Army knife of audio
103manipulation</a> one because it didn't require
104anything else.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>sox output.wav -n spectrogram -o spectrogram.png
105</span></span></code></pre><p>An example spectrogram of Ludwig van Beethoven Symphony No. 6 First movement.</p><audio controls><source src=/posts/dna-synthesized/symphony-no6-1st-movement.mp3 type=audio/mpeg></audio><figure><img src=/posts/dna-synthesized/symphony-no6-1st-movement.png alt="Ludwig van Beethoven Symphony No. 6 First movement"></figure><p>The other option could also be in combination with
106<a href=http://www.gnuplot.info/>gnuplot</a>. This would require an intermediary step,
107however.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>sox output.wav audio.dat
108</span></span><span style=display:flex><span>tail -n+3 audio.dat &gt; audio_only.dat
109</span></span><span style=display:flex><span>gnuplot audio.gpi
110</span></span></code></pre><p>And input file <code>audio.gpi</code> that would be passed to gnuplot looks something like
111this.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span># set output format and size
112</span></span><span style=display:flex><span>set term png size 1000,280
113</span></span><span style=display:flex><span>
114</span></span><span style=display:flex><span># set output file
115</span></span><span style=display:flex><span>set output &#34;audio.png&#34;
116</span></span><span style=display:flex><span>
117</span></span><span style=display:flex><span># set y range
118</span></span><span style=display:flex><span>set yr [-1:1]
119</span></span><span style=display:flex><span>
120</span></span><span style=display:flex><span># we want just the data
121</span></span><span style=display:flex><span>unset key
122</span></span><span style=display:flex><span>unset tics
123</span></span><span style=display:flex><span>unset border
124</span></span><span style=display:flex><span>set lmargin 0
125</span></span><span style=display:flex><span>set rmargin 0
126</span></span><span style=display:flex><span>set tmargin 0
127</span></span><span style=display:flex><span>set bmargin 0
128</span></span><span style=display:flex><span>
129</span></span><span style=display:flex><span># draw rectangle to change background color
130</span></span><span style=display:flex><span>set obj 1 rectangle behind from screen 0,0 to screen 1,1
131</span></span><span style=display:flex><span>set obj 1 fillstyle solid 1.0 fillcolor rgbcolor &#34;#ffffff&#34;
132</span></span><span style=display:flex><span>
133</span></span><span style=display:flex><span># draw data with foreground color
134</span></span><span style=display:flex><span>plot &#34;audio_only.dat&#34; with lines lt rgb &#39;red&#39;
135</span></span></code></pre><h2 id=pre-generated-sequences>Pre-generated sequences</h2><p>What I did was take interesting parts from an animal's genome and feed it to a
136tone generator script. This then generated a WAV file and I converted those to
137MP3, so they can be played in a browser. The last step was creating a
138spectrogram based on a WAV file.<h3 id=niels-bohr-quote>Niels Bohr quote</h3><audio controls><source src=/posts/dna-synthesized/quote/out.mp3 type=audio/mpeg></audio><figure><img src=/posts/dna-synthesized/quote/spectogram.png alt=Spectogram></figure><h3 id=mouse>Mouse</h3><p>This is part of a mouse genome <code>Mus_musculus.GRCm39.dna.nonchromosomal</code>. You
139can get <a href=http://ftp.ensembl.org/pub/release-106/fasta/mus_musculus/dna/>genom data
140here</a>.</p><audio controls><source src=/posts/dna-synthesized/mouse/out.mp3 type=audio/mpeg></audio><figure><img src=/posts/dna-synthesized/mouse/spectogram.png alt=Spectogram></figure><h3 id=bison>Bison</h3><p>This is part of a bison genome <code>Bison_bison_bison.Bison_UMD1.0.cdna</code>. You can
141get <a href=http://ftp.ensembl.org/pub/release-106/fasta/bison_bison_bison/cdna/>genom data
142here</a>.</p><audio controls><source src=/posts/dna-synthesized/bison/out.mp3 type=audio/mpeg></audio><figure><img src=/posts/dna-synthesized/bison/spectogram.png alt=Spectogram></figure><h3 id=taurus>Taurus</h3><p>This is part of a taurus genome <code>Bos_taurus.ARS-UCD1.2.cdna</code>. You can get
143<a href=http://ftp.ensembl.org/pub/release-106/fasta/bos_taurus/cdna/>genom data
144here</a>.</p><audio controls><source src=/posts/dna-synthesized/taurus/out.mp3 type=audio/mpeg></audio><figure><img src=/posts/dna-synthesized/taurus/spectogram.png alt=Spectogram></figure><h2 id=making-a-drummer-out-of-a-dna-sequence>Making a drummer out of a DNA sequence</h2><p>To make things even more interesting, I decided to send this data via MIDI to my
145<a href=https://www.elektron.se/en/model-samples>Elektron Model:Samples</a>. This is a
146really cool piece of equipment that supports MIDI in via USB and 3.5 mm audio
147jack.<p>Elektron is connected to my MacBook via USB cable and audio out is patched to a
148Sony Bluetooth speaker I have that supports 3.5 mm audio in. Elektron doesn't
149have internal speakers.<figure><img src=/posts/dna-synthesized/elektron/IMG_0619.jpg alt></figure><figure><img src=/posts/dna-synthesized/elektron/IMG_0620.jpg alt></figure><figure><img src=/posts/dna-synthesized/elektron/IMG_0622.jpg alt></figure><p>For communicating with Elektron, I choose <code>pygame</code> Python module that has MIDI
150built in. With this, it was rather simple to send notes to the device. All I did
151was map MIDI notes to the actual Nucleotides.<p>Before all of this I also checked Audio MIDI Setup app under MacOS and checked
152MIDI Studio by pressing ⌘-2.<figure><img src=/posts/dna-synthesized/elektron/midi-studio.jpg alt></figure><p>The whole script that parses and send notes to the Elektron looks like this.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>import</span> pygame.midi
153</span></span><span style=display:flex><span><span style=color:#00f>import</span> time
154</span></span><span style=display:flex><span>
155</span></span><span style=display:flex><span>pygame.midi.init()
156</span></span><span style=display:flex><span>
157</span></span><span style=display:flex><span>print(pygame.midi.get_default_output_id())
158</span></span><span style=display:flex><span>print(pygame.midi.get_device_info(0))
159</span></span><span style=display:flex><span>
160</span></span><span style=display:flex><span>player = pygame.midi.Output(1)
161</span></span><span style=display:flex><span>player.set_instrument(2)
162</span></span><span style=display:flex><span>
163</span></span><span style=display:flex><span><span style=color:#00f>def</span> send_note(note, velocity):
164</span></span><span style=display:flex><span> <span style=color:#00f>global</span> player
165</span></span><span style=display:flex><span> player.note_on(note, velocity)
166</span></span><span style=display:flex><span> time.sleep(0.3)
167</span></span><span style=display:flex><span> player.note_off(note, velocity)
168</span></span><span style=display:flex><span>
169</span></span><span style=display:flex><span>
170</span></span><span style=display:flex><span>nucleotide_midi_map = {
171</span></span><span style=display:flex><span> <span style=color:#a31515>&#39;A&#39;</span>: 60,
172</span></span><span style=display:flex><span> <span style=color:#a31515>&#39;C&#39;</span>: 90,
173</span></span><span style=display:flex><span> <span style=color:#a31515>&#39;G&#39;</span>: 160,
174</span></span><span style=display:flex><span> <span style=color:#a31515>&#39;T&#39;</span>: 180, <span style=color:green># is D</span>
175</span></span><span style=display:flex><span>}
176</span></span><span style=display:flex><span>
177</span></span><span style=display:flex><span><span style=color:#00f>with</span> open(<span style=color:#a31515>&#34;quote.fa&#34;</span>) <span style=color:#00f>as</span> f:
178</span></span><span style=display:flex><span> sequence = f.read().replace(<span style=color:#a31515>&#39;</span><span style=color:#a31515>\n</span><span style=color:#a31515>&#39;</span>, <span style=color:#a31515>&#39;&#39;</span>)
179</span></span><span style=display:flex><span>
180</span></span><span style=display:flex><span><span style=color:#00f>for</span> nucleotide <span style=color:#00f>in</span> [char <span style=color:#00f>for</span> char <span style=color:#00f>in</span> sequence]:
181</span></span><span style=display:flex><span> print(<span style=color:#a31515>&#34;Playing nucleotide </span><span style=color:#a31515>{}</span><span style=color:#a31515> with MIDI note </span><span style=color:#a31515>{}</span><span style=color:#a31515>&#34;</span>.format(
182</span></span><span style=display:flex><span> nucleotide, nucleotide_midi_map[nucleotide]))
183</span></span><span style=display:flex><span> send_note(nucleotide_midi_map[nucleotide], 127)
184</span></span><span style=display:flex><span>
185</span></span><span style=display:flex><span><span style=color:#00f>del</span> player
186</span></span><span style=display:flex><span>pygame.midi.quit()
187</span></span></code></pre><p><video src=/posts/dna-synthesized/elektron/elektron.mp4 controls></video><p>All of this could be made much more interesting if I choose different
188instruments for different Nucleotides, or doing more funky stuff with Elektron.
189But for now, this should be enough. It is just a proof of concept. Something to
190play around with.<h2 id=going-even-further>Going even further</h2><p>As you probably notice, the end results are quite similar to each other. This is
191to be expected because we are operating only with 4 notes essentially. What
192could make this more interesting is using something like
193<a href=https://supercollider.github.io/>Supercollider</a> to create more interesting
194sounds. By transposing notes or using effects based on repeated data in a
195sequence. Possibilities are endless.<p>It is really astonishing what can be achieved with a little bit of code and an
196idea. I could see this becoming an interesting background soundscape instrument
197if done properly. It could replace random note generator with something more
198intriguing, biological, natural.<p>I actually find the results fascinating. I took some time and listened to this
199music of nature. Even though it's quite the same, it's also quite different.
200The subtle differences on repeat kind of creates music on its own. Makes you
201wonder. It kind of puts Occam’s Razor in its place. Nature for sure loves to
202make things as energy efficient as possible.</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
203a lock on a Linux NFS server, which turned
204out to be specific to NFS v3 (which I really should have seen coming,
205since it involved NLM and lockd). Finding the NFS v4 client that
206owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
207and Bradley Kuhn, are interacting on the OSI's license-discuss
208list where the're doing
209bad computer history and insisting that a guy Larry Rosen
210coincidentally interviewed for a book years ago is clearly the origin of
211somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
212i2c, plan9
213Another month, another file system.
214Well, if you can’t fix it in software, fix it in hardware (looking at
215you, bme680, we’re not
216done yet). The show must go on, as they say, and I would like my
217experiments to go on.
218So a “new” addition to the environmental sensor family connected to
219the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
220this mortal coil, we are endowed with self-awareness, agency, and free will.
221Each of the 8 billion members of this human race represents a unique person, a
222unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
223My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
2241.0 has been released:
225wifi_da-1.0.sit
226(StuffIt 3 archive)
227SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
228This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
229classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
230In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
231Design Goals
232I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
233at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
234catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
235specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
236 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
237 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/who-knows-what-the-world-will-look-like-tomorrow.html b/public/who-knows-what-the-world-will-look-like-tomorrow.html
deleted file mode 100755
index d0de2c0..0000000
--- a/public/who-knows-what-the-world-will-look-like-tomorrow.html
+++ /dev/null
@@ -1,109 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Who knows what the world will look like tomorrow</title><meta name=description content="This site has gone through a lot of changes over the years."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Who knows what the world will look like tomorrow</h1><p><cap>post</cap>, Jul 8, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>This site has gone through a lot of changes over the years. From being written
10in Flask and Bottle to moving on to static site generators. I have used and
11tested probably 10s of them my now. From homebrew solutions to the biggest and
12the baddest. From Bash scripts to Node.js disasters. I've seen some things, no
13doubt. Not all bad.<p>I have been closely observing the web and where the trends are going, and I
14don't like what I see. Instead of internet being this weird place where
15experimentation is happening, it all became stale and formulized. Boring,
16actually. Really boring. And sad. Where is that old, revolutionary FU spirit I
17remember? It's still there, I know. But it's being drowned by the voices of
18mediocrity and formulaic boredom.<p>It almost feels like that the internet stopped for 10 years and only now
19something has started happening. With all the insanity around the world. People
20hating people without actual reasons, just because it's fashionable to hate and
21crowd is saying so. Sad state of affairs.<p>All this is contributing to this overall negativity masked as apathy. Everybody
22walking in lockstep. Instead of being creative and bold, we are just
23re-inventing the world and making the same mistakes. Maybe, just maybe, some
24things are good enough and there is no need to try to be too smart for our own
25good. After N-attempts, maybe something should click inside our heads to maybe
26say: "This thing, opinion, etc. is actually really good, and even after several
27attempts it still holds."<p>The older I get, the more careful I am of my own thoughts and why I think the
28way I think. More and more, I try to understand people with opposite
29opinions. Far from perfect, but closer to bearable. And then I see people
30hearing or reading a thing on internet and let's fucking goooooo! Strong
31opinions are a sign of a weak and uneducated mind. I am more and more sure of
32this.<p>It's gotten to a point where you can with great certainty deduce a person's
33personality based on one or two opinions. How boring have we become. No wonder
34people can't talk to each other. These would be very quick conversations anyway.<p>I just got remembered of a song, <a href="https://www.youtube.com/watch?v=s_nc1IVoMxc">"Hi
35Ren"</a>. The ending talks about being
36stiff and not being able to dance. Such an amazing metaphor. And we as people
37have gone so far, we can't even walk or even crawl normally anymore. We have
38forgotten that the most beautiful things in life have a great deal of
39uncertainty about them. We want instant gratification. Not only that, but we
40want absolute obedience. Complete control over others, because we have zero
41control of ourselves. And all the lies we could tell ourselves will not help us
42out of this situation.<p>It is funny how I catch myself from time to time being a complete idiot. It's
43like having an outer body experience. I can see myself being an idiot, and
44cannot stop myself. It serves as a learning lesson to stop before speaking. To
45think before saying. And to crawl before walking.<p>So there is still time. We can dance once more. All we need to do is stop for a
46second. Me and you. Us two is a start. Let's not try to change the world, but
47rather nudge ourselves just a tiny bit. And if we only did that?! Just
48imagine. Each of us nudged ourselves a small, tiny bit, the world would heal. If
49we would just put down the phones and ignored Internet for a day or two. Put
50visiting websites that feed on us on hold. Listened to just one sentence and try
51to understand it from a person who we completely disagree with. I truly believe
52that this is possible.<p>Life is about suffering and joy. And instead of wishing suffering on others and
53excepting joy for yourselves, we should for a brief moment want suffering for
54ourselves and wish joy on others. Wouldn't that be an amazing sight to see?<p>I caught myself hating on Rust. And I deeply thought about it afterward. Why did
55I do it? It is obviously not for me. So why the hell was I being so negative
56towards it? I think that I know the answer. I was negative because that is
57easy. Because it's much easier to hate on things than to say to yourself: "Well,
58you know what? This is not for me. I will focus on creation and not
59destruction. This is who I want to be. This is what fills me with joy and
60purpose." Where joy is keeping me happy and purpose scares the shit out of me
61and keeps me honest. This is who I want to be. Admit to myself when I am wrong
62and accept the faults that I have without reservation and with courage march on.<p>I just realized that this blog post is a sort of therapy for me. It's
63cathartic. Going thought the history of this site and remembering all the
64decisions and annoyances that came with it. When I was cursing at the tools. And
65time moved on, and the site is still here. It serves as a reminder that
66perseverance wins at the end. If we just let things go.<p>This came with a decision that simplifying life and removing all the unnecessary
67negativity is key. Rather than worrying about what the internet is saying, what
68the world is trying to take from you, you are the only one who can say no. And
69create instead of destroy.<p>I don't have an ending for this post, so I will say this. We live in the most
70amazing times in the recorded history, and we should be internally grateful for
71it. Create and study, this should be my mantra. Just create and let the world
72happen. And when you feel yourself to be too certain, stop and check how deep in the
73shit you are already. Strong opinions are a sign of a weak and uneducated
74mind. Hate and disdain is for the weak.</div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
75a lock on a Linux NFS server, which turned
76out to be specific to NFS v3 (which I really should have seen coming,
77since it involved NLM and lockd). Finding the NFS v4 client that
78owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
79and Bradley Kuhn, are interacting on the OSI's license-discuss
80list where the're doing
81bad computer history and insisting that a guy Larry Rosen
82coincidentally interviewed for a book years ago is clearly the origin of
83somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
84i2c, plan9
85Another month, another file system.
86Well, if you can’t fix it in software, fix it in hardware (looking at
87you, bme680, we’re not
88done yet). The show must go on, as they say, and I would like my
89experiments to go on.
90So a “new” addition to the environmental sensor family connected to
91the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
92this mortal coil, we are endowed with self-awareness, agency, and free will.
93Each of the 8 billion members of this human race represents a unique person, a
94unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
95My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
961.0 has been released:
97wifi_da-1.0.sit
98(StuffIt 3 archive)
99SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
100This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
101classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
102In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
103Design Goals
104I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
105at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
106catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
107specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
108 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
109 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/wireless-sensor-networks.html b/public/wireless-sensor-networks.html
deleted file mode 100755
index c53f4e1..0000000
--- a/public/wireless-sensor-networks.html
+++ /dev/null
@@ -1,71 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Wireless sensor networks</title><meta name=description content="Zigbee networks have this wonderful capability to self-heal, which means theycan reorder connections between them if one of them is inoperable."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Wireless sensor networks</h1><p><cap>post</cap>, Oct 24, 2013 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>Zigbee networks have this wonderful capability to self-heal, which means they
10can reorder connections between them if one of them is inoperable. This works
11our of the box when you deploy them. But you have to have in mind that achieving
12this is not as easy as you would think. None of it is plug&amp;play. So to make
13your life a bit easier, here are some pointers which, I hope, will help you.<ul><li>Be careful when you are ordering your equipment abroad. There are many rules
14and regulations you need to comply before you get your Xbee radios. What they
15do is they wait until you prove that you won’t use the technology for some
16kind of evil take over control of the world project :). For this, they have
17EAR (Export Administration Regulations) which basically means “This product
18may require a license to export from the United States.”.<li>I don’t know if this applies for every country, but when we purchased our Xbee
19radios from Mouser, this was mandatory! What we needed to do was to print out
20a form and write information about our company and send them a copy via
21email. With this document, we proved that we are a legitimate company.<li>When you complete your purchase and send all the documentation, you are not
22clear yet. Then customs will take it from there :). There will be some
23additional costs. Before purchasing, make sure you have as much information
24about costs as possible. Because it can get costly in the end.<li>I suggest you use companies from your country. You can seriously cut your
25costs. Here in Slovenia, the best option so far as I know is Farnell. And
26based on my personal experience, they rock! All I need to say!<li>Make plans when ordering larger quantities. Do not, I say, do not make your
27orders in December! :) Believe me! You will have problems with stock they can
28provide for you. So, we were forced to buy some things from Mouser, which was
29extremely painful because of all the regulations you need to obey when
30importing goods from the USA.<li>Make sure that firmware version on your Xbee radios is exactly the same! Do
31not get creative!!! I propose using templates. You can get template by
32exporting settings/profile in X-CTU application. Make sure you have enabled
33“Upgrade firmware” so you can be sure each radio has the same firmware.<li>And again: make plans! Plan everything! In months advanced! You will thank me
34later :)<li>Test, test, test. Wireless networks can be tricky.</ul><p>If you are serious, I suggest you buy this book, Building Wireless Sensor
35Networks. You will get a glimpse of how networks work in lumens terms. It is a
36good starting point for everybody who wants to build wireless networks.<p><strong>Additional resources:</strong><ul><li><a href=http://www.digi.com/aboutus/export/generalexportinfo>http://www.digi.com/aboutus/export/generalexportinfo</a><li><a href=http://doresearch.stanford.edu/research-scholarship/export-controls/export-controlled-or-embargoed-countries-entities-and-persons>http://doresearch.stanford.edu/research-scholarship/export-controls/export-controlled-or-embargoed-countries-entities-and-persons</a><li><a href=http://www.bis.doc.gov/licensing/exportingbasics.htm>http://www.bis.doc.gov/licensing/exportingbasics.htm</a></ul></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
37a lock on a Linux NFS server, which turned
38out to be specific to NFS v3 (which I really should have seen coming,
39since it involved NLM and lockd). Finding the NFS v4 client that
40owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
41and Bradley Kuhn, are interacting on the OSI's license-discuss
42list where the're doing
43bad computer history and insisting that a guy Larry Rosen
44coincidentally interviewed for a book years ago is clearly the origin of
45somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
46i2c, plan9
47Another month, another file system.
48Well, if you can’t fix it in software, fix it in hardware (looking at
49you, bme680, we’re not
50done yet). The show must go on, as they say, and I would like my
51experiments to go on.
52So a “new” addition to the environmental sensor family connected to
53the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
54this mortal coil, we are endowed with self-awareness, agency, and free will.
55Each of the 8 billion members of this human race represents a unique person, a
56unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
57My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
581.0 has been released:
59wifi_da-1.0.sit
60(StuffIt 3 archive)
61SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
62This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
63classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
64In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
65Design Goals
66I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
67at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
68catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
69specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
70 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
71 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/write-iso-usb.html b/public/write-iso-usb.html
deleted file mode 100755
index ed21a73..0000000
--- a/public/write-iso-usb.html
+++ /dev/null
@@ -1,45 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Write ISO to USB Key</title><meta name=description content="Write ISO to USB key."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Write ISO to USB Key</h1><p><cap>note</cap>, May 8, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><p>Write ISO to USB key. Nothing fancy here.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>sudo dd <span style=color:#00f>if</span>=iso_file.iso of=/dev/sdX bs=4M status=progress conv=fdatasync
10</span></span></code></pre></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
11a lock on a Linux NFS server, which turned
12out to be specific to NFS v3 (which I really should have seen coming,
13since it involved NLM and lockd). Finding the NFS v4 client that
14owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
15and Bradley Kuhn, are interacting on the OSI's license-discuss
16list where the're doing
17bad computer history and insisting that a guy Larry Rosen
18coincidentally interviewed for a book years ago is clearly the origin of
19somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
20i2c, plan9
21Another month, another file system.
22Well, if you can’t fix it in software, fix it in hardware (looking at
23you, bme680, we’re not
24done yet). The show must go on, as they say, and I would like my
25experiments to go on.
26So a “new” addition to the environmental sensor family connected to
27the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
28this mortal coil, we are endowed with self-awareness, agency, and free will.
29Each of the 8 billion members of this human race represents a unique person, a
30unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
31My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
321.0 has been released:
33wifi_da-1.0.sit
34(StuffIt 3 archive)
35SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
36This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
37classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
38In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
39Design Goals
40I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
41at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
42catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
43specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
44 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
45 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/public/xterm-color-palette.html b/public/xterm-color-palette.html
deleted file mode 100755
index ff0bee8..0000000
--- a/public/xterm-color-palette.html
+++ /dev/null
@@ -1,112 +0,0 @@
1<!doctype html><html lang=en-us><meta charset=utf-8><meta name=viewport content="width=device-width,initial-scale=1"><meta name=generator content="JBMAFP - github.com/mitjafelicijan/jbmafp"><link href="data:image/x-icon;base64,AAABAAEAEBAAAAEAIABoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL69vf8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv76+/8LBwQkAAAAAAAAAAAAAAAC+vb3/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAL+9vf/Bv78JAAAAAAAAAAAAAAAAu7q6/wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAC7ubr/vr29CAAAAAAAAAAAy8nJAZ6foP8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAnqGj/6GipAoAAAAAHLjU/xcXHf/BwsL/I8XY/yPK3v8XGiD/IbjL/yPF2f8XGiD/Fxkf/yLF2f8gnK3/Fxog/62ztv8fwNf/FRcd/x271v8mz93/GRsi/xkXHf8p097/GiIp/xobIv8p0t3/KdPe/xocIv8fYmr/KNPe/xoZH/8aHCL/J87c/xy81/8VFxz/IsPZ/8zS0/8XGiD/Ir/R/yPH2/8XGiD/Fxkf/yPH2/8dd4T/GBog/yPJ3f8jyNr/uru9/xcUGv8cudb/EhITDKi5vRKlvMP/RUpOERwcHRAdOj4QHTk8EBwdHRAdNTgQHTo/EBwcHRAcHB0QSGduEKW4vf+koqQfHzg+EBqz0ewSFRv7EyMr/xq51vsTERb7ExUb+xq41fsau9j7ExUb+xiPp/sZudb7ExUb+xMVG/sZuNX/GKvI/BIUGfMdvdn/IrfL/xcaIP8n1eb/J9Dh/xkcIf8ZGR7/J8/f/xxCSv8ZGyH/J9Dg/ybQ4P8ZHCL/FSQs/yPK3/8UExj/GE1b/ybS5P8ZGB7/Ghwj/ynW5P8p2Ob/Ghwi/yWrtv8p1eH/Ghwi/xocIv8p1uT/J8XT/xkcIv8m1un/Hb7d/xUYH/8hzOr/HtHu/xcaIf8XGB//I8vi/xgxOv8XGSD/I8rg/yPK4P8XGiD/GUFL/yPP6f8SERj/Fhkh/x3A4f8AAAAAJ2f9/ydr//8mZPH/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlYu38J2v//ydo/f8AAAAAAAAAAAd8/fkFqf//Iob8sAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMY39awWr//8FfP3/AAAAAAAAAAAFm/7/SfD//wR+/f8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAOB/f9B7v//BaX+/wAAAAAAAAAAQ878SAyZ/v9n1v4KAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADu9v8DDJb+/z3N/XgAAAAA3/sAAN/7AADf+wAA3/sAAAAAAAAAAAAAAAAAAN/7AAAAAAAAAAAAAAAAAAAAAAAAj/EAAI/5AACP8QAA3/sAAA==" rel=icon type=image/x-icon><title>Display xterm color palette</title><meta name=description content="bash xterm-palette."><meta name=author content="Mitja Felicijan"><link rel=alternate type=application/rss+xml title="Mitja Felicijan's posts" href=https://mitjafelicijan.com/index.xml><link rel=alternate type=application/rss+xml title="Mitja Felicijan's notes" href=https://mitjafelicijan.com/notes.xml><style>:root{--border-color:gainsboro;--border-size:2px;--link-color:blue;--bg-color:#eee}*::selection{background:var(--link-color);color:#fff}*::-moz-selection{background:var(--link-color);color:#fff}*::-webkit-selection{background:var(--link-color);color:#fff}body{padding:2.5rem;max-width:1900px;background:#fff;font-family:sans-serif;line-height:1.35rem;font-size:16px}hr{border:0;border-bottom:var(--border-size)solid var(--border-color);margin-block-start:1.5rem}a{color:var(--link-color);text-decoration:none}h1,h2,h3{line-height:initial}h1{font-size:xx-large}footer{margin-block-start:2rem}cap{text-transform:capitalize}blockquote{font-style:italic}table{max-width:100%;border:var(--border-size)solid var(--border-color);border-collapse:separate;border-spacing:0}table thead tr th{border-bottom:var(--border-size)solid var(--border-color);text-align:left}table th,table td{padding:.5em .8em}ul.list li{padding:.2em 0}ul{line-height:1.35em}pre{text-wrap:nowrap;overflow-x:auto;padding:0 1em;border:var(--border-size)solid var(--border-color)}code{padding:0 3px;font-size:14px;border:0;background:var(--bg-color)}pre code{line-height:1.3em;background:#fff}pre,code,pre *,code *{font-family:monospace}figure{margin-inline-start:0;margin-inline-end:0}figcaption{width:800px;max-width:100%;text-align:center}figcaption p{margin:.3em 0 1.5em;font-style:italic}img,video,audio{width:800px;max-width:100%;border:var(--border-size)solid var(--border-color);padding:.5em}header nav{display:flex;gap:.9rem}article iframe{margin:0!important}audio::-webkit-media-controls-enclosure{border-radius:0}@media only screen and (max-width:600px){body{padding:.5em;word-wrap:break-word}header nav{gap:.7rem}header nav .hob{display:none}a{word-wrap:break-word}img,video,audio{padding:0}}</style><header><nav class=main itemscope itemtype=http://schema.org/SiteNavigationElement role=navigation aria-label="Main navigation"><a href=/>Home</a>
2<a href=/#posts>Posts</a>
3<a href=/#notes>Notes</a>
4<a href=/#sideprojects class=hob>Side Projects</a>
5<a href=/vault.html>Vault</a>
6<a href=https://github.com/mitjafelicijan target=_blank>Code</a>
7<a href=/mitjafelicijan.pgp.pub.txt target=_blank class=hob>PGP</a>
8<a href=/curriculum-vitae.html>CV</a>
9<a href=/index.xml target=_blank class=hob>RSS</a></nav></header><main role=main><article itemtype=http://schema.org/Article><h1 itemtype=headline>Display xterm color palette</h1><p><cap>note</cap>, May 25, 2023 on <a href=https://mitjafelicijan.com>Mitja Felicijan's blog</a><div><ul><li><code>bash xterm-palette.sh</code> - will show you number of max colors available<li><code>bash xterm-palette.sh -v</code> - will create a list of all colors with codes</ul><figure><img src=/notes/xterm-palette.png alt="xterm color palette"></figure><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f>#!/usr/bin/env bash
10</span></span></span><span style=display:flex><span><span style=color:#00f></span><span style=color:green># xterm-palette.sh</span>
11</span></span><span style=display:flex><span>
12</span></span><span style=display:flex><span>trap <span style=color:#a31515>&#39;tput sgr0&#39;</span> exit <span style=color:green># Clean up even if user hits ^C</span>
13</span></span><span style=display:flex><span>
14</span></span><span style=display:flex><span><span style=color:#00f>function</span> setfg () {
15</span></span><span style=display:flex><span> printf <span style=color:#a31515>&#39;\e[38;5;%dm&#39;</span> $1
16</span></span><span style=display:flex><span>}
17</span></span><span style=display:flex><span>
18</span></span><span style=display:flex><span><span style=color:#00f>function</span> setbg () {
19</span></span><span style=display:flex><span> printf <span style=color:#a31515>&#39;\e[48;5;%dm&#39;</span> $1
20</span></span><span style=display:flex><span>}
21</span></span><span style=display:flex><span>
22</span></span><span style=display:flex><span><span style=color:#00f>function</span> showcolors() {
23</span></span><span style=display:flex><span> <span style=color:green># Given an integer, display that many colors</span>
24</span></span><span style=display:flex><span> <span style=color:#00f>for</span> ((i=0; i&lt;$1; i++))
25</span></span><span style=display:flex><span> <span style=color:#00f>do</span>
26</span></span><span style=display:flex><span> printf <span style=color:#a31515>&#39;%4d &#39;</span> $i
27</span></span><span style=display:flex><span> setbg $i
28</span></span><span style=display:flex><span> tput el
29</span></span><span style=display:flex><span> tput sgr0
30</span></span><span style=display:flex><span> echo
31</span></span><span style=display:flex><span> <span style=color:#00f>done</span>
32</span></span><span style=display:flex><span> tput sgr0 el
33</span></span><span style=display:flex><span>}
34</span></span><span style=display:flex><span>
35</span></span><span style=display:flex><span><span style=color:green># First, test if terminal supports OSC 4 at all.</span>
36</span></span><span style=display:flex><span>printf <span style=color:#a31515>&#39;\e]4;%d;?\a&#39;</span> 0
37</span></span><span style=display:flex><span>read -d <span style=color:#a31515>$&#39;\a&#39;</span> -s -t 0.1 &lt;/dev/tty
38</span></span><span style=display:flex><span><span style=color:#00f>if</span> [ -z <span style=color:#a31515>&#34;</span>$REPLY<span style=color:#a31515>&#34;</span> ]
39</span></span><span style=display:flex><span><span style=color:#00f>then</span>
40</span></span><span style=display:flex><span> <span style=color:green># OSC 4 not supported, so we&#39;ll fall back to terminfo</span>
41</span></span><span style=display:flex><span> max=<span style=color:#00f>$(</span>tput colors<span style=color:#00f>)</span>
42</span></span><span style=display:flex><span><span style=color:#00f>else</span>
43</span></span><span style=display:flex><span> <span style=color:green># OSC 4 is supported, so use it for a binary search</span>
44</span></span><span style=display:flex><span> min=0
45</span></span><span style=display:flex><span> max=256
46</span></span><span style=display:flex><span> <span style=color:#00f>while</span> [[ <span style=color:#00f>$((</span>min+1<span style=color:#00f>))</span> -lt $max ]]
47</span></span><span style=display:flex><span> <span style=color:#00f>do</span>
48</span></span><span style=display:flex><span> i=<span style=color:#00f>$((</span> (min+max)/2 <span style=color:#00f>))</span>
49</span></span><span style=display:flex><span> printf <span style=color:#a31515>&#39;\e]4;%d;?\a&#39;</span> $i
50</span></span><span style=display:flex><span> read -d <span style=color:#a31515>$&#39;\a&#39;</span> -s -t 0.1 &lt;/dev/tty
51</span></span><span style=display:flex><span> <span style=color:#00f>if</span> [ -z <span style=color:#a31515>&#34;</span>$REPLY<span style=color:#a31515>&#34;</span> ]
52</span></span><span style=display:flex><span> <span style=color:#00f>then</span>
53</span></span><span style=display:flex><span> max=$i
54</span></span><span style=display:flex><span> <span style=color:#00f>else</span>
55</span></span><span style=display:flex><span> min=$i
56</span></span><span style=display:flex><span> <span style=color:#00f>fi</span>
57</span></span><span style=display:flex><span> <span style=color:#00f>done</span>
58</span></span><span style=display:flex><span><span style=color:#00f>fi</span>
59</span></span><span style=display:flex><span>
60</span></span><span style=display:flex><span>
61</span></span><span style=display:flex><span><span style=color:green># If -v is given, show all the colors</span>
62</span></span><span style=display:flex><span><span style=color:#00f>case</span> <span style=color:#a31515>${</span>1-none<span style=color:#a31515>}</span> in
63</span></span><span style=display:flex><span> none)
64</span></span><span style=display:flex><span> echo $max
65</span></span><span style=display:flex><span> ;;
66</span></span><span style=display:flex><span> -v)
67</span></span><span style=display:flex><span> showcolors $max
68</span></span><span style=display:flex><span> ;;
69</span></span><span style=display:flex><span> *)
70</span></span><span style=display:flex><span> <span style=color:#00f>if</span> [[ <span style=color:#a31515>&#34;</span>$1<span style=color:#a31515>&#34;</span> -gt 0 ]]; <span style=color:#00f>then</span>
71</span></span><span style=display:flex><span> showcolors $1
72</span></span><span style=display:flex><span> <span style=color:#00f>else</span>
73</span></span><span style=display:flex><span> echo $max
74</span></span><span style=display:flex><span> <span style=color:#00f>fi</span>
75</span></span><span style=display:flex><span> ;;
76</span></span><span style=display:flex><span><span style=color:#00f>esac</span> | less --raw-control-chars --QUIT-AT-EOF --no-init
77</span></span></code></pre></div></article></main><section><hr><h2>Posts from blogs I follow around the net</h2><ul><li><a href=https://utcc.utoronto.ca/~cks/space/blog/linux/NFSv4ServerLockClients target=_blank rel=noopener>Finding which NFSv4 client owns a lock on a Linux NFS(v4) server</a> — <a href=https://utcc.utoronto.ca/~cks/space/blog/>Chris's Wiki :: blog</a><div>A while back I wrote an entry about finding which NFS client owns
78a lock on a Linux NFS server, which turned
79out to be specific to NFS v3 (which I really should have seen coming,
80since it involved NLM and lockd). Finding the NFS v4 client that
81owns a lock is, depending on your perspective, either simpl…<li><a href=http://www.landley.net/notes-2023.html#28-10-2023 target=_blank rel=noopener>October 28, 2023</a> — <a href=http://www.landley.net/notes-2023.html>Rob Landley's Blog Thing for 2023</a><div>Oh good grief, two of my least favorite licensing people, Larry Rosen
82and Bradley Kuhn, are interacting on the OSI's license-discuss
83list where the're doing
84bad computer history and insisting that a guy Larry Rosen
85coincidentally interviewed for a book years ago is clearly the origin of
86somethin…<li><a href="http://offbeatpursuit.com:80/blog/?id=25" target=_blank rel=noopener>A fix by any other name</a> — <a href=http://offbeatpursuit.com:80/blog/>WLOG - blog</a><div>tags:
87i2c, plan9
88Another month, another file system.
89Well, if you can’t fix it in software, fix it in hardware (looking at
90you, bme680, we’re not
91done yet). The show must go on, as they say, and I would like my
92experiments to go on.
93So a “new” addition to the environmental sensor family connected to
94the h…<li><a href=https://mirzapandzo.com/next-image-url-parameter-is-valid-but-upstream-response-is-invalid target=_blank rel=noopener>Next/Image "url" parameter is valid but upstream response is invalid</a> — <a href=https://mirzapandzo.com/>Mirza Pandzo's Blog</a><div>Getting "url" parameter is valid but upstream response is invalid error with Next/Image on WSL2<li><a href=https://drewdevault.com/2023/10/13/Going-off-script.html target=_blank rel=noopener>Going off-script</a> — <a href=https://drewdevault.com>Drew DeVault's blog</a><div>There is a phenomenon in society which I find quite bizarre. Upon our entry to
95this mortal coil, we are endowed with self-awareness, agency, and free will.
96Each of the 8 billion members of this human race represents a unique person, a
97unique worldview, and a unique agency. Yet, many of us have the sam…<li><a href=https://szymonkaliski.com/writing/2023-10-02-building-a-diy-pen-plotter/ target=_blank rel=noopener>Building a DIY Pen Plotter</a> — <a href=http://github.com/dylang/node-rss>Szymon Kaliski</a><div>This article documents my learnings from designing and building a DIY Pen Plotter during the summer of 2023.
98My ultimate goal is to build my…<li><a href=https://neil.computer/notes/chart-of-accounts-for-startups-and-saas-companies/ target=_blank rel=noopener>Chart of Accounts for Startups and SaaS Companies</a> — <a href=https://neil.computer/>Neil Panchal</a><div>Accounting is fundamental to starting a business. You need to have a basic understanding of accounting principles and essential bookkeeping. I had to learn it. There was no choice. For filing taxes, your CPA is going to ask you for an Income Statement (also known as P/L statement). If<li><a href=https://journal.valeriansaliou.name/deploy-a-nomad-cluster-on-alpine-linux-with-vultr/ target=_blank rel=noopener>Deploy a Nomad Cluster on Alpine Linux with Vultr</a> — <a href=https://journal.valeriansaliou.name/>Valerian Saliou</a><div>After spending countless hours trying to understand how to deploy my apps on Kubernetes for the first time to host Mirage, an AI API service that I run, I ended up making myself a promise that the next app I work on would be using a more productive & simpler<li><a href=https://jcs.org/2023/10/25/wifi_da target=_blank rel=noopener>BlueSCSI Wi-Fi Desk Accessory 1.0 Released</a> — <a href=https://jcs.org/>joshua stein</a><div>BlueSCSI Wi-Fi Desk Accessory
991.0 has been released:
100wifi_da-1.0.sit
101(StuffIt 3 archive)
102SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a
103This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for
104classic MacOS.<li><a href=https://michael.stapelberg.ch/posts/2023-10-25-my-all-flash-zfs-network-storage-build/ target=_blank rel=noopener>My 2023 all-flash ZFS NAS (Network Storage) build</a> — <a href=https://michael.stapelberg.ch/>Michael Stapelbergs Website</a><div>For over 10 years now, I run two self-built NAS (Network Storage) devices which serve media (currently via Jellyfin) and run daily backups of all my PCs and servers.
105In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up.
106Design Goals
107I use my netw…</ul><p>Generated with <a href=https://git.sr.ht/~sircmpwn/openring target=_blank rel=noopener>openring</a>.</section><footer><hr><p><big><strong>Want to comment or have something to add?</strong></big><p>You can write me an email
108at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or
109catch up with me <a href=https://telegram.me/mitjafelicijan target=_blank>on Telegram</a>.<hr><p>This website does not track you. Content is made available under the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless
110specified otherwise. Blog is also available as <a href=/index.xml target=_blank>RSS feed</a>.</footer><script>
111 window.va = window.va || function () { (window.vaq = window.vaq || []).push(arguments); };
112 </script><script defer src=/_vercel/insights/script.js></script> \ No newline at end of file
diff --git a/shell.nix b/shell.nix
deleted file mode 100644
index 18d6c87..0000000
--- a/shell.nix
+++ /dev/null
@@ -1,6 +0,0 @@
1{ pkgs ? import <nixpkgs> {} }:
2 pkgs.mkShell {
3 nativeBuildInputs = with pkgs.buildPackages; [
4 go
5 ];
6}
diff --git a/static/general/9front-cursor.png b/static/general/9front-cursor.png
deleted file mode 100644
index 1448a32..0000000
--- a/static/general/9front-cursor.png
+++ /dev/null
Binary files differ
diff --git a/static/general/9logo.png b/static/general/9logo.png
deleted file mode 100644
index b6a8f7c..0000000
--- a/static/general/9logo.png
+++ /dev/null
Binary files differ
diff --git a/static/general/alert-dark.svg b/static/general/alert-dark.svg
deleted file mode 100755
index d453564..0000000
--- a/static/general/alert-dark.svg
+++ /dev/null
@@ -1,99 +0,0 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
3
4<svg
5 xmlns:dc="http://purl.org/dc/elements/1.1/"
6 xmlns:cc="http://creativecommons.org/ns#"
7 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
8 xmlns:svg="http://www.w3.org/2000/svg"
9 xmlns="http://www.w3.org/2000/svg"
10 xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
11 xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
12 version="1.1"
13 id="Layer_1"
14 x="0px"
15 y="0px"
16 viewBox="0 0 492.804 492.804"
17 style="enable-background:new 0 0 492.804 492.804;"
18 xml:space="preserve"
19 sodipodi:docname="alert.svg"
20 inkscape:version="0.92.4 (5da689c313, 2019-01-14)"><metadata
21 id="metadata43"><rdf:RDF><cc:Work
22 rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
23 rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
24 id="defs41" /><sodipodi:namedview
25 pagecolor="#ffffff"
26 bordercolor="#666666"
27 borderopacity="1"
28 objecttolerance="10"
29 gridtolerance="10"
30 guidetolerance="10"
31 inkscape:pageopacity="0"
32 inkscape:pageshadow="2"
33 inkscape:window-width="782"
34 inkscape:window-height="480"
35 id="namedview39"
36 showgrid="false"
37 inkscape:zoom="0.47889223"
38 inkscape:cx="246.40199"
39 inkscape:cy="246.40199"
40 inkscape:window-x="1970"
41 inkscape:window-y="125"
42 inkscape:window-maximized="0"
43 inkscape:current-layer="g4" />
44<g
45 id="g6">
46 <g
47 id="g4">
48 <path
49 d="M482.592,381.614L288.863,69.966c-11.22-18.044-26.348-27.96-42.656-27.96c-16.32,0-31.456,9.924-42.672,27.976 L10.267,381.142c-11.216,18.04-13.316,35.268-5.94,48.564c7.432,13.38,23.36,20.728,44.864,20.752l394.608,0.3h-0.336v0.04 c19.272,0,37.56-7.316,44.984-20.652C495.824,416.89,493.808,399.666,482.592,381.614z M256.96,388.59 c-2.868,2.86-6.736,4.484-10.792,4.484c-4.048,0-7.988-1.64-10.868-4.5c-2.856-2.86-4.476-6.852-4.472-10.932 c0.008-4.056,0.956-8.024,3.82-10.86c2.924-2.888,5.404-4.54,9.26-4.54l0.72-0.008c4.04,0,8.84,1.66,11.744,4.564 c2.872,2.856,4.932,6.812,4.924,10.876C261.292,381.762,259.852,385.742,256.96,388.59z M246.216,331.398 c-4.12,0-7.94-1.6-10.852-4.512c-2.912-2.916-4.488-6.792-4.484-10.92l-1.616-139.068c0.016-8.512,5.972-15.416,13.684-15.416 h1.772c4.124,0,8.88,1.604,11.788,4.52c2.916,2.92,4.932,6.788,4.928,10.916l0.1,139.068 C261.528,324.482,254.724,331.398,246.216,331.398z"
50 id="path2"
51 style="fill:#ffffff" />
52 </g>
53</g>
54<g
55 id="g8">
56</g>
57<g
58 id="g10">
59</g>
60<g
61 id="g12">
62</g>
63<g
64 id="g14">
65</g>
66<g
67 id="g16">
68</g>
69<g
70 id="g18">
71</g>
72<g
73 id="g20">
74</g>
75<g
76 id="g22">
77</g>
78<g
79 id="g24">
80</g>
81<g
82 id="g26">
83</g>
84<g
85 id="g28">
86</g>
87<g
88 id="g30">
89</g>
90<g
91 id="g32">
92</g>
93<g
94 id="g34">
95</g>
96<g
97 id="g36">
98</g>
99</svg>
diff --git a/static/general/alert-light.svg b/static/general/alert-light.svg
deleted file mode 100755
index 86658ec..0000000
--- a/static/general/alert-light.svg
+++ /dev/null
@@ -1,99 +0,0 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
3
4<svg
5 xmlns:dc="http://purl.org/dc/elements/1.1/"
6 xmlns:cc="http://creativecommons.org/ns#"
7 xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
8 xmlns:svg="http://www.w3.org/2000/svg"
9 xmlns="http://www.w3.org/2000/svg"
10 xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
11 xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
12 version="1.1"
13 id="Layer_1"
14 x="0px"
15 y="0px"
16 viewBox="0 0 492.804 492.804"
17 style="enable-background:new 0 0 492.804 492.804;"
18 xml:space="preserve"
19 sodipodi:docname="alert.svg"
20 inkscape:version="0.92.4 (5da689c313, 2019-01-14)"><metadata
21 id="metadata43"><rdf:RDF><cc:Work
22 rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
23 rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
24 id="defs41" /><sodipodi:namedview
25 pagecolor="#ffffff"
26 bordercolor="#666666"
27 borderopacity="1"
28 objecttolerance="10"
29 gridtolerance="10"
30 guidetolerance="10"
31 inkscape:pageopacity="0"
32 inkscape:pageshadow="2"
33 inkscape:window-width="782"
34 inkscape:window-height="480"
35 id="namedview39"
36 showgrid="false"
37 inkscape:zoom="0.47889223"
38 inkscape:cx="246.40199"
39 inkscape:cy="246.40199"
40 inkscape:window-x="1970"
41 inkscape:window-y="125"
42 inkscape:window-maximized="0"
43 inkscape:current-layer="g4" />
44<g
45 id="g6">
46 <g
47 id="g4">
48 <path
49 d="M482.592,381.614L288.863,69.966c-11.22-18.044-26.348-27.96-42.656-27.96c-16.32,0-31.456,9.924-42.672,27.976 L10.267,381.142c-11.216,18.04-13.316,35.268-5.94,48.564c7.432,13.38,23.36,20.728,44.864,20.752l394.608,0.3h-0.336v0.04 c19.272,0,37.56-7.316,44.984-20.652C495.824,416.89,493.808,399.666,482.592,381.614z M256.96,388.59 c-2.868,2.86-6.736,4.484-10.792,4.484c-4.048,0-7.988-1.64-10.868-4.5c-2.856-2.86-4.476-6.852-4.472-10.932 c0.008-4.056,0.956-8.024,3.82-10.86c2.924-2.888,5.404-4.54,9.26-4.54l0.72-0.008c4.04,0,8.84,1.66,11.744,4.564 c2.872,2.856,4.932,6.812,4.924,10.876C261.292,381.762,259.852,385.742,256.96,388.59z M246.216,331.398 c-4.12,0-7.94-1.6-10.852-4.512c-2.912-2.916-4.488-6.792-4.484-10.92l-1.616-139.068c0.016-8.512,5.972-15.416,13.684-15.416 h1.772c4.124,0,8.88,1.604,11.788,4.52c2.916,2.92,4.932,6.788,4.928,10.916l0.1,139.068 C261.528,324.482,254.724,331.398,246.216,331.398z"
50 id="path2"
51 style="fill:#000000" />
52 </g>
53</g>
54<g
55 id="g8">
56</g>
57<g
58 id="g10">
59</g>
60<g
61 id="g12">
62</g>
63<g
64 id="g14">
65</g>
66<g
67 id="g16">
68</g>
69<g
70 id="g18">
71</g>
72<g
73 id="g20">
74</g>
75<g
76 id="g22">
77</g>
78<g
79 id="g24">
80</g>
81<g
82 id="g26">
83</g>
84<g
85 id="g28">
86</g>
87<g
88 id="g30">
89</g>
90<g
91 id="g32">
92</g>
93<g
94 id="g34">
95</g>
96<g
97 id="g36">
98</g>
99</svg> \ No newline at end of file
diff --git a/static/general/index.css b/static/general/index.css
deleted file mode 100644
index d9014f7..0000000
--- a/static/general/index.css
+++ /dev/null
@@ -1 +0,0 @@
1/*! tailwindcss v3.3.2 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:""}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.mx-auto{margin-left:auto;margin-right:auto}.my-12{margin-top:3rem;margin-bottom:3rem}.mb-1{margin-bottom:.25rem}.mb-10{margin-bottom:2.5rem}.mb-12{margin-bottom:3rem}.mb-2{margin-bottom:.5rem}.mb-4{margin-bottom:1rem}.mb-5{margin-bottom:1.25rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.mr-2{margin-right:.5rem}.mt-4{margin-top:1rem}.mt-6{margin-top:1.5rem}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.inline-flex{display:inline-flex}.grid{display:grid}.contents{display:contents}.hidden{display:none}.h-3{height:.75rem}.h-6{height:1.5rem}.h-full{height:100%}.w-3{width:.75rem}.w-6{width:1.5rem}.w-full{width:100%}.flex-grow{flex-grow:1}.cursor-pointer{cursor:pointer}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.items-center{align-items:center}.gap-1{gap:.25rem}.gap-10{gap:2.5rem}.gap-2{gap:.5rem}.gap-4{gap:1rem}.rounded{border-radius:.25rem}.border{border-width:1px}.border-0{border-width:0}.border-2{border-width:2px}.border-gray-100{--tw-border-opacity:1;border-color:rgb(243 244 246/var(--tw-border-opacity))}.border-gray-200{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.bg-orange-600{--tw-bg-opacity:1;background-color:rgb(234 88 12/var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-yellow-200{--tw-bg-opacity:1;background-color:rgb(254 240 138/var(--tw-bg-opacity))}.p-2{padding:.5rem}.p-4{padding:1rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-1\.5{padding-left:.375rem;padding-right:.375rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-1{padding-top:.25rem;padding-bottom:.25rem}.py-2{padding-top:.5rem;padding-bottom:.5rem}.py-4{padding-top:1rem;padding-bottom:1rem}.pb-16{padding-bottom:4rem}.text-2xl{font-size:1.5rem;line-height:2rem}.text-4xl{font-size:2.25rem;line-height:2.5rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-xs{font-size:.75rem;line-height:1rem}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-semibold{font-weight:600}.uppercase{text-transform:uppercase}.italic{font-style:italic}.leading-relaxed{line-height:1.625}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity))}.text-gray-800{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.underline{text-decoration-line:underline}.no-underline{text-decoration-line:none}.underline-offset-2{text-underline-offset:2px}.shadow-md{--tw-shadow:0 4px 6px -1px #0000001a,0 2px 4px -2px #0000001a;--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.outline-none{outline:2px solid #0000;outline-offset:2px}*{cursor:url(/general/9front-cursor.png),auto}.container-blog{max-width:740px}::selection{--tw-bg-opacity:1;background-color:rgb(254 240 138/var(--tw-bg-opacity));--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity))}::-moz-selection{--tw-bg-opacity:1;background-color:rgb(254 240 138/var(--tw-bg-opacity));--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity))}.blue,a:hover{color:blue}article.single h2{margin-bottom:2rem}article.single h2,article.single.note h2{margin-top:2rem;font-size:1.5rem;line-height:2rem;font-weight:700;line-height:1.25}article.single.note h2{margin-bottom:.25rem}article.single h3{font-size:1.25rem}article.single h3,article.single h4{margin-bottom:1rem;margin-top:2rem;line-height:1.75rem;font-weight:700;line-height:1.25}article.single h4{font-size:1.125rem}article.single p{margin-bottom:1.25rem}article.single a{text-decoration-line:underline;text-underline-offset:2px}article.single .content blockquote{background-image:url(/general/alert-light.svg);background-size:30px 30px;background-repeat:no-repeat;background-position:0 5px;margin-top:2rem;margin-bottom:2rem;padding-left:3rem}article.single .content blockquote p{margin-bottom:.5rem}article.single figure{margin-top:2rem;margin-bottom:2rem}article.single figure figcaption{margin-top:.25rem;text-align:center;font-style:italic}article.single img{image-rendering:crisp-edges;image-rendering:-webkit-optimize-contrast}article.single img,article.single video{width:100%;border-radius:.25rem;--tw-bg-opacity:1!important;background-color:rgb(249 250 251/var(--tw-bg-opacity))!important}article.single audio{margin-bottom:1.5rem;width:100%}article.single code{background-color:rgb(254 240 138/var(--tw-bg-opacity))}article.single code,article.single.note code{border-radius:.25rem;--tw-bg-opacity:1;padding:.25rem .5rem;font-size:.75rem;line-height:1rem;font-weight:500}article.single.note code{background-color:rgb(243 244 246/var(--tw-bg-opacity))}article.single pre{margin-bottom:1.5rem;overflow-x:auto;border-radius:.25rem;--tw-bg-opacity:1!important;background-color:rgb(249 250 251/var(--tw-bg-opacity))!important;padding:1rem;font-size:.75rem;line-height:1rem}article.single pre code,article.single.note pre code{background:unset;padding:unset;line-height:1.625}article.single table{margin-bottom:1rem;width:100%;border-collapse:collapse;border-width:1px;--tw-border-opacity:1;border-color:rgb(0 0 0/var(--tw-border-opacity))}article.single table td,article.single table th,article.single table tr{border-width:1px;padding:.5rem 1rem;text-align:left}article.single .content ul{margin-bottom:1.5rem;list-style-type:disc;padding-left:1.5rem}@media (min-width:768px){article.single .content ul{padding-left:2.5rem}}article.single .content ol{margin-bottom:1.5rem;list-style-type:decimal;padding-left:2rem}@media (min-width:768px){article.single .content ol{padding-left:2.5rem}}article.single #TableOfContents{margin-bottom:2.5rem;margin-left:1rem;line-height:1.625}article.single #TableOfContents ul{list-style-type:decimal;padding-left:1rem}@media (min-width:768px){article.single #TableOfContents ul{padding-left:1.5rem}}article.single .content ul ul{margin-bottom:auto}article.single .katex-display{margin-top:2.5rem;margin-bottom:2.5rem}article.single .ll-iframe{border-radius:.25rem;--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}article.single .ll-iframe:before{display:flex;height:100%}@keyframes pulse{50%{opacity:.5}}article.single .ll-iframe:before{animation:pulse 2s cubic-bezier(.4,0,.6,1) infinite;cursor:pointer;align-items:center;justify-content:center;border-radius:.25rem;border-width:2px;--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity));font-size:.875rem;line-height:1.25rem;font-weight:500;content:"Click here to load resource…"}article.single .ll-iframe.empty:before{content:none}.hover\:cursor-pointer:hover{cursor:pointer}.hover\:bg-gray-100:hover{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.hover\:bg-gray-200:hover{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.hover\:bg-yellow-200:hover{--tw-bg-opacity:1;background-color:rgb(254 240 138/var(--tw-bg-opacity))}.hover\:text-gray-800:hover{--tw-text-opacity:1;color:rgb(31 41 55/var(--tw-text-opacity))}.hover\:underline:hover{text-decoration-line:underline}@media (min-width:768px){.md\:mb-0{margin-bottom:0}.md\:block{display:block}.md\:inline-block{display:inline-block}.md\:w-40{width:10rem}.md\:w-auto{width:auto}.md\:grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:flex-row{flex-direction:row}.md\:gap-0{gap:0}.md\:border{border-width:1px}.md\:border-b{border-bottom-width:1px}.md\:p-0{padding:0}.md\:p-3{padding:.75rem}.md\:hover\:bg-yellow-200:hover{--tw-bg-opacity:1;background-color:rgb(254 240 138/var(--tw-bg-opacity))}}@media (min-width:1024px){.lg\:block{display:block}} \ No newline at end of file
diff --git a/static/general/og-big.jpg b/static/general/og-big.jpg
deleted file mode 100644
index da8273b..0000000
--- a/static/general/og-big.jpg
+++ /dev/null
Binary files differ
diff --git a/static/general/og-big.xcf b/static/general/og-big.xcf
deleted file mode 100644
index ae0b007..0000000
--- a/static/general/og-big.xcf
+++ /dev/null
Binary files differ
diff --git a/static/general/og.jpg b/static/general/og.jpg
deleted file mode 100644
index 132f62d..0000000
--- a/static/general/og.jpg
+++ /dev/null
Binary files differ
diff --git a/static/general/og.xcf b/static/general/og.xcf
deleted file mode 100644
index 0572715..0000000
--- a/static/general/og.xcf
+++ /dev/null
Binary files differ
diff --git a/static/mitjafelicijan.pgp.pub.txt b/static/mitjafelicijan.pgp.pub.txt
deleted file mode 100644
index ee10621..0000000
--- a/static/mitjafelicijan.pgp.pub.txt
+++ /dev/null
@@ -1,41 +0,0 @@
1-----BEGIN PGP PUBLIC KEY BLOCK-----
2
3mQGNBGU+WGUBDADCwsBTgAEN8WGHQtLd+j3CMHCmzFOVZJeZ6MvRx3BgJvemKYO4
4hNLyLpvJFk0XaeomFL4VdPvY6/awIagWgQo43hDVJYemi86c0RYMKxX7lJOldyrM
5hS/hkwILXWYrUJGWIbulWN6Q66PqMNAMrFKrDAtJv2/g5ykN4U8NRWg2GHC8j2dD
6ULPmLncbtdmnUm5/+ah7HqUIXzAZkb65h3Sswr0Si6EpzQd2dASfZIECNd+2VO4j
7+iqnnt0k7ELvCoqz+vbUaK22r2D24BQ9GpZ9SvncWtqZjjtje+RV/VY8WlqLxZN2
8ZxMo1lx1Fj2ZijvJEg9SrBRVRj2Hi6AnJSwfREv/447I30+KfJeXWeMbDxdZneoY
9VH+3LhO6/aVr06Ezy9grSFYuZshIQfBqklA7/wcOhwfrNfKL9IWiEbQRVA1YrpWk
10h9EZSchTp8OK8ZYeb82SzJy9WmnNNCZTT6TN7rpG1lNYmIeoOoL1myoACeQD7FFO
11fPNwWkl7zLlkS28AEQEAAbQrTWl0amEgRmVsaWNpamFuIDxtaXRqYS5mZWxpY2lq
12YW5AZ21haWwuY29tPokB0QQTAQgAOxYhBOWRfEBxolPeoI30PkgS32rvgtmXBQJl
13PlhlAhsDBQsJCAcCAiICBhUKCQgLAgQWAgMBAh4HAheAAAoJEEgS32rvgtmXxGoM
14AIr5Ij9dcoi41e7ChY1H8ioPxTcqUrcsJJK1Ls+X+/oCbk+fUUgmDb1ZFoFm9e0/
15C+48TpmBNixjpRoOh3hXxzBbQd8aOYjeZvKATxYtErLEKHz+LIw6G8gnBilrvqvv
16JP2JfhERqTpW1GJlAVRwEPBSQFMbPc8a1WZbrHaciJ2aj2GiTEaDkl5Ft805Vom7
17MkcbrD6Tv2Aaq0VTtFnBX1d8dartHln2LpK7gpgSeaJIkJq+FBUQ7S8k2IaMvXOG
18G8ktNrwrYAC1bUgfyXHMdTTHPIH2TxnxCrNCMi9pT9G96W1P5ZlAcDQR9BnuQ7uf
19oFcUCErAuKLPL3ajTw0Rj+pNyEY+o5bG9VSo7U35u+9suSbDiYVmoL4vWPffm6MP
202Fk4OQq9wNbP5IUl9LN2nUYQJ2BXXjI+JzjwAT0xBD/+/FUCgTUcgGVdsJBpfOeS
21VEfu4VanYCVI9D9zGhLjDuz0zxzg7jufo13dwjSux2C6qSMm+2+frTsccrn7ZLks
22YLkBjQRlPlhlAQwAwjn+MXMOxk4ANP1TLPE+q05thOdvbmxfp6e6jqOmCFGbpHx/
23OTYRQ3OUTpovj5SXehhKTnDV6B1FWT9AvwhXjWhNv8NAfaF7xGrgbARb5ecHePak
24uVi1l4SXTTaYG6A5U2Sw53fhraaanlH0j3DIBON2B3lvQ464vHbMmxangWEijueN
2512Me6Jl8gWaoEzxdv+KkTxbwkjyq/yxotdl48aNHczmV8RLKnnIQuQ5VG2aFwGpJ
2691fKFUhsALd/o5lb3A6duzBBAnsCipAio6Ukwo0FnYR8GzkTpED69wmGQ/apLv4d
27WP8Y7GAzxElHaKWSaWSRm9EYEgvjSWhUZLgZpr0ZX60AkHnjQMPJiXUkWdh/XxNH
28OOTLf4MrUAxOv8iSvmq/iWll3AOJzIGCsho9vjjJ8LG6ZcTvHa1CY6XH5L6NlTFF
29UGwJ9x6Rx8o7kpOlbUABwjEfUR2OXeJYQcslZ13IfwbZfVtSbmn9HsacEls5Uahw
30+J/nRleeR7JQQeHdABEBAAGJAbYEGAEIACAWIQTlkXxAcaJT3qCN9D5IEt9q74LZ
31lwUCZT5YZQIbDAAKCRBIEt9q74LZl+gGDACN6JhNnwWO1q9Mu16Z8R/28jEO7vua
32kXFV5/38k57qzLe5wFvcynfrnZzwomgrAm9RNuaUaG7gDPllAWPPRYvtMQSY3VJX
33oLzZje8kWNDL7al9shMKy4suFBxU2EaKYf2m2SO4nk+J6d3qKl6oxr+9Rthx4M6r
34s+7Jq4UYZ0qsGW7kc62dnDYtzG8kzFvFspUCpzEXyGEAoT4jBPYfqImlKw09lBEN
35KvB55zc58X3NCIl39cpENsL1eoPRETB6h0oCOqQL4gDjUea/ipOmrPidahF89xsL
36vILB/RvxawjhWvS0pYfeHJ6hSjc1lEGYFrQdaCq0nFI2LfZ1PHUIOVcRVHI1LfT4
37q8CJ09O8zQwLG24Ny0PpEkADsSPqnry4gz86mzQu/fI+bDQuoig/HMRO+Q1HPD/x
38S9xiNmEDXniGLU9kusSNBQG5oZwFnCEkkW9HAsRVtqtkL9SjYBPug3IzlgNqBU5M
39IBuToBH0bKUHmWLaHUffu2H5hDrKfC3fF/Y=
40=/NqR
41-----END PGP PUBLIC KEY BLOCK-----
diff --git a/static/notes/10gui-10-finger-multitouch-user-interface.jpg b/static/notes/10gui-10-finger-multitouch-user-interface.jpg
deleted file mode 100644
index 270b4ea..0000000
--- a/static/notes/10gui-10-finger-multitouch-user-interface.jpg
+++ /dev/null
Binary files differ
diff --git a/static/notes/10gui-10-finger-multitouch-user-interface.mp4 b/static/notes/10gui-10-finger-multitouch-user-interface.mp4
deleted file mode 100644
index 8afdbf8..0000000
--- a/static/notes/10gui-10-finger-multitouch-user-interface.mp4
+++ /dev/null
Binary files differ
diff --git a/static/notes/60s-ibm-computers-commercial.jpg b/static/notes/60s-ibm-computers-commercial.jpg
deleted file mode 100644
index 1d49e93..0000000
--- a/static/notes/60s-ibm-computers-commercial.jpg
+++ /dev/null
Binary files differ
diff --git a/static/notes/60s-ibm-computers-commercial.mp4 b/static/notes/60s-ibm-computers-commercial.mp4
deleted file mode 100644
index 9ff1567..0000000
--- a/static/notes/60s-ibm-computers-commercial.mp4
+++ /dev/null
Binary files differ
diff --git a/static/notes/9front-desktop.png b/static/notes/9front-desktop.png
deleted file mode 100644
index 3a0964b..0000000
--- a/static/notes/9front-desktop.png
+++ /dev/null
Binary files differ
diff --git a/static/notes/dcss-quickstart.pdf b/static/notes/dcss-quickstart.pdf
deleted file mode 100644
index 1b70615..0000000
--- a/static/notes/dcss-quickstart.pdf
+++ /dev/null
Binary files differ
diff --git a/static/notes/dcss.jpg b/static/notes/dcss.jpg
deleted file mode 100644
index ffe7c6a..0000000
--- a/static/notes/dcss.jpg
+++ /dev/null
Binary files differ
diff --git a/static/notes/dcss_manual.pdf b/static/notes/dcss_manual.pdf
deleted file mode 100644
index 03cafd2..0000000
--- a/static/notes/dcss_manual.pdf
+++ /dev/null
Binary files differ
diff --git a/static/notes/floods/IMG_1461.mp4 b/static/notes/floods/IMG_1461.mp4
deleted file mode 100755
index 6b7f325..0000000
--- a/static/notes/floods/IMG_1461.mp4
+++ /dev/null
Binary files differ
diff --git a/static/notes/floods/IMG_1466.mp4 b/static/notes/floods/IMG_1466.mp4
deleted file mode 100755
index f15cdb9..0000000
--- a/static/notes/floods/IMG_1466.mp4
+++ /dev/null
Binary files differ
diff --git a/static/notes/floods/IMG_1469.webp b/static/notes/floods/IMG_1469.webp
deleted file mode 100755
index b668039..0000000
--- a/static/notes/floods/IMG_1469.webp
+++ /dev/null
Binary files differ
diff --git a/static/notes/floods/IMG_1470.webp b/static/notes/floods/IMG_1470.webp
deleted file mode 100755
index 74496ba..0000000
--- a/static/notes/floods/IMG_1470.webp
+++ /dev/null
Binary files differ
diff --git a/static/notes/floods/IMG_1471.mp4 b/static/notes/floods/IMG_1471.mp4
deleted file mode 100755
index ac7f8b5..0000000
--- a/static/notes/floods/IMG_1471.mp4
+++ /dev/null
Binary files differ
diff --git a/static/notes/floods/IMG_1474.mp4 b/static/notes/floods/IMG_1474.mp4
deleted file mode 100755
index e1018d0..0000000
--- a/static/notes/floods/IMG_1474.mp4
+++ /dev/null
Binary files differ
diff --git a/static/notes/grep-less.png b/static/notes/grep-less.png
deleted file mode 100644
index f69a935..0000000
--- a/static/notes/grep-less.png
+++ /dev/null
Binary files differ
diff --git a/static/notes/plan9-pixels.png b/static/notes/plan9-pixels.png
deleted file mode 100644
index 536dd82..0000000
--- a/static/notes/plan9-pixels.png
+++ /dev/null
Binary files differ
diff --git a/static/notes/plot.svg b/static/notes/plot.svg
deleted file mode 100644
index f7cc7a4..0000000
--- a/static/notes/plot.svg
+++ /dev/null
@@ -1,1546 +0,0 @@
1<?xml version="1.0" encoding="utf-8" standalone="no"?>
2<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
3 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4<svg xmlns:xlink="http://www.w3.org/1999/xlink" width="720pt" height="288pt" viewBox="0 0 720 288" xmlns="http://www.w3.org/2000/svg" version="1.1">
5 <metadata>
6 <rdf:RDF xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
7 <cc:Work>
8 <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
9 <dc:date>2023-08-01T13:35:35.032079</dc:date>
10 <dc:format>image/svg+xml</dc:format>
11 <dc:creator>
12 <cc:Agent>
13 <dc:title>Matplotlib v3.7.2, https://matplotlib.org/</dc:title>
14 </cc:Agent>
15 </dc:creator>
16 </cc:Work>
17 </rdf:RDF>
18 </metadata>
19 <defs>
20 <style type="text/css">*{stroke-linejoin: round; stroke-linecap: butt}</style>
21 </defs>
22 <g id="figure_1">
23 <g id="patch_1">
24 <path d="M 0 288
25L 720 288
26L 720 0
27L 0 0
28z
29" style="fill: #ffffff"/>
30 </g>
31 <g id="axes_1">
32 <g id="patch_2">
33 <path d="M 90 256.32
34L 648 256.32
35L 648 34.56
36L 90 34.56
37z
38" style="fill: #ffffff"/>
39 </g>
40 <g id="matplotlib.axis_1">
41 <g id="xtick_1">
42 <g id="line2d_1">
43 <defs>
44 <path id="m9d8e166088" d="M 0 0
45L 0 3.5
46" style="stroke: #000000; stroke-width: 0.8"/>
47 </defs>
48 <g>
49 <use xlink:href="#m9d8e166088" x="110.239669" y="256.32" style="stroke: #000000; stroke-width: 0.8"/>
50 </g>
51 </g>
52 <g id="text_1">
53 <!-- 0 -->
54 <g transform="translate(107.058419 270.918437) scale(0.1 -0.1)">
55 <defs>
56 <path id="DejaVuSans-30" d="M 2034 4250
57Q 1547 4250 1301 3770
58Q 1056 3291 1056 2328
59Q 1056 1369 1301 889
60Q 1547 409 2034 409
61Q 2525 409 2770 889
62Q 3016 1369 3016 2328
63Q 3016 3291 2770 3770
64Q 2525 4250 2034 4250
65z
66M 2034 4750
67Q 2819 4750 3233 4129
68Q 3647 3509 3647 2328
69Q 3647 1150 3233 529
70Q 2819 -91 2034 -91
71Q 1250 -91 836 529
72Q 422 1150 422 2328
73Q 422 3509 836 4129
74Q 1250 4750 2034 4750
75z
76" transform="scale(0.015625)"/>
77 </defs>
78 <use xlink:href="#DejaVuSans-30"/>
79 </g>
80 </g>
81 </g>
82 <g id="xtick_2">
83 <g id="line2d_2">
84 <g>
85 <use xlink:href="#m9d8e166088" x="212.719008" y="256.32" style="stroke: #000000; stroke-width: 0.8"/>
86 </g>
87 </g>
88 <g id="text_2">
89 <!-- 20 -->
90 <g transform="translate(206.356508 270.918437) scale(0.1 -0.1)">
91 <defs>
92 <path id="DejaVuSans-32" d="M 1228 531
93L 3431 531
94L 3431 0
95L 469 0
96L 469 531
97Q 828 903 1448 1529
98Q 2069 2156 2228 2338
99Q 2531 2678 2651 2914
100Q 2772 3150 2772 3378
101Q 2772 3750 2511 3984
102Q 2250 4219 1831 4219
103Q 1534 4219 1204 4116
104Q 875 4013 500 3803
105L 500 4441
106Q 881 4594 1212 4672
107Q 1544 4750 1819 4750
108Q 2544 4750 2975 4387
109Q 3406 4025 3406 3419
110Q 3406 3131 3298 2873
111Q 3191 2616 2906 2266
112Q 2828 2175 2409 1742
113Q 1991 1309 1228 531
114z
115" transform="scale(0.015625)"/>
116 </defs>
117 <use xlink:href="#DejaVuSans-32"/>
118 <use xlink:href="#DejaVuSans-30" x="63.623047"/>
119 </g>
120 </g>
121 </g>
122 <g id="xtick_3">
123 <g id="line2d_3">
124 <g>
125 <use xlink:href="#m9d8e166088" x="315.198347" y="256.32" style="stroke: #000000; stroke-width: 0.8"/>
126 </g>
127 </g>
128 <g id="text_3">
129 <!-- 40 -->
130 <g transform="translate(308.835847 270.918437) scale(0.1 -0.1)">
131 <defs>
132 <path id="DejaVuSans-34" d="M 2419 4116
133L 825 1625
134L 2419 1625
135L 2419 4116
136z
137M 2253 4666
138L 3047 4666
139L 3047 1625
140L 3713 1625
141L 3713 1100
142L 3047 1100
143L 3047 0
144L 2419 0
145L 2419 1100
146L 313 1100
147L 313 1709
148L 2253 4666
149z
150" transform="scale(0.015625)"/>
151 </defs>
152 <use xlink:href="#DejaVuSans-34"/>
153 <use xlink:href="#DejaVuSans-30" x="63.623047"/>
154 </g>
155 </g>
156 </g>
157 <g id="xtick_4">
158 <g id="line2d_4">
159 <g>
160 <use xlink:href="#m9d8e166088" x="417.677686" y="256.32" style="stroke: #000000; stroke-width: 0.8"/>
161 </g>
162 </g>
163 <g id="text_4">
164 <!-- 60 -->
165 <g transform="translate(411.315186 270.918437) scale(0.1 -0.1)">
166 <defs>
167 <path id="DejaVuSans-36" d="M 2113 2584
168Q 1688 2584 1439 2293
169Q 1191 2003 1191 1497
170Q 1191 994 1439 701
171Q 1688 409 2113 409
172Q 2538 409 2786 701
173Q 3034 994 3034 1497
174Q 3034 2003 2786 2293
175Q 2538 2584 2113 2584
176z
177M 3366 4563
178L 3366 3988
179Q 3128 4100 2886 4159
180Q 2644 4219 2406 4219
181Q 1781 4219 1451 3797
182Q 1122 3375 1075 2522
183Q 1259 2794 1537 2939
184Q 1816 3084 2150 3084
185Q 2853 3084 3261 2657
186Q 3669 2231 3669 1497
187Q 3669 778 3244 343
188Q 2819 -91 2113 -91
189Q 1303 -91 875 529
190Q 447 1150 447 2328
191Q 447 3434 972 4092
192Q 1497 4750 2381 4750
193Q 2619 4750 2861 4703
194Q 3103 4656 3366 4563
195z
196" transform="scale(0.015625)"/>
197 </defs>
198 <use xlink:href="#DejaVuSans-36"/>
199 <use xlink:href="#DejaVuSans-30" x="63.623047"/>
200 </g>
201 </g>
202 </g>
203 <g id="xtick_5">
204 <g id="line2d_5">
205 <g>
206 <use xlink:href="#m9d8e166088" x="520.157025" y="256.32" style="stroke: #000000; stroke-width: 0.8"/>
207 </g>
208 </g>
209 <g id="text_5">
210 <!-- 80 -->
211 <g transform="translate(513.794525 270.918437) scale(0.1 -0.1)">
212 <defs>
213 <path id="DejaVuSans-38" d="M 2034 2216
214Q 1584 2216 1326 1975
215Q 1069 1734 1069 1313
216Q 1069 891 1326 650
217Q 1584 409 2034 409
218Q 2484 409 2743 651
219Q 3003 894 3003 1313
220Q 3003 1734 2745 1975
221Q 2488 2216 2034 2216
222z
223M 1403 2484
224Q 997 2584 770 2862
225Q 544 3141 544 3541
226Q 544 4100 942 4425
227Q 1341 4750 2034 4750
228Q 2731 4750 3128 4425
229Q 3525 4100 3525 3541
230Q 3525 3141 3298 2862
231Q 3072 2584 2669 2484
232Q 3125 2378 3379 2068
233Q 3634 1759 3634 1313
234Q 3634 634 3220 271
235Q 2806 -91 2034 -91
236Q 1263 -91 848 271
237Q 434 634 434 1313
238Q 434 1759 690 2068
239Q 947 2378 1403 2484
240z
241M 1172 3481
242Q 1172 3119 1398 2916
243Q 1625 2713 2034 2713
244Q 2441 2713 2670 2916
245Q 2900 3119 2900 3481
246Q 2900 3844 2670 4047
247Q 2441 4250 2034 4250
248Q 1625 4250 1398 4047
249Q 1172 3844 1172 3481
250z
251" transform="scale(0.015625)"/>
252 </defs>
253 <use xlink:href="#DejaVuSans-38"/>
254 <use xlink:href="#DejaVuSans-30" x="63.623047"/>
255 </g>
256 </g>
257 </g>
258 <g id="xtick_6">
259 <g id="line2d_6">
260 <g>
261 <use xlink:href="#m9d8e166088" x="622.636364" y="256.32" style="stroke: #000000; stroke-width: 0.8"/>
262 </g>
263 </g>
264 <g id="text_6">
265 <!-- 100 -->
266 <g transform="translate(613.092614 270.918437) scale(0.1 -0.1)">
267 <defs>
268 <path id="DejaVuSans-31" d="M 794 531
269L 1825 531
270L 1825 4091
271L 703 3866
272L 703 4441
273L 1819 4666
274L 2450 4666
275L 2450 531
276L 3481 531
277L 3481 0
278L 794 0
279L 794 531
280z
281" transform="scale(0.015625)"/>
282 </defs>
283 <use xlink:href="#DejaVuSans-31"/>
284 <use xlink:href="#DejaVuSans-30" x="63.623047"/>
285 <use xlink:href="#DejaVuSans-30" x="127.246094"/>
286 </g>
287 </g>
288 </g>
289 <g id="text_7">
290 <!-- Epoch -->
291 <g transform="translate(353.689062 284.596563) scale(0.1 -0.1)">
292 <defs>
293 <path id="DejaVuSans-Oblique-45" d="M 1081 4666
294L 4031 4666
295L 3928 4134
296L 1606 4134
297L 1338 2753
298L 3566 2753
299L 3463 2222
300L 1234 2222
301L 909 531
302L 3284 531
303L 3181 0
304L 172 0
305L 1081 4666
306z
307" transform="scale(0.015625)"/>
308 <path id="DejaVuSans-Oblique-70" d="M 3175 2156
309Q 3175 2616 2975 2859
310Q 2775 3103 2400 3103
311Q 2144 3103 1911 2972
312Q 1678 2841 1497 2591
313Q 1319 2344 1212 1994
314Q 1106 1644 1106 1300
315Q 1106 863 1306 627
316Q 1506 391 1875 391
317Q 2147 391 2380 519
318Q 2613 647 2778 891
319Q 2956 1147 3065 1494
320Q 3175 1841 3175 2156
321z
322M 1394 2969
323Q 1625 3272 1939 3428
324Q 2253 3584 2638 3584
325Q 3175 3584 3472 3232
326Q 3769 2881 3769 2247
327Q 3769 1728 3584 1258
328Q 3400 788 3053 416
329Q 2822 169 2531 39
330Q 2241 -91 1919 -91
331Q 1547 -91 1294 64
332Q 1041 219 916 525
333L 556 -1331
334L -19 -1331
335L 922 3500
336L 1497 3500
337L 1394 2969
338z
339" transform="scale(0.015625)"/>
340 <path id="DejaVuSans-Oblique-6f" d="M 1625 -91
341Q 1009 -91 651 289
342Q 294 669 294 1325
343Q 294 1706 417 2101
344Q 541 2497 738 2766
345Q 1047 3184 1428 3384
346Q 1809 3584 2291 3584
347Q 2888 3584 3255 3212
348Q 3622 2841 3622 2241
349Q 3622 1825 3500 1412
350Q 3378 1000 3181 728
351Q 2875 309 2494 109
352Q 2113 -91 1625 -91
353z
354M 891 1344
355Q 891 869 1089 633
356Q 1288 397 1691 397
357Q 2269 397 2648 901
358Q 3028 1406 3028 2181
359Q 3028 2634 2825 2865
360Q 2622 3097 2228 3097
361Q 1903 3097 1650 2945
362Q 1397 2794 1197 2484
363Q 1050 2253 970 1956
364Q 891 1659 891 1344
365z
366" transform="scale(0.015625)"/>
367 <path id="DejaVuSans-Oblique-63" d="M 3431 3366
368L 3316 2797
369Q 3109 2947 2876 3022
370Q 2644 3097 2394 3097
371Q 2119 3097 1870 3000
372Q 1622 2903 1453 2725
373Q 1184 2453 1037 2087
374Q 891 1722 891 1331
375Q 891 859 1127 628
376Q 1363 397 1844 397
377Q 2081 397 2348 469
378Q 2616 541 2906 684
379L 2797 116
380Q 2547 13 2283 -39
381Q 2019 -91 1741 -91
382Q 1044 -91 669 257
383Q 294 606 294 1253
384Q 294 1797 489 2255
385Q 684 2713 1069 3078
386Q 1331 3328 1684 3456
387Q 2038 3584 2456 3584
388Q 2700 3584 2940 3529
389Q 3181 3475 3431 3366
390z
391" transform="scale(0.015625)"/>
392 <path id="DejaVuSans-Oblique-68" d="M 3566 2113
393L 3156 0
394L 2578 0
395L 2988 2091
396Q 3016 2238 3031 2350
397Q 3047 2463 3047 2528
398Q 3047 2791 2881 2937
399Q 2716 3084 2419 3084
400Q 1956 3084 1617 2771
401Q 1278 2459 1178 1941
402L 800 0
403L 225 0
404L 1172 4863
405L 1747 4863
406L 1375 2950
407Q 1594 3244 1934 3414
408Q 2275 3584 2650 3584
409Q 3113 3584 3367 3334
410Q 3622 3084 3622 2631
411Q 3622 2519 3608 2391
412Q 3594 2263 3566 2113
413z
414" transform="scale(0.015625)"/>
415 </defs>
416 <use xlink:href="#DejaVuSans-Oblique-45"/>
417 <use xlink:href="#DejaVuSans-Oblique-70" x="63.183594"/>
418 <use xlink:href="#DejaVuSans-Oblique-6f" x="126.660156"/>
419 <use xlink:href="#DejaVuSans-Oblique-63" x="187.841797"/>
420 <use xlink:href="#DejaVuSans-Oblique-68" x="242.822266"/>
421 </g>
422 </g>
423 </g>
424 <g id="matplotlib.axis_2">
425 <g id="ytick_1">
426 <g id="line2d_7">
427 <defs>
428 <path id="m1516ce9edd" d="M 0 0
429L -3.5 0
430" style="stroke: #000000; stroke-width: 0.8"/>
431 </defs>
432 <g>
433 <use xlink:href="#m1516ce9edd" x="90" y="249.291243" style="stroke: #000000; stroke-width: 0.8"/>
434 </g>
435 </g>
436 <g id="text_8">
437 <!-- 0 -->
438 <g transform="translate(76.6375 253.090462) scale(0.1 -0.1)">
439 <use xlink:href="#DejaVuSans-30"/>
440 </g>
441 </g>
442 </g>
443 <g id="ytick_2">
444 <g id="line2d_8">
445 <g>
446 <use xlink:href="#m1516ce9edd" x="90" y="222.048" style="stroke: #000000; stroke-width: 0.8"/>
447 </g>
448 </g>
449 <g id="text_9">
450 <!-- 25 -->
451 <g transform="translate(70.275 225.847219) scale(0.1 -0.1)">
452 <defs>
453 <path id="DejaVuSans-35" d="M 691 4666
454L 3169 4666
455L 3169 4134
456L 1269 4134
457L 1269 2991
458Q 1406 3038 1543 3061
459Q 1681 3084 1819 3084
460Q 2600 3084 3056 2656
461Q 3513 2228 3513 1497
462Q 3513 744 3044 326
463Q 2575 -91 1722 -91
464Q 1428 -91 1123 -41
465Q 819 9 494 109
466L 494 744
467Q 775 591 1075 516
468Q 1375 441 1709 441
469Q 2250 441 2565 725
470Q 2881 1009 2881 1497
471Q 2881 1984 2565 2268
472Q 2250 2553 1709 2553
473Q 1456 2553 1204 2497
474Q 953 2441 691 2322
475L 691 4666
476z
477" transform="scale(0.015625)"/>
478 </defs>
479 <use xlink:href="#DejaVuSans-32"/>
480 <use xlink:href="#DejaVuSans-35" x="63.623047"/>
481 </g>
482 </g>
483 </g>
484 <g id="ytick_3">
485 <g id="line2d_9">
486 <g>
487 <use xlink:href="#m1516ce9edd" x="90" y="194.804757" style="stroke: #000000; stroke-width: 0.8"/>
488 </g>
489 </g>
490 <g id="text_10">
491 <!-- 50 -->
492 <g transform="translate(70.275 198.603976) scale(0.1 -0.1)">
493 <use xlink:href="#DejaVuSans-35"/>
494 <use xlink:href="#DejaVuSans-30" x="63.623047"/>
495 </g>
496 </g>
497 </g>
498 <g id="ytick_4">
499 <g id="line2d_10">
500 <g>
501 <use xlink:href="#m1516ce9edd" x="90" y="167.561514" style="stroke: #000000; stroke-width: 0.8"/>
502 </g>
503 </g>
504 <g id="text_11">
505 <!-- 75 -->
506 <g transform="translate(70.275 171.360732) scale(0.1 -0.1)">
507 <defs>
508 <path id="DejaVuSans-37" d="M 525 4666
509L 3525 4666
510L 3525 4397
511L 1831 0
512L 1172 0
513L 2766 4134
514L 525 4134
515L 525 4666
516z
517" transform="scale(0.015625)"/>
518 </defs>
519 <use xlink:href="#DejaVuSans-37"/>
520 <use xlink:href="#DejaVuSans-35" x="63.623047"/>
521 </g>
522 </g>
523 </g>
524 <g id="ytick_5">
525 <g id="line2d_11">
526 <g>
527 <use xlink:href="#m1516ce9edd" x="90" y="140.31827" style="stroke: #000000; stroke-width: 0.8"/>
528 </g>
529 </g>
530 <g id="text_12">
531 <!-- 100 -->
532 <g transform="translate(63.9125 144.117489) scale(0.1 -0.1)">
533 <use xlink:href="#DejaVuSans-31"/>
534 <use xlink:href="#DejaVuSans-30" x="63.623047"/>
535 <use xlink:href="#DejaVuSans-30" x="127.246094"/>
536 </g>
537 </g>
538 </g>
539 <g id="ytick_6">
540 <g id="line2d_12">
541 <g>
542 <use xlink:href="#m1516ce9edd" x="90" y="113.075027" style="stroke: #000000; stroke-width: 0.8"/>
543 </g>
544 </g>
545 <g id="text_13">
546 <!-- 125 -->
547 <g transform="translate(63.9125 116.874246) scale(0.1 -0.1)">
548 <use xlink:href="#DejaVuSans-31"/>
549 <use xlink:href="#DejaVuSans-32" x="63.623047"/>
550 <use xlink:href="#DejaVuSans-35" x="127.246094"/>
551 </g>
552 </g>
553 </g>
554 <g id="ytick_7">
555 <g id="line2d_13">
556 <g>
557 <use xlink:href="#m1516ce9edd" x="90" y="85.831784" style="stroke: #000000; stroke-width: 0.8"/>
558 </g>
559 </g>
560 <g id="text_14">
561 <!-- 150 -->
562 <g transform="translate(63.9125 89.631003) scale(0.1 -0.1)">
563 <use xlink:href="#DejaVuSans-31"/>
564 <use xlink:href="#DejaVuSans-35" x="63.623047"/>
565 <use xlink:href="#DejaVuSans-30" x="127.246094"/>
566 </g>
567 </g>
568 </g>
569 <g id="ytick_8">
570 <g id="line2d_14">
571 <g>
572 <use xlink:href="#m1516ce9edd" x="90" y="58.588541" style="stroke: #000000; stroke-width: 0.8"/>
573 </g>
574 </g>
575 <g id="text_15">
576 <!-- 175 -->
577 <g transform="translate(63.9125 62.387759) scale(0.1 -0.1)">
578 <use xlink:href="#DejaVuSans-31"/>
579 <use xlink:href="#DejaVuSans-37" x="63.623047"/>
580 <use xlink:href="#DejaVuSans-35" x="127.246094"/>
581 </g>
582 </g>
583 </g>
584 <g id="text_16">
585 <!-- Median value (ms) -->
586 <g transform="translate(57.832812 191.839219) rotate(-90) scale(0.1 -0.1)">
587 <defs>
588 <path id="DejaVuSans-Oblique-4d" d="M 1081 4666
589L 2028 4666
590L 2572 1522
591L 4378 4666
592L 5350 4666
593L 4441 0
594L 3828 0
595L 4622 4091
596L 2791 897
597L 2175 897
598L 1581 4103
599L 788 0
600L 172 0
601L 1081 4666
602z
603" transform="scale(0.015625)"/>
604 <path id="DejaVuSans-Oblique-65" d="M 3078 2063
605Q 3088 2113 3092 2166
606Q 3097 2219 3097 2272
607Q 3097 2653 2873 2875
608Q 2650 3097 2266 3097
609Q 1838 3097 1509 2826
610Q 1181 2556 1013 2059
611L 3078 2063
612z
613M 3578 1613
614L 903 1613
615Q 884 1494 878 1425
616Q 872 1356 872 1306
617Q 872 872 1139 634
618Q 1406 397 1894 397
619Q 2269 397 2603 481
620Q 2938 566 3225 728
621L 3116 159
622Q 2806 34 2476 -28
623Q 2147 -91 1806 -91
624Q 1078 -91 686 257
625Q 294 606 294 1247
626Q 294 1794 489 2264
627Q 684 2734 1063 3103
628Q 1306 3334 1642 3459
629Q 1978 3584 2356 3584
630Q 2950 3584 3301 3228
631Q 3653 2872 3653 2272
632Q 3653 2128 3634 1964
633Q 3616 1800 3578 1613
634z
635" transform="scale(0.015625)"/>
636 <path id="DejaVuSans-Oblique-64" d="M 2675 525
637Q 2444 222 2128 65
638Q 1813 -91 1428 -91
639Q 903 -91 598 267
640Q 294 625 294 1247
641Q 294 1766 478 2236
642Q 663 2706 1013 3078
643Q 1244 3325 1534 3454
644Q 1825 3584 2144 3584
645Q 2481 3584 2739 3421
646Q 2997 3259 3138 2956
647L 3513 4863
648L 4091 4863
649L 3144 0
650L 2566 0
651L 2675 525
652z
653M 891 1350
654Q 891 897 1095 644
655Q 1300 391 1663 391
656Q 1931 391 2161 520
657Q 2391 650 2566 903
658Q 2750 1166 2856 1509
659Q 2963 1853 2963 2188
660Q 2963 2622 2758 2865
661Q 2553 3109 2194 3109
662Q 1922 3109 1687 2981
663Q 1453 2853 1288 2613
664Q 1106 2353 998 2009
665Q 891 1666 891 1350
666z
667" transform="scale(0.015625)"/>
668 <path id="DejaVuSans-Oblique-69" d="M 1172 4863
669L 1747 4863
670L 1606 4134
671L 1031 4134
672L 1172 4863
673z
674M 909 3500
675L 1484 3500
676L 800 0
677L 225 0
678L 909 3500
679z
680" transform="scale(0.015625)"/>
681 <path id="DejaVuSans-Oblique-61" d="M 3438 1997
682L 3047 0
683L 2472 0
684L 2578 531
685Q 2325 219 2001 64
686Q 1678 -91 1281 -91
687Q 834 -91 548 182
688Q 263 456 263 884
689Q 263 1497 752 1853
690Q 1241 2209 2100 2209
691L 2900 2209
692L 2931 2363
693Q 2938 2388 2941 2417
694Q 2944 2447 2944 2509
695Q 2944 2788 2717 2942
696Q 2491 3097 2081 3097
697Q 1800 3097 1504 3025
698Q 1209 2953 897 2809
699L 997 3341
700Q 1322 3463 1633 3523
701Q 1944 3584 2234 3584
702Q 2853 3584 3176 3315
703Q 3500 3047 3500 2534
704Q 3500 2431 3484 2292
705Q 3469 2153 3438 1997
706z
707M 2816 1759
708L 2241 1759
709Q 1534 1759 1195 1570
710Q 856 1381 856 984
711Q 856 709 1029 553
712Q 1203 397 1509 397
713Q 1978 397 2328 733
714Q 2678 1069 2791 1631
715L 2816 1759
716z
717" transform="scale(0.015625)"/>
718 <path id="DejaVuSans-Oblique-6e" d="M 3566 2113
719L 3156 0
720L 2578 0
721L 2988 2091
722Q 3016 2238 3031 2350
723Q 3047 2463 3047 2528
724Q 3047 2791 2881 2937
725Q 2716 3084 2419 3084
726Q 1956 3084 1622 2776
727Q 1288 2469 1184 1941
728L 800 0
729L 225 0
730L 903 3500
731L 1478 3500
732L 1363 2950
733Q 1603 3253 1940 3418
734Q 2278 3584 2650 3584
735Q 3113 3584 3367 3334
736Q 3622 3084 3622 2631
737Q 3622 2519 3608 2391
738Q 3594 2263 3566 2113
739z
740" transform="scale(0.015625)"/>
741 <path id="DejaVuSans-Oblique-20" transform="scale(0.015625)"/>
742 <path id="DejaVuSans-Oblique-76" d="M 459 3500
743L 1069 3500
744L 1581 525
745L 3256 3500
746L 3866 3500
747L 1875 0
748L 1100 0
749L 459 3500
750z
751" transform="scale(0.015625)"/>
752 <path id="DejaVuSans-Oblique-6c" d="M 1172 4863
753L 1747 4863
754L 800 0
755L 225 0
756L 1172 4863
757z
758" transform="scale(0.015625)"/>
759 <path id="DejaVuSans-Oblique-75" d="M 428 1388
760L 838 3500
761L 1416 3500
762L 1006 1409
763Q 975 1256 961 1147
764Q 947 1038 947 966
765Q 947 700 1109 554
766Q 1272 409 1569 409
767Q 2031 409 2368 721
768Q 2706 1034 2809 1563
769L 3194 3500
770L 3769 3500
771L 3091 0
772L 2516 0
773L 2631 550
774Q 2388 244 2052 76
775Q 1716 -91 1338 -91
776Q 878 -91 622 161
777Q 366 413 366 863
778Q 366 956 381 1097
779Q 397 1238 428 1388
780z
781" transform="scale(0.015625)"/>
782 <path id="DejaVuSans-Oblique-28" d="M 2731 4856
783Q 1903 3822 1495 2892
784Q 1088 1963 1088 1100
785Q 1088 606 1206 120
786Q 1325 -366 1563 -844
787L 1063 -844
788Q 775 -306 634 201
789Q 494 709 494 1197
790Q 494 2125 923 3036
791Q 1353 3947 2222 4856
792L 2731 4856
793z
794" transform="scale(0.015625)"/>
795 <path id="DejaVuSans-Oblique-6d" d="M 5747 2113
796L 5338 0
797L 4763 0
798L 5166 2094
799Q 5191 2228 5203 2325
800Q 5216 2422 5216 2491
801Q 5216 2772 5059 2928
802Q 4903 3084 4622 3084
803Q 4203 3084 3875 2770
804Q 3547 2456 3450 1953
805L 3066 0
806L 2491 0
807L 2900 2094
808Q 2925 2209 2937 2307
809Q 2950 2406 2950 2484
810Q 2950 2769 2794 2926
811Q 2638 3084 2363 3084
812Q 1938 3084 1609 2770
813Q 1281 2456 1184 1953
814L 800 0
815L 225 0
816L 909 3500
817L 1484 3500
818L 1375 2956
819Q 1609 3263 1923 3423
820Q 2238 3584 2597 3584
821Q 2978 3584 3223 3384
822Q 3469 3184 3519 2828
823Q 3781 3197 4126 3390
824Q 4472 3584 4856 3584
825Q 5306 3584 5551 3325
826Q 5797 3066 5797 2591
827Q 5797 2488 5784 2364
828Q 5772 2241 5747 2113
829z
830" transform="scale(0.015625)"/>
831 <path id="DejaVuSans-Oblique-73" d="M 3200 3397
832L 3091 2853
833Q 2863 2978 2609 3040
834Q 2356 3103 2088 3103
835Q 1634 3103 1373 2948
836Q 1113 2794 1113 2528
837Q 1113 2219 1719 2053
838Q 1766 2041 1788 2034
839L 1972 1978
840Q 2547 1819 2739 1644
841Q 2931 1469 2931 1166
842Q 2931 609 2489 259
843Q 2047 -91 1331 -91
844Q 1053 -91 747 -37
845Q 441 16 72 128
846L 184 722
847Q 500 559 806 475
848Q 1113 391 1394 391
849Q 1816 391 2080 572
850Q 2344 753 2344 1031
851Q 2344 1331 1650 1516
852L 1591 1531
853L 1394 1581
854Q 956 1697 753 1886
855Q 550 2075 550 2369
856Q 550 2928 970 3256
857Q 1391 3584 2113 3584
858Q 2397 3584 2667 3537
859Q 2938 3491 3200 3397
860z
861" transform="scale(0.015625)"/>
862 <path id="DejaVuSans-Oblique-29" d="M -397 -844
863Q 434 191 840 1120
864Q 1247 2050 1247 2913
865Q 1247 3406 1130 3892
866Q 1013 4378 775 4856
867L 1275 4856
868Q 1563 4316 1703 3812
869Q 1844 3309 1844 2822
870Q 1844 1891 1411 973
871Q 978 56 116 -844
872L -397 -844
873z
874" transform="scale(0.015625)"/>
875 </defs>
876 <use xlink:href="#DejaVuSans-Oblique-4d"/>
877 <use xlink:href="#DejaVuSans-Oblique-65" x="86.279297"/>
878 <use xlink:href="#DejaVuSans-Oblique-64" x="147.802734"/>
879 <use xlink:href="#DejaVuSans-Oblique-69" x="211.279297"/>
880 <use xlink:href="#DejaVuSans-Oblique-61" x="239.0625"/>
881 <use xlink:href="#DejaVuSans-Oblique-6e" x="300.341797"/>
882 <use xlink:href="#DejaVuSans-Oblique-20" x="363.720703"/>
883 <use xlink:href="#DejaVuSans-Oblique-76" x="395.507812"/>
884 <use xlink:href="#DejaVuSans-Oblique-61" x="454.6875"/>
885 <use xlink:href="#DejaVuSans-Oblique-6c" x="515.966797"/>
886 <use xlink:href="#DejaVuSans-Oblique-75" x="543.75"/>
887 <use xlink:href="#DejaVuSans-Oblique-65" x="607.128906"/>
888 <use xlink:href="#DejaVuSans-Oblique-20" x="668.652344"/>
889 <use xlink:href="#DejaVuSans-Oblique-28" x="700.439453"/>
890 <use xlink:href="#DejaVuSans-Oblique-6d" x="739.453125"/>
891 <use xlink:href="#DejaVuSans-Oblique-73" x="836.865234"/>
892 <use xlink:href="#DejaVuSans-Oblique-29" x="888.964844"/>
893 </g>
894 </g>
895 </g>
896 <g id="line2d_15">
897 <path d="M 115.363636 239.483676
898L 120.487603 242.970811
899L 125.61157 233.817081
900L 130.735537 243.515676
901L 135.859504 242.752865
902L 140.983471 241.11827
903L 146.107438 241.445189
904L 151.231405 241.554162
905L 156.355372 239.047784
906L 161.479339 242.861838
907L 166.603306 242.752865
908L 171.727273 241.990054
909L 176.85124 238.393946
910L 181.975207 205.92
911L 187.099174 242.534919
912L 192.22314 239.919568
913L 197.347107 243.842595
914L 202.471074 240.137514
915L 207.595041 241.11827
916L 212.719008 240.682378
917L 217.842975 239.810595
918L 222.966942 239.592649
919L 228.090909 240.137514
920L 233.214876 239.047784
921L 238.338843 245.368216
922L 243.46281 206.791784
923L 248.586777 241.554162
924L 253.710744 243.29773
925L 258.834711 240.355459
926L 263.958678 244.823351
927L 269.082645 241.11827
928L 274.206612 242.534919
929L 279.330579 203.304649
930L 284.454545 244.605405
931L 289.578512 237.958054
932L 294.702479 243.188757
933L 299.826446 238.720865
934L 304.950413 238.829838
935L 310.07438 242.425946
936L 315.198347 245.041297
937L 320.322314 242.861838
938L 325.446281 243.515676
939L 330.570248 240.464432
940L 335.694215 240.900324
941L 340.818182 245.15027
942L 345.942149 240.791351
943L 351.066116 242.970811
944L 356.190083 242.425946
945L 361.31405 245.477189
946L 366.438017 245.259243
947L 371.561983 245.695135
948L 376.68595 240.355459
949L 381.809917 203.958486
950L 386.933884 244.605405
951L 392.057851 242.425946
952L 397.181818 242.208
953L 402.305785 239.374703
954L 407.429752 242.752865
955L 412.553719 243.079784
956L 417.677686 244.823351
957L 422.801653 237.413189
958L 427.92562 241.663135
959L 433.049587 240.137514
960L 438.173554 243.29773
961L 443.297521 245.586162
962L 448.421488 245.586162
963L 453.545455 187.067676
964L 458.669421 243.188757
965L 463.793388 241.227243
966L 468.917355 242.425946
967L 474.041322 245.041297
968L 479.165289 244.823351
969L 484.289256 245.804108
970L 489.413223 242.970811
971L 494.53719 245.15027
972L 499.661157 245.913081
973L 504.785124 239.919568
974L 509.909091 241.445189
975L 515.033058 242.099027
976L 520.157025 244.932324
977L 525.280992 245.368216
978L 530.404959 242.643892
979L 535.528926 245.259243
980L 540.652893 245.913081
981L 545.77686 244.605405
982L 550.900826 243.079784
983L 556.024793 241.445189
984L 561.14876 244.278486
985L 566.272727 244.932324
986L 571.396694 243.406703
987L 576.520661 239.592649
988L 581.644628 242.643892
989L 586.768595 204.394378
990L 591.892562 241.445189
991L 597.016529 241.663135
992L 602.140496 176.60627
993L 607.264463 243.188757
994L 612.38843 242.752865
995L 617.512397 240.246486
996L 622.636364 245.368216
997" clip-path="url(#p09249702fb)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/>
998 </g>
999 <g id="line2d_16">
1000 <path d="M 115.363636 186.413838
1001L 120.487603 116.453189
1002L 125.61157 243.515676
1003L 130.735537 244.714378
1004L 135.859504 242.970811
1005L 140.983471 238.502919
1006L 146.107438 242.643892
1007L 151.231405 242.099027
1008L 156.355372 242.316973
1009L 161.479339 242.861838
1010L 166.603306 244.278486
1011L 171.727273 243.842595
1012L 176.85124 237.413189
1013L 181.975207 242.425946
1014L 187.099174 241.445189
1015L 192.22314 243.951568
1016L 197.347107 152.850162
1017L 202.471074 243.733622
1018L 207.595041 177.913946
1019L 212.719008 157.862919
1020L 217.842975 245.695135
1021L 222.966942 244.060541
1022L 228.090909 245.477189
1023L 233.214876 242.425946
1024L 238.338843 243.733622
1025L 243.46281 243.515676
1026L 248.586777 243.733622
1027L 253.710744 244.823351
1028L 258.834711 243.406703
1029L 263.958678 176.933189
1030L 269.082645 244.714378
1031L 274.206612 244.496432
1032L 279.330579 243.188757
1033L 284.454545 245.586162
1034L 289.578512 244.605405
1035L 294.702479 245.15027
1036L 299.826446 245.259243
1037L 304.950413 243.515676
1038L 310.07438 82.126703
1039L 315.198347 242.425946
1040L 320.322314 44.64
1041L 325.446281 239.701622
1042L 330.570248 244.932324
1043L 335.694215 245.368216
1044L 340.818182 245.259243
1045L 345.942149 244.823351
1046L 351.066116 245.804108
1047L 356.190083 245.477189
1048L 361.31405 244.169514
1049L 366.438017 244.605405
1050L 371.561983 245.586162
1051L 376.68595 245.586162
1052L 381.809917 243.079784
1053L 386.933884 242.861838
1054L 392.057851 244.823351
1055L 397.181818 242.970811
1056L 402.305785 245.259243
1057L 407.429752 241.663135
1058L 412.553719 243.624649
1059L 417.677686 244.714378
1060L 422.801653 246.24
1061L 427.92562 243.733622
1062L 433.049587 245.15027
1063L 438.173554 138.138811
1064L 443.297521 240.573405
1065L 448.421488 243.951568
1066L 453.545455 243.406703
1067L 458.669421 242.208
1068L 463.793388 242.208
1069L 468.917355 242.534919
1070L 474.041322 244.278486
1071L 479.165289 242.534919
1072L 484.289256 242.534919
1073L 489.413223 244.714378
1074L 494.53719 242.534919
1075L 499.661157 245.15027
1076L 504.785124 243.29773
1077L 509.909091 245.259243
1078L 515.033058 245.041297
1079L 520.157025 243.515676
1080L 525.280992 244.496432
1081L 530.404959 244.605405
1082L 535.528926 244.387459
1083L 540.652893 244.714378
1084L 545.77686 244.060541
1085L 550.900826 245.15027
1086L 556.024793 244.387459
1087L 561.14876 245.913081
1088L 566.272727 245.15027
1089L 571.396694 160.587243
1090L 576.520661 244.823351
1091L 581.644628 243.624649
1092L 586.768595 243.951568
1093L 591.892562 244.714378
1094L 597.016529 188.157405
1095L 602.140496 243.624649
1096L 607.264463 242.534919
1097L 612.38843 243.951568
1098L 617.512397 173.010162
1099L 622.636364 243.733622
1100" clip-path="url(#p09249702fb)" style="fill: none; stroke-dasharray: 5.55,2.4; stroke-dashoffset: 0; stroke: #000000; stroke-width: 1.5"/>
1101 </g>
1102 <g id="patch_3">
1103 <path d="M 90 256.32
1104L 90 34.56
1105" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/>
1106 </g>
1107 <g id="patch_4">
1108 <path d="M 648 256.32
1109L 648 34.56
1110" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/>
1111 </g>
1112 <g id="patch_5">
1113 <path d="M 90 256.32
1114L 648 256.32
1115" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/>
1116 </g>
1117 <g id="patch_6">
1118 <path d="M 90 34.56
1119L 648 34.56
1120" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/>
1121 </g>
1122 <g id="text_17">
1123 <!-- Connect median NLB vs ALB -->
1124 <g transform="translate(283.8825 28.56) scale(0.12 -0.12)">
1125 <defs>
1126 <path id="DejaVuSans-43" d="M 4122 4306
1127L 4122 3641
1128Q 3803 3938 3442 4084
1129Q 3081 4231 2675 4231
1130Q 1875 4231 1450 3742
1131Q 1025 3253 1025 2328
1132Q 1025 1406 1450 917
1133Q 1875 428 2675 428
1134Q 3081 428 3442 575
1135Q 3803 722 4122 1019
1136L 4122 359
1137Q 3791 134 3420 21
1138Q 3050 -91 2638 -91
1139Q 1578 -91 968 557
1140Q 359 1206 359 2328
1141Q 359 3453 968 4101
1142Q 1578 4750 2638 4750
1143Q 3056 4750 3426 4639
1144Q 3797 4528 4122 4306
1145z
1146" transform="scale(0.015625)"/>
1147 <path id="DejaVuSans-6f" d="M 1959 3097
1148Q 1497 3097 1228 2736
1149Q 959 2375 959 1747
1150Q 959 1119 1226 758
1151Q 1494 397 1959 397
1152Q 2419 397 2687 759
1153Q 2956 1122 2956 1747
1154Q 2956 2369 2687 2733
1155Q 2419 3097 1959 3097
1156z
1157M 1959 3584
1158Q 2709 3584 3137 3096
1159Q 3566 2609 3566 1747
1160Q 3566 888 3137 398
1161Q 2709 -91 1959 -91
1162Q 1206 -91 779 398
1163Q 353 888 353 1747
1164Q 353 2609 779 3096
1165Q 1206 3584 1959 3584
1166z
1167" transform="scale(0.015625)"/>
1168 <path id="DejaVuSans-6e" d="M 3513 2113
1169L 3513 0
1170L 2938 0
1171L 2938 2094
1172Q 2938 2591 2744 2837
1173Q 2550 3084 2163 3084
1174Q 1697 3084 1428 2787
1175Q 1159 2491 1159 1978
1176L 1159 0
1177L 581 0
1178L 581 3500
1179L 1159 3500
1180L 1159 2956
1181Q 1366 3272 1645 3428
1182Q 1925 3584 2291 3584
1183Q 2894 3584 3203 3211
1184Q 3513 2838 3513 2113
1185z
1186" transform="scale(0.015625)"/>
1187 <path id="DejaVuSans-65" d="M 3597 1894
1188L 3597 1613
1189L 953 1613
1190Q 991 1019 1311 708
1191Q 1631 397 2203 397
1192Q 2534 397 2845 478
1193Q 3156 559 3463 722
1194L 3463 178
1195Q 3153 47 2828 -22
1196Q 2503 -91 2169 -91
1197Q 1331 -91 842 396
1198Q 353 884 353 1716
1199Q 353 2575 817 3079
1200Q 1281 3584 2069 3584
1201Q 2775 3584 3186 3129
1202Q 3597 2675 3597 1894
1203z
1204M 3022 2063
1205Q 3016 2534 2758 2815
1206Q 2500 3097 2075 3097
1207Q 1594 3097 1305 2825
1208Q 1016 2553 972 2059
1209L 3022 2063
1210z
1211" transform="scale(0.015625)"/>
1212 <path id="DejaVuSans-63" d="M 3122 3366
1213L 3122 2828
1214Q 2878 2963 2633 3030
1215Q 2388 3097 2138 3097
1216Q 1578 3097 1268 2742
1217Q 959 2388 959 1747
1218Q 959 1106 1268 751
1219Q 1578 397 2138 397
1220Q 2388 397 2633 464
1221Q 2878 531 3122 666
1222L 3122 134
1223Q 2881 22 2623 -34
1224Q 2366 -91 2075 -91
1225Q 1284 -91 818 406
1226Q 353 903 353 1747
1227Q 353 2603 823 3093
1228Q 1294 3584 2113 3584
1229Q 2378 3584 2631 3529
1230Q 2884 3475 3122 3366
1231z
1232" transform="scale(0.015625)"/>
1233 <path id="DejaVuSans-74" d="M 1172 4494
1234L 1172 3500
1235L 2356 3500
1236L 2356 3053
1237L 1172 3053
1238L 1172 1153
1239Q 1172 725 1289 603
1240Q 1406 481 1766 481
1241L 2356 481
1242L 2356 0
1243L 1766 0
1244Q 1100 0 847 248
1245Q 594 497 594 1153
1246L 594 3053
1247L 172 3053
1248L 172 3500
1249L 594 3500
1250L 594 4494
1251L 1172 4494
1252z
1253" transform="scale(0.015625)"/>
1254 <path id="DejaVuSans-20" transform="scale(0.015625)"/>
1255 <path id="DejaVuSans-6d" d="M 3328 2828
1256Q 3544 3216 3844 3400
1257Q 4144 3584 4550 3584
1258Q 5097 3584 5394 3201
1259Q 5691 2819 5691 2113
1260L 5691 0
1261L 5113 0
1262L 5113 2094
1263Q 5113 2597 4934 2840
1264Q 4756 3084 4391 3084
1265Q 3944 3084 3684 2787
1266Q 3425 2491 3425 1978
1267L 3425 0
1268L 2847 0
1269L 2847 2094
1270Q 2847 2600 2669 2842
1271Q 2491 3084 2119 3084
1272Q 1678 3084 1418 2786
1273Q 1159 2488 1159 1978
1274L 1159 0
1275L 581 0
1276L 581 3500
1277L 1159 3500
1278L 1159 2956
1279Q 1356 3278 1631 3431
1280Q 1906 3584 2284 3584
1281Q 2666 3584 2933 3390
1282Q 3200 3197 3328 2828
1283z
1284" transform="scale(0.015625)"/>
1285 <path id="DejaVuSans-64" d="M 2906 2969
1286L 2906 4863
1287L 3481 4863
1288L 3481 0
1289L 2906 0
1290L 2906 525
1291Q 2725 213 2448 61
1292Q 2172 -91 1784 -91
1293Q 1150 -91 751 415
1294Q 353 922 353 1747
1295Q 353 2572 751 3078
1296Q 1150 3584 1784 3584
1297Q 2172 3584 2448 3432
1298Q 2725 3281 2906 2969
1299z
1300M 947 1747
1301Q 947 1113 1208 752
1302Q 1469 391 1925 391
1303Q 2381 391 2643 752
1304Q 2906 1113 2906 1747
1305Q 2906 2381 2643 2742
1306Q 2381 3103 1925 3103
1307Q 1469 3103 1208 2742
1308Q 947 2381 947 1747
1309z
1310" transform="scale(0.015625)"/>
1311 <path id="DejaVuSans-69" d="M 603 3500
1312L 1178 3500
1313L 1178 0
1314L 603 0
1315L 603 3500
1316z
1317M 603 4863
1318L 1178 4863
1319L 1178 4134
1320L 603 4134
1321L 603 4863
1322z
1323" transform="scale(0.015625)"/>
1324 <path id="DejaVuSans-61" d="M 2194 1759
1325Q 1497 1759 1228 1600
1326Q 959 1441 959 1056
1327Q 959 750 1161 570
1328Q 1363 391 1709 391
1329Q 2188 391 2477 730
1330Q 2766 1069 2766 1631
1331L 2766 1759
1332L 2194 1759
1333z
1334M 3341 1997
1335L 3341 0
1336L 2766 0
1337L 2766 531
1338Q 2569 213 2275 61
1339Q 1981 -91 1556 -91
1340Q 1019 -91 701 211
1341Q 384 513 384 1019
1342Q 384 1609 779 1909
1343Q 1175 2209 1959 2209
1344L 2766 2209
1345L 2766 2266
1346Q 2766 2663 2505 2880
1347Q 2244 3097 1772 3097
1348Q 1472 3097 1187 3025
1349Q 903 2953 641 2809
1350L 641 3341
1351Q 956 3463 1253 3523
1352Q 1550 3584 1831 3584
1353Q 2591 3584 2966 3190
1354Q 3341 2797 3341 1997
1355z
1356" transform="scale(0.015625)"/>
1357 <path id="DejaVuSans-4e" d="M 628 4666
1358L 1478 4666
1359L 3547 763
1360L 3547 4666
1361L 4159 4666
1362L 4159 0
1363L 3309 0
1364L 1241 3903
1365L 1241 0
1366L 628 0
1367L 628 4666
1368z
1369" transform="scale(0.015625)"/>
1370 <path id="DejaVuSans-4c" d="M 628 4666
1371L 1259 4666
1372L 1259 531
1373L 3531 531
1374L 3531 0
1375L 628 0
1376L 628 4666
1377z
1378" transform="scale(0.015625)"/>
1379 <path id="DejaVuSans-42" d="M 1259 2228
1380L 1259 519
1381L 2272 519
1382Q 2781 519 3026 730
1383Q 3272 941 3272 1375
1384Q 3272 1813 3026 2020
1385Q 2781 2228 2272 2228
1386L 1259 2228
1387z
1388M 1259 4147
1389L 1259 2741
1390L 2194 2741
1391Q 2656 2741 2882 2914
1392Q 3109 3088 3109 3444
1393Q 3109 3797 2882 3972
1394Q 2656 4147 2194 4147
1395L 1259 4147
1396z
1397M 628 4666
1398L 2241 4666
1399Q 2963 4666 3353 4366
1400Q 3744 4066 3744 3513
1401Q 3744 3084 3544 2831
1402Q 3344 2578 2956 2516
1403Q 3422 2416 3680 2098
1404Q 3938 1781 3938 1306
1405Q 3938 681 3513 340
1406Q 3088 0 2303 0
1407L 628 0
1408L 628 4666
1409z
1410" transform="scale(0.015625)"/>
1411 <path id="DejaVuSans-76" d="M 191 3500
1412L 800 3500
1413L 1894 563
1414L 2988 3500
1415L 3597 3500
1416L 2284 0
1417L 1503 0
1418L 191 3500
1419z
1420" transform="scale(0.015625)"/>
1421 <path id="DejaVuSans-73" d="M 2834 3397
1422L 2834 2853
1423Q 2591 2978 2328 3040
1424Q 2066 3103 1784 3103
1425Q 1356 3103 1142 2972
1426Q 928 2841 928 2578
1427Q 928 2378 1081 2264
1428Q 1234 2150 1697 2047
1429L 1894 2003
1430Q 2506 1872 2764 1633
1431Q 3022 1394 3022 966
1432Q 3022 478 2636 193
1433Q 2250 -91 1575 -91
1434Q 1294 -91 989 -36
1435Q 684 19 347 128
1436L 347 722
1437Q 666 556 975 473
1438Q 1284 391 1588 391
1439Q 1994 391 2212 530
1440Q 2431 669 2431 922
1441Q 2431 1156 2273 1281
1442Q 2116 1406 1581 1522
1443L 1381 1569
1444Q 847 1681 609 1914
1445Q 372 2147 372 2553
1446Q 372 3047 722 3315
1447Q 1072 3584 1716 3584
1448Q 2034 3584 2315 3537
1449Q 2597 3491 2834 3397
1450z
1451" transform="scale(0.015625)"/>
1452 <path id="DejaVuSans-41" d="M 2188 4044
1453L 1331 1722
1454L 3047 1722
1455L 2188 4044
1456z
1457M 1831 4666
1458L 2547 4666
1459L 4325 0
1460L 3669 0
1461L 3244 1197
1462L 1141 1197
1463L 716 0
1464L 50 0
1465L 1831 4666
1466z
1467" transform="scale(0.015625)"/>
1468 </defs>
1469 <use xlink:href="#DejaVuSans-43"/>
1470 <use xlink:href="#DejaVuSans-6f" x="69.824219"/>
1471 <use xlink:href="#DejaVuSans-6e" x="131.005859"/>
1472 <use xlink:href="#DejaVuSans-6e" x="194.384766"/>
1473 <use xlink:href="#DejaVuSans-65" x="257.763672"/>
1474 <use xlink:href="#DejaVuSans-63" x="319.287109"/>
1475 <use xlink:href="#DejaVuSans-74" x="374.267578"/>
1476 <use xlink:href="#DejaVuSans-20" x="413.476562"/>
1477 <use xlink:href="#DejaVuSans-6d" x="445.263672"/>
1478 <use xlink:href="#DejaVuSans-65" x="542.675781"/>
1479 <use xlink:href="#DejaVuSans-64" x="604.199219"/>
1480 <use xlink:href="#DejaVuSans-69" x="667.675781"/>
1481 <use xlink:href="#DejaVuSans-61" x="695.458984"/>
1482 <use xlink:href="#DejaVuSans-6e" x="756.738281"/>
1483 <use xlink:href="#DejaVuSans-20" x="820.117188"/>
1484 <use xlink:href="#DejaVuSans-4e" x="851.904297"/>
1485 <use xlink:href="#DejaVuSans-4c" x="926.708984"/>
1486 <use xlink:href="#DejaVuSans-42" x="982.421875"/>
1487 <use xlink:href="#DejaVuSans-20" x="1051.025391"/>
1488 <use xlink:href="#DejaVuSans-76" x="1082.8125"/>
1489 <use xlink:href="#DejaVuSans-73" x="1141.992188"/>
1490 <use xlink:href="#DejaVuSans-20" x="1194.091797"/>
1491 <use xlink:href="#DejaVuSans-41" x="1225.878906"/>
1492 <use xlink:href="#DejaVuSans-4c" x="1294.287109"/>
1493 <use xlink:href="#DejaVuSans-42" x="1350"/>
1494 </g>
1495 </g>
1496 <g id="legend_1">
1497 <g id="patch_7">
1498 <path d="M 589.085938 71.91625
1499L 641 71.91625
1500Q 643 71.91625 643 69.91625
1501L 643 41.56
1502Q 643 39.56 641 39.56
1503L 589.085938 39.56
1504Q 587.085938 39.56 587.085938 41.56
1505L 587.085938 69.91625
1506Q 587.085938 71.91625 589.085938 71.91625
1507z
1508" style="fill: #ffffff; opacity: 0.8"/>
1509 </g>
1510 <g id="line2d_17">
1511 <path d="M 591.085938 47.658437
1512L 601.085938 47.658437
1513L 611.085938 47.658437
1514" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/>
1515 </g>
1516 <g id="text_18">
1517 <!-- ALB -->
1518 <g transform="translate(619.085938 51.158437) scale(0.1 -0.1)">
1519 <use xlink:href="#DejaVuSans-41"/>
1520 <use xlink:href="#DejaVuSans-4c" x="68.408203"/>
1521 <use xlink:href="#DejaVuSans-42" x="124.121094"/>
1522 </g>
1523 </g>
1524 <g id="line2d_18">
1525 <path d="M 591.085938 62.336562
1526L 601.085938 62.336562
1527L 611.085938 62.336562
1528" style="fill: none; stroke-dasharray: 5.55,2.4; stroke-dashoffset: 0; stroke: #000000; stroke-width: 1.5"/>
1529 </g>
1530 <g id="text_19">
1531 <!-- NLB -->
1532 <g transform="translate(619.085938 65.836562) scale(0.1 -0.1)">
1533 <use xlink:href="#DejaVuSans-4e"/>
1534 <use xlink:href="#DejaVuSans-4c" x="74.804688"/>
1535 <use xlink:href="#DejaVuSans-42" x="130.517578"/>
1536 </g>
1537 </g>
1538 </g>
1539 </g>
1540 </g>
1541 <defs>
1542 <clipPath id="p09249702fb">
1543 <rect x="90" y="34.56" width="558" height="221.76"/>
1544 </clipPath>
1545 </defs>
1546</svg>
diff --git a/static/notes/ps1-prompt.png b/static/notes/ps1-prompt.png
deleted file mode 100644
index e27c714..0000000
--- a/static/notes/ps1-prompt.png
+++ /dev/null
Binary files differ
diff --git a/static/notes/xterm-palette.png b/static/notes/xterm-palette.png
deleted file mode 100644
index e286c5e..0000000
--- a/static/notes/xterm-palette.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/algae-sava/dji-algae-0.jpg b/static/posts/algae-sava/dji-algae-0.jpg
deleted file mode 100755
index d444c80..0000000
--- a/static/posts/algae-sava/dji-algae-0.jpg
+++ /dev/null
Binary files differ
diff --git a/static/posts/algae-sava/dji-algae-1.jpg b/static/posts/algae-sava/dji-algae-1.jpg
deleted file mode 100755
index 26ee43c..0000000
--- a/static/posts/algae-sava/dji-algae-1.jpg
+++ /dev/null
Binary files differ
diff --git a/static/posts/algae-sava/dji-algae-2.jpg b/static/posts/algae-sava/dji-algae-2.jpg
deleted file mode 100755
index d38f8cd..0000000
--- a/static/posts/algae-sava/dji-algae-2.jpg
+++ /dev/null
Binary files differ
diff --git a/static/posts/algae-sava/dji-algae-3.jpg b/static/posts/algae-sava/dji-algae-3.jpg
deleted file mode 100755
index 9706fa0..0000000
--- a/static/posts/algae-sava/dji-algae-3.jpg
+++ /dev/null
Binary files differ
diff --git a/static/posts/algae-sava/dji-algae-4.jpg b/static/posts/algae-sava/dji-algae-4.jpg
deleted file mode 100755
index b0db4a2..0000000
--- a/static/posts/algae-sava/dji-algae-4.jpg
+++ /dev/null
Binary files differ
diff --git a/static/posts/algae-sava/dji-algae-5.jpg b/static/posts/algae-sava/dji-algae-5.jpg
deleted file mode 100755
index f3c1b3b..0000000
--- a/static/posts/algae-sava/dji-algae-5.jpg
+++ /dev/null
Binary files differ
diff --git a/static/posts/cv/avatar.gif b/static/posts/cv/avatar.gif
deleted file mode 100755
index 82e5f39..0000000
--- a/static/posts/cv/avatar.gif
+++ /dev/null
Binary files differ
diff --git a/static/posts/dfd-rice/desktop.png b/static/posts/dfd-rice/desktop.png
deleted file mode 100755
index 8dcfd51..0000000
--- a/static/posts/dfd-rice/desktop.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/dfd-rice/install-00.png b/static/posts/dfd-rice/install-00.png
deleted file mode 100755
index 2660f90..0000000
--- a/static/posts/dfd-rice/install-00.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/dfd-rice/install-01.png b/static/posts/dfd-rice/install-01.png
deleted file mode 100755
index 1281be1..0000000
--- a/static/posts/dfd-rice/install-01.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/dfd-rice/install-02.png b/static/posts/dfd-rice/install-02.png
deleted file mode 100755
index 9cac5e3..0000000
--- a/static/posts/dfd-rice/install-02.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/dfd-rice/install-03.png b/static/posts/dfd-rice/install-03.png
deleted file mode 100755
index dc7cbd1..0000000
--- a/static/posts/dfd-rice/install-03.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/dfd-rice/install-04.png b/static/posts/dfd-rice/install-04.png
deleted file mode 100755
index 675a78f..0000000
--- a/static/posts/dfd-rice/install-04.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/dfd-rice/install-05.png b/static/posts/dfd-rice/install-05.png
deleted file mode 100755
index 8b580b9..0000000
--- a/static/posts/dfd-rice/install-05.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/dfd-rice/installation.svg b/static/posts/dfd-rice/installation.svg
deleted file mode 100755
index bb9560b..0000000
--- a/static/posts/dfd-rice/installation.svg
+++ /dev/null
@@ -1,1388 +0,0 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<!-- Created with Inkscape (http://www.inkscape.org/) -->
3
4<svg width="210mm" height="297mm" viewBox="0 0 210 297" version="1.1" id="svg5" inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)" sodipodi:docname="installation.svg" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
5 <sodipodi:namedview id="namedview7" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageshadow="2" inkscape:pageopacity="0.0" inkscape:pagecheckerboard="0" inkscape:document-units="mm" showgrid="false" inkscape:zoom="0.093984989" inkscape:cx="-883.11975" inkscape:cy="1877.9595" inkscape:window-width="1462" inkscape:window-height="940" inkscape:window-x="1725" inkscape:window-y="74" inkscape:window-maximized="0" inkscape:current-layer="layer1" />
6 <defs id="defs2" />
7 <g inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1">
8 <g id="g368" transform="translate(76.329351,109.97993)" inkscape:export-filename="/home/m/Vault/projects/mitjafelicijan.com/dfd-rice/install-01.png" inkscape:export-xdpi="75" inkscape:export-ydpi="75">
9 <image width="169.33334" height="127" preserveAspectRatio="none" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAyAAAAJYCAIAAAAVFBUnAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAd
10X0lEQVR4nO3dvbqjOKIFUNf9KujHm9CP6HAeb4IJbnCm3RQ/sgQbI2CtrwMXxpIQAvYR2P3r8Xg9
11AADI+b+jGwAAcDUCFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUA
12ECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUA
13ECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUA
14ECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUA
15ECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUA
16ECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUA
17ECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUA
18ECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUA
19ECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUA
20ECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUA
21ECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUA
22ECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUA
23ECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUA
24ECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUA
25ECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQ9jtV0OuVKgnO7fl8vhwP9Mr4
26hB/P577lm8ECAAgTsAAAwgQsONrz+b//IqvtZ6n2A5tUo/PmARclYEEHXq+ZxxhHyWB2nbJ3Jtse
27Mp7PNQ34vt7i1H7t6W1LgT/FHnIH+vITiZb+GVQudr96ATomYMH9DCc/3unnJwm936pMRT/rj1ae
28LWQp8BXqnW1nuSWtTWoqv6mdS+2ZJs5hV8yW83G/SLHQn10C1tPcNfRm6QI//Ofs63JwGV77ywUW
29LNXbNAM3+6lg+a3lFNozW2Prfmlq+bhmp2ju62s/U7LXDJbfWeG2Tnz1mj1sPwaFnertsPyjTmuF
30elftF+dnbuub52e3CIGeLN1620Oq/G9G6u88VwdsJmABUSse5CoUtasLzGzJWNArP9MAvcpeOL98
314/IUv+lwAdNn4IA+CFjQq1NfOMu/v7Vi09wuXCJjQZfcIoSLGl133/NJS8tXmP2CYeFbdcNbhx8z
32wbp2vj/1cf1UP5TLmbZnuGT41pb2uFcI/fn1eGSOyT/PqP5v7dxX8/ivfGIp9WDT3r72A6es4vzM
33nQ3H/94zv2aw4Gj1czOnEJwhAzgtAQvCTA8IVT0zPuFvS1NYmWPEQ+4AAGECFgBAmIAFABAmYAEA
34hAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEA
35hAlYAABhAhYAQJiAdR3P57Orcrr1fD6/uY0f67p8hwPc0JEB6/mn2XcPaVjE3o0/S+f01s7n8/l6
36vV6v137l71Tyd5y9/QCd+H1s9cPr3M+Vb/iWcz13sF/aA+AoBwesVsPINQpnkeVN9f4kwvdbw+XD
37Fx/rXSrnY2Om5Q/f3bK9reUsbddsOwvbWy7n/anpW/XbNeuo/fJx5Zp6y+0frlPutxXj9r1kdisA
387uxMAWvpgpFa3lrv0uvZWlaUs2Sp/KVyWre3tZyl5cF2jlZ4R5/W/Th8URlE9tsv70+NZmqD47Np
39/RXjdna/FKoGuI+DA1ZkBqLyg3uc+lNlXqmcms/OrrP3tXlFCDhLf35zfQBqdPQMVo2lp7Jmlxfu
40XLQ+3ZV6GqymnD0ueLs+zRa8Q3TUfqnxtSDS2p97r//w5DtAuzPdInwsXBKmtzBG608vJ0f9lX/U
41bMHXJoe21FXYj+V6r6e1P7+zPgD1bvE7WK/Xa/qkC3H6Oau1P0frD18vTfHaXwA7OXHAmr0wDBdW
42Xjl6vl24h3i9e2zIijIvExSCA/InP62YGlxX3Wi1y+wRgBU6vUU4+4Wv0V/bw68yzf7VXrP+o+L2
43R+v6o0+trre1/I9rbqx3XX+ua2fNzMre27WxtJpymsb5xxpn159+vHV/ZfsH4CZ+PR6pp4v+ee3b
442tAbRyXA6EdzFtbKnCo7ncECtjPzBHAUAQsuS6gCOMqJH3IHAOiTgAUAECZgAQCECVgAAGECFgBA
45mIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBA
46mIAFAOzi+Xwe3YTD9BiwUvvj8vu1tw3srT1Zq7fua91Srmi/ZiyV/Hw+Z9+69ji5Lbt1o6Xj5Vgd
47NulEjgxYzzkHtqes57ZdSefD4KOr/nnQ2p7n8/l6vV6v107tuaq997vxeWDJhYvd3Y6X3sbPTn4f
48WPd7MP2MrQNbclK9ddq69oz2/uv1usmxF3fUeGitt7dxC9/xM/Jd7+7jyIBV9r7KDsfi8NJbOUab
49ypld/l7482KUC+vLH645LWrddo1Wbi0nuP60PTX907oTaz4yPX+9lyztl0g7l8ZJoaim8VZTe02l
50hXpn+6Fmu+ovGE3jdst+H/6zsL3T9QvjobxRleUX1h++2HI+KTeysvwV5TwWhtyK/bj9eAmeB6Yl
51HCg1zstVjAr5WH6h35YKaT11nFGnAWs0aGaDf+VAqS9naXnhz47Wdo5WeA/N1u16zM30tJaTXX92
525ulj/7TuxMqP1HxwqRlL7fxYXWqcFMop114YD8O3Wvuh3J7ZeocvRp+qH7er9/tI6ryRKr91v7ee
53T5bqXVF+UzmPhX7b+7z9cds3ngeaWr5CKnDscbxsOW8sWXd+O6keH3J/5FLtlnIqU0620qCPzdjY
54ztX906FD+uqbnVNZV6RJr9frfeULbmOH3RX57FmOkRo9nLd3qne/QLDT8RLxzfPGJXU6g7WkZiJh
55tVfdTHuN1nZGtmtF+5vqDfZPq133+8g3t+6b29VDvUtm23PgeBs14+MKTe3c+zjtUKr9R50HbjLd
56QtzJAtbeo/w9e7mlrulUamW92zW1f3U7N/bPq/EBly119WxF/6f01p9L7YmMty9obee69c/rAjNb
57MhYrdHqL8Fg/U7Xn/atx7/ZHyu9wPpw+VY634TqHHLyjdn5sz9nPM7fSz546fJxT78QBKz629his
58K8pc3Ywt7a/5bLZ/nn9b8cFgMzqp9MDyeztHb7l4/Fx7Vkw27HTszLZnY4f3tr9anfF24Y/ZjLXu
59JBZpyRfG+dkH2+HOdItwNL4jt6iG5ZTLr39yYumv2Nb2FMx+8aS1nGA7m74IU/42SnC7Rrts7/6Z
601r6l/KYndT72W6GuLU8ONe33mnYOC1ndzqWWF8rfMj/x8bzRuv6oM1PnvWz568Z5ffmt5RS2a+N5
61YFrL6k1oPV7KLZlt23SFLef57eeNj7Vc+z7Gr8cjdXf8n9duV1NQCFiQ0tu46q09XINx1Wr2T/qJ
62TJeeaQaLa8j+JQRvvY2r3trDNRhXZyFgcQAnBfbQ27jqrT1cg3F1Fid+yB0AoE8CFgBAmID1j6t+
63JfWq27Xky9v7sbq79T9dqR9+vsO/ziG/1HBhV+rMIwPWNfrxGltR74bbe7dNbrLUP1fttP2266o9
649uO8P3/1GPxo33S0/3wlzUNRS5b217VH+5sZLChx6izTP5fRuivvs+vfEUqW+oJ1PdxnYuvlW4Sj
65n6YY/b7ZcLX369H6S6WV65qtvb7e4YuaX1n8+AObhe16/7PQP+XaK7er0J7hiy37671kWtRsez5u
661HT91eOn5ndlWju/qT0rtO7HLcfXx/45y3GxetzOjv/ZLWrt/9lOKG/CtPzHp8E2+xuPs0sK7Zzd
67ud85byw1frr+ivPkflLjvFzFUjmR80/qejG7fGlhTfsP37lLughYHxPP8ARa+akv1Dv77grrDqTC
68+b1y/fKFarq8sL2t+2u0wvsQar2QF05YK8ZPpaUzY/1H9mtPZfm7tueqx8XH7So3+GP/N21pofzC
69+Jw97t5vTQdzoZ3T9fc+byyVs7qfNyoHhaZydj0PLL1OnW9b91f5OKofh7vu3JTjbxHOds1RnbW0
70y7/fkrLWJm3ZhJrP9tBvo7P/9yvdvlrE6v21Yp3efPO42KJQb/2l4gs78eznjV337+v1eieJHg6W
71Qhv2aF5v57Q+HTyD1W3wHKmcqDhEvANfuf9LVGu/Na0fbOdRuhpXF+jPoS1b8c39smX24krjZ9QP
72sWbNlX9VNf22up8L+7ercdiVgwPWa9v/O/M7plOgBzbmO95zsI8NJ6YV/bZuBuK8saC3Np+9P1MO
73nNmqPx92eF466rzB49Dz7SHHy6unB+yWHH+LcPae6yUNt/QUm/wz9d1/U8/SzrP4cn+e7rjY1QVG
74suNx1mXGeVf7t5P7s0uOD1iPU51TNrbzZ0tXTNp9s3/2qGtFmR8/0kM7K9evWW36yPC6DVzdLSsa
75mdLzcfH9U9OK8+HS+jc8b9SXfNSe/cI4P/B8++Veff7tm5XW6+JbhI+6ufHReee98vDecM3s9Or1
76p22oL2Ta7Prtmq13u5p6pw2u397W9pfr3W/9QjtHf3G+n2lt3S+zs9mV/dxUeH3568qp6Z/Rmpc5
77Lkbvfjz/tPb/tJZ156UV/VPYj/Xrf+e8Uej/2XojWvunYL9xftT5dt1+n13e1M/Pxm9BHuLX45Fp
7803DT+tzU3uglyu45Qu651dyNcb7R6oD1/PP3HRbWyuyaXmawbmLvv7S4jFudfx0X3IFxHvSFmcvt
79BKyv6nMQ0KFbDZVbbSy3ZZxn9d+fXTzkDgBwJQIWAECYgNWvbr96Cl+Q+t74UTpvHrA3AYuMXX+x
80ZqeSr+1c/Xau1gJ8JGABp7TuEVdJDviOI79FuPQ7Fj8vpj/M2FrOY+Frsal6K8sfltxa/rCK2R9k
81G9X7XjL6obamr7MW2lmud1rpbD8UyvnYP1t+vCA1TspVTMspl980zt9rtu7f6baU11+q+rHDOCz/
82uuBS/8z+SuHHcVu5sanzw1LVreOh/6+jA1Od/kzD6OK3+k/VFRfI+no/ll9esro9hXpHKwyDXaFV
83G+udfbfQD+WgU5PPslK/CFy+MM+u1joe1u3f+v5PbVdTOwvjp9A/r7nfqv44bjcOob2P39b1gZ51
84eovwqDPI3vW2ln/VflhR7+muK6O0UV4nUtGseL99cy/0drzs3Z5zjXCgrNMZrB5c6WQ3/Vv/2HJq
85XOmv9r37ban8pX5ras/0Tt9q3xw/Pavph6VbhMBZCFi3kEonB85snTdjFZ5/2rv8pX5bN7OyPWYd
86sgdXPDi1NzNbcAed3iJsMjyB+lPvqmafuVldwn3GyfZ+GxYVLO3Lfhp/dCuAG+klYI3O2q0n8Z/z
87/opJjpNeLbY44+3CH0vPNde35JvjZPYjh9wrLKeij03aqc1fHj/Pv7V+qvDPiO1NuuFJDE7hyFuE
88o6n76a2N9+vK0grlD1co1NvkY/nBh1dq6k2tv66c6cYu9cOW9kzvebXuwf3Gyd7jrabepfKH/ZYa
89P9lx2HSwjGYimx7z/xivs+elcvk15aSOX+DLfj0eqadz/nkd/C709z/O6azb48bJTaR+5sCAgQsY
90/RjKwlqZI/0iD7n7C++2mi57xskNmQECDtFjwFpxBnTSvK3WO4z7tYRuRfa7wQM06eUhdwCAyxCw
91AADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOw
92AADCBCwAgDABCwAgTMACAAgTsAAAwgQsAICwIwPW8/ks/HNjaQAARzGDBQAQ9vvoBswbTke9Xq/y
938vfCnxfD5a/X6/1ufTnvT03fGpUzrRQAoMeA9ROMpv9cWj777rSoj+VMi3pHtKX1AQCmDg5YWx6c
94qkk5s+tk45GwBQCMHBywlm7bLa2cuh/XGuw8QQ8A1OvxFmHB+87dY0PMmt7yq6wXAKDGKb9F+Hq9
95hk+vH+v5fHbSEgCgE2cKWHvkmBVlilMAQFmPtwhHs1PDr/gVfi6h/gmt0W831D/7tVRv+eMAwN38
96ejwy+WAYM/yQAQDQm9GPNy2slQkwZ7pFCABwCgIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm
97YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGG/j6r4+Tyq5nmv
981/zy3toJAEwtXcePYgYLACBMwAIACOsoYH2c3Nu+AgDAF3QUsAAAruFSAcsD6QBADw77FuGP9029
99UTYa3uxbemt2eU05r9fj+VwsBwBgoyMD1k/Qeb+eXT5dbfb14/FHZtpSDgDARr3cIqyMOE1JqLCy
100RAUA7OfgW4RLUt8H9L1CAOD7Og1YkRmm6S1CAIAv6OUWIQDAZfQSsArTS6Pn3+PlAwBkHXmLcPRb
101CbOvH4/FrwrO3v4b/lhDoUwAgP0c/AzWKDzNvh4tLLxVWf5o5aXlb7PJbCmxWW655ZZbbrnl31/e
102m1+PR6aZf845PV+ftr63H0pYam9v7QQApmpS1zCfPBcv8JlcdNgM1ini5+M87QQA+tHLQ+4AAJch
103YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm
104YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWABwU8/n8+gmXNbvoxtwjOGQer1e2wvZWM7qzwJwSZHr
1051LsoV5nvu1HAeo+w0VDbMvJS5cxySADcyh7XqbKdinX9etwnYFXu7NRfDEvlfCx/2M7X62WMAtzE
106luvUz2ffbw2XD1+Myp8uLJSzFPhm2+P69bhJwCrv5poBtKW6+r9IpkuMUYA72H6dmn09e/UZFjt9
107BmupzJpmmyMYun7A2nUHLyX3ms9+TFfv1W4+RgGuLXKST10mgpebm1+/Lh6wyrt2OgvaqmbKtMbH
108v13uPEYBLuzsp/fy9e7O16+LB6zyrn3PnWYrnU6ZfvxIuZ23HZ0Al3f2CNJ0D/FWrv87WLP3mDu0
1091M47j06AO/h4nTrFVWzq5tev6wesR3Hs7j1qC+VP35q28+ajE+AmzjIX8Ki+rrl+XfwW4dtwDnb0
110HdTZ14+6B7MKX09dV/6wnUYnwH0sXaceC9eXR/UDxO9PzT6+MvsLDkslFF4PC3H9ejwevx6P1PcO
111/nmtZwGA3tR9HS0TYG5xixAA4JsELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA
112wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA
113wgQsAIAwAQsAIEzAAgAI+71Tuc/nc6eSAQA6t0vAer1eexQLAHAKbhECAIQJWAAAYQIWAECYgAUA
114ECZgAQCECVgAAGECFgBA2K/HY+/frPKLowDAWWRykRksAIAwAQsAIEzAAgAIE7AAAMIELACAMAEL
115ACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAI+/V4vI5uAwDApZjB
116AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA
117AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA
118AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA
119AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA
120AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA
121AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA
122AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA
123AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA
124AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA
125AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA
126AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA
127AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAICw30c3AADg
128vJ6zS81gAQCECVgAAGHJgPWf//4rWBoQ0fmB2XnzANYpPYM1e+L76/e/d2vMdQy77mI99rNp2zfq
129P//915d7Zjqeaxrw/Xaus3c7e+uHpfb01k7gtmYC1vsM9T5PbTxn3eSU997M0fZ+bfO/U9Ffv/99
130rimHYbccMg4PH/93OPoAejMOWJUXg8IMzfut4VWt6RozLGE0XzJbbyHQLLXzY/tbr0k1G/izzrR/
131VrRzdnlrP6+oN1LOe+G0q7vaL63tXCpn7/1SaOdS45uOlxX7a8UM7mz/z7ZzqT2p/bWu/QAjfwSs
132+nRVOEHPvm69xoymgt6nwqaZocIJOjvDVC7hY1+1trPQ/qZ+TvVPazmz766o96N1XbGlnZHxn+rP
133YdVb6m3thxX7canfZi21J7W/4uMQuKd/Alb9eaQyTEzf6vNUNXuarjd7ol+ablm6BK5oZ2G1df28
134965pLT++Xx7LMxOpbY+M/+x4qLfTAAhuclzPbQPO7n8Ba8stjHo7ZaxhsdO/PpfWf+z5pPbwXkbl
135pGBrvYV3K/u50A/Z9lT62n7ZrmZ7Z+N1/STxypZVaD1eCvY+vg5x9vYDnfhfwNp4C6Oysu/PYC1V
1361xqACuUXNqp87+ZtRX82FfixnGk/bJxtWu07+2W7dSWvvgW/oq4VguMwtR+Pcvb2Az3453ew6p/V
137WKfD+4N//f73dKv/899/NfXDbAmZ9q2yop9n++FAO+2XY3U4/vfW27hqdfb2A8f644dGV5xNKrPF
1383leXn5aXa3m37eP9tXW116z5cbXCCoW+Hb6ub3+qzZXrb9n2x877ZYuaKlaP/xXjocbH42VF4ZXH
13917rqvplyJCogYvwzDTX3VobXrdE1bPTWz4tUuprWtW791nLq2/bX39+6KjxMPe2fpf5sbX9rP6/o
140n9FFtLy95X6ePumy9355TK6dNVVsb+eW/VIzHpba+VjYX631LpUfPL6ajovC9ja1s6Yxle0HmPr1
141eLyObkNf9ptsu+FNoiC9B0CXnrNL/c+ex1zF+2S/AAAAAAAAAAAAAAAAAAAAAAAAAAAU/T9NrMo+
142adlPnAAAAABJRU5ErkJggg==
143" id="image41" x="-234.20293" y="-199.01341" inkscape:export-filename="/home/m/Vault/projects/mitjafelicijan.com/dfd-rice/install-01.png" inkscape:export-xdpi="75" inkscape:export-ydpi="75" />
144 <image width="169.33334" height="127" preserveAspectRatio="none" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAyAAAAJYCAIAAAAVFBUnAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAg
145AElEQVR4nO3dzZKjuLYGUPJGDfrxeuhH9PA83hn04A582kUBkiWxBQKvFR0dLieWNuLvS8DkzzQ9
146JwAA4vzf2QUAANyNgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzA
147AgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADB
148BCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUA
149EEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglY
150AADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCY
151gAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAA
152gglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAEL
153ACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQT
154sAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBA
155MAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmAB
156AAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGAC
157FgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAI
158JmABAAQTsAAAgglYAADBBCwAgGC/aj/wfPYoA77X4/F42q74xHoCx3g8YtpxBgsAIJiABQAQTMCC
159q3k8/vffKR/vp7akY2Zh3cuAQweMR8CCC3o+N26HTB34F+9vfjbjHchCYtmYKaqH61YORKi+yR34
160OvNA9nj0+qpLbbNn3fHtTnOggIAFtJqfpHnHjlcCe/9o/v78xSKmrN+snb62nozMxOX9LibYnLXC
161eoAL2hWwHs6Bw9dah4ZFplm8fv0/dQJsnoHe71RNX1tPyXytd3FV/ZZMUHNG0C4X+gl/DMreM1ie
162ywI7XeCouXnGJbPtj7ZbaK5nHadq+/qYn2pqs7+FTnrsh10iBD5JHddLdkm3zwTvELZ5PXH9ZmZ6
1634EYELKBJ5r6ib/O+mjn9GZteWWozY21OD9yIxzTAXaQO1Q7hx3g9/2J9J1kqem5OD9yFgAV3Ufgc
164rCO7vrqS+fo4zSJF3XWsgD+5RAg0WTz7oDA3bN6BlHkiQ/n0ixpCbmxPZaPafufXCqPqBMb2M011
165m/efezl/3R32qt6Oqh7pFP5xTmJ/C/3Mt6+os8zOYMHV7DzKOkgD9CdgwcmclqCE9QSOkjqFVbcN
166uskdACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmAB
167AAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEOzMgPV4PAZvkCr58b/c0jmr4GEHqrawqBkZ
168c0DWVR1QZ0gXx4xn+fg8Ho/NH6Xe/0733pru6oiA9dhyQL9tGo4i9g43YGG9nJWivkfziD0ej+fz
169GVvM6V4ztZ6v1PsH1DNUO1zaEQHr+a/F6x4d9Wi2rdPb7ArL9xS3meVTjL9Hrl2+UetDWzvHj+dV
1701v+zxvMq4wNRfp1dwO/tdr75zTfmws3y9ZFFI8/ns7z995ubTdXWkyly3W+qzqp2erS/Hs/MP9eN
171pzqtGs9Mv5n5TX18s/2qWWhYrz7Wv/kbfOpH6ykb6tmcr/mLzXHYbLxw+tp6Mv1+nN+qnUb5Rz4u
172r9r1vPyk1HrK2u0iVWeP8Swcn1q160/g+l9VT6qd5vp3bke1y5EoJwesxU7h9br2APkyX7fa2t/8
173aXM9a/kdYup4XN5Oj/bLZ3Y9/qk9/gHjWSW13KeyMWxebzPjXLsIauvZfJ0Zh2lr+dZO37Z+tm3X
174tYNW8pHU+pyq82P7zWtsXr7fY8azcHzmLz4GlNr1J3b9z89vSTt76i/cf1a1wwFO/hZh70BdmMz2
175N7LTni7en800cvovLqcX0CZV9gjr7cfpR14fFkLmt3enOz97TLr62G/zND06fSeSRQTcfH9nd3um
176D2lzz/a4GJ8eNdDD+ZcIN3UN2u/fpcrXtqh6StrZsw1c5ReUq9RZYuR9Vu/17erO2s90TVcN+7er
177qF2fHUc416AB65gzBIWbx/qU7M5+O4mq81l5w1ZbFz2avZbe4xy43l5C7XgeMD6p/cyr1K4Za7Pf
1782kZ67wdqjXCmat3+wceRb9uuL23QgHWM2ovuX2WcMZkfje63NxlnnO9hwPHc3M/0zlipftsaIcNx
179hJQLPMk9/Ji6p8HAYrqeLt7f+ONf5Z3mW2v40dvraNSwCxstkG3eX5wZ5+Zmaye4jbbx7DH9x2me
180W/ebt028uAm6sM0Sx4xng9NLOvI4csB+mB5GPIO12JUUnu2fv8h/JN/++sr64lT55r5s8ZHN9xvm
181q6r+TJ1VUt9SqR2H1PRt47CeLHYc9t+5UltPapx3dt1jHDLbV/n0vbfr2vGsHZ8963+q+D3nsRq2
182r7PGs6rfkvZLGmnezxQWGXgc+dh+4bKuaocD/ExT7VXt36/3HBIYVuCBv4fR6mkWNc63GZCdBl9v
183Qxw5U98wnvA2X8PTMbRuExjxDBbnijrTFmi0ekIMOM6X9g3jeeRMfcN4QlcCFhtG25mOVk+UkPm6
1846+A0MBSxjCfscYGb3AEArkXAAgAINmLAOvFrDmN+wyLzHd0xC97prvN1jP1DZ/BjFY7nYcOe7+i6
1853/w/q/JxRiDWXefrSCMGrBNd6Fusr6883O8mibvO19VdaLvYLLVfal80O1qcupnr5r97OH77ujQB
1866wKkDY506fUtVfyJM3VM1+WHt0sv34za+Yoah+anq4T03k/qyW3lE3PQtwg/PvhuWi2h9YMTU9Ov
187n6K2+TSLwn6rHv2XqmfzwY9t9jyab17P5j8z9ac+nmp/Pb+ZcWh+4GRh+1V6j0+qnXz7VfOVmrjh
188a/br9a32KZG122N+/Zk3+3G7rnLMc55qx3P/cs/PV1WnH9fbwiKr9gOZ9eHjLNSOc8n85rfHzX4/
189zm/5uG3+M3C/nXpn/3GH6ZiAlVrw+RVo/Toz/WKC9ype22/IfGVeN1hftaw94KUEHmBK5v3j+Kfm
19065hxzs/Unvaj1v+S9uerSlv96/Vts9qPjUyrOe0xv7WFHa9qPPcs98JB2NyfVK0/qelrS61dH/Lr
191Ye16mx+HknpS7ZTMb9TOdmdTmRY254taJ1wiTK0Ni7X2qHK69NW1/ufz+d7jDHJoKVmmJY3Uztcg
192s19l8VtBfprmxgcUNb9jzuPj8dh/QDp91moL2LOd9lj/O+k0LNzeEWewnqsrBc1qd2Gb0wfWU8LG
1939rL4ravqsyXTX3Gcv+13xKj5/bZxO0vvcb7rdg0vB92DNb8GtPN6Wcj0UfXQxm+EU+LmmBuLmt8B
194x219mfsAz7gbPTNd9Gj2ZcDl2NUBy4vRHHqJ8HXpZ5wNabR6OpnP4+1ntoHx+U73WO7j3CdAiar7
195H26wfn65IwJW+Y2QPZpdT5//YO97ZkPu1aj12lYbZq3Tstvz2fKSylvuPT4fP/Jt186iFvrO+c0s
19699r1Z/HiMI9/pX5a21rVj6L2D1dZb/fLL6+FI/dL9HDoPVjvf+bfr22nd79R9Wx+Km8RCmOvrpaM
197T2G1VWe/ey/3zU+VTF/Yb+34BI7zx/YzbZaMW2Z923/n4p5xK5zHVP35+WqbnRJdx3N9ie3573dE
198qsandv2J2j+0rf+b41Y7zh/HYSpbLlX759Tyyjtgv7QeotrtKPA4dTM/01R7N8zv1w3JenDHzNG5
1994xbe+7CrQVthw84OXV1uubcdsI83bGEH27m8DGNv8xFOx9O6RXDQTe5Xcdd0FXLG7lqqxvkLx4fp
2004ss96kw8x9hzhqxwekbjDBYA8NV6nMHytwgBAIIJWAAAwYYOWJ2+a3r1r7Bevf6vNeaCG7OqEgdX
201ft2BAk5xfsCq3W2lHiJS/nAReqgd/94Ly8owpqssl6vUmZLZTx5fDHyn8wNWxuYd9Knb6t1ufy7j
202/5EhimU8MwwOnO6gxzRsft00/3Sy3o8s23wwZqrO1PNLen/tNjN9bf3l0zfUWVV/ZrnX1p/vtLD9
203TDtV45Z/zk1mJc+3s/nOutRUO/n6CxduyHbRsNzf76Q+UjKemffzM5vv4rD1KvV+7XOVorYLoNAR
204ASu1I3j9P7VfKH+2786S3q8bdlhnTV9bf9X0tXXW1p9a7rX1pzS0XzILO8dnvT5/bKew5T3LvWQT
205i1pvG5bL4iOLHxWOZ239mf1S1PpwyvYYuF0AJU64RDjC1puKdMd32vbx2voLE0BbYQc0eNY6M8K6
206+tGe5d4wg7UfudOyi2pzTzuD76aAt0P/FuH4m+7mL/Sv+lO/Te5vP1BU+2e1UzL9CAfs2vUkZbTl
207FeKs7T3T78jbXeF6NXUbzwvtn+FaDroH633UmQbejBvCU9W87AxnR7Yfsox6j+eJRjiT8dZ7vWpw
2081vae6vcqZ31S7fQez0vsn+FyDr1E+Hw+13dOALd01vZ+1/1M7/m667jBWY4IWFfcYhc1v/Y7+es+
209VbPZMCZntR+y+HrP74nmdZasJyXthBTTqdPNj8zfPGvBFfY78uXCzXYKv4iwv6PUT6+yJcJoDr0H
2106/3PzZ9uXuZY/Kj2/eY6S36Ty8/Xdduv7XdKjH++nvVyb+g3o1/7PcZns87Cm2P2LPeo9STT5sft
211/bDxLG9/s86PU1a1X95O7fhP2f1h7+0OePuZKv869Hzra/tNHQBgHI8/H56SmKou8Az9JHcAgCsS
212sAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBA
213MAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGBDBKzH4/F4PM6uImnk2qrkZ6R2NscZ
214lrMq7z0Cg28X4Y6Z2XUvXzXI0+3m96Kz01z2xw8Wtrxz3GxHJQ4KWI8/LX70fD6fz+cxlXBR181/
215be66XVx3uVy38hKpNH9Wyh9/tMevcExfNW4HBaz3oeKWx4xzla+vdx352vmKGoe2dr5q/1LlrPXz
216rttFyub8pgbh2wbnBmxH4/h1dgEVXr/Tb/5zftCav5maPtPFup3FjxZtbk4f9f7HOjMzuP5n4UyV
2171FlY5PP5LB+31PTvdzKzsNl44fS19WT6/Ti/O/dBDXWO007Dcqxaf0rqXE9cvj4sJmhelL33Y+sJ
2181l30OBa2be/rIvPrSab3wn5LGqltZ3Nnm2mnfP+Zeqd8v5Svv217H2E7uoQzA1bbhrTZTm2Qqm1n
21983VmBxHyfkmd5TM73/dttpMqYLPOwtMwVeOWer35qcx81U5fW0+qnZL5rUr5i+2irc7N9k9pp3a5
220pNrZub187Pdj+52OClH7sXwLm+McJWR55deTfv0275/zE+zZf5b0+HG/1GN7H3k7GsqZN7k/n8/3
221nnfAgV6stV3bP11tMeWpruqzQ43JdNLFx4btoqrfA8Z/tHb2NPiFR4Vmtevh/HeJPaMatd01TNZW
222+c6Co8aquR3bUaErXSK8uvcOZb1i9fudsk3vekra/4bNr4eScYtavkeut4vfhrt2lNlOrZYNUssr
223M9Rd+62avmF9GG1/fgrb0SRgHex9rnja8ZvEs/JGmQZd1/71qeN+fY3ggOVVJXD8z5qd3v1mttPv
224OTYEusR6ktkuatcHa8iL7WiI52AVWpxSPreYPV6XfnbOwpjXVUmxvC5nczsN2XLvsR/b73WU3T+k
225x+i0PtzeN4/blQLW9O9SaQi/DcsyfPEXNlg+2cueRkqm3/xR1Lx8wzb2kl9eZwms56xZq71feP80
226m8eGqoV75H5sNJv3Xe083IYs1tTEbetD/uMnLseQrvttRzdz0CXCxW9ssfczLpbT5kZbsixT7dRO
227H/V+SurbGZn53Rz/1PRR47n+SHM78yk3T+OnzkKXTF87/vl+NyfeXF61Gur82M6efVxbPbXLcX+/
228e7aLVPvraxy1I3nAfmw91Klxrn2/SuB6UtJF8361dn+4/mx+/QlcjilR+7d8Pes2A7ejm/mZptrv
229Sf1+fe7Q3HvBZEQdsHsbtrCDXWV5sVPbkrU+wAjmW2I6/tZtqhe7yT0kiV9d1G8kHMPy+gZVOcn6
230AN/gYgHLzujlEuNwiSKPYShur2oRWx/gG1zsJncAgPEJWAAAwc4MWAd/RfNjd4N/ZXTw8gCAt/uc
231wap6Dg0AQD/3CVjuGwUABnH0g0anVRJaPyAuNX3D84Q2G2/4SMiDQDPtfHxffASACzkiYOUDx/p1
2321IMZy54blvtIv3pK2m+oHwAYwQmXCBd/X+L4TvdPFsKDcwDgro44g1X1V6XGFHICKTMOTlABwJ0c
233dA/W+5rXdM2YFVVzahyuOCYAQMqhlwifz2ft35y/JeMAAPd2RMDqkSRq2yy/yT226/nEe2pYv+m5
234XwAwrEPvwXr/s236+fuLad6v51ffMtOXdL3Zb239mRo+tt9QPwAwgp9pqrv7Z54umh9YAAAwiLLn
235ItUFnvs8yR0AYBACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAEL
236ACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEOxWAevxeHSdvnc7
237newsb/C5A4ABHRGwHn/a31rX6a/u2+YXAAb065huns/n+/Xj8Zj/s1MvPaaPbaffOAAA5zooYKXM
238T7e808Yrebx/NH9//mKRTtZv1k5fW0+m39T0qUY2zSde9JKqs2TWNuspr3OzcQBg7syAtTiFM//n
2395uvX/1MnfuaZ5v1O1fS19aTaSU2faSRl8cF3dNusMzO/H+vJ1PmxSABg4aCAtXmmJJMwRjtBctbF
240xyjN9aRiKwCQccI9WHMlJ0gc0decWAKAkY11ifDEYg6QuZGroamIigCALk6+yf0LXT0buckdAD4a
2415UGjtz999Rb1PLB5g1FNHdw4ANzVmWewFpfMCo/l62cWTNknFJRPv6ih6kkKJed1Mt9SrJKvc3N+
242q9rJLxfnrgDgo59pqv1+3O/XHpVZJSpgAQCByp5PVHfIdg/WcRrOkAEAVyRgHUqoAoBvMMpN7gAA
243tyFgAQAEE7AAAIIJWAAAwQQsAIBgAhYAQDABCwAgmIAFABBMwAIACCZgAQAEE7AAAIIJWAAAwQQs
244AIBgAhYAQDABCwAg2K+zC+AiHo+zKwD40/N5dgWQ5AwWAEAwAQsAIJiARX/50/i1J/ldFDhmBNa9
245GHmAYgIWNZ7P3//R1XVH+LqVA8RxkzvFns8/bnVf/DPDDfKxzhpPyxGgmIDFbvng9TqfsTg2v09y
246pN5f/Cg1fYhM/R/rKSxpc/pXR+tZe7+TGbp1wZtD1FzneuL8cky1X57CAe5FwKJV+emrxTWjVIJJ
247BZ3U9L2V1LP+Z3k7qdebvbytxzPVzp46113kl+Nm+9IV8MXcg8Wpag/AJx6we3Qd1WZ4bQ0NSlcA
248M85gUa/fBbuQE1SbZ18avM/ZpK6X7Smpn9Qlwh4dZcZHugK+m4BFvfcVqE4tj9DIvKl1jLjKibfe
249/WbGR8YCvptLhPDJ47F95xMvm+NjxIDvJmDRJHXsDLx2tvmj3sfsxU33tR/pMX2Uqn5LJv44jYwF
250fDGXCCm2eBbAx9dT4okDhZ99X2DKTBNiTz1TwWW42ukXn9q8pyp189Oefvcsx1T7rhUC3+pnmuoO
251V3/uUR9Pv6F+CcdIYDQOQASZ55lH8nhXt765RAgAEMwlQsr4TREAijmDBQAQTMACAAgmYNFd+obB
252zz/dP/39HDMC617GHPkxqwIQsKjwmDm7lpu77ghft/K54+ci1WMq6S7ev8eww524yZ1Si6dylD+k
253w7M8Yp01npYjQDkBi73ywev1i/Xi2Pz+bTv1/uJHqelDZOr/WE9hSZvTvzpaz9r7nczQrQveHKLm
254OtcT55djqv3CFF41Pvk6y9vP9Dt/8bGL1PqTqT/KvK/wxoGdBCwalZ++Wl/L2Eww+QPVevreSupZ
255/7O8ndTrzV7e1uOZamdPnesu8stxs/3ydFU1PrXrQ+1yzI9/ldS8VHmN/P52gIO5B4sz1R4qTjy0
2569Og6qs3w2hoabEtX+b4+trC/zq569/XKXiIXjMkZLKr1u+oRcoJq8+xLQzvvczap62V7SuondQms
257R0eZ8aka8xPr7Ncv8OUELKr1u+0jJLEFxr75nM6bvcqJtwPOoEyJ8SnPWJs37cWKWo5neY/nelSv
258MgvwhVwihA+ez+fmnU+8bI7PgCNmOQJHErBoUf7MnrZ2Uj/qfXRc3HRf+5Ee00ep6rfw5vH8BA1p
259psf0nZZjSSOBy7rqpCAwApcIKbX4zvnH11PiG++Fn30fSzLTHDZfqXqmgms0tdMvPrV5+azkCQJ7
2606qxdjqn2S2JB7fLdM/1UvBwzd26V17P4Ub6daRXIxCm4tJ9pqr2b5Pdrv1EBbLJ7hAspe/5L3Rbt
261EiEAQDABCyCe01fw5QQsAIBgAhYAQDABi+7y3/O6ymMOxnHMCGz+xcMD+q01ZlVYLiBgUeExc3Yt
262N3fdEb5u5XP3mIv9+o1D+bP0Xu/0e8YYdOI5WJRa/0mT/X/NlwZ3/cM7AHciYLFXPnhtPq0x9fTF
2631IMf+/156Slb/8d6CkvanP791+XW789fbA7RuuDNIWquM/V3kQuX16K28n6ngvHJ11nefqbf+YuP
264XaTWn0z9VXXWLt/MelVVZ2YcTtlOFzX3aB9iCVg0qn0i+VsqweQPAOvpeyupZ/3P8nZSrzd7edt8
265dvlmO3vqXHeRX46b7Zenq6rxqV0fapdjfvyrpOalqs7U69rpa+tMjUPv7XTx9P+QBQGncA8WZ6rd
266dZ64q+3RdVSb4bU1NNiWrvJ9lfyZmpIudn6k2ZHLdz7N6ZtVp0F+ZS+Ri6twBotq/S4EhJyg2jz7
2670tDOM/3X6GrrPPLEW+pSTo+OMuNTNeYn1tmv3wY96umRRUYbNxiTgEW1frdBhBwMAo8o8zkd6gzB
268IP1mxqc8Y60vOUWXGbYcexutnpQD1qv3nWGLvq4yRDC5RAgfPZ/PzTufeNkcnwFH7MuX43zev3YQ
2694EgCFi1SO+jAa2ebP+p9YFjcdF/7kR7TR6nqt/Dm8fwEDWmmx/SdlmNJI3va7DEUqXuYwuvcP5hV
270J0FhTC4RUur553e5P76eEt/0Lvzse9+ameaw+UrVMxVcs6idfvGpzctnqZuK9vS7Zzmm2i85TNYu
2713z3TT8XLMXPnVnk9ix+11Rk1fWayTJ3rcQjcTtdnPUtmAa7iZ5pq7yb5/dpvGACbBt89ph73AN+p
2727DkjdVuKM1gAX6HhjBfQTMACiDdggkldHzy+EvgGbnIHAAgmYAEABBOwAACCCViUCnzGT1vvno4I
273wFUIWFyDW3EBuBDfIqTC/Nk5i/ffr+ePEtl8gOH6b89tPn1EogLgugQs9soHplSuqmoHAK7FJUIq
274bP4ts0wMqkpI4hQAt+EMFgGibj93GzsA9yBgUWd9nml9aa+t5ah2AOB0LhECAAQTsIhUe9opNb3T
275VwBcmkuE7LV4FsPHbJSaPtPO+/XrhdvhARjczzTVHavmhzZfpAcAri71RMY/1QUelwgBAIIJWAAA
276wQQsAIBgAhYAQDABCwAgmIAFABBMwAIACCZgAQAEE7AAAIIJWAAAwQQsAIBgAhYAQDABCwAgmIAF
277ABBMwAIACCZgAQAEE7AAAIIJWAAAwQQsAIBgAhYAQDABCwAg2K+zC+jr8Xi8Xz+fz/2N7Gyn+bMA
278wIXcMGC9c8wi0OzJN1HtbBK8AOBm7hawCsNKyJmtTDsf25/X+Xw+ZSwAuJNbBax8THn/KOrMVqqd
279j+2v35GxAOBO7hOwugaUzTNShd19TFfvyWQsALiHmwSsfDR5x6Pwe7AW979/9PEcm4wFADdwk8c0
280vKJJ5qc9UssrDL2VfCRfp3QFAPdwk4A1fcou40jVKV0BwG3cJ2BN2YzVO3vlz0st3lnXKV0BwJ3c
2815B6st/ltTPMck3o9ld2YlbrJvbn9eZ3SFQDczM801R3a50lAMgAArq7s62t1gedWlwgBAEYgYAEA
282BBOwAACCCVgAAMEELACAYAIWAEAwAQsAIJiABQAQTMACAAgmYAEABBOwAACCCVgAAMEELACAYAIW
283AEAwAQsAIJiABQAQTMACAAgmYAEABBOwAACCCVgAAMEELACAYAIWAEAwAQsAIJiABQAQ7NfOzz8e
284j5A6AABuY1fAej6fUXUAANyGS4QAAMEELACAYAIWAEAwAQsAIJiABQAQTMACAAgmYAEABPuZpqhn
285WXniKABwV3V5yRksAIBgAhYAQDABCwAgmIAFABBMwAIACCZgAQAEE7AAAIIJWAAAwQQsAIBgAhYA
286QDABCwAgmIAFABBMwAIACCZgAQAEE7AAAIL9TNPz7BoAAG7FGSwAgGACFgBAMAELACCYgAUAEEzA
287AgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADB
288BCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFjjIp80AAAS+SURB
289VABAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAI
290JmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwA
291gGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzA
292AgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADB
293BCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUA
294EEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglY
295AADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCY
296gAUAEEzAAgAIJmABAAQTsAAAgv06uwAAgOt6bL7rDBYAQDABCwAgWGTA+u8/fwe2BoQYfMMcvDyA
297Nrl7sDZ3fH/9+k+3Yu5jPnQ3G7HXrO2fqf/+8/fBI7Nen0sKOL7ONr3rHG0cUvWMVifwtTYC1nsP
2989d5P7dxnfcku7z2bi/k9bPaP6eivX/+51imH+bCcsh6evv5/w9YHMJplwCo8GGTO0Lx/ND+qVR1j
2995i0szpds9psJNKk6P9Zfe0wqmcHXNOvxaahz8/3acW7oN6Sd95vroR5qudTWmWqn93LJ1Jkqvmp7
300aVheDWdwN8d/s85UPVHLq61+gIU/AlZ5usrsoDdf1x5jFqeC3rvCqjNDmR107BmmfAsfx6q2zkz9
301VeMcNT617Wz+tKHfj9qGYk+dIet/1HjOu97Tb+04NCzH1LhtStUTtbzC10PgO/0OWOX7kcIwsf7R
302mLuqzd10uc0dfep0S+oQ2FBnZrK2ce69aGrbD18uU/rMRNS8h6z/setDuU4rQOAshxu5NuDq/hew
3039lzCKNcpY82bXf/2mZp+6nmn9vxaRuFJwdp+Mz8tHOfMOMTWU+iw5bJfyfxuxuvyk8SNlRWo3V4y
304em9fp7h6/cAg/hewdl7CKOzs+DNYqe5qA1Cm/cxM5a/dvDWMZ1WDH9tZj8POs03Njlku+7W13HwJ
305vqGvBoHrYdRyPMvV6wdG8Ps5WOX3arQZ8PrgX7/+s57r//7zd9U4bLYQU1+ThnHeHIcTdVou5xpw
306/e9ttPWq1tXrB871x4NGG/Ymhdmi99HlVXm+l3dtH6+vtfVeMuXHyTITZMZ2/rq8/qiaC6ffM+9T
3075+WyR0kXzet/w/pQ4uP20tB44fbV1t2RKUeiAkIsH9NQcm1lftxaHMMWP3q9iEpX677apq9tp7y2
308v/791lXmZur1+KTGs7b+2nFuGJ/FQTQ/v/lxXt/p0nu5TKtjZ0kX++vcs1xK1odUnVNiedX2m2o/
309cPuq2i4y81tVZ0kxhfUDrP1M0/PsGsbS72TbF14kCmT0ABjSY/Ndf+x5yVF8TJYLAAAAAAAAAAAA
310AAAAAAAAAAAAAEDW/wMXMWZMdK+KTQAAAABJRU5ErkJggg==
311" id="image69" x="-64.869583" y="-199.01341" inkscape:export-filename="/home/m/Vault/projects/mitjafelicijan.com/dfd-rice/install-01.png" inkscape:export-xdpi="75" inkscape:export-ydpi="75" />
312 </g>
313 <g id="g372" inkscape:export-filename="/home/m/Vault/projects/mitjafelicijan.com/dfd-rice/install-02.png" inkscape:export-xdpi="75" inkscape:export-ydpi="75" transform="translate(407.41482,-79.959051)">
314 <image width="169.33334" height="127" preserveAspectRatio="none" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAyAAAAJYCAIAAAAVFBUnAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAO
315fElEQVR4nO3dwXaqZgNAUdOVQR+vQx6RYR+vgw7+Qbr8jQqCHoWYvVcHXoJ8BJPLuR9oPw6H8QAA
316QOePrXcAAODdCCwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwA
317gJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjA
318AgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCI
319CSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwA
320gJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjA
321AgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCI
322CSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwA
323gJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjA
324AgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCI
325CSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwA
326gJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjA
327AgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCI
328CSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwA
329gJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjA
330AgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCI
331CSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwA
332gJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjA
333AgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCI
334CSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCIfa59
335wjg+Yzfg5xmGYfT7wE/j5xbmDUOzHTNYAAAxgQUAEBNYwHfV/PiLh3vxbgPMEljwfMPw7b8HN3XH
3360MuXP5sMmuf4wLsQWPB84/jf20OOD1459Krl81+aoQwATqx+FyHQGIbDOP6/S06z5jRWjsuPC78e
3373Fz/7r263PjN/Vwy6Mz+T23qju9r1XbWLr856OH763V5GOfXP32w/Ofh+Op4byDsyUOBNfg3Kzzi
3387KT79XjqxHz1qzPr3+e0pZbv55JBp/Z/yfYXDrFqO2uXLxn0kfXveH3PnrL4pfdXN1zKP77k0Rks
339n6fCrxWcpZb8+iwMl6d69hDV9q9uZ+HGn7oPLxh33Zj+3oZvnvGvDpcIYWfuuOLzrhMST32D4cxx
340XjXu2tfL6wu/g8CC/Tle8TksOA1fXkJ6jakbs9ohHjdzfKaO832zUMuz6b71gR/Fuwhhr77ecrjz
3412YvXvy8yVx3ns+2cPp6aQtv/6wvcS2DBzjxyxn392Tr5cK+FAz2+zukKC/d51TbPfPVTO8UoyOCH
342cIkQnm/+EwrOnM1qnK18eQfP1KzJzLhrl19137sXl9+BNH8cbj7l5vGZ2v7acW++XmvXn3l9l+wP
343sA8fh8O6X9fvf6P6v7Lze/32n//24yHe3m6Oz2//uYVrTn8vqmliM1jAXcys3OT4wC8msOBOpgFE
344ww27PD5+buGWqSmsdb87bnIHAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJ
345LACAmMACAIgJLACAmMACAIgJLACAmMACAIh9Pn2EYXj6EGxnOIxb7wIATBo3Ok2ZwQIAiAksAICY
346wAIAiD3/HiyAWf/8+9fx8Z+ffy9cflzyz79/nX4VYA8EFrClszw6/vHm8q8H6grYJ5cIAQBiZrCA
347LU3NP80sP14iNH0F7JbAAnbh7M6qmeVXryEC7IrAArY3VUsqCvih3IMFbOyOujre4X76TkOA/RBY
348wJYeqas/P/8+3pIFsCsCCwAg5h4sYGNnU1CnnyB6ufw4s3X6dsIX7SjAYgIL2NIdH9Nwcx2AzblE
349CAAQe/4M1jg+fQi249UFgEtmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAA
350YgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsK4YhmEP497cjWEYrq4z
351s/yR3QMAFvp8wRiX5/VxHJc8a8lqd3v29mfGPSw7Aje3c3Ujy7+v+14XAOCmVwTW4aedue/b24Vl
352M47j1EzSs4/S2fbP/mh+CwAqLwqsq86K5PjH45n+bLLna4XjV8+ee3x8c/nU9qcWLhk3mZG6up1q
353iGrmDAC4acvAmnLMrKu1cdZbl2veXD6z/cPEDNPNcR+/4Lhq3OOSw+JwnJk5S/YfADh6UWBdnUn6
354OuXP586ZqSRasg+PBMRW8THz/V4esVVHEgB4no3vwTpOq9zRBFOXAgEAtrXHS4RrXV4KfM24Uzdm
355/TgmvQCgtXFgrb1EuEM/dLcBgOfZ8oNGT6Nq/hbsVdu840sPjjj1wZ7Jxp+x2YVDr/0UUxdqAeDL
356Bje5H5bN+iy/PevsUt3Vx5fbubr9+TfinZl6l+L8U65uf2p5dRVy1fcFADzo43BYd649PTX/3Ot6
357iTsCCwDYm7MPRZpYa90p/h1uct/K/AwZAPBrCayHiCoA4NKWN7kDALwlgQUAEBNYAAAxgQUAEBNY
358AAAxgQUAEBNYAAAxgQUAEBNYAAAxgQUAEBNYAAAxgQUAEBNYAAAxgQUAEBNYAAAxgQUAEBNYAAAx
359gQUAEBNYAAAxgQUAEBNYAAAxgQUAEPt88PnDMCT7AQDwNh4KrHEcq/0AAHgbLhECAMQEFgBATGAB
360AMQEFgBATGABAMQEFgBATGABAMQ+Dofqs6x84igA8K7W9ZIZLACAmMACAIgJLACAmMACAIgJLACA
361mMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACA2MfhMG69DwAAb8UM
362FgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBA
363TGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGAB
364AMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQE
365FgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBA
366TGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGAB
367AMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQE
368FgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBA
369TGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGAB
370AMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQE
371FgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBA
372TGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGAB
373AMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQE
374FgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBA
375TGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGAB
376AMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQE
377FgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBA
378TGABAMQEFgBATGABAMQEFgBA7HPrHQAA+LmGq0vNYAEAxAQWAEBMYAEAxAQWAEBMYAEAxAQWAEBM
379YAEAxAQWAEBMYAEAxAQWAEBMYAEAxAQWAEBMYAEAxAQWAEBMYAEAAAAAAAAAAAAAAAAAAAAAAAAA
380wBv4H+xMBAXacnSYAAAAAElFTkSuQmCC
381" id="image81" x="-565.28839" y="184.09018" inkscape:export-filename="/home/m/Vault/projects/mitjafelicijan.com/dfd-rice/install-02.png" inkscape:export-xdpi="75" inkscape:export-ydpi="75" />
382 <image width="169.33333" height="127" preserveAspectRatio="none" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAyAAAAJYCAIAAAAVFBUnAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAg
383AElEQVR4nO3dwbKjOLYFUOeLHPTn9dCf6GF/Xg968Aa3ykUaJEuwAWGvFR0dTl8sHQSIbbBdv263
384xw0AgJz/O7sAAIBPI2ABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
385AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
386AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
387AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
388AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
389AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
390AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
391AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
392AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
393AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
394AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
395AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
396AABhv/fu4PHYuwfoc7/fH/ZL2Ifji6u43/dt3xUsAIAwAQsAIEzAgnfu97/+F1lsP6XeTyypxeDl
397Aayy+2ew4BMsfqbkfv/j+Z/HXXFhuvDGj628FDOs8escv0LgClzBgpP8nMif/9vvQk49LriAlHWV
3988bxKnXBZrmDBeBavbP0EsuefGq+y/Cz/svBiIy9Xbp7/rPTbdQXuuXBXSV3t99b5tv35mNTbKa1U
399qf3FhZ9rMd3083a2rG9Lnev2N+Bvhwasu/dMUPJyYnua/nPxcT24zK+NlRqsKPVbyWdzi68Ktt/b
400ztv26wsstlMZ25b6Xxp8Rpze/SFV54pd5a9lTfWM67CfETn6CpbfR+F0F579Fw+fSnDZtd8B26+M
401T+9r5+N51txV6XfL+m7s+s3rzPMM6sj53y1CoEfpVtQeUu33tlNKqyvaidi735blZSboJGDBlwl+
402sOYSV7Yqn6Oq9Ntyx3C68PPxSzvb9dZ/Vp3AnwQsWCt7Wjr41wGcU+sWM1Z9+Uu4Sp1wfX6mAda6
4037me5bu9+FnXFqo1wu7Dl6k77nyq/nTF/vj6eLbW12H7v75g6AVew4DQv5+/npYXS8yssfsGw9K2x
404l1tIb0+06+qc/wZBsP3Fu2Cl9Wppf3odq/TalvFsrL9lpbq2y5F1An/6dbvtezj9eUT7r6xzvu79
405sPETS1f5xaAVPx9wCWetyFXG86g6zfOMbLp/7n251hUseGfd9/yH5YpF1lXG8yp1wqcQsPg63l5/
4065sn1xJW6yngeUqfji+soXcLK7MM+5A4AECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYA
407QJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYC+73+9kl
4087MJ6HWleVarO+/2+2NS69uOjd9bmGHM3AL7WoAHrPnF2Lfyhd4tU0kBXU/aEH/f7/fF4PB6Pswv5
409y97bZe9JwCQD7GTEgPU8hfw4fvpbd/Yaf5o+5axc6jRYzDhpo27vOq8yDl0MGnBRv88uoM80xExn
410xsXnf4La809vn5829dJ4aflSI6Xi582+rX++fL3+Su8r1uulnkpT8+VX6O23/uS8na5xmy750svb
411/XDeeHud60T22656WrZLqd+W9lu63q/fxZUCaHeBgNUYOObPr3h8m5xNpxaXrzTSpVJ/y0sau163
412XtN/Lv51Xf1vV6ql39J6rdgfSl66fkaWt/vhfKi76lxUDzSr99vV9VS2S9d+1at3+6b6Begy4i3C
413n1PF2ztuz1myMl2m7k+NNiOn6mlMZuMUM34X7R2t2AmfibPxtVu23Zax2nWcd6p53tRoRz1wLYNe
414wXq+9by1TZrjf/5pP/HTwPyO2Fup8b/KdvzI9V2x3XudNW5DjTPwJQYNWD/q94ae5rcAdq/sdrv9
415eVPmw97sdgXc1PiftR1XiGzuAde3943NuvY3WjFuH3Z4Apcw4i3CEc407bru17x8jGZwP6t2iVIJ
416st1vfr4B2GzEgNVocfo7fk68/61l4efHy3rfUh+5Xlv6+sh7Z3WR/fCs9X35kPtZXacaaWnzQrsW
417cGkj3iJ8efc8/TD72+c3vvOuf1FrvvCKbyfNlxltvUr1vPy1pc5Sv4vP19d38RNCb9t5u7IrrNhe
418K9a3y+rtW6mh97psywfqe9vvHbfFu/aVfivj5q4isNGv223feWQ6TX3YF6Q3fv37w0YDAAZ3r/6e
419zt8yp+YRr2BdxZZ35I3LAwBXJGBtsuKnjHaqBAAYx4U/5A4AMCYBCwAgTMACAAgTsAAAwgQsAIAw
420AQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAj73fuCx2OPMgAA
421PocrWAAAYQIWAEDYJwSs+/2+cYGL+tT1Ykz3+31xl6s839v+ysr2NGZVwPi6P4N1gOmM9hj7M1+L
422pd7v92nZz3+Wnp+3ubj8ON5WvrGd0sK3bfvDy5mysalSv9vrGVDl0Ett9JSzxv85RKtHozI/vCxZ
423er70p7fzTGm+KrVfWYXSkovbpT6ld+1aXcfjulNJV7+VRl6WL21fPtiIAetWDisbW8uqT2QHHDwn
424ntjan+9tp7RwJHS2BNz5S0pnoA+7ttH4BqBd78u7lj9l/Otj0l5PqZ36k/NXlQ6KUkRY3L69s1bL
425vFeZDOf/LPVS6brlTey6/bmr30oj8+Ur4Y9PNfotwpdp9D7xsmT9+dLCL41X2jlG+1ltXmSp/sXF
426Ks+vKK/3ZNy1/MskFd80K8ah0tTi/lPZ3xb/WdnPr6L9uFu3/Ipi5uP/fKbyp+mT9XT15RckVhyn
427XfNJqf3g/NDV7/Ovlf3k896G0WXTFayWXSc46dwb3jnNF1s8JFa089a8095173rJ4qG7pf7GTrue
428723n0kr7VWV/62rnLPc/E/n81tLL8z+6jrsVy3fVX2rnZQP9PHg5iFZ08da6+SHb/uregwd7aj5J
429Oazf0w9qjrH1FuEge8nqJLSlnQGtnuW/5ICfni/3Xt+PGc/SHrJxz3n7qtQAbmlnfgV93mzw2Nl1
430/3yuS7barkvRwd7fOubq0ccc5uxh0M9glaQOmOyB92xty0WsUyJOfM4d3K5XhiqD2bu/RfbPeSOX
43128qjHe/B/WdxfghuoEr7kUO+d/XPmt+mBbw8WFwMgi4WsCJHwvyWwcYGp9MW36x0AjvlFurVTxup
4324zR+vC92UepuQNsvWl8iXZWcXslQo8GuRv+Q+6W1X6M+65D76dcnMbMah/Tx5wd196+LXTwmbj3n
433772Pu8r9zS0una7i5h9yh6fRA1bl4IzMHSPcgzhyAiq91d5vru+dgObLPwrfGNrDxu3Yu9jPqtVX
4346lOn79694vhOg/1+g72P01L7Lf1uqad3vY6crxjcoLcIK59qmv5z8U+V++7Pt5jThVfPoS3tVJZp
435OfDmUePl+ZaPU6TWt9JvVz0rlk99Vmxx/Cvj07W+pe1b3+7zNVqxn0QE++0an5blG7fLot79v7T8
436HtulfpFp+3G0U/2lOkvHae88Vnq+1P7bfhtXtrffUsup+Yqr+3W79X465J/HrhUzoFLSPb6SLm+P
437jouuF8A4pjNt+e1WZl4d9AoWrHahzNF1ReFC6wWAgAWnkZkAxpO5sjX6h9wBAC5HwAIACBOwAADC
438BCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADC
439BCwAgDABCwAgTMACAAgTsPLu9/vZJfxhtHqezirsfr8POyZT5xZZ6n3+fG+dlxj8t7aPQ6XlKw7R
4403jVfcUz4ciMGrP1mrm8w2lgNWM/j8Xg8HmcX8uGk53Xsnz/G34jjV8jpRgxYfAlnkbp143P8vN9b
441567b/cSdyv5Mu6vks6vUOabfZxew4PF4/LyN+/nny+PpYvMF5v+c+1ng2dTLa9+239LFtKne9t+u
44279sefx7Ma26sp6WLef3z9lvqKRXZ0n5vnSuU2ul6vjI+lfWaj0/Lftu4sm/rb9l5KnWW/lR/8qWL
4433uO017Tll6p6x+fWs15bSr1tOC5WzDMr6i/t56UyKi3sNI+t2K/etj9fx3o7W/aT3v12y/ruND9/
444jxEDVknvgdrY1PPx2/bbe1zXfqWRluUXezmmnsXHlXpuk9lhdfu9ddYn7q52up5f8fi2ND6l5bsG
445p7H+adel50t17r3dg/PAS4PPU0XX+KxYr0Wl/TN1XFT67d2fW5paXc/e81hvO73nhcb9Z3UAvXXu
446t1vWt7HOyHb/SIPeInzOVjttrb33gNKpZddOK05Z39Hafzwez+S3osHSS57PV9p8+9qNNcQbSRW8
4470WjHUVcNKzZu7/452tx4iXmg1M66MZ+foc7aP3vnn2CdIxySYxr3CtY8kn+A+Rvf259rOn+XcHw9
448/HjMrsC/dZXxvEqdJVc5Lo4c5y2X8Ur7+VX2k7O2V+kMtaKdruVT7eyx/IedsjcaN2B9nhXh6Srv
449CD/VM/XeGsbq4HD89Oj/gNopdaYcUH/kuLjQOJf286vMD2dtr8WrAKV2KsfpKfWfVedXEbDgjcqH
450QsYxcm1cwk77+csV+mDLI+i903KV4/QqdQ5u0M9grXaVA3j+ueD7/V4/UEe+LXKVYe/SuFKLix0/
451IPe/9b4q8vxZDqgnsn1HHrct+3njMi3zW8qWOlsWmP/psfR9lNLCb4/TyK6yff88ps6Pd6UrWC/7
4528fTDxYuXN+Ptr/hQTqn9ljpL9TS+6u3yve1Xlq9fVZ7X81x4+qd169tVZ6SdvffDW/kLZaWFX8a2
453vnypzt7H9Tr32+7r6mm3Yvu+Xa895qUt7VRqe7uft3fx8qd11cbnsVKdveMzb7C+3UvH6d7bt3f5
454vev8Kr9ut979/p/Hve9IjnkHw8Fs1nP1Biw40en751kFXOU4vUqdq03XqP9tT99QXOkKFjDnnSWD
455s3/ernOcXqXOSxCw2MoReDqbgJENtX+eWMxQ41BxlTrH92kfcgcAOJ2ABQAQNnrA2um7oL5iusJo
456g3ZwPVu+2r26xxHGfIQavpnx/zHIOLSXMcjx+9aYdQ5Y0gpDB6zI9xcWt9PGb9Evtnz8+X6xx9TR
4578hn7d7vRZpmfnf/4D0MMNQgnOmscjP8x9h7ns47fRfc/vfxpnDo/z9ABa3wnzoalQ8Khso5xAz7S
458M0LJUgcb91uEi5evFr8++rPk/Ifj6r86OP1puLh1dc5/Wy/yddne3zWpj9viDwmW6ux9/m1JW+pZ
4598fsupV9N7H1JcDt2re/zmcVNWap8+3Z/28XG+o/pt2XQVrT/tpGDx793v6o0Xjq+UsfjrXMcerfv
46023a2nC/2Pn73dsD2LY1zZP48xbgBa66+geePf/5/vxR1K6S03jrnpT4PxRUT0HaVcVusv1Rn7/Ml
461veOZGrfSDNL+ktXrO33wdt0r7S/uV6V+U9u9sl69+0PkuOjtt3feSO3nZ41/qv0V/W5pavU8Uxrn
462lnZa5oGzjt9elTp729l1vj3rPBhxpVuEb88N4+uqc8CV2lJSanWm7Rw2RI0dRep5PB7PM8FLg2ft
463Env0+3IWOUy8uwP2jb2HaMCpZtHpdbYUMODxu6hS5+lGq2e1K13BujVfSDjS/C11+wvfLjPg+i5a
464rPNRvrLdtV6Vdq5ij+04wmiktmPv+JzVb1c9B+y3e88PV5l/Uo5c3xGOX/Z2pYA1v1R4YjEHuND6
465liaL55Xtl2V6J5dSO1dxxZpbRLbjiv08tf9Etkul/r33W1e2sr5tfdnblW4RDuuR+NGH/Tz+/C+l
466n1JAZIhS7XCus7bjt/V7sNPnGXZl+64wbsCqT0kvf1qxvUv39e73+4B7z8aSfgbzmI8H9h6Ebxfb
467Y3PsdE+q6zOwHyayHdcdyJE2I9vl5cO52xtc1/VZ7a+eZ47cRo0W+xrn4D3lPLX39l29/LCudIvw
4688ed3XF8uxU//tPiqXbNFvbZ4m6UvgFS+GLLirkrjuJXWt/f53va31NMynpXlW7pevb69su1v3+69
469y/eO8x79zttZNw7b54Hjxz+1fGmx1Hafv6S9/Xlh83EO1tll7/nhlvvC4OJr9ziu9zifnuLX7dZ7
4703v3ncW+SXZd8375kp2Y/1TevO3AM88xnu+72vXf+7saf+lZ59CtYO23Ci+4Zq133HQBwFeaZz2b7
4719ho9YLWwpd8yRMDezDOfzfbtNe6H3AEALkrAAgAI+8aA9TFfAV2ntPrz57/zu7XbxyFeQO8CnP59
472/iMdU8DpqwmX8zkBy/F/jLPG+ZTffTnAaCs1Wj1nGWccxqkE6PI5AYu4FT+dtVMlezc+bNeLRqtn
473QF81RF+1snAhI36L8OdnKhZ/OHTxa6LrfkWtq/2XZRZ/RaOl30r783oq/Xa1fyusbOX529Jg1se5
4748uTierWPf6/5L9S93V5d4xCvs97F6nFu6frWdhz1bseufoPtL9bfe/zuPZ+0NFJafj4JLG6synzS
475VeeKwQeeRgxYt9kk+Pj7v5m6OFEu/jXYfksjG5cvPe5Sar90Rqn/3tr8t3fr4zxfvnd9VwTKkpcG
476n6eWrvFZsV5biix18bLA9np6j6PUftsy/lvaf5oPUVc9w84niy0srmzLGL6ts35cAG8Neotw7zdM
477pYhwfKfBrlsaKS1z8DvUU8a/xZYxPLiM1GuP7GvxtXsfF43OGofGNrsCX/wwH+HYhMsZ9ArWWRbf
478qE0vfszf7W1vP+jqbzSvMj5DjfNjdic0u/ztOtuly4px6NW1XpV6tlzNbTHU/gwfQ8D6x4rw1DXr
479bQxnp7e/twPqj5ylBhznZ/q/9VyE611+JyeOZ+84rGt/ez3zG9xZLlDBHga9Rcjtz09XjHAWZ3CP
480x6Px40frlv9Uo43DYj1DVQi0ELCWLc5u9TeRXdNf48It/Xa13/v8WQ6oZ7GL7fd8f7bX+rL6HXyf
481+uV7EpF2Ig32dhrsq/Ez9RsXaM9YWw7zxu1y/H4Ol3OlW4Qv88tL5tj+iYrHn99h7p3v3vbb235j
482s2/b7318m8ynpbsVL08uLh8cn0o97Ur19PZb3469Vxq69tv4OM+Xn9dTWf5lKNb1u+64aNe4z2+Z
483TxbHIbtdpss8/1Q6LkrbpavOvbcLfLxft1vvpwT+edx7ZWXvj2p+NqN3FV+ypUZbzXvhmyjfprT6
484Xz4s8GPxLUqzviPoSlewvlDXO2BG4DR2lu3XsAGCBKyhOVVczvdssgHXdMCSjlcaBIMDB/MhdwCA
485MAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACA
486MAELACBMwAIACBOwAADCBCwAgDABCwAg7JIB636/3+/3s6t4r7HIS6wL881kw/348nH48tUHSn6f
487XcCylznr8XhM/zT959cyDt/p59Cw6c/a/x13QKNBr2A9Ho+fWez54IquWzktTtm+A+5UA5YEcLpB
488r2BFvLzXnP5zeoVs+mTXpbL5AvMu5gvM+33509vT1XPJeReV9utNNbZTGbcV9T9f1bJdFtvvWt/e
489fm/VjdK7fdv1jmel39Tzb7ueHzhd26tru1f2/3qRje1Xlq/029VOZPsGj4vecajMe8DTlQLWiom1
4901E72nuNiC9M5622/pceLfv76dprrDYjPf/Y+31v/fBWeU3xX+yu2Y1e/pUT+bKp9+/bqGs/UdlxX
491/3wcSvWn9qvS/l+S2q8q/fbun5Htu6Lfli7a25GroG7QW4SLHo/Hc6b7gAN7ugojrE6phufzlSL3
492rv/08WmMGkd2l2pkj7FNDdfe45Ba9952zup373aAqStdwbq6x+zO1LlW1DO/VnG80i2MLUZrJ9Xv
4934vOV7b5r/Rv73XLUjLZdpvaYDUY4TgEB61DPa++3MWJWVz3zWwa71tZiqHfwJ47PYv2Vekrb/Zgr
494kQf3O9p2+eB+gakr3SLsNf10yAhp4OnnFuc4JY1WD8c4a7vb34Bv8MkB6/Z3xlrxYcw9Zv/RziiN
4959SwuNtq63Ha+zdfb+OLnvtsb2bIub+vfst23OKvfwxofs+uD++3az+GzDXqL8OXK05Yr3vPXvrx7
496nn6I+/l8yzvs6WdKXupcrL/U7zrzTnvbbxmH0vN7XIFI1Z/qt7K+b7fvfHy6RuylqfZ+W+rv3e4V
497XcdpsN/pq7r2k67jerGedf22LJ9q57DjYrQPlcJoft1uvd9/+edx75Whc7/W60vFnKtxD7SjAuzk
4985UdJOl/dNzMPegUrJXjFCLYQmwC+yocHLKc0BtG+K9ppAT7Ah3/IHQDgeAIWAECYgAUAECZgAQCE
499CVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCE
500CVgAAGECFgBAmIB1Aff7/ewSdjHmes2rGrNOAEb2++wClk1PaY/H48RK3rrf74NX+KO3zp9NMH9J
5016flUv5d2of0WgF2NGLBeTslfdYZedMrqPx6PxSs3pefXdRFpZ2+NddpvAXgaMWBVlK4QLD7/c4Z7
502/qnlbFdpZ7rMzz+fC79c1Kn0u+IKx/yKUW/7pTrX1VMpsr3f+pPzdrq243TJ+aaZt//yksXWWuoE
503gKetAevtxYztp5+WoFO6clB6vKj3CsRi75V+113hWLxi1NV+qc7UFZfefkvrldqO866fEe3t/jMf
5046vY6JS0AnjYFrJ3OKPMLD/XeK4tFKpyem9tT0U7FtDfVmEKOKWb8Lp4dRd4zuD8I8OUGvUU4vQfX
505e2tvi1I7jZmv9Nq37UesKHLvcRvNMesrXQEwaMD60XjRaH7LZmOPOwnWWdIVTFP1HLBeKZHte6H1
506BeAsI/4O1oBnrJ9zavALdLu6UKkfyeUrAEYMWI0WA0QwVUy/BDf9vFekiz3Sz5Y2v+1e4S20/+y9
507EwJwUSPeInwJMaVws/j8lgBUar/xVS0fKu+ts/5LB5X25wvP66zUU/kFivnz9fVaHJ+37bxd2RVW
5087D8r1hcAbrfbr9ut7zS25aznw78AwFnqv8vzTl+AufAtQgCAMXXfIiwHvuIPHPR2AQBwaa5gAQCE
509CVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCE
510CVgAAGECFgBA2O9cU49cUwDAse73fdt/XCUnZOp0BQsAIEzAAgAIE7AAAMKCn8H6BPfJHejH2rvF
5119z9vY29pZ/VrATjefN7+kJn88fjjE1ov/2SJK1j/5KGfw+DpvmHvSbWzKN4gAFt87Dw/jYZdMfED
512MuVm334Fq/G9ReTKVqWdt+1P6/wJbZ/wlgjg+irz88vj50vezv9DzPONl6mmRT6Xv99d5frqgFXf
513fRePkLevau/u+c+37c+fGeLYA/h67e/Se+f/k+f5eTxazEyVW4dfn7G+9xbhrjvufWJ6tLS8tvH+
514/R43HwFotzg/PyfnFWeZxffSG4tcIxWMfjLWt/rSK1j1/f65Q69OYKV3JL2HyttrbK5jAZyiMv0u
515Ts6L8/8zQnU1ta9KulpxUeqLr2N9acCq77LPK7fZTueXgt++pF6ndAVwlt7o03LGmS9zwjyfjUTf
516mq5u33yL8Cq32Ep1SlcA5wqeRxa/dX7aPF+5tdd11++L09XtmwPWrXps7J29Ku3P/zTQUQfAxLqM
517Nf15oMoyZ87z2z8+9d3p6va1twifptd4p8dJ6fGt7YNZla/drmt/Wqd0BTCOlnuFpXm+9PwQ83zp
518XuE0e73ksOfCX5+ubrfbr9R/Nbrkz5EfYI8BAOb2jkQDBIC2r51l6vzqW4QAAHv49luEAMDtNsQV
519pk/iChYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
520AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABD2++D+7vf7
521wT0CABzs0ID1eDyO7A4A4BRuEQIAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAEDYr9vtrN+m
5228oujAMBoMrnIFSwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBM
523wAIACBOwAADCBCwAgDABCwAgTMACAAj7dbs9zq4BAOCjuIIFABAmYAEAhAlYAABhAhYAQJiABQAQ
524JmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQ
525JmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQ
526JmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAPEh2noAAAUSSURB
527VABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
528AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
529AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
530AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
531AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
532AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
533AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
534AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
535AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGG/zy4AAOC67ovPuoIFABAm
536YAEAhCUD1n//9+9ga0DE4Afm4OUBrFP7DNbixPev3//ZrZjPMR26Dxuxn1XbvlL//d+/Dx6Z+f7c
537UsDxda6zd52jjUOpntHqBL7WQsB6zlDPeWrjnPUlU95zNV/W97DVP6ajf/3+z7UuOUyH5ZT98PT9
538/xuOPoDRvAasxpNB5QrN80/Ts1rXOWbawsv1ksV+K4GmVOfb+nvPSS0r+LPMfHxW1Ln4fO84r+g3
5390s7zyflQD7VdeusstbP3dqnUWSq+63hZsb1WXMFdHP/FOkv1pLbXuvoBXvwRsNrTVWWCXnzce455
540uRT0nAq7rgxVJujsFaZ6C2/HqrfOSv1d45wan952Fv+6ot+31g3Fljoj+39qPKddb+m3dxxWbMfS
541uC0q1ZPaXvH9EPhO/wSs9nmkMUzM/zTmVLU4TbdbnOhLl1tKp8AVdVYWWzfOe2+a3vbj2+VWvjKR
542WvfI/p/dH9rttAMEVzlu5NqAq/srYG25hdFup4w1bXb+7rO0/G3PT2pP72U0XhTs7bfy18ZxroxD
543tp5Gh22X7VrWdzFet18kXllZg97jpWLv4+sUV68fGMRfAWvjLYzGzo6/glXqrjcAVdqvrFT93s3T
544ivHsavBtO/Nx2Hi1abVjtst261pefQt+RV8rBPfD1HY8y9XrB0bwz+9gtX9WY50B7w/+6/d/5mv9
5453//9u2scFlvI1LfKinFeHIcT7bRdzjXg/r+30farXlevHzjXHz80umI2acwWe59dfiqv9/Ks7e39
546tXW9tyz5drHKApWxnT5urz9Vc+PyW9b9tvN22aKli9X7/4r9ocXb42VF443H17rujkw5EhUQ8foz
547DS33VqbnrZdz2Muffh6k0tW8r3XL97bTXtu//v7WVeXD1PPxKY1nb/2947xifF5OovX1rY/z/JMu
548e2+X2+zc2dLF9jq3bJeW/aFU562wvXr7LbUfPL66jovK+nbV2VJMY/0Ac79ut8fZNYxlv4ttX3iT
549KMjoATCk++Kz/mPPr5zFx2S7AAAAAAAAAAAAAAAAAAAAAAAAAABU/T+x9xtLJOr2IAAAAABJRU5E
550rkJggg==
551" id="image93" x="-395.95505" y="184.09018" inkscape:export-filename="/home/m/Vault/projects/mitjafelicijan.com/dfd-rice/install-02.png" inkscape:export-xdpi="75" inkscape:export-ydpi="75" />
552 </g>
553 <g id="g364" inkscape:export-filename="/home/m/Vault/projects/mitjafelicijan.com/dfd-rice/install-00.png" inkscape:export-xdpi="75" inkscape:export-ydpi="75" transform="translate(456.74601,90.184622)">
554 <image width="169.33333" height="127" preserveAspectRatio="none" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAIAAAC6s0uzAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAg AElEQVR4nO2dd9gkR3Xu3+qe8IXdlVa7LELSLgIktAoEgUVYAQZhkgkm2GCiBNjgAPc64XSxTboX uDbGBmwTbEuYiwk2GGzAYGwBRrsIRBAiCSEJpRXKu9r4hZmu+0fN1FTH6Z5O1T3v79Gzmq+np/t0 qrfPqVN1hFg4CwHWhxh6wYXzhQBkMVvqdyDEaJPTd5pqmY/FHnqdmJ9M32VZuA5OvVfSCoMhvnIV 1odVGUQIIdbhRCzruehELZ8bihSu1QG8grQ8kqNrFsqYWOhNWeP6Oyw0mxBCqiRGaLsuum61llhE wYK5Vr4G2xaxWOgmfbs6wE13VGUKIYRYSryn23HmWIOL1su1QYkaKSWOrEKWqfEZkYuJAvzjWzG0 yFpCCKmFxFBzx0VvbjW4aNbK7Fn3JA6tFv7aMCNCYLEf++2RVfxkX4XWEEKIpUzr63XdYI7PfFBK /tLaEIPyNNgTR1bK2ngWxEIXbvx9dfWttrwoEEJIraRItnKdOdTgsjRifYhBWclHcuCJI2slbTyD GcsLsd8dOII7DlRoCyGE2Eu6bGfXQX/uNLgs1r3yEoDl+kCsDEraeFqW4+PPP7qlQjsIIcRqUg83 Uhpc38jSVjEoU4NX1rBanwY7DuLGIN1xAHcfqdYaQgixlyzjfV0H/e78aHC5B1qmBuPoGtbrGZgk lvvRJ05KXHNr1dYQQojFZJxwwxHzo8GlpwoNPKyV5qoeWa1lcLDcGNMB/JP9OLxarS2EEGI12We8 cgQWujP8rpmUrMJDibVBKTuREodXy50AJIzjYEOUAHserrutUksIIcR6ZhJSIdDvzY0Gl0x5Gux5 4vBKlRN0iOU+nKjb4sY7sbJemRmEENIIZlVRAfR7cFoejK7o8DyJtUEZ3rYceqLCwK/ctBSxdDDE DZx4khBCguRwYwWw0G23BsvKurs9idVBGd6qHAzFkUo02HGwIWoA0nW3s+4CIYSEyR1HXujCbbMG V4fyg8vQ4LVBBRFgsXFhVHjRZHUde+8se9eEENJEiujI7SdOPdhwKn258CRW10vptV1ZKzHjGkBc /Pla1l0ghJBoChLOfmfOSwgXhkRZGnx0rbxZMNHrREyAdXgVt+wva4+EENJwilPNXjs1uAb3baTB RY/iHQ1MKmdw8ObliIXX3MK6C4QQEkehktnvznEJ4UKRwMqgeLGUqmph0aroCGwKCfD+w7jjYME7 IoSQFlG0z9rrtK90Um05ZquD4mez8jxxqODBwWLTUkQiHieeJISQREoIGnfntIRwKZSgwYUPDpbH htzf21l3gRBCplBOr227NLjmfszVAQZFa3Bxg4PFUh8LXf/WJa7lxJOEEDKF0tKmui5LCBfGWgka XNDgYLl1Y3DRT/bj8Er+LRNCSLspM2+54wZ9o8ZS/1Qja4Pi55NaXc85OFgs9rDkH33kefgx3V9C CJlOyQOHXKcdGmzFaJr1YcEaLCWOruXxreXWTcFFN9yJVdZdIISQ6ZQ/crfjYHFeSgiXzvoQa0Vr 8OGV2cY7iYVecPIN1l0ghJDUVDJ1hutgoUcNLobBsOBJJWcdHBzR+/vj20ucbIsQQtpFVXNXuQ4W m63BFtk+8ArWYDU4OEugXSz2sWHBt2iFdRcIISQDFU4e6Qgs9qrcYbFY0Q2sGXhYLVKD5dAThzIM TJLbQu7vtbfCs+skEUKIzVSrh46DxX5zNdguhkVr8GAojqbSYLFpCYv+3t9DK7j17gKNIYSQ1lO5 GAqBxT4ciwK6DWboFVvoV64OpucwCyci+fmaW0up4EQIIe2lDm9UCCz1ImYPth4bLfYkVtaLjI+v TBkcLDYvo+cvubH/MO5k3QVCCMlGXeFggcU+3IYFoy118TxZZAnh5MHBriu3hHp/WXeBEEKyU6sE LvZaWUK4BgrX4LjBwds2BUMXt93NuguEEDIDdevfAjW4IDxgZb2wPOSowcFiqY9jlvyrgRNPEkLI bNQtfgJY7KHrTl/TDmzsBtZIYLU4DQ4MDnYcefzm4Do334VCKxsSQsj8ULcAKxa6wbweW7G0G1gz 0uBiSifJoScOr43+2LoxeI2GrLtACCGzY4cAA+h321RCuE4ksDIoTIPXB+LoqljoYvOG4Hc33lHw hFyEEDJPWCPAAPodlhAujAI1eG0oF0LlNNYHuMGuiSet7h0ghJAQNgkwgF7H/vKFjWnoVwYYFqHB Cz3cfRQH/KnO9tVdsL13gBBC/FgmwAB6Lhat1mAJNEaFVwd5yv0CEB0X/Q6kxE/2T/KtVtZx810F mEcIIXOMfQIMoGu7BjfJ3VrLocHCkUu90Wcpsfeu0USV19xiZ92FhrwWEUIIALiisy24TER8StW2 iaiVhPm/0ArhX6glrgPXwbpdQc6mMvQgxCzzby/30TEyn9UEHS5wtaXJzxRgQkiDsNIDVnRcLFla QthKoxJZG2R9mxH9bsT47PWh+P7N1tZdkPofQgixHosFGEDHwVLfQrlrZBu/Pkw/akh0OnKxF/HF 6kAeXYtYbhH23S6EEBKF3QIMwLVUgxupwgMvlQY7Qi7F9MEfsH3aZxvvFEIIicJ6AQbgOlhesM/S Zjb1UzVYCCwtwIk63UfX7O+Vb1KOOiFkvrFO1qJxlCpY1LBaZEpWBh5W4zU4rjyGBA4eLc+oQilm BhJCCCmVhggwAEdguW+PBjcwAG0w9EYDivyIXvxkZEdWcw4prgzR5LcjQsj80BwBBiAENvTh2mNz kxv6ocSKT4NFx5VL/eiVpWyO+0sIIc3AHjFLicByzxINFg13g+FNNFi4jlyOUV9AHlq1c+aNSBpj KCFkvrFCyTIisNyP7qesmiZ7wAqlwULI5YXoeVSgCwM3C6owIcR2bJCx7AhgqR8xTUS1SMg2NPSe xMpakoN7cMXamTfiYDcwIcR+minAUBrcC5aIr8eO5jOUuONAdHWjoYcjqxHL7aZh7wuEkLmksQIM AAKLPfTqLCHcCvkFAHgSdxyMGCJ84CjVjBBCyqDRAoyRBseNnCGZ8CTuOuzT4PUBbJ94khBCmkrT BRgAsNDDQj3lC9vmHHoe7jw4mabjQONyrya0JzhBCGkprRBgAP0uIosHkKxI4K5DWFnD6nrkZB1N oW3vRoSQ1tGi4G2vAwEcqTpkKtrX1kuJuw5bMtiaEELaSrsa2V4HS1X7wW1TX82wGRNPJsAoNCHE ZtolwAB6HcTP6DT3zJcktfbdiBDSClonwAC6LjYszJnWpISSRAghttBGAQbQcbBcnQZT6wkhhGSl pQIMoONU5gdLiz1LAcyz48t3I0KItbRXgAG4DjYuVHKIlrbz4wxtS82rgPl99SCEWE+rBRiA42DD Ipx5VKAWjo8ihJAW0XYBBuAIbFyAW64GW6jwVF+FhZeGEEIwFwIMQAhsWCx1ZgmqnbXw0hBC7GQ+ BBiAA2xcQKflxysoN4QQ0hAc0XZNmiAENrRZgwUgGXAlhJCG4MiFrqi1pG6lKA3uuaVsu4yNZoHO bxy1XxpCCAnjAEL2OljozkszJQSWS9HguvSPYeep8AQRQixkHI/tuFjqifkpgLO8gH5L/H6GnQkh pIkYius4cqkvuqWEZ21kqY+FBmswVTcTPF2EENsIurxyoYeF3ry0V0t9LBZZvrCys8ZJNrLC00UI sY2omHPXxXJfOPMRjl7sFlhCuIJ5H8VkR4QQQhpMjMo6Qi730e9Wa0xNLHSxVGAJ4XLFsdU9vi0+ NEIICZLo5qri9vMwkfJCF8sFanDxGNegtd5v2encc3AfE0KaxLQ4s+tguS/akjCcRL+DDQv5N1NC Ky/RYtU1KPsY5+EcEkIaRIqOXiFkv4vlfvsHKfU62Ji3hHAJrTw9N0IIaSGpNdV15PICFnsQrZbh bgEaXAgWmFAjZTmr831WCSF2kVFNux1sWGj51JWdDjYu5qlSkbOVZ54zhZIQMg9k1xkBudjDhkXR ba8Md1xsXKq+UhSlt2yk/ocQQupmVpFxhVzqYcOC6LR05izXwaal2TLAZ2jgKb1hSvOC6V4TQqzA wcr67L/uuHLDApYXSq11XxuOg02LcCuYWENSesPIcqSS8ksIsQRXrB2L9SG6Lhxn1DhNmigx+SyM LyYLBQC4DvpddFzhyQgpEeb/Qq1fuDkUgU9RDaYIrhq7Nd9XCevHmSfQ72J9mFUi07TyIvIj8VPO qeEJJ4TUjyuwFZ7Eyjo8D70OhMgswArHkGHPkKtGCzAAR6DfwfrQd1DTSG7glddLGSCEkHnGFdg6 +jjwsLIOIdBxJwqXXoDVn46DfgfdjpCA9IyVGyvAYuwHD7JpcLQJ/hNKaoGnnhBiA4YAA5DA2gBr 63BduM4sAqy+dQR6HfS7EA48DxLNFmD1b292DabLaxW8DIQQG/ALsEJFpIceOg50TaRMAqz/7Ljo 9yLi0pOfJCyxSYDVh34XQw9DL343vt+J4AJCCCFkRJQAKwYejq5h6KHrwhGzCLD6Q4yztBY6cISQ kT3EiFpimQAr+h14UzRYb4u5zYQQQuKIF2DFwMORNXgS3c5kUGxWAVYfHKDTQb+Lflc4AiplunEC DKXBEoOgBtPDrYCiTjIvFiGkdqYJsGIwxNFVeB66/jTpTAKsJdAR6LpY6KHfhesIiBif2FYBFkCv AwkMhoAUbMyrhaebENIO0gmwYn2Iw6u+vuHZBNj0ibsd9LtY7KLTEY4QMEcS2yrAriP6XRy3Ab0O Dq3G75JSURY8sYSQFpB9Puejazi6hoUOlhaw0C3GCiHQ60hVdVhKDIZi3cNgINeHxWw/N6LbQb8r ey76XXRdCQACGxfRdXHjnXG/Yh9wSfDEEkJagBA4bfZf91xsWJzI8BQPWAY9YEjDhxYhL1QAUmUd i4GHoScHw9GgplI8YGOYUMcRnQ66jux20HHQ60A4EIFfjY/lrkO4/vZ4TeDoI0thlhwhpF7yVTRa G+KuQ+g4WOpjqV/KtMkdFx1X9nW4W2IoMfTgecIbybOUElLCQ7YW1RFwHOEKNehZug46DlwHHReO kFqSpx7TcRsgBK67jc15s+DlIoTUSz4POEC/g+UFLPZ8nmVOD1ivYPY3C/9PzKXSgxxXN9A/UenW aqIuAWPWa9OrlX4PPiDAgTlJ4D8W4MBRXHtreKyziE71JoQQMu8UKsAK18FyH8t9/1xalQhweAs+ 1RTG58A2cwswBA6t4JqfYEjPqjEwCk0IqZEsWdApkRKrAxxaweo6pFQR3egsaGCaAKNCAUZIgJFN gPsdbFzC/sM5p4wmWWGEgRDSREoQYM3Qw8o6Dq5gbQAAHTdC4dokwALodXDMIvZRg6uGGkwIaRxl CrBGzWp58CjWBpASrjPyidE6AQbQ6+DYJew/oqerpDZUA88zIaRZVCLAmsFwpMRqlmkBuM5YBdsi wALouNi8jP2HxxpMabAXXhtCSF1UK8CaoYfVdRxaxcGjWF2HJ+EIuMKvqY0VYACugy0bcfcRDGyZ S2RuoKQSQppBTQKskcD62C0+cBSr66MiB67uMG6mAANwHGzZgANHYc18XoQQQuwh30QcxeJJHFnD kTUAEEC/i34HPfVvJzjvtLUMPRxdw+EVHF7DkVWsrAMQHO5iMbw6hJBasEmATSSwso6VtYmj2e2g 1xlJcs9Ft2NFrHEwxOoAK2ujf1fWsboebs7ZvtsMrw4hpBZsFeAAElgbYG2AQ8bCjoNuB10XXRdq 0uaOi44L1ylYmyUwGGB9iPUhBgOsDTEYYm2AlbVwVWBiCfRrCSGW0xABjmTgYbCGo1HVDlw1q7Mz yrJ21H8OhIAQI4X2jNKHagOehJpfejzLNDwPQ48q20QkNZgQYjdNFuAElHyu6b/TlCQqt2wRxaB6 0mswrw4hpHqcug2YF0YlhEm1pJRVqi8hpHoowFUiQx9INfDVhxBiHRTgKgkOJSZVMf2Nh5eEEFIx FODSMVp2Gb2YVETSOWdQghBSMRTgUhgPXpaIadkFG/wa4DknhFgEBbgwzKkp5eifWJdLUgzqgGEH Qog9UIDz4JseU+p/0v22aGPIdJKHmvGSEEKqxHIBTtMkVrlOYD2Zx41lc18LCRrMoAQhpEosF2Bb GDfZEhBsppsOryAhxAYowLEIw1UypqwsrPVmN7CFMCxBCKkMCrCPgOiWrJCWnHy+BxBCSA1YogE1 oyPM5YuuibTD32pKpeWS8B09X0YIIZUxvwIcSmBG9QFIS5p7OdcabMlFIITMHfMlwFPnx6gcO6yA LLcUlN2I4J9zeyYIIZXSfgHOND9G5VjkemYcx9weZDAcYtUdQghpLe0U4BzzY8w5cyo8IcnlDUMI KZ32CHBUn24DaJCp7YaFMgghFdNsATYaSs6PQQghpEk0T4Cj5sdAoz1J+lu20eCbiRDSHJohwNXO j1E1dh7OfBdM5EsRIaR0rBbgFouu/Ug4c6xClsyRQghpM9YJcENzqdrIXA8OJoSQsrFCgENDdecO a3VuPi8HRgOTrL0shJA2UJsAR82PMb/M9cHbimQgmhBSJpUKMOfHIA2iyNqThBASonQBZp9uSuhs 2QZvV0JIqZQiwDFDdUkS9p8oviIQQkiBFCbA7R6qSzDKS5qvCyt8H/kGQggpklwCLIxcKoruPDBv g4P9U63xBieEFMks7WnI02XDVAxN0La5Hhw8twdOCCkDJ6V4CkALLfW2JGRDWvi5vQE4OJgQUiBJ IejQUF02PWUzt9JmL4GbnoODCSFFERBgwfkx6oWNu22EHwA+EoSQQggIsKTo1gtPPSGEzAlWzAVN mss8uOzzcIyEkOqhAJNczMPg4JYfHiGkJijA1tE4PZu3wcGEEFIIFGDraMpgJAMODiaEkMxQgEkx NMxtz0iCynJwMCFkNijANsLm3DaSXy84OJgQMgMUYBtptzfZSnjJCCFZoQATkgr6uISQYqEAk+Jp pVbRxyWEFEunbgNINAJCRrX5nrzS/NMRO5O3o9ePW1OtMHU7mVBJ0dJvrdpFYHf6z7jlcbsIbzly hWKPKw1F7deTV6bfSNxVnnr1G415qgPPBfyHHHm3xD1KWR+x2ch0aeq6mUnZ0AO2lEj1hfEQCrGE qHYnbn2JGxJ3l/TtDEgIZZsQS2FTA2brvQfMSLDKPA8JqxV+XCnJuV91ftJvJO4qp7z6TUTfXerQ zPshfL+F7xbz5jTXj1teOJkuTdxLBmk6FOAGU8hj6YidqqEpFk/+AOO3BIEdylSzrZnZ7PAPBXaE VyvjuNKE1ks6n8REyySirr5eEqltgfUFdkSuH7e8LqjBrYQhaHsRqfsdJW4Q2JEcOpPySHhhZBws IV6nY8XhTcUfxY649WdoTbRrGCm64S1PtT8cxowMlUcuSd6v6kRIOG+R18tcGLhkU6PuKUnYb/rr O/U0ptx+8jmfSvJtMAPKQimPKDMcsTNZfbOeh8CvIjcVXt9k6s1PGgQ94JYwNXQWuTAyDqZ8uMD6 uk3RHt4M8qkbjtl8RNPvSSZ8XMn2m4dvhjT1OoGAZ5r9qsHBcfuNu16mA62+Mg8hf1w0Yb/wn+GU u/DkleZZmrr9lOd/ZqQ8kv4+iUSbOtqO4QonkPI8IOY2riz0TayCAmwvcd3AST+RR9R/4y1E9AhO fbCVBxC3EfMFPE1bqRojs3kyjUlPctQxPentDzbEYgmAk2XX0vfZt99RTF4eUe27kiVlj3l0Zuuf fF0ykXCfmMIwdRfmu0LK7We9f7KiBUyd29k2kvUtM+48IBTKTn45SH5+SfugANtM5quj36B1MxRJ woMdyJzKj+nSxaUITaUo9c1KIOWt2F1n8rSKvS7J94l+IShp+2VTiMDrxIWSPNHIa13veSPVwz5g m5Hpu4E1RYlEgWKTc1Mp1TfTuJ1MuwagOwWLHQ2suhhV1DRrn3pOpm4n544a2k8Z2Q9dZbdrQ88b mQ16wFaTXBkpIZwVDvlWjA6x5txOevVF0SG7hGFUhWxcO74JnlbZ17Gh2y/q7oqj9thv+Lzl7Ngm dkIBthwv+LfhkyE8zkceMfssfX1vUckpga3BaNq0TzZzM2eGWMcuRez7RKT96qtI9TUtDzfx4eNK s1/zeAPC78tRit9a1v2aveOBfCsYl9jsM468LnH7Tb6+5n7TW56M7n+Nuw8jz8MM91tklhxmus99 ffzx92EmIs9DwvEmP791dcGQshECp9VtA8lGoDkzH8i4r1L+JLy+wA4zMyjucxpr1aYCG4zcZsCe uABg8ijPhOOKO5bA8YYPMM0hJ+zXwXYJMfV4w5uael3i9ptsT2B53BaSjzTyjCXfhynP/1QD4jYS eRTpz0PC8mQbsp4HhI536nNK9W0ZFGDbmaEb2HpkohvZZuJmGCWEzCEMQdtOcjdwM2n8Ec18AKwc TAjRUIDthw5Tq+DlJIQoKMANgD6TbVBECSH5oQA3gBY394JvF4SQeYUCTOqkuX2iDTWbEGIPFGBS Mw1NiS4kLCEK2xIhpHlQgJtBEyUqPQ3V4PzM7YETQkABbgqt95Jaf4BxSAhqMCHzCQWYkBkpSjjn 9uWDkDmHAtwY6CfZRtHCyStMyHxBAW4M9JPaDnuECZkvKMDEOhqkQkWbyrcsQuYICnCzmIsGukGe 4FxcD0Lmg+qbHQpwk5ifeaMapMGFw8HBhNRC9U8dBbhJzFWrPFcHazLPLx+E1IKo6aFLI8DSjsaw rlNkmw05seFS1m5Dkbf0rDdEkg0VDg624Za2xIY8FDcxWs025DSgkTaI4k1Pe0vTA24Y8xOFbgol NTmyxG0TQkaIWmNOFOCGwSZ5nuDLFiHlIo1/q4cCTBqB1VJUsnFWHzshjaV+d4YCTBqB1VULS36O 628mCGkj9TcqnboNIEl48kr92RE71QdRRJO8e89F6sO5uy5IWCHu26L2kn6/MuOB795zUdadhvc7 g/2lweRoQsqgzieLHrC9KPUVYkmIJRhiXIhDpBVF4oaE1ZK/LWovKfeb/kFRwpl+p3F2zmx/4Yhi 3rsIIZMhBkL/UxP0gC1Fqy8AgR2O2OnJKyVuELh3NQacu+uCWlQneb/WSlDZ8igBAWHt4RPSFASk fo5qf6AowLYjsEN9UCHo3XsuBPCoXS+9ZM+Farn20nS8NLzw3F0XJERTw1HfyJXN7U/d72yE95tg f6Q95sI9ey6Ot/P8PHaGqeBJzhqEJ4SE0U+QDU+TEDht2jrKyNr7n5QB9Z6x6myYxJ/HAqxt2D2W 3l27zgtojPIdI4VHeZbmV6akxWnwrl3nKQP0n+rbNPuN3M5o9fjbKbx+pP0J9ujV9Ld6UxntTFqe m5kfq2K7rObrsUq0IY8BhVwUG2zIgw1KYYMNSH9L0wO2ncg8LBjqAkDiBoEdAY9QLYz80/wc3k6y PWoFHSieut+iCNivNHjPnouVjpr2mHs3P5dtZ1Uv1LU3LoQ0HhvcXzAJy34csVP1BCOUCiSw49xd FygF1Y6aKagpmU2HlNTl2W9Ozt31UgC791ykbAhIb4AK7Kz2eaYMEzI7NqgvKMCNIEZXhP42zuer kjr2Kx/lf/9IQ13np2gsaUAIaQDWvq5SgC1FRZulPBK/Sp1NsPY76zVAAg52hNOvAqtVa1qVUIYJ mYIl0eZImIRltQ26A1gNQxJiSSUQKRJmjTCTqgIKpFxGvR2VXhSZchXYS+R2zD7gcDJXTIJ0bLZI wn7DdsbZE9hUlJ3n797z/hR2Zk7wzvKoF/BYFdGyzONjFWND7QlQNtiQBxuUImhDTeqb9pamANtu g+73FdihxgFLXG8YtCNhZRjCY/Z9ql+ZK+s/AwnDgb2EO6ET9hu/naSWImG/YTvj7AlbFVqyXeLG qcebsDw3xTxWuduXOX2somyoXfxssCEPNijFFBuqzZSkALfTBjn+JGQKY/zebe1PKUqzIf3DZcMt bYMNsOaWtsGG2sXPBhvyYMMtPdWGaiQ47S3NPuAGk159YcSc24sVHT21KyohJBIBWNJKaOgBN9GG bHO5+IOo2y24lG1+VU/9gs3HyjYbavc+bbAhDzbc0jbYgPS3NCfiqJnfeOdf1G0CIWRO+YtX/0bd JhRP5IuMnbnQDEETQsicUnuZr8KJE1oL1Rf0gC3nz1/1ZP35t9712ZybSr8Fvd/AT+KWE0JI7djp 5iZAD9hqtM7lV9/Z9ptyOSGE1E6z1BcUYEIIIc2nceILMATdOJQv+1vv+mw4Ghxwc9Vyc6H+bXh9 uraEkCbjRGqw5UFpesANQ8vqb73rs6bEanENLNd/Bj5HrkwIIQnUPr4nkoQBvtJSk0fQA24JyifW mVZpPFqKLiEkJcqVtM+bFAIyziqRbraiGqEH3B60L5tGWcP+MSGERGJtIDdBfWGrzSYU4FbBkDIh pFisVV8kGmZ16HkMBbglmI5vggan9I8JIUQxTeQsVTprXxpMKMBWo8Vyqmqa8edAtjP8kmx2Epvd xuF86fB+09tDCGk9EhCWKp2dVgVhMYaabeBc0ISQunj7q5+dWOU6U/jZBqWwwQakVwp6wIQQQoJY WLxPUbu6FggFmBBCiImYKfGqCmWcaliz5JkCTAghZELy2J54JErWvzSvBZbPvBGAfcD125CxIpjN gwJI42jtY5Xdhtofq3psSOwDzsRIKWo8leOZNxqjVpwJq34yPgDJt/fUm8+Gu7N2G+pvKcbugqi7 1bdE/GywIY8BhdzSNthQAHJ0Y9dwQS2f9yoMBdh2PHmlI3aGl+/ec5H6cO6uC/TCGhv0SHuK3X7k ltV+Z9uprNXxscHnIqQMahHCJj5Q7AO2Gk9eqf8NoCXHjGDXeP9F2lMUSmUTtjzzTuvzGmr3fUk7 2b3nIv02PFc0zv0FBdhmlO4KsYQYDSYAzt11wa5d5+XZQtlPbYzAN6+xII1AvQpn1WArgtcRiCyG 2XoQ8TAJy1IbTPUV2KH+dMROFWgxn65du84T2KEjsToOo5eYK5+763x1FOFvtRKK9zYAACAASURB VAsbeHSnLg98pexJOLTI7cTZE25HIvcbZ8zU7cetXz58rGyzofb+1yJtyNQ1U1DwNvaWFqPk5Mw7 yf6bhj1WFGBLbdACrMTM+PPeu/dcCGDXrvP27LkYfgE2xc9coiK0av2A8Jy76wKJG/RX+ldqnanL zR2Z9sQd19TtBOwBoP/UvzK3HzjwrNtPWL9w/K0JHyvbbGiVACO1BhfXdZp0S1fVQduwx4pJWFYj 5ZHAEq2+6TcS8PAkbjAFzPzT7ElVC5Vc6YVKn8zfBqQxPQk2BD6ba6bPGE/c/nb9WWnwnj0Xq3ZK H29xYzOUMWp3hFSHurfjshc11dyWJSc8NjEBC6AAW44KQSNKiVMqhCmQAflMa4OxowShLVaxqkS3 UxjF8Es5kNlCcITMjBndibmrK81BlJP/F77Tpj5ZTMKynYALGId6yVUSK0KRWBQnkMoe/V8h26wd ncm1e89FhbcNFF5SPSnUFzWFaovcae2x5pxQgNuD7um8JKS+MxM3pKGuoQ6F71dvUGCHOoGXFKzB wnjxJ6QK0qmvpWR6+pr+UDEJy1IbpiZhwcghCucAm8+emfdrrm+mL4U/a/Smpi6PtCdM1u0HfhV5 aIjPag5sf9eu8wS2797z/uTjdbCj2Msc8oP5WNlmQ0uSsFKor5h1tuepBiD9eYicLSvTKYhauWGP FQXYXhsC2UDjP+8NSJ0YpTOcAzlHkUsACGyXuFF/a64Z/qyJzNKKXB5pT/jIlA2B7UwNm5t7CS9M b6dKwgqfh7j9lgMfK9tsaIkAI6oFKHA3iQYg03kIWDLToCMRWpLNhnKgALfZhhTXNXYlGyaMjbYh PJKqTAOQ7jwUO3jR/IaPlW02tEeAa8KGW9oGG5D+lmYfcDtpXNeIjgPPlqpdGkVOHSCad1kIsZPa JbYY6AE30YZGvybH2hAZTC7NAJRxHgSkhJPuAvGxss2G2h8rG2zIgw23tA02IP0tzXHAraWuimAz 07h0zQAzz7dHCEG2F5CWPGgMQbeWZqmv5aR4o05Z3aj2d3Myj1h725mGZXHhW9K40QO2nakzyVVM YKBRchngAosE63pQkdWRp5LTkhQT6U1pEdR1LGf4x2T7mdYHcO6ul1a537irYI6sy2kPCWOttxg2 bPygxWqxtccyG/SArUY1WDNPPVHea6/ur00uA1xgkWCtu7NtKr8leXrYdD1jCZRxWabWS44j53XJ ut+4q6DfA8ooJj1vBCarsVax4gxLfkbsPJaZoQDbizkudlYNLr6tz19/t7kEHn4RsWyGzdTDPF/H dhOo42nF3RbBLKGg9o0jYAjaUkz1DVQ1SV+vV3UDZ63vm6bubzhUmL6Qn5qFKnL7cej4s387F4U3 klD3N2xDphm7xisLHS81l6epZ6xO0aN2XSANA5LrE6esc2xuP90l0Dt9qbkkfb3khP3G2Z+VrHWd kzcS+HnW7Yd/aHO0PGUdpPqYMZzUNvnlMCRrbYgrcxso/zetru1LA+UL89T9jTQsbFuoey/6QOK2 H0ZPw6lKQunpOTGOWMYJQMCkyHMYl3qd4vwIQOaoZyz1i0j41IWPK+G8JddLjmO8wccrY+Lsn22/ kdclcGINI9UEihci3X0Sd30TDjOOGepGR9betnMYUuUvCqUohR5ckO7sNEyt6AFbTcKsFJH1euOW h+v4xtXBzVMfN/17d9ieuO1r9Q1/FWhbAxsx46vmV2nU1yT+PG+P3H7WesZhOyOPK+G6zFYvOY6A /TPsN/m6ZCLhPom7vpGYb13mNhO2H1cnu0HY6QdnfcuQo+H1LXR/QQG2nMAbeiTxM75OqeMbVwc3 f33cNA1i1m0GNmh6SHEnR+lWXOuZ9bjKG6Zs2plwXNXULQ6Tab9prkt6ku+T5OubcfvW5irNgjoY C2sizXaW23NhQjAJy3aKKrs7ruC73dygWQfXXDlueYEUVVd46m8D2y9KG/IgokJkaXzZCq5LJDPs t7L60/nvn5bVt26Z+rYbCnCz2Z2xXu/uPe/XQ5t2++vgJi8viTg7S+XcXecj43EVZafazgxzpKS8 LoWfz7r2W/n2L6z+PiwDa9UXhalvq0ScSViW2hCXu2TWA1akr9ebczn8je/U+rszrB+JOQWH+qzG BJt5quHkVfjTT8zMnUA94Lj9znbe4vJ0TAPgd8Ej05QCx5VgT+T20wSKx3t5qZmElb4+dNx+4+wP 7VcftS+xPPk+SThvCUca7gMOdAaH7U84D+HjsioJqz71rUgpEk9Tw9SKAmyvDWnqAY/NSlUHN//y wFezrh9dDziBuHrDkcvjijqYRZEBmPWAp+43sLVp9YZ3IHT5AtYi5kymPN6pv0o4KP/KAkZCWdb6 0HH7TagPHXXUAoDE9eHtR+43a9GOwI0Rc6uoPNsp1zH+uCwSYETde5VQnVIkllutyIZEKMBttqHR JVNssKH+Wzp5vr1qDYEFt7QNNtT+WDW9k7TSxyqm2Ez9j7ZhAOsBEwAW3I8kAEtlkAKZdVK20ilz NlwbjzcrFOC5oA23KiEkAmGt42ytYdOozmoKMCH1EDkYiZBMlFdfKyeNVV9UGTGkABNSD+2IoZF6 sfYeqtgwof9pFJwJy1LM8TbhP+MwR0oEvmryCykhxH7q1D9pcTAgAXrAVhMYhjF11r2EqreNuzUJ ISQ9NgwqyAoFmJDaaFx7QYjNNM7NYAi6eYTnbZ66cvr6qaRKGtdeEBuwtjtJQEq+VWaBHrDVSHnE k1ea5eh12VT1H6bNaaxnMaxrHn8yDTZYJAMWqy8sUF/RrAeKHrDV6Dq4qha9Jn093ch18pRoJcXS xMwRUhfWqi+s9H1jZsuyCAqw7UQq5Qz1dImdWN08EMuw+G6xTn0BSEiLX1kACnBzoQtLCCHJ2Ky+ YB9w06mlni4hhJD8sBqSpTaoxCshlpSna/wZWw8YBdXfLZ/aB+zZcEtPbKg1SjZfj1WiDU2vhlTD Y2V5gLc+WI6w+TbMUA9Yr2YuNwt0h9evAwqwJTZgDh+reBtqF79oG1JbVvVjRfWNJ+0tzT5gewnI pPlngoJO+6p28SOEpMVakbPWsGbBPuCWo+PPgZFLxCr4TkQisVbkrDWsWTAE3UQbshngD0pvt+BS 1u6F23BL22ADrLmlbbDB0hB0tTbMF6WdMoagyRh/UFqC4SNL4WUhpFJqf2FhCHoeYTNvJbwsxH54 lxYJPWCriRxWNPOm0m8hrnJDgRUddJWI8HJzYVNqSOS3M6f/W/Z5i7tepHCsjYTYMdtzq6AHbDW6 vdu167ypxYATUK2nvzM41X4DO02oNzwbge2E7Sx8jyWR386c6otKzpvlV6EF2K2+pGDoATeGugfv Fsy5uy5gax7C3laO16sCrL381hrWdCjADUNNgxVZ3zeyTrC5UI1EUstlofHtKDsvCmzWXJJsvGln 8jYjMas3AnDETvO3Kc/bDMuz2rl7z/sD2xGQl/h/GzA7bP8M5y1k/0tjlk+2ExnQzlSXmqTBWpGz 1rCmwxB0w1DNZbi+r57uKlAnWK+mv9V+jPqq1CLBYZ9JLQkHSBPsVOzZc3FYcsJM5uwUS6qYo1oS Vxc57rxlXZ7VTqW+ge3oZi5w7BI3xNmf9bxF2X/h1OMKX6+p54Fkx06Zs9OqlkAPuKkE6vsq30i3 tjpgKLDDP4XWZBxwoMWsvUhw8lRf5lSaCaY6Yqcnr5TyiHJ8HbEzPKOnwHb9WX0I11dOXq43aJ7n THaeu+v83XveH75eUwnXdc503uKOK+H+ibE/2/qksTDrqkQowO1BtYnaMUpuCs0JokudJKvA7NmU jbvSYOX4OmJnml/F1VdOU3c5vP2UdioNTnm98pCoypPmNdP9M8P6hJAADEG3ikB8Mg3VtJsV5+84 YqcZf06DciX1f1OXF8IM16soIo8rqz012t8arHUwrTWsTVCAW4L2RQR2JPRBaperGrRvndXJnrnO sfZ9BXaoKHR6DU7Yb9blKXb0ftUNnHy9sm82mz2791yo+4DT3D/hHRVr/7xhbXaxtYa1DM4FbbUN UYkwQrWYu3adJ7BDR5L1Z02g7q/+Vi83U1sTEmXjEl9TZPleBH+Ue7zr7WYCcNxcH4HwePh44/Yb UFzlCiecn0KWZ7dTBrKg47Yfuc3w9tOft5D9jwdk8v1Tcp1pSx7tqudhLlrkck5szKmkC4T1gNti QyjxR+h6wKqxC3/2rx+xqUCNYbUksvxweDtxyxOMD9kpAZGwnYCdkX8m7zryPCTURY47b5mWZ7RT ApC40VzkYLuaaSiQLaWFNu66B6yaao9hv8AoNS/peBFz3ZPvt9RY8mg3vRDCjDbQ2S0BCnCbbSiw pajl6auntTK8QKU3VlRDSrgA5htDaV31ltzSNthQpQCX8Qhk2yZ1t0wowG22ociWoo7nsAYB9gdR zwdQ7y0tABl1HoqL66Y3BBbc0jbYUKUAl/HYpbKhzOfdEqWwAQpwm20otqWoXoLr8YBrr4vsP9Gx j1VBcd30RsGCW9oGG9ocgk5zeLkbAkuUwgZYD5ikZV4CUYaSVXrIul1LuVcOqG0vQkDW8ryVr75k FjgMiZDiMb0AtmtEUY36zuCBUn3rggJMGDMqDH0m2ZyRMKXeFXnuPd6uJZDqpFKACR+/XAj9D88k qRrJdz4rSXs1KMCEzIK/4WPrRyplfPsJ3nmNhgJMAEah00Fnl9QL/d2WQQEmAJ/neETQ2+CpIhnI /2pbUkKfKOVO5pt8NijAhIQRAhjPFqkbKkovyUae7OJSnV0ByOLFkuqbGQowISOM9kMNF2GDQmZn NvWtJsjMd0lLoACTEXOrNuxXI2WQ6XbiTTifUIDJiHl68gUnyiA2QN2dcyjAZI4Yt3f1TAdISADe h3MOBZhMaGUUms4usYHaH67aDSBhKMBkQpv0icE9Uj3hsT2W3Iec7dlOKMCkPYwnyhgNHyKkSsyx PZboroLqay0UYNJ4QhNlMNhGqkdKy3RXY5UxxIQCTHw0RbuiZoVkO0PqQd+NvAVJJijAxIfNLch4 VkgdYbbZWNJu5Dwm9wnAARwBpykv6rbTqdsAYhu2hXCFgJSQRuEXq8wj88W4P7URZYiKeJZHr73C t6VhE46+CVCASQBhQ8qGYQNnhST1o29IGbPcNvLO9uwgKLoaz84jbiQUYBKkxscrrpkjpA5U9AWI uSHtVt8cP06IMEtbj7lB9DpwBDyJoUcBJjVjNhZ8tIkNjO/JpBnT5lF9Qfc3N64D1wFUb7rLJCwS SekhXzsHbBCCdPekffdtYFDAbNug+paJEOi65gIKMImgnGLdnBWSWEe7kgvyPVVOTKfvaNuSD21e um7gFYcCTCIo9kGjs0tso6X3ZJ6sq0T1RdvOVA04AqGQMwWYlAJnhST2IYvQ3Tbezs4U7ZZeO4+7 UnoRGVdWJmEJRN0OoWeHN0SZzJbKYYySlPYNKSZzSlGDd/OO7SmNvIlXyV2/gGABz5yEgs8KawR4 2h1grhr4P6u71su4VTKdXV4RUj/Fjmqb07RnMPcqN45AJzrYzBA0iSb5meOskMROSkr0s1Z9kdOw qerLgb/56bpxsUALPOCA7xss5xX8AkCwzR9tgUl6ZaNnhXTG59rGcByZQ3QYpqQ2oJ1NS5opnen+ 5qTjwol1dOsWYFN9RZqXVznxvnT1kdG6YtTzSApCjE83Z4UkViLFuFu3zDBMS1MZpqY9g+qbm9DA 3wC1CrB5+SfqG2jkhf+D9L/j6mRb7ZDxjikMfwkEQmyh2ooITgtblTTqy4G/+eklqS/qFGCtuJOc Z1N6zXqvBlLfN+ZUcWIyaasqJcD7phja+OJPGktNU4Xb2JrkcjWmDToa4c28AwIA6DgJwefRKtVY EiRSfbX0RncDB0qwi4l7JqVPgxmLJqSNVPtMTxoUKzAkt+xBRwDVNzdCoDPF/YUFWdCm+goIMZZk MerqVbeLGH810WYxvpPEpDN4cmPRdSOkwdT+AFukvgLmIJbSBx1BBZ9tOfqm0u2kedGp3AOOyLrS 6gvDzTW7KMKyqhxctbIcpWIE/WBCSMOoKcgcQe0GjOg4cB2sDYoZYp9GfQF4TKbJx6jk0fRzWHsf cJT6BgcmjQPLUv9pjjsKBZxHybtqnCpvI0IsJ5DMXDt2yI/rjBJoDfXNRVr1teDYG40AummFte5h SECs+kZ0CRtKLMZLpPFbqQcp8R4ixHaqTWZOT93muA46zqglXB8Wo4hp0p7BaTeKIF3wWVGtAAdj yXJsqF99R8tCxzByajFxeXXO8yTy3NJBe4S0BXvizNbhCN+kwYMhhkVkQ6VUX9D9zc0o+JwWCzxg Eae+gZFIgRC0DjsLnx7ruSJ4IxFiDeYTae2jWWezoeKWZpTYkxh4+st8g47SbYDqm59pA38DVCzA pgscKCsSSM4yXtkmXrIOQUvD90VQfX0rE0Jqo0HObp1NRsdBx/WZICXWBgUYlnLQERh8LoJeB0Jk Oo3lCHDcJZ/4uNrr9U0u6R9ZFNiONPKq9M9kcLbESU/w+E/wxiKkUhqku4ra1DcQc9YUpb7TJoKY wHzVnDgOOpl7P2vMgobPqUXoZS1iUK85z8Y4cVLPjSUj71a6woRUgy8Ro1nUMHGPALox0/RXPOgI dH+LoBdb8iiBgibimMyVIbJU9gXgjH9lWGJsYMvxW7efcpJwAp3EYW1OMi6LPYSQbIwfsIb6UHW0 Dx0H/W60+q4PCkt7Tn9o7P3NSdfN8LpjUIQHnE1xwz/HaCqrkXiLSbRZ4NHP+Oln/tKzjx45+uPv Xvv9y777va9+57qrrpNDVXks0ruly0tIpTT8eavWfGecbBW528EQw6IGHVF9q8KZUvIoAVdga7o1 4y9nwpUWgf/E5IP6WgifaztJfh4teeYrfn7rvbZ2u917nLjtjIc/4LHPfvzC0sJ3v/qdGKMyecYz YIMznd+GdmwhP7QhqwEy9XCW8mywlhRH0XGCqc4mQ89Me56dTOrLkkf56XdDJzzt+c/hAftCweGF RlaU+a2Zp4yxJAc3MppRstvvnXLm/SYLASFx9RVXzW4zISQ74wfXthkzcqFGU1S0s5HjGz89oSex PhwbVkna82i/M++JAAA6MwafR7+e5UfC9z9juSG9ZqqzuYL+7eguUys7QOjpFjjlrFM7/Z65TEL+ 8JtXTv4K0qb2gZCaaVwyc3pEaBxkiahRRgm6WOCgo/Rpz2DwOTci88DfAIX0AetPY+k157cKr6q0 Wa+iZHi0UIwGEUkJIXaevVNIKcVYzKW88ZobD+4/OAmbMH5CSNG0WHc1FR2a6h2cKopj9UXetOcs 6svM5/z08gpo9izokRr6B9rqz45OpBp37kb/N66XYNYZVDWw9EBmKQeDwb7b9wkpxbg81pXfvDJp pIOMXM67jJDpBEb7kbx0HPQ7qdS3yloLGrq/Oelkm3UyEiFw2rR1jKG6CAzVNT9E1hOU/vUFYEyU MZFhc19ipMHjTuJtJ267/4NPO/WB9z/rEQ/88Ns/cNnFXxsJrRxXYtDVK6WcbFzrdJG3mb97ux5y pnkXMle2DTbkwX9Lz7ENAo6cGFMXNjxWOfHf0gLodmJaZ/8I3/ViZ3tOuJ38p9dr7KgxSxACC93o 861UafwpFimRS4CD6uuX3rg+YOh7VYml49vOKBztGKv5rBBCSG+orR9HUeTkXz1Plo5RF4kNLYUN 4meDDXmwQvxqtMG4fpbc0rXbkBPjlnbEaErC2DXH/x8MddpzLkZxx+THSvo+0v3NSb8D140PxKYV 4Cwh7DjfdzJ5pFJcCaFl1Z/kbK4zClMrpXSA8eRWUkB6gDP67DsqSOlXX+Mr3yfeXYSEmIfO3QRy vjamouOmHRLqeYXWWsgC1Tcnrgs3V+6VJrUAR15i3R88cnxVwNkZ9/5iorIKCQgnlO0sAA/Sr8Hw gvNsCDHpJNYxagmjOJI/CMMACyGjPp651l1F6eorgF6KHl+FJ7FW1KCjjN2QVN+cCJEz89lk5iSu 8W0jTPV1jBC0IbS6l1eaP3cghiOVlQ6EocFjbze4T2mUIDTDzr5/Md/tDCEjxHh0AZ+H0tXXdTKU Ya9r0BGY+VwEkcUzZiW9AAdyqeQ4+Ayf+gqjM3iizeOfm3mW0jO6hA0NluY0k0Y2lrkFKX1yO3m9 H28Q/l+BDjGZO3jHa8o9FV0XHSdtd76so9bCZO+8KfLhqMKRhZHdAxb+P8a5yhP1VXLrjEPTwvjV yE8VcASkNwkgjzRYQHiAM9ZXOUrI8vX1BnI2zWQrM/k5dGsL/7eEtIgqejdJmExhZwCQWBuOJ5/K l4qYqdaC3iHvkpzkHvgbYLbNhdxfOKNE6IkMG7nQk4Qsadx1zkg+AxqsdNdU04mmyqANo19RX8lc w/u+BhygF54EOJH1ITyd9pxPfWeIgrL3NyezljxKIIUAB/eo892NygqTt7Gx+jrjz8BErSPys8fS C8BTE2CNnWAzo2q0rkq/8gBMpHoSeZYTsR9N6BG64XQ+Cm9F0lRqH8TVIEo7V45Av5Nt44UNOsqe 9gyqb24cgW7B7i9m8oClX25V76/WXa2+ZkTamHVV3TreWHSVnHvjD2qJz9EdT7KhhVsCwhv3Ezs+ xQVG8jzqMI7sAB6Pg+INSRoJ1TcVorzSEaqoUSaGXjG1Fpzsac8w01fJbAj0umVsN181JNNJ9XX3 jsUYxsCk0XcSUsIRIw3WbutooeGeynGylYPRgGApR8+UNDqWdVh7kiCNkerrJUIYfxJCWo4o7xW7 FzfFVTxecWnPM6gvWPIoN12n8OCzIs3lFD6VDSwZLfBnPoux5gkHG5dwj42TuPTkKwB6ibmd8Vim STx5HG0ezfih/nPGc0qL8cpjr3fS9ywmMWcIv8kifBCEkBZQ1uu2APoddLKO/JFYW5/8lceA2TTA Y/JVPoQoPPdKk6ccISbxZ+38ap9YyXC/gyc9EBsXcfF3ceOdfhU0U64myyaDi9Rm1dQcMKPNvvWC Iqq7hMXYmR65v6LU12JCiCWU8oirCSazSqAa8luIQbPN+6+78MjM9MtSXwCuwNYpqwjjfzrrKpjz DDi6A3i8pNPBkx6IexwL18H9tmFlHXceNDbqjzZrh1Sayc9CdRePcynGPcowDYBvxg/TsIneaxU3 3wBmcIFtcJnz29COLeSHNthgAAq1oZysK0eg353FAV0fFpP9lDbtObQOc69ykn5uUR9pb5WcAuzP vRLOJMjsCPHTZ+HkbQBG45S2bxX9LvbeBRgjeqHzqvTLmvZu9bSUppoaomvGwydijND6YrK1uOB5 WtrRWrVjC/mp0QatE7Wfh9oNQKE25C0PF4HroB9T9yaZ9UFxlY5S7t6/GtU3JwJY6M10e6b9TRnO tQAgzjlFnnp84At55nbR68hLroQ3NBf7V5psZLw9MYokC0xcZmG4xZP9Sv9WlEuthySJUcMXOUKJ kOoQJQVK556iz6pKeJ6hCR4WVWthpiG/YPC5CHqzqW8GCnph1FnKyrU9c7t80MmjJcDEbZWQ970n jlky3F9zIklDfX0LJ1nRhrJqn1tMot/B/7S/bv4rJ38SQtpAOc/zzOrrecWlPc96ZHR/c9JxMifc zbCTzL+I7mQZT0clJSTEsctyEvg1/VKJL30fdxwcfTUa4OsA3uRlTZiTYYlxNpbZBzxeDX5LxPg9 QOgQt5gItvaDww8EZ9EipcAZMyqilIhWd7bOv3HiFYD86pu11oKG6psTUdbA3wDZ+4DV/8xqg74u WAcCuPFOrA2w/bjxD+Voha9djR/sHQ0Fltr9FSP9NjuA9XvfRGjH446EgONAINrrhRmXDqRcaRWf uWW0oT21of/Vhi3kp2wbZsqaqZraDYAdNvjpdWZVX2B1vb60Zx2JpADno9+dMe18RHlJWMAkwDtJ iTLzngAAtx3A/sO49z3gjOqEiB/chMuuMdQXo88APIzKH+mfS51p5Y7n3jLnl4ZPdEfdJMZQYMNW /6kwOozL7FovExvEz4Yt5Ic22GAA8tlQgv0zDPbVrBWlvmKmQ1MCXIQB84zr5HZ/ixRgI6EJE6fX cHwni0auqvpw12HcdgAnb4XjiBvvlF/8LuR4TFHQ/dVDksZzY2EcUhZqtksxLncIX91DMSoDMVFl /a/vLIjQn7M5wU1vrdq0hfzQBhsMgB02jOlnn+hKsz7AsMpBR2EE3d8CWOjlTiooyQM2/5zMMzX2 fYMzckgcXMENt4vFrvyv74wy8rXKTmQ4MCOHVl853o7ycQ3dnQSfDVdYu+O+gw+fCNMJznqWbWgp bBA/G7aQH9pggwGwwwYA+dS3sFoLM6svAMHe37z0OhmqO8dSoACPNih8H3SHq0/2AsonAeDIGq69 bTzJ81hlPel7WZOmE2wkYAXm+oA/1h3s/dUhaHNqLYHJdo3zEtTplNjQUtggfjZsIT9ZbSgjqar2 81C7AZjNhuLtzqO+/loLszNbrQUN53zOieOM572qSIBnqoaEcc5wRP6wmKioVDJp1AAeqawaZeTB k6M48yjreVweWC1UgiqNZCu9C63Nwa5cOQpxa9k14+eTRGstzFGGExIkagoXUh/FP6x51LfIQUc5 1FdyKEduypx1MpLZhiEZt9lkgguNGI9KwliGjRmYlfTK8Q+lB2/sGY+EW4yqJPkGGklTd0W3P0qE lh6EkNKDlPA833gnHQYPeb+jhC+OEiFp4X1iEcWr7wwFjjQ2DDpSMPick65bUsmjBGYTfO3jjsVY hu89Q4ZNl9QXavZGgeiJ+srJ+sL8pa9fxFne5GzcPPJJDH1dv/laeOMojJ7TQ6R8MaQLTEgDKF59 Z59vwVdrIZdhOZt+j9HnfDglljxKIPUutUs6YjypxcTHNd1iMemI1RN0jH6F8ahf+ITc5yKPvWe9 L22Ayoh2xh+k7vQVoRcAI7Oa4kpIGyj6Qc6lvsBaQbUWZhx0NEZKNm95SLBuPwAAIABJREFUqUN9 MaMHLMdJTKNIb5QGq9XUA6MLJ+i5KoHgB1OnR13LvoRlP8bfYqzinOGZkJZjk/oWWGshZx8Hvd+c dN18027MzqyyL3W93pAGS0B4wVvK5+COddcMTWOcCx1WX6lj3WMi0/SpvoSQlHTdXOo7HNZca0HD 4HNOhJhx1rMiyCLApnuKGA2GkdgsMHo3C96eRrhYq+ZEPoVPfUff+rOdtUhjks8s5RCEkDZScOi5 4+Rqcz0Pa5NBR/nSnvOpL4PP+el3aqzNky/w7dNgjOPA4aRo32+MyPM47DyRdhHqbIbPHZYq9u2M HG5zV9Lz+dnS6HhmjIaQxlKw+rpOrg4/T2LVjrRnsGHLTae24PNo/5l/ERDIUSqWocHQPcSYLInb lNTBajPyLI1xunKcaG12CRup19oYb5xNPdmhkV8NGF9FmsQ3SUKso2D1dUSusZ4SWn2RN+05v/pK tlq5EEC/W+85nC0JKxCLNua70BlVMCor+JzgUM7+ZDaPyfQZAILaPHkQxWRH5pY9f5Gl0QyX3kTa ffsNhbl5J5Mkwv0ipAoKVV/V4M6KVJWOCkl7zq2+klkvuel3ax8fU1DutVY1YQzOlcGvQ4wVN/B9 sK0LbE2v4/+hDE8xPZ5lejLRdNSmCJkO1bfhiHGDOzPrg2IGHTmigHaf027kxHXQqS33SpMnGhPu rDVeyqLd39FK43+kbwUZP5RI+FbzDu4TnS4EIFwAcF1IwBtM1DfCWjMEbeRdE0IspTj3ZKS+OeR3 vbhaC/mnW2LwOT95YiHFUdroY9P9jYpAT/mZHHf96hm19GchvMMHJnNBQ7vC4zUnBR4MV3jilweD 0YQQ29CPfTH0O7lkb+CrtZBr0FF+9WXwOT/9bvWzTkaSOwtakfxqmfJu0eN9hZn2rP8XEk6z11j9 TxoS6wtEh7dQd+yfEBJN0VPq9Dq5Mp6GxdVaKKTRl0x9zofroFtn5rNJUX3A6ZQ46pcRd7TUEzgL /zSTZsg6Ms5sdPFOpFf/GVgho6WEkPIpWH07Tq4JNzxrai0oOPA3P/2uPSkd9UyAOR1zSixE9g3r YUvaITb6kjEWYGhX2NiyNWefEBKg0LTnfDPsS2BtPTxuYyZLnGJaHeZe5UP2OsKO4LOiaAGe5eVV AlETbOmxv3q87yRvy/jtZMSwN9kCDNHVIejRT8VkndltJoTYjcidaLO6Pm5U8r21u6Ig9WXwOR+O EDUVXYjDLmtGyLHcBss86KmyzCfC3xXs01pThvVy1mwgZA7IOehozRx0lGND+Wd7VjD4nB87Mp9N rBRgwMiTMjR4MvBXTlbRf04+6m5jwwme9B/zLiak7fTypT1bNehIweBzTuoreZSANQIcnOHScH/h 94OF0d0bsR34hzCY3nCU+tIbJqRuiq+1kKvSUVGDjgpKewbVNzdCoGed+wuLBBjwJzmPl5gaDOmr Ohz5cJjjj33ucvr5uQgh1VHwkN+ciVdW1VpQcOBvfnL2R5SGVQLsR5qFGaQvD8tX7CHql0EZDqsv IaR+ClZfoQeZzLRNCayum3/NbkaB0U7mXuWkk6/2c5nYJMAjBzg0C4cw0q8mIWjj6Yh43LTcxkw3 XehTTwiZjYKfwl6O2q5KfQsxqCjfF1Tf3Ih89a9Kxj7LJkN7TRkee73Qj6ye+sN4iCcPj5gsitVm QkiNFD0iv+PCzTG9/lpBtRaKGnSEUeCP5KKf452sfOwT4DgmMqwIzFUZ+RPevIRYS6HNoiPQy6O+ QwwLSnsusLln7lVOXBedjs1vMVYKsOnjBu7mgKYGbvWp55mSTEgr6eWYX3DgYWBNrQUNSx7lRAAL NmY+m1gpwCaRRQ8n32bZDiGkfoqutYB8o369gmotFDjoCJjMpEtmppevAGUlWJobVjS2XwZC5oTi 1TdPZXULBx0pqL45cR10rXcvy/SAixtb77sXEx3ihF8RQiyg4EdRYPYcV1lorYUC4ayT+bFv1slI yhPg0u4gvhsSQhR52tlJrYV8uAVVOtIw9yon/W7Br0SlYZ+VS31sXIhY3nXRnS3QxPgzIW2k48ze 7WrhoCMF1TcnOadCqxZrDBUCWzdifYj9h6NXWB/g8Q8AgG/+GPsOZdk0b2hCWofA7O1sgbUWik3z 4ayT+bE+89nEFdiabs0y/cjFHjou7j6ClfWk1fYfwSPuj9NPxDFL+Mn+YsbtZaOYkyCAjRBrtdnQ ji3khzZUZEAp++ibmc9Z9jD0sDYZdDQ7TtFdv+C8V7npueh2LGig0v7cAgG+9z1w/GbcfNf0NVfW cO1t2LyMHVtx33vilv04OquKTWPDhqW1tfDbwJSTsHHjsuM4g/GYwjiej+4F6H4DwxhnP5na7y1L tpAf2lCFAaVUAO04/g6p1EdRYNpz4bXtGHzOiSOw0JvMmZiLigRYCJw2bZ1wkaKspsTfWKeegEfv xP7D+JevZYi9nHYiHnl/SIn/vAJ7Uyh3OjZuXD777DNOP/2+j/nph5199ulnnP6zoVXGM0sb9Pu9 U07ZcdZZ93/Skx/9nOc88cwznnrTTbck7OX56D4DHQB3QL4Rq7dlbgRyNmiFzP9ngw15yHlLt8YG RN7SxW69+E0LYLEXWhQgarcSWFlLKKWWwYD86hvYvZQU4Lws9sZFFwKlehJPbLTuGJMZJ20j5jZL 81hJiUr6gOON2L4Vj96Jg0fxH9/O1vPxw73YfxhPeCDOewA+9XXsm8mTDLFp04ZPf+a9y8uLAC67 7Dspf3Xaaff52mX/3BsXmzx8+EjSynCePj7nWyGei+67UJYTT0jtlCIpquLCDH2lq1YOOlJQfXPS tbfkUQL1Wby8gJ8+A6vr+OzlOLSS+ee37sfF30XHxRMeVFSl5b17b929+5vq8+23p3Wsr7jih1// +nf1n4cOJQnwD+G9D+vqUbsK3t8hsc+bEBJg5mk3VnXacz6pK3zQEai+uRGNGfgboDIBDt1hjzwN vQ6+9AMcPBr3m+XlxVNPvXe/3+tEPnI334Wv/QgbFvCgexdl5d13H1QfknU0wDe+8T31YX19sL4+ SF75Cxi8D+tXwnsLVo8yQ5uQ9Mw87cbawMjZzKGfhQ86AjOfi2DU9ds8KhNg/+nZdgx2bMG1t+Gm OyLX7vW6v//7r7jxpi/98KrPHV25Yt/+r1940Vte/OKfcwLBn+/vxV2HcMZJ2LhYiJWrq6OA8MrK avpf7d9/QH1Ijj9rvoDBG7EW+95RMs9+9hPe8c4/umT3hw4e+pYnr/zQh/98tnUIqZruTKXlBp4e dJQv7bnoQUcKur856ThNDD4rarL7jO0AcPmPI7886aTjv33Fv77u9a/+9Ke/9OQnvfz0nU95xtN/ ZX19/aL3v+UTn/zrft/Iv5AeLrsaroMzTirELi3A+kMaDo/d5aNH08q2V5/v+wd/+CuvetULzzrr 1L17b82zDiGRlOWKOALd7O2VnbUWNCx5lBMhsNCbvpqt1DERR8fFjq247e7IOTccx/nHD71tOBye 97iX7NnzLbXwhz/88Re+8NWvX/add7/nDa97/av/4PffNvnBzftwaBX3vSe+dnXWSM7xx2+94IJn P+CBp23ffvyhQ0euv/7m+9//ZPXV6qqvd3bLlmMvuOBZj37MOSecsO3QoSNXXnnt//vAJ7V5R4+O +rAHg4E6hBe96BnPfNbPHHfcMVdddd3f/e0/f/Wr39abOvbYTfe73/Yzzzz1OT//pDf/n3dfeuno q3vf+4QnPOHchz/iQdu2bTnuuGOOHl256aZbv/zfl33oQ5/W7rgQYtu2Lfe61z0e/OCdz3/B03/v d//0iit++MIXPv1Zz37CSScdf/fdB3fv/uY73/GBO+/cn3DUr/mdt9500y3XXHPjU5/60//6b++e eR1CwpSS9qzoZR/fKW2ttaBgyaP89FVQpKmnsQ4B3n4clvu44rrIL1/ykp/bsGHpkY943sGDI3k+ 7rhjjh5dPXp05b3v/eizn/OkE0+8p+8HUuKWfXjRo3HpVfjxbemteMUrnvuX73itz582UFKqeNSj Hvrxf3nX1q2b9ZLHPvZhr3zl89785ve+9n+9HYA3DiJ5nhRCfOSjf/Gc5zxRLXnMY8552cue83u/ +6dve9uFADZv3nTZ1z923/tuV9/++q+9HsD27fd639++6Wd+5pHBADtwwQXP+l+v/dUnPfHl11xz g1ryvr9909Oe9lj1+Q8c8cF//LPnPW8yXOrxj3/kC17w9HN+6jm6MzvMF7/4tSmnJt06hAQosSHs OLOM/FkdFJD2XMaQX0VTVcMaGlLyKIE6QtD33oZHnBo5h0a32/n1V73o1371dVp9n/vcpzzqUQ89 44z7KaX8p4/+e6fjikBPzN1HsNTHve+R3oQXvegZ737PG9Q29+699e///mN/9Vcf1B4tADl+Mz3r rFM/9en3bN26eWVl9Y1v/JvnPfc3//RP/24wGAoh/vAPX/nMZ/6MufJwOHzZy56j1VfhOM5b/+9r HvvYhwHYt+/ARz/67/or1Xl8xx37HvzgnUp9Dx48fOml3/7CF7566613qnXue9/t73nvG7RVH/7Q p/XPX3L+s573vJ+98caffO97Vw+Ho9k/Tjllx8tf/vPpTwUhRVGioMww6+TKejHdqyVN60/3Nz+N mnUykjpeHzYuwnWwHjFd1Natm5eXF3VU9jGPOedb3/r+j350PQAhhOM4N910y5Ytm2Xgxr39AABs 3Zhy/5s2bXjHO1+rPn/mM1967i/8zyNHRjHkj338nc961hNgaOqfve33N23aAOCVr/jjD3zgXwH8 0z/9+8EDh97wxv8J4Hde8/JPfOI/PWMCuT/641//ylcu/5M/fofrOq97/asf/vAHAXAc53de83Ll Vu69adKrqibbOnp05ROf+K+HPvTM17/unZ/97JfVRFqdjvv/Pvhnz33uUwA87nEP37x50759BwBc e+2N+ue/9Eu/8Mu/9Nq/+7t/BvDIRz74v7/8Qdd1ATxy19n48wtTng1CbKfnZs5+srbWgkIy9yo3 zSl5lEAdB6C0LeqJklLqWCuABz94p1JfzcaNy3v2fDP4szsPAMCWtAL84hf/3LHHbgJw+PDRl17w B1p9YeReqajy6aff74lPPBfAwYOHP/KRz+jVPvjBf1MfHv7wBx5zzEat1ve5z0kLC70nPfFl//mf ez73uUt+9im/rMcTP/7xj1QOt5lfPRwPjXjz/3n3rkc+71Of+qKexnIwGL7zHR9Qn4UQOvB+992T QhSXXPINpb4AvvKVy7UHv2XLsSlPBSEFUdooEIHMA3/XB5bWWtBQfXPiOA0qeZRAHQKsBv4esxT+ Zjj0zAG4t9++70EP2glg69bN3W7H87ynPu1xH/iHT0ZvNvU9/cQnPUp9+NKXvhaYcEP35ipNffrT H6f+3LPnW+bU0Nddt1d1srquqzt0AQgh3vOej+hD2LfvgJbqfr93xhmnICa/+vrrbw4PIP7e967W n485ZvR6cejQJHPt4v/6irm+zr1aWOhHHzkhJSCAEsPPvYxDj4ZDHV3LO+iojLRnAB6Dz7lpfvBZ UYcA/2QfAGzfEv7m4MHDp512H/3n5z+/+5df8dz73//kO+7Yt2HD0p+97fc+/rHPmTHYEffYBAB3 p50646yzTlUfvnrptwNf6Rk/VFT57IecMTL5J7ebq0kptcoed9wx5lf//aXLzD/37J746/e4x2ak G+DU7/d6va5Oroavm3nyan/jjT8xfxVVPYKQUik5A9UV2dxfzysu7bk0n57ub0563bLS4iqnDi/+ 2tuwOsADduCTlwW+WVlZXVtbP/30+/3gB9cAuOOOfe/4y394xSufNxgM77j9rrf/+UXRw1J3nggA P047YnXbtpH2h6smdDqjE6Jc4ZNOOl79ec45D3j3e95grqk6hgFs3rzJXH7lldeaf37/+9fozyoy bIagzTf7e93rHr/6ay94ylMec+aZpygX1qyqZOZ56YW3377P3BcFmFTMTDMyZyFTmFFKjEcP1l9r IY4h1TcfjkB/prlIraQOAR4McfmP8bBTcPyxuCU4YvUjH/7M+//hrQ87Z5THe9VV1/3Ob791ygbv ezwGQ3zvpjQ7X1joq3ILiJruyh0/eErwNm5cVn+eeeYpZ555SuQGh/6yxIHxP+HhQKZM6nTuJzxh 10f/6S91nPngwcP79h0YDAYnn3yiyo42Rzrpn5tjpQBMnQWTkGIpV0w6TpYsG1lYrYXy1JezTuZn oWtBDbHCqKkf+/NX4OGn4pkPw7v/I/DNe9/7kVf/jxefeuq9A+lXSXzvBiz2cCTVLFSu8XT1QlUc dAhaCbAWyOuvv/lrX7sicoPXX79327bj1GfP8w4f9k0xaTqsKn9KJSqbeznhhG0f+/i7NmxYAvDh D3/6/771by+//AdqhbX176kmSHvAZga4549lBfSYkGaTaYinr9ZCntmey4xt0v3NSc+F2x73F7UJ 8JV7cfl1OPc0XPIDfNfXp3v48NGXvPh33/u+Nz3piS9LG1O99Cr85O6Uez58+Ojq6ppKSL7XvbYF vtUhaKXTBw6MUo4vu+w7z3vub8RVeTznnAeoD0eOrASGSKl0a8X11++FofEYC/yv/toLlPpecsk3 XvTC1+hBTUtLC4E+afhfIMzhT0j9bv3sZz/h6c94PICTTrongIc//EEXXvQWAHfcse81v/PW9OsQ UiIdJ0Mv7Nq6vbUWNEPOOpkPIRAzb1JzqS+T+x++hDf9In7tSfiTj44G8o655JJvvOXN7/nQh//8 Bc//7VRzMg8lrg325iawb9+B44/fCuDk+wRnkNbyppxjPRvGPe8ZkTIWJjhDCKDnz1pZWb366hvg F2DF4x73cPXhY//8OVNTN2+epHdpXdevCPB7w+k5+yFnnn/+M/WfJ5984sknnwjg+utv1uKaZh1C SiS9+2vUWshFeYOOwGk3imCxW+Zca/VQXy7ZbXfjPf+JjYv4/WeF59D43Ocu+R+vftPv/d4vn3fe I5aWFord89VXj4Lb5577kMBXxx03GkHb7XYBfOubozqDZ599xuLidDPcUPxKDaMCcOml31YvE6aC KtTbAAA9/5dCZ2vDCFyHd6FJ2Xr80Wv/whE7w//d5+TzMq1D5pMq+t/Su79DX62F2Slv0JGCmc85 6boz1oG2m1qTub9xDS78ArZtwut/EaceH/hy795b3/CGv7r44kvDMyTn5EvjkUJnnnnKwx72QL18 cXHhjDPupz6r9KuLL75U/blhw9JLXvJzcRs01DF4izxtPJL4Q//4qfE6k8NRHrPOdr6PMaQYwPNf 8DT9WfvN5i4Cu+v12hafIbZRkQeSMvnZK7DWQsnqS/3NgxCtGfgboO7RVBd/F3/9OSx28YfPxuPO inTizKk5CuHTn/qC/vw3736dnjfqN3/zfD2FhQodf+Url19xxQ/Vkje/5bdNtda4rtvt+nqONY96 1EPVRFp79976oQ+NBNj0gJUA33DDzerPF7/45/QQqV/4hSc///lP09oc6JxWdP1husJDBWQm2pOi GaAi9e2mm3hSAkbJMksHHQGQku5vXhZ6JfYO1ErdAgzgK1fhdR/F/iN4+Xn4g2finsdM/0k+Lr30 29q1PfvsM66+5vP/+m/vvuzrH3vT//5NnXqtw8KvftUbVSbzscdu+sIX3//Xf/MnT33qY88885QH P/j05z//qZ/59/edfvp9dTa14zi6G/gpT3nMx//lXUIIKeWrfv0N+jVC5Vsp1GDi//jcJerPHTvu 9Y1vfvzCi97yxS994MMfefsHP/hvOgtMe8Bm5nagO1kL8EKTC2Q2n3xZuBZTkYx0U0QapW/QUS7K ntKB6puTjpPqlmgmFggwgBvuwB99GJf8AKefhDe/EM9/FDYulrrDV77ij/UklMccs/FpT3vsQx96 5iWXfOM//mOkhaeffj8V+v7yl7/+y7/0WpWPvbi48Cu/8ov/9ql3f+e7n/rmt/7lg//4tic/+dE/ +tH1JxgVEn9yyyXfuvwTt9y6+9Ofee/WrZsHg+GrX/XGT37yv/QK24x8LiXz73nPR/ScVieeeM/z z3/mYx5zzt69t77md96qc9BOOGGUsG3O86wHNCuWlkZ/mqnXpA7a1+ZWdUQp3d/V4motlAqDzzkR QKvdCTsEGMChFbz78/jfH8dtd+OpD8Hbz8dzd2HzhpL2ds01Nzzm0S/8whe+qpd8+tNffM6zX60H Pi0vL+rBRRdd9C8PO+fnP/rRfw+M8QVw8823ra6uXffjm/S8zdu2bXnQg3Zu27ZlZWX1M5/50rm7 fvGv//ofzZ885CFnAlAVIB796J8CcPDg4Sf8zEu//vXv6nW++MWvnfe4l9x55349Vchjx5nS97// yXq100+/n7nlU07ZsbKy6nnejh33Yj0GUihV+fRpfJ21AYbWpz2DJY+KoBUljxIQAqdNW0fdQ1U9 ga7Arp14+k/hhM0YerjsalzyQ3zn+mIeuRDHH7/1xBPveeONt9x2250AlpcXe73u3Xcf6vd7UsrA VFmdTueMM07ZsuUY13Xvumv/7bfvM2dj3rLl2OOP37ply+Zer3vw4OHLL/9B5BiqzZs3HTx4eDAY drudXq9rivrJJ5+4ZcuxN998m556evPmTevrg9XVteXlJVU8eMOG5eFwePToigpl68i2EGLjxmUV st60aYOa1DPqiAsJkObsDaw9SFvtLW2vDYgb2l4PHQf9abk2g2ExiVdlpz0DGHqWnNem4jpY7gdv 0ehTGlgq/AsSL0P08DB9b2Tar16W4rEazfVkmwArhMA598MTHoSdJ0AIHDyKv/8CLrt6+g9LNgtA 3a2VDeJngw15qOCWnnqKGiHAovTZnk0We1NEcehhpYjZnh2U7ld5zL3KzfKC0UPfTgF2BbYmrRRh UFXsvQtf/gG+chWOrmHrRjzy/vj8t0vyg1NTe3OJguSzBVvID22YYkCl0x6403JtvCbUWtBw1smc 9LvZ5iL1UXsDlfbntnrAYU44DnceNAce1AE9YHtsyIMNt7QNNsCOWxoAsJBYY05KrKyhkNfvTgXq y+BzPhyBDQv+p6OdHnB9U1Fm5eZ9VjQThJDCcUSi+qq05yJ2VIHvyymf87PYs+DdtAqalWA2F5eE kLkjOfjsq7WQA9epogmpuZus+fS6LSt5lECzBJgQ0jqESJrmd31QXK2FAjYzBXb95kQI9JsTl80N BZgQMqGGKFOC+zsYYm00G6vVtRYULHmUn8VuW2edjIQCTAgZUU+1tzj3d+g1o9aCZljFTtpMS0se JUABJoQAtalvTL+sbNSgI6hJr+j+5qC9JY8SoAATQoC61CMy/iyBlfUpA0BSUo36ctbJ/CzMV/BZ QQEmhNRE3IxUq+tjPcunatWoL6i+uem4LS55lMAc5ZsRQuyiE9X+rJq1FnK4RG4lac8APE67kQ+h Bv7OI/SACSkby5vn+swLT0q1PsSgoLTnauKZEsXMEDLPLEybA7y9UIAJKRt7GxdRr/oGNHLoYa2Q SkdVpT0D8Ci/+XBd9OYx+KygABMyp9ST9qwJDDgpsNZCZRVkPWl7dMN+5mbWyUgowITMIzWrr+PP kJLAyloBac+VDToCM5+LYKELd37VFxRgQirBupa6ZoMC6VeG+uaiMvUF1Tc3rkB/7gb+BqAAEzJv WKAcZvrVZNBRPipWX846mZPFft0W1A8FmJAKsCrOVvdTb6YorxVUa6GyQUcKur856SeWf54beAoI mSMEUL8HrNOvBkOsN2rQkYIFB3PiMPg8ggJMyJwgak680qj4c1G1FqocdASAUz7nZ7FnV0ioPijA hMwFwpJOS1dAiCJrLVQ26EhB9zcnvbkreZQABZiQucAK9QXgupCyYbUWNOz6zYkQWJjTWScjoQAT Qiqk42B1UIyShWeyLBUO/M3P4jyWPEqAAkwIqQrXwdqwmChu9Tm0nHUyJx0XXZb/8UEBJoRUhYCu tZALp9pBR+Csk7kRYm5LHiVAASaktVgX7BsP+c1VBMIRVRfPkZLB57wszm/JowQowIS0E1sGHYUQ gJz53UBUO+hIQfXNScdFj8HnCCjAhLQQa9UXeUZDVVlrQcPgc34YfI6BAkxIC7FYMnL4r9WrLzOf 87PQ46yTcfC8ENIyWioYtTTiVN+cuA4WOOtkLBRgQlpGG1NdKq61oJC54uUEEFhiyaMkKMCEkNJp Uq2FEYLub176HQafk+HZIaQd2DvDUJNqLYwQkKz4mw+Hs05OhwJMSBuwpdZCiIbVWhjtV7LoQl6W +q3sDCkWCjAhbcBO9UVO9a0lgOk6esIQMiO9LksepYECTAixkjrUVzgOhhz4mw+Hs06mhQJMCLGP WtRXCFnUbNXzzCKDz2mhABNCyiCHF1nLoCMB2XGxRvXNR9dFl8HntFCACWkq1roZQv8zA/UMOgI6 LtaHtqayNQQhsMiBvxmgABPSSKyd7bmBg46AjgspmXuVl8UuSx5lggJMSPNop/rWNejIdeEIrA1t PakNoeOw5FFWKMCENA9rhSKXYbUkXrkOXCHXh5z3KheCs07OAgWYEFII+QSsU8+gI+k68KRYZ+5V PhYYfJ4FCjAhpBAaVWdQDTpSqr82qH7vrcJ10GfJo1mgABNCasWpZdDRWH0HHoPPeWHweVYowIQ0 A2sDfHkrHdVSa6HjQAhIYJ3ubz4Wuix5NDM8cYQ0gPamPdcy6MgZDTVeG1h6WpuCKxh8zgMFmBDb sVZ90dBaC0r1Bx5LHuVlqW9xGcwGQAEmxHasVd9c1FNrQYz2KyWY+ZyTPkse5YUCTIjNtFN86xl0 JBypBWONs07mwxFYZPA5LxRgQmymjU+oW0fQUgjZHZ/MIYPPuWHwuQja+HgT0goEYKcHnDftuYaG W0yCpRIseZSXXocljwqBAkyIhQhrE68aWGtBDToa/8WSRzkRAouFfzvXAAABf0lEQVS9uo1oCRRg QqxD2CoRjay10HEmqu9JDOj+5mOpx1kni4ICTIh12Km+aOCgI+E6PrXgrJM56bgseVQgFGBCSPnU M+jIkeZ+WfIoJwJYZvC5SCjAhJCScZ3qJ9Kc1FpQeBz4m5vFXj2dCO2FZ5MQUiauqKGZCagvGHzO TcdFn8HngqEAE2IF1qa1iDxd0vXWWtCss+RRbpZ6Ft+kTYUCTEj92D3oaNZm16llzg2BjutTXylZ 8igncqHHkkdlwHNKSM1Yq77IMxqqrkFHgbRnMPicG9cRCww+lwIFmJCasVV9kSvkWEvileMEHbWB h6HFJ7gRLPU462RJUIAJIUXjilrUV3b8jpoEg895YcmjMqEAE0KKpnqHSTiy4wSjCWsDm8MLDcDh rJPlQgEmhPgoQDyr1l8HHSe416FkyaO8LC0w+FwqFGBCasDaVq2AjLCqj02g6wR1QjL3Kje9Lkse lQ0FmJCqsTbt2VrDkuhE1TdkyaOcCIElBp9L5/8DVQnRDPkysQUAAAAASUVORK5CYII= " id="image17-3" x="-614.61957" y="-372.38272" inkscape:export-filename="/home/m/Vault/projects/mitjafelicijan.com/dfd-rice/install-00.png" inkscape:export-xdpi="75" inkscape:export-ydpi="75" />
555 <image width="169.33334" height="127" preserveAspectRatio="none" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAyAAAAJYCAIAAAAVFBUnAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAP jElEQVR4nO3dwZai2gFAUTurBvm8DP1Eh/m8DDLIoFZ8PgQK8KBo7b0yqK5GuIIt513Q/DmdLicA ADr/ePUAAAA+jcACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMAC AIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJ LACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACA mMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMAC AIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJ LACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACA mMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMAC AIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJ LACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACA mMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMAC AIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJ LACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACA mMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMAC AIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJ LACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACA mMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMAC AIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJ LACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACA mMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACA2Nfa B1wuewwDjut8Pl+87vmtvP75bc7nZj1msAAAYgILACAmsODY7merq/nrbaa2/vg4X/u8AFICCyL6 YIlX7aXz+XcdoF/1ZOGQBBa8m213HD//jLt2nLveSe02beC5Vn+KEFjtNm5uz/Q//v4+C77/arDw 5TL+kJn1bBvnYD1rxzn1V/O/HGxiyfMdHdJyq47X7Uhun8XacVbLz+znav8ACzwUWGez0PCj7xPh /R+X/P7+n9jtOXV0E1Pr+fGEunY8a8c5+qxnlp8az9TPM8uvsvZ4ne6e2vwhCJ/X6M9T+/mB/eOt nt8g/zqSR2ewfD8KH2+vs8uSfzujObVtVclKpsazcJyVqUR72rZ2euwzL6queaz3eT7eHu/zLhHC 6xxtYuBo41nr3cc/JXlegyuYwM4EFrzI/SWb1tQNPa8az97effwzqiS6Xj0M1wlMEFjw0ZxHGZi/ GQ6I+JoGOIDl3965Yc0bvgJq7XiONl0UjueRVe2xWzav82jHCD6dGSzojH5ubnAD+O1Hz+4/4T/z 8+36l1zlWfupsbXj2TbO0TuBRpef2m9rxz8/nvn1nCaO15Lx3A9p23o2bPc0tp+3rQfY6s/ptO6f 2d/fFf2/rPP53vV1Xn1tAdt8yg5/19c/rHH7Oq9me81gwYcyYwHwOgILfvDG//n+viP/AJ+y89/4 9Q8bTU1hrfu34CZ3AICYwAIAiAksAICYwAIAiAksAICYwAIAiAksAICYwAIAiAksAICYwAIAiAks AICYwAIAiAksAICYwAIAiAksAIDY1+5bOJ933wRwbOfT5dVDAH6py4vefsxgAQDEBBYAQExgAQDE BBZwFP/5778Gf7z+7/73U48COIL9b3IHWOC+ov759e/7Pw5+GCwGcBBmsIDX00nAhzGDBbzYqrr6 nrW6/iDLgGMSWMArTUXSNaSufxz8rK6AIxNYwBFN3YMF8BYEFvBig48ELgmp6x3up79PbgEchMAC XmnDNNXg84Mmt4AD8ilCAICYGSzgiKZucr/OV7lECByZwAKOYpBKU58unF8A4AhcIgQAiO0/g3W5 7L4J4Ni8CwC/jRksAICYwAIAiAksAICYwAIAiAksAICYwAIAiAksAICYwAIAiAksAICYwAIAiAks AICYwAIAiAksAICYwAIAiAksAICYwAIAiAksAICYwAIAiH1UYJ3P50OtZ+0mzufzEzY95YWbZsbe x+V+/V4JAI/7esI2Bu/Xl8tl4aMWLvkZ3uX5fh/NPYZ6f15/5KWydpyrlr8d6pOP2nXTo9t9l1cR wMd7RmCd/n4y2O8cUK1223pWPa/3PQteLpf9Zjg27JapucDvVS08KKuWHyzzzKaZ31Z1XN73xQlw HE8KrCmjMwHXXw4mFb7PLlP/BT86AzG1/pkT5P16ZrY7P50wZflkyaqZktvB3O+60fVMPam1AfHj +peMf4PBobn95XWjP45/7fLbxnn9+f6gzByv5QdidFf8OJ7HZ/4AGPXKwJo6kc/MJdz+crDA/Il2 aoX3Rs9So9udGcyqTcwH5arxDwZ2PemOrmcw/oWDv7dk/QvHv9ZbdMDMfvjxeC0PplUXQ2fWv+sM JcDv8aTAqmYyXnVC3XW7Cy9O7T2GvU+r+Yzdq6zdVw++4Edb/DQd4o+sH4DKU+/Buj8TPPLmvvaE ffvAtffovMT9laNvm28G38/Mfj4tHv/9Yq99XjP7efQy6Mzye9wdteTS58zDAdjVUy8R3l+u2vsd /2mzPjtt6FqBp4mz+0FMDeldxj9q7Tinlh+9ya81mOUaDVYAnunFN7l/gCecxo4/2Tbv3cd/cHvf 6AbABs/+otGZez72vhdkcP/K+XxOzkbn/3twPaNrzte5dlsbxjBzyWzbGK5/u3CFt6+x0avSg/XM L//jmNcuv3zhDcuv5QYsgJ28cgZrEFuDE9XUHTyjRj+IN7/+5euZWXjXyYMN41+1nsElzh9/Pq3c z2vHHx6vVS+eDcuvujQ8sz9XLb/H62HJ8QVggz+n09obTf76+Zdfj1gbWG9xZz0A/DbLvh9n3Ynb PVjbbZ6hUVcA8NkE1kOqD5oBAJ/k2Te5AwB8PIEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEF ABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABAT WAAAMYEFABD7evDx5/M5GQcAwMd4KLAul0s1DgCAj+ESIQBATGABAMQEFgBATGABAMQEFgBATGAB AMQEFgBA7M/pVH2XlW8cBQA+1bpeMoMFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABATWAAA MYEFABATWAAAMYEFABATWAAAMYEFABATWAAAMYEFABD7czpdXj0GAICPYgYLACAmsAAAYgILACAm sAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAA YgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgIL ACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAm sAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAA YgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgIL ACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAm sAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAA YgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgIL ACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAm sAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAA YgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgIL ACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAm sAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAA YgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgIL ACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAm sAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAA YgILACD29eoBAAC8r/Pob81gAQDEBBYAQExgAQDEBBYAQExgAQDEBBYAQExgAQDEBBYAQExgAQDE BBYAQExgAQDEBBYAQExgAQDEBBYAQExgAQAAAAAAAAAAAAAAAAAAAAAAAADAB/gfm8Fj1ALsE0sA AAAASUVORK5CYII= " id="image29-6" x="-445.28625" y="-372.38272" inkscape:export-filename="/home/m/Vault/projects/mitjafelicijan.com/dfd-rice/install-00.png" inkscape:export-xdpi="75" inkscape:export-ydpi="75" />
556 </g>
557 <g id="g513" transform="translate(1043.4871,32.342183)" inkscape:export-filename="/home/m/Vault/projects/mitjafelicijan.com/dfd-rice/install-03.png" inkscape:export-xdpi="75" inkscape:export-ydpi="75">
558 <image width="169.38" height="127.035" preserveAspectRatio="none" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAyAAAAJYCAIAAAAVFBUnAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAg
559AElEQVR4nO3dsbarOJcuUNcdFfyP16Ef0WE/Xgcd3GB3uXwMkiXxAcJ7zlGBy1uWloQQy4A5f91u
560jxsAADn/7+wAAAC+jQQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBM
561ggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAA
562wiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQL
563ACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJ
564sAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBA
565mAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2AB
566AIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJ
567FgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAI
568k2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwA
569gDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbB
570AgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABh
571EiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUA
572ECbBAgAIk2ABAIRJsAAAwiRYAABhf6cqejxSNUHG/X5/mJdwLPsdV3G/71u/M1gAAGESLACAMAkW
573/ON+/7//IsX2U2p975BO7PJUjAPQQIIFLx6PldsJ3w6oq2XqnjnZ9mPz/T4SAHvnxLNlXal4ZusX
574XIcEC3b2TIl+/tvviFXPura3O5bVTXKEDqakslugQexXhEC31+Tjedj+Scief2o8nP+Ufyu8WslP
575/cv/rbe7rL9Sviv4lnpuDeNT6le96fb6Xz+yGuTbn1Lx9MZZimeg/lI9QINdEqz7JN9ZYUItB+DV
5761/UD3vLcWKnCispHVs+9leKMtNs7Pr3G6l+Ow2q0wXh64yzF01v/hn45BDCzwx4jstcZLM9B4XQX
577XuVXd5/Ugby33WD5qdqtVDLD8tUSwx5xJuq0/jOtI48LLhECa37DMbJlqY2Pw7LRw4Z6tb/Pc3K/
578YYvDgSRY8KUGbuS6dLu9lpfGjnHimJSafr0GPfMmg0vxK0L4JHvIOfjC5VnPdPAsiddE8xJXq/f+
579lSv8MhIs+OTSh5z687f261rXc796w/hYPl7hmJ98Zey2ucMeG3vp6Q0Tc4kQdvZ2VuB5rC29P2D1
580B4aVX4e9XsJrOb52/WJ/4PEEq1cVK+PzsfzbZ1fjz45D6U6m9s2anSfLeMbqd4cWjPrrdsvsNn+u
581qP41dc7XPQ8b7xy6xA1Gt6FE55R2ewM7rCNZFw27n/Wfmb3Oz73P3jqDBf9oPzdwCcEzZJdod0LG
582AX4xCRZfy9fo0w7qXe2e9fCtA1wo1Bz7HddROoWVmcNucgcACJNgAQCESbAAAMIkWAAAYRIsAIAw
583CRYAQJgECwAgTIIFABAmwQIACJNgAQCESbAAAMIkWAAAYRIsAIAwCRYAQJgECwAgTIIFABAmwQIA
584CJNgAQCEzZhg3e/3s0OAy9hpf1lWu/eO+VZ/vLljFhbLV0njyEw7gKnADu7gbOM5Wzy7OjPBuq85
585MZ66mWP7zSafNk+pOC/R2dt5cV5lfHpdZZ73Ojhrj5ffu57ZnDWeF3VmgvX4x9traHeVOXOVOCv2
5867sLV69/VpYP/cfUupOK/+jjQ7u+zAyh6Zr6v0/E1HW6Zpqvl7/f7W52vf1ot//riYzyvkS8/Ugly
587Wb43/o9NLOtpH+dS+VI8wX51bffs+Kz2qzIOq+MZibMyD29/jna9Xy1NLAvXG7017C/18SntKQPz
588rRJqY/xd23E1yI/1L+MvlW9ptzH+SPlKMMvuv3VttfL2+Vxpehnn8Lq9ff5E6qm8X1Ip3zsfXsu0
5897F+VYPZbr+Y3aYL1tme+HthWy3ysZEv51dbr9b995GPTq+UHEoWufpVe95bfu1+pcQjW3zIm8Tgr
590cym+v7yudM/W397s3V9KcZbqr5dfqu9r7fH3tlsat7PWq9LrYPm61ZLL8R+bJx+bG163U/MnVc+J
59182FV47GspXx2vs1sxpvcb/tkr711nr51UwFU6rncmBwQQ0v9pTJnjU+83YEKt4xbMIyI4XZn2EFu
592+4zzkV3b0lbjt764vZfrLf2aZFo+zRbPfiY9g1Wy/I5b8Wi7QjdcvjeeAan6945zVwPbZar6T7Tr
593dt84bt832kur4/94OYm7/NZ+fDxvnvFcZb84a92ecF269Dp/u378SxdLsMa+mbVP07HyO0ktvgcv
5944nvo3S6z1X+WY872fd+4pcx2xm7v9fMsXXEG18Op1qWvWee/yaSXCLMej8fjz7s4n69LXzGXV8rn
5958TH+gx0WT+N2GY7n4O0+23YcNvn+wkZX2b5nxbl3u1cZf5YunGB9nHCVAj/zNZvy77oDLO8PXcY/
596UE/KcDwlbzcL7xpPS/3L+1KHq3oVH7eKrtgGxmQPW/bxU1Tief1Ty3bf0rXI5pttbEv2Hqg9PttS
597bTC2LVc/hmPY6CrTr+5KlwjfsviWm/4q5Zcf/1j+7VRtbzy9Smfdepur11Mv397QWDy3wnhWYl7N
598iZdn0feLZ/mnj+9H4nxrYuP8r5d/++xq/L37S0VpfFbH8+N+sWx3IP52A/P2Yz0b4/84bhvjqZdf
599boL6/G+fJwNx1tft/ebP9nqC+2/XfBgYn5ao4vPtEv663VK/ffj39THfyFOuFe3SbPF/fTylCjc2
600NNu4cVEmElTc/3xIRKFUZg+60hmsoKtnyrPFL54xV4kTgF7OYAEAv8KRZ7AufJM7AMCcJFgAAGES
601rJjv+FnphL7m9+QHO2zceuv5eUJBpOmIvYO5+vhkbe/awHhubPEUs4WdWk9m69euvucm999z49d3
6029/TqvTs+/tUFa9oxPGv7XmVeVX6jept4swJL35Ng0egqR5p2X9adXq83bHYNRWrcrj7+e8cfqX/5
603RKJfa+DRcTtFwivjvHRmgrV8mtnqvf2rD2pbLdz4Je++eID7WLtvXag3+myo/iDKxvcrfemKc7jd
604ZRjL8pX+1itZ3Y71LjT2ayD+1zL1eVKJv15++7MWK3Ydt9V6erd7qd1SPb3rRsu8ahmHgX6t1j9W
605z2rNvfMztf4M71/b15/eeRvZvqesJ29/Gm63N/7l97TVUCPbpSWeSzv5DNbP4D6333OKr07E0vur
606fx3Q225pD2lsoqv+5f9+LFCK8+MO/7HdSqfam1uqbMdKPctv9sH4u8qX4q/Uvzr/K0332nXcSvWU
6072i0lOgPzp2vdqI9t1zh0zedS/aV66olgu974t6x7y/+tx/M6FGP1987b7dv3rPWk8rqrnrH9erVk
608aj0Z2I8u6sI3ue+9VbrqbyxcWuIHPruclzsNyJZqUyEdGcPe5Y901rYrzfNnxrNlf4kUHrPrfB4Y
609n0i7A2WGyw/068j98fTxeSt/2DEo28THz868ZmZd6R6sx55XUur1N56gGtZbfynrH6hn+ebe47y3
6103vj3Ln/bf/5ETL7dW6K6xDgfIDUOe68PkThPPC6cEk/FV67nl3alBOv2crb/ts90KdW/69Rcnkr9
611+JHH4oJIpZ5H+YaPUr/2Hue99cZ/TPn5XXq7D+xH32rvM8epeZKN8/jjwlnxrKrM/0vv15d2yUuE
612P6fQ91tA964/ojfCgesOlxiHit7438q/vi59Nbz0+JR8a7/Imm2ezHZc+G3jw9KVEqw9ZsbbTZfD
613YWz5bGOB5Z8qe8vqfbU/PtZ/9T0wcp30x88IZ0+NtE+VgzfE1bf7q2/qS4uudWOsqsj6MBDnljUz
614IrietJSJdGfguLa3ScI42IyXCN/yhuexrfT+218/nqcpnaXobbfy2camx+JZVvj4597Y0tmXt/xg
615Wb6lvy2dainfWFtLPW+Lfr1fH1tcLb/8eO88zI5PRGTcSvX0So1PfX9cnVepcSiJjE9LnL3rxqst
616615v/VvW21v/9jpgfWgvn9peLe1G5kP7Urz3fnRdf91C/2r06+jdv/qHl8POGpZSgkUX4wZwdfc/
617HxJRKJVZ6mc8g0WWbxLDjBsAYyRYxznxCC05GGPcABhzpZvcAQAuQYIFABAmwTqOX92PiXek9ASE
618c0ds2frBvz/fY5yzFQJcyDckWL9zHT/+OUnHOCCr+Hng3n7171Szdl8bfaq/CXCWb0iwNrrochxP
619ES46DkGz3dK+dzwXrf+ZIv94+6Xn8k2AU5z5K8KfhXL54M1b+efxH382v3zmU72et0qG212GUSrf
6203t+B51eV+tVbPtLfyvatV7L6dLuueTJg9SmUXfNz4KmSlcGpD0JLu/XxLwW5LF+ahy3bqzH+rnnS
6214rH2j3UCHOnkxzS8PfLruXCXFvR6wlEvsFpP6XVXu5VOtTSXehBo2/PTiuWHE7ve/pasjkalnoE4
622X1+8FV497dHVbiX+UjyV7bWMZ6Ddyvi397ek3t/2+HvbXQ0DYDYnXyIsLc0Dn12uyzutvL3Vvh3V
6230uF8bvREqTBSZzWeGcnYHBsus0cle8R21rSZZLoCBE36oNHeWyhK33oH6lm++Wj+J5nGyjPsyFtt
624nlvzrO27sV2zEeBIMyZYlfuoSlZvuSjVU7nho3QQer3ppP3MweRpVvzGl+Ode8bl+O17iXkFwO30
625S4RBq/eU1MsPXEDpaqW3/CkGxoEfZ23fS8yrwxgHYE4nJ1gfF8dKgZb7giuF7//4WH/kOuNG+8Xw
626cRyu4rAunLV9D+jglv1xKqvns68SPPAdTr5EuHqV6u3N1de3wiWS12uFpc9Wfo21Wn9Lu6VObSlf
6276fvqD+Iq5Vf1jkNv/GPa7zQKtlv/gWFXu2Px927fLe2W6l+G9DHOUrsD8ber1HP1S97AN/nrdkv9
628zuvf140/tO79PXZK5efiv4pxAOBXuVefj/OPzKFwxpvc95Y943JdxgEAdnJmgnXiEV0y8cM4AMAe
629vudXhAAAk5BgAQCESbAAAMIkWAAAYRIsAIAwCRYAQJgECwAgTIIFABAmwQIACJNgAQCESbAAAMIk
630WAAAYRIsAIAwCRYAQJgECwAg7O/eDzwee4QBAPA9nMECAAiTYAEAhE2dYN3v9/v9fnYURTPHdgm9
631A3jRAb9o2Nsd3PHh5lJxXmVDnxXnVcYHUk5OsO5/evvT4/F4uOer02yr2G+LR3/5JgfMn9UmJv92
632zbBftVlPTrCeKZRc6hfq3eJmyLVcZXul4vxt/Y20WwrmKoMJFd2/IpzQz7mu1f99TZZf3yyVrzSx
633rOftT291rpZPvV8P8ufFlnoej0d7v0rlK/HU31yNc7VTvXFWqiq1266lvxvb7ZrPvf19jfDtI73j
634WX9zp/4ue/GxX71xds3Pevyr86GkK556/e37UX37rga5bOuttj3Spkr8pf0iMv6960/l/YF2l/3q
635jbP3OFjZvsP9bTn4XtqmBCtyWKpUu3GfHEikeutZfV3fsbe/X7L6qYF6evtVel2K5xnt27niepzL
6368r1xBsdnVaW/veO56oD58PaR59LcNZ7Pqrq27/b+3spzcrVfvXH2zs/e/aWlU43xVOpv34/q27c9
6374Eq7KV3j2Vt+7/V/oN1InMPqgbX39+uzq9v2M1h7DNDwjn2Mt9Vq1/rPUjpkdpXfI4aWMjMM4JtI
638SGf1a6d2e6sdng8blerc0tYen92yLk24y3Q5q79nzcleM8TwZtrje9Y3XCK8usfalYsf+33nG9MS
639zwy7Te+4nTXO3xpnRGW/OKXd2eJp/3g6oqnN3N/I/v56Unl5luhjnXuMT6ndyvszb6YgCdYUnnvL
640bds30V0N7MynmGTRadHV7lnjf+J2L+0XZ7U7Wzxcy95n2mZbxyrv/5Ica+rnYDV6vbo/7VG/xePx
6412PVOBbiis/aLUruzxQMDzj1u/pKZ/A0J1u2frTV2P2ZvW/Fp0VjhkdPxY1sHBNPSxB5xLm9VPmbk
642u1rpPSefEqw/su2WG2tTTNVKJr8+uyW8rz/UndjB1HR6Ld9yvGs8cz923Kxo7+9qjnXYenuMky8R
643vmXQ2Xs/37bfs8Djz9+sftycpXp6y6feb2x9Sz1vQ7T6ZuNusHoHyep2r8RZmicDcfaOT+83rfY7
644ZrbMq5bXpXhS7Zbqv/Vv34/tluJfllnOh4quOHvn59j+uxRcH7r2o7c/tW+v5UdK7fa+32VsvarX
6450xJManvtXb6r2K28fbf097G4VvhlZ7b+ut16r/L++7qU+WYz4l7ntv4FrjKAh8V5lQGBAaY3t5mm
646wd6R3P98aEWhVCaAL7nJPfJNEZbmWXcAgiY8bn7ZevslCdY3bZLTXWUwj4nzKqMBY8zwX2vCTT9N
647SJkzW19ykzsAwDwkWAAAYV+YYK3+8vOUSFJS8V90HHYK+/h5ssczBXat8MRWvoCBWjXPsFhXv6mh
648ObfCFyZYk+jd3lff268ef6+rj/Nsrvv8m/uas4MqjmcqvKvM/9+2LjGVX5Fgjd03N88elbrvb5r7
649Bye19/hcvf5dXTf4xz/eXp8eVdf7v5B19Ri/eXxmedDorfDgvtf3f37AufpAvMrTBVefgjhQT3v8
650lafk9Zavv7lTPZX3V/X2d6CeW2HT9P7MuGuelOqvPB2x8sDG0iMTl+Xvi3/77/HyT9HVQ22MvxLn
651qnqnGuMvlW9ptzH+SPms7LzdWE+k/oH93bpaf78kdXxsaWLLul3a32+d47ws9rb0leKcNoc7M8Gq
652HEgqC/TydWkF//FYezJsSz3DE2u1FwPlS/HvXU99h1mtuau/vfXcGrZXS/2982RgnCtTqH0elqS2
653b2+7pXHbMv4by/fOh8j8GRCft3vE31t/7/5e3+/a4/lt62rq+NjYxE77Rde61FJgeF6dYqJLhC1b
6548WOZxqkQX0lb6tyj0WC1pXp2CrtLPIaBCiPzc3sYEcPtzjAZbvuM8ylrwiR1HtbuHvvdL1lXn+Ur
655H7zK+hM3bUfOPIP1KP8rV9MmpK8q8ZdE+jXQ7lT1B+06TzaOw/yjt93q+D9e/n2x5bfP4+N583qg
656Omuez7a+peI5a337bevqDPvRU2V/j9Q/UH4eJ9+D9dwqtz+n3SkHp0f/BexS/KuCB5uudiesP2Xv
6572K4yDmeZ7RvzWDzHb9/Z5tLeZ2vG6rGurjrgS8uc++kVTfFP5XQlv8cEM/CR4+Pfu92ptsuJjMN3
658s33nZF3l6s68B6sx9e7K0Len8/d/7NrWWZ9tqfai52Pj8+SAcfjYxGzbohLP659+TgbXDyF77wIb
659x7ZxEdhutsslpfojcVpXt9fz8c2NdQ6Uadnft9T/sfxs6+TTX7fOf7zwdQBLA9o+0G+Lcv39+q8n
660noUrPy4o3RdSf38g/te/rvbrLc6P5d+aGG63sZ56/SX1dofradnujfV3zZOP9dfjXG33taqf8qtX
661pXedJ1vmeWXcPgZZKT8Qf33cluXr/WqMv64+sJF5e2vbv1rGs/R++/7bvr/X5/OSdbWxnkf1fsd6
662E737UUuolf391jw+j8XNaql59fxUaY9o0JcvnZxgTWXgwAMczI4JDDsywZriHqxJPP58YodFHAAY
663I8H6g6QKJmcnBS5hogeNAgB8BwkWAEDYNyRY0/5E87t9HPbtBQDgor4hwaorHcUPO7qfHgARthcA
6647b4/wWJac96tLJECYLuTf0XY+yDBlqqWj7goPbVs9UGRvQ9eqz+QsOVRYWMPTuyKMzXOpcIfx6f0
665fks9W+JsrOdj5Z69BECXMxOs+pOOWx7EXP/s6vNtK++X6hl+AGn7g1h72+0qnxrn0vPZxup/e+rY
666TnG21POxctkVAL0mvUTYezxLHf9a6lmma9tb36O/qTJbPthVf6XwkdsXALbzoNHPlv80Uosv+3eE
6676lL3LR15/9PG05AAUCHBavK8lnRzFmRNZEyWl/a219li4IY/AKiTYHUo3dJ0W7tZ+/ecvvoOthcA
668QZPeg3WW1bMmvadSBrKrgSYiZeofr9TQ+KfhGNo/WI+zq8W3qurZVapdAL7SmWew3n5HttOpgtId
669VKvvr14tqscZCbu33a7yqXF+a3T1dUuct8KTMip1Dsd5a+jv8K9EAaDkr9ut9/dr/77+sgthZ4Xd
6702+5Fh3daEiyAX6L0vKE2fYcG92Dx2x1zJhWAX0WC9a+zjqxnPfSLJ0MKQJab3AEAwiRYAABhEiwA
671gDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbB
672AgAIk2ABAIRJsAAAwiRYwMXc7/fV18B29q+UGROsj1t0p00+XO1Fp+BFw97bclhKA3W/31f/NDaw
673Z037/Zwb8OWGa1h2HmLcSPn7xLZX5/Hj8Tg+Erb72Zrtm+9+v196W189fr5jC35HL7brXX8G6p9q
674nFPxzNavL3PmGazHP95et3xw59D6zBbPKb54EHq79sVD0WVsHGY7fzBbPO3q43/dfq0K7nT2X1LO
675PINV99z/36b76jeV18WiZfeolF9t92P5xnhSca6+//NdpDRuH5vYEufHyt/ifH0R79drybcmPo7n
676svKBM3PL8gPt1uu/LcbntcDHI+vqeJbqqZdv308r5XvH4bXYx3pa5s+y7+3xtPRry/tb9uvGxa1r
677u1fiL0XSVU/v/Kw33V7/60dWg1wuJpF4euPsXT8r9ZfqKb2m16QJ1utkfZu4r3NutUDjAeZjW28L
678Tenj7fGk4uyNv7GJ4Th7419tJduvtyaeS9XH8Vx+rV/dvq8v3oIZmw/Ldlf1jkOqnpZt8XG/KJXf
679qVMt8a++MxBP136U2q+3zMM9+hWsJzIlxupfjltpvUrF0xtn7/rZuw4TNONN7rdtWXPvZ/fO1lN1
680PuupVLil73HByg9bAloaejwezxUqvnEjxeL1lMpPNd8qDVXajRxg9l6vVsvsMQ9b2j2gnki7wXVy
681D8Pb/YB2SZn0DFaXx+JK0LQaT1QcVs/e9ffW01J+/q28tPf22uKK45nSlV2tnt1cFns7WzAc22yu
6822K9T1pPGebKH1f5e6Pj4fb4hwbq9nO28zT2NIrEtT/lur/PNWXHOvO22+NZ+RTz6bzDKNl25uLbx
6839PZU2z04zlP1q+SAdXLViYNTP9M8//Hx+0x6iXDMz6nyq3y7gojXOX/dyb/fda6P7Za+93/loehb
684+3W8y+13jo/H+4YEa+OMOetyW+Ty2QF9j4zPQCWnLAQHNLplO5aK/aybwftVjx/8+z9StVX+983q
685UScbTyWGg4e63q+d9tP4rQJ73HswYMt+d9hxJ9tQdqf4ehe7RPg2aZ73eL5u8o9zPVi+K55Uu2+n
686+rdM99WrBr1x3hrGYRnn8s6AgXa7DIznar8qhudD43asXOWJ3Kmdmldd47a8lDPWl0r8H6+OvV4r
6873COeW8M8D87/1fEv9at3uw/E2bvOfCzfsp8OzOfKvF2uV8uw67LbvX39rNdf6hcRf91uvb/v+Pd1
688aekJfpMGulxu70slNI31nx7PWc7q18bxv4qLhv0LvW6p/q+RfZv4YmewgKVdz/ztbe8zl71miyfl
689W/t1IuNJnQQLLu/qi/uu8Q9UfvXxLDmlX72NXmjwLxQqp/iGm9wBAKYiwQIACJNgAQCESbAAAMIk
690WAAAYRIsAIAwCRYAQJgECwAgTIIFABAmwQIACJNgAQCESbAAAMIkWAAAYRIsAIAwCRYAQJgECwAg
691TIIFABAmwQIACPsVCdb9ft+1/N52ime2bgLA1/j7xLbfDvCPx2NjbRtryBJPr/kj/LVed1XbCKDF
692mQnW7c/Fer/ja2+1sx1CZotnTrPlZ7PFM+ytI1/TL4BdnZxglax+Y/5Z2Z9/en3/9cXb6l95862e
693UvlSu5U4K1WV2i3piqdSw2pVr38djrN3fFrqXx7U6/W0b9+WtpabsjH+SDyl8qU4K/tFV78kUgBB
694WxOs9sN8V52VA8Py9ethZlnb67HnY/2r5UvtluopxTN2AGuPp1JDqVhXvyq66vlYf73Aaj2VARlO
695FHrjT8WTGv9U/dIsgAGbEqztK+/qN+lKtXus9Y1ZzjHBNEo1vWs9jZXXs6v2evbWMj93bXdjmQin
696tQAaTXQP1quWH7jNsNBf/feJJak4B8andMVw13ZXPc8drp752y+eSruNH3+tp3TWbaBm2RVAuxnv
697wYocDA4wEOdVjk+ROMfGp+WK4Wvh1YCzZ+be0p0D4lltN+gq8xDgun7Fc7C4kNV7zurl904Xfppo
698jCoYT1e7kebefg+xLHBMJABfYPYE64CjS0sTH8sMxDntmbk3e4/P8k+VrGL1fv8fw7GVCo91fHs8
699kQH/8TOS9Ut7b/dBVspfZcYCzGDGS4Rvl1q6jiW3ws/mX//0VufH8suQWuJcxlNpt6QUz4D2O3sG
7004uwan5b6X68Vlj5b+jVcb/y9cR4ZT0u7verxOE0FEPHX7dZ7d8jnMl92M+yXdSfurPHpfdzAb4tn
701o6vHD7B0//OhNp2f7lsSZzyDBS0GzrTtarZ4Blw9foB5dJ/BKnldjX33BQBmc+QZrNlvcgcAuBwJ
702FgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLAOvvCyoAAAjzSURB
703VCBMggUAECbBAgAIk2ABAIRJsAAAwv4+OwAAYAL3+771Px771h+TidMZLACAMAkWAECYBAsAIOyX
7043oN1f7nS/Bi9Knz/83L1lnqGPwvAPJbr+Zes8I/HH3dovf0va37RGaxnPvQz3Z/uG2ZJqp5V8QoB
7052MPXrv+vqWFXmvgFOeVmv+UMVuN3iMiZrUo9H+t/jfMnafuGrz4A36uybr+9fn7k43FhivW/8TTV
706a5DP8ve7s1y/IsGqT9PVPeHjp9qbe/7vx/qX70yxjwFQ0P7tvfe4cPL6v0yPVnOmyqXDX59jff8l
707wl0n6P3F617R8tnG6/R7XHwEYLvVdfu5aA8cfVa/Y28MckQqMfrJsX6rLz+DVZ/fz4k7nIGVvnn0
7087hIfz7E5jwUwlcqyvLporx4XnilUV1X7qmRXAyelfvF5rC9PsOpT83mGNtvo8pTvx4/U45RdAcym
709N/VpORIty5yw/mdTot+aXd1+wyXCq1xiK8UpuwKYU/D4svpr9NPW/8qlva6rfr84u7r9hgTrVt0H
7109s69KvUv/zTR3gVAg7Ec6/WxQZUyZ67/22+f+t3Z1e3rLxE+vZ7Lfd0fSq9vbTdmVX5eO1b/a5yy
711K4D5tVwrLK3/pfenWP9L1wpfc6+3POxZ+NdnV7fb7a/Uvxr95whPMDMAgHZ7p0QTJAZtP0fLxPkr
712LhECABzpt1wiBABqJjjD9E2cwQIACJNgAQCESbAAAMIkWAAAYRIsAIAwCRYAQJgECwAgTIIFABAm
713wQIACJNgAQCESbAAAMIkWAAAYRIsAIAwCRYAQJgECwAgTIIFABAmwQIACJNgAQCESbAAAMIkWAAA
714YRIsAIAwCRYAQNjfO9V7v993qhkAYHK7JFiPx2OPagEALsElQgCAMAkWAECYBAsAIEyCBQAQJsEC
715AAiTYAEAhEmwAADC/rrd9n5mlSeOAgBXkcmLnMECAAiTYAEAhEmwAADCJFgAAGESLACAMAkWAECY
716BAsAIEyCBQAQJsECAAiTYAEAhEmwAADCJFgAAGESLACAMAkWAECYBAsAIOyv2+1xdgwAAF/FGSwA
717gDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbB
718AgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABh
719EiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUA
720ECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRY
721AABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBM
722ggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAA
723wiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQL
724ACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJ
725sAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBA
726mAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2AB
727AIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJ
728FgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAI
729k2ABAIRJsAAAwv4+OwAAgOu6r77rDBYAQJgECwAgLJlg/c///lewNiBi8h1z8vAAxtTuwVpd+P7z
73093/vFsz3eB26Lxuxn65t79T//O9/HTwyy/ncEsDxcY7ZO87ZxqEUz2xxAr/WSoL1XKGe69TGNeuX
731LHnPbr7197DuH9PQf/7+72udcngdllPm4enz/zfsfQCzeU+wGg8GlTM0zz+9HtW6jjGvNbydL1lt
732t5LQlOL8GH/vMamlgz9lluMzEOfq+73jPNBupJ7nm8uhnmq79MZZqmfv7VKJsxR81/4ysL0GzuCu
733jv9qnKV4UttrLH6AN38kWO3ZVWWBXn3de4x5OxX0XAq7zgxVFujsGaZ6DR/HqjfOSvxd45wan956
734Vv860O5HY0OxJc7I/E+N52vTW9rtHYeB7Vgat1WleFLbKz4Pgd/p3wSrfR1pTCaWf5pzqVpdptut
735LvSl0y2lQ+BAnJViY+O896bprT++XW7lMxOpvkfmf3Y+tNtpAgS7HDdzbMDV/V+CteUSRrudcqzX
736apffPkvlb3veqf16LaPxpGBvu5W/No5zZRyy8TQ6bLts19Lf1fS6/STxYGQNeveXir33r1NcPX5g
737Ev+XYG28hNHY2PFnsErN9SZAlfornapfu3kaGM+uCj/WsxyHjWebhh2zXbYbq3n4EvxAWwOC8zC1
738Hc9y9fiBGfz7HKz2ezXGTHh98D9///ey1//zv//VNQ6rNWTiGzIwzqvjcKKdtsu5Jpz/e5ttXvW6
739evzAuf540OjAatKYW+x9dPmJvN7KM7aP19fGWm8p+bFYpUBlbF9ft8efirmx/Ja+33beLlu0NDE8
740/wfmQ4uP+8tA5Y3711hzR2Y5Miog4v0xDS3XVl6PW2/HsLc//bxIZVfLtsbK99bTHtt//vnVVeVm
7416uX4lMazN/7ecR4Yn7eDaL2/9XFe3umy93a5LY6dLU1sj3PLdmmZD6U4b4Xt1dtuqf7g/tW1X1T6
7422xVnSzCN8QMs/XW7Pc6OYS77nWz7hReJgoweAFO6r77rH3t+5yg+J9sFAAAAAAAAAAAAAAAAAAAA
743AAAAAKDq/wP4EB/RpJmzCAAAAABJRU5ErkJggg==
744" id="image382" x="-1201.4072" y="264.93607" />
745 <image width="169.3797" height="127.03477" preserveAspectRatio="none" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAyAAAAJYCAIAAAAVFBUnAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAg
746AElEQVR4nO3dzbKjOLYGUPJGDurxesgjMuzH60EP7sDZJAeQkMTm12tFRYUTYyEw4O9Isvyr64YO
747AIA4/3d1BQAA3kbAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmAB
748AAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGAC
749FgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAI
750JmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwA
751gGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzA
752AgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADB
753BCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAsN+1LxiGI6oB
75479f3/eD6IZrzCmL1fUw5WrAAAIIJWAAAwaq7CIGTjO3U+Q6gwtWi6qM3qlbfO2jwhQQsuLHVD+bZ
755B/bncdWogenKhZ/9qZTw9PQQlRqffhyAaAIWfJlZFPjyZDAMYSNaM5sAvo+ABfxPVcvWuPKsEWiZ
7562MYlq+V/nl3t6KxtaUutf2g5qeOwuXBZTuo4AA+0K2D1R//lBxwtFYyWqWiWFcZnU1Eg31Q2/efq
75749qWtkz9Dy0nfxyWLWS1x6GAWzHsFz7dyd4WLPOvQKG7fAqOH/mFF+9mkCrfbsNTR2zutuW3luk+
758DDsdcX/WRQjfZ9o0deZnc8ktLNUlV/LC1B7V3jpvEoWBJxOw4FtFNU0VWnaNbaqtWCo4tpUDsIOJ
759RuFpdn78v755ZhjO+G4gQJaABU/zgujQsAubLyksM6q78AXvAnAkXYTwZWatO9NvBTZMQLoc+TRd
760Mn1qNgfBZkCprU/Dfq1+QbLt+KyOAKsqH3iXX11Xd3n/vHv4FXcoVX293O2ncrgl92HYb3odRTVP
761a8GCu6qaRgGAOxGw4CSaGTiC8wqipZqw6q41g9wBAIIJWAAAwQQsAIBgAhYAQDABCwAgmIAFABBM
762wAIACCZgAQAEE7AAAIIJWAAAwQQsAIBgAhYAQDABCwAgmIAFABBMwAIACCZgAQAEE7AAAIIJWAAA
763wd4QsPq+v7oKrHj9+9L3/Z59fP3xSYna8XccwHfsRSAHhNc4L2ClPo1qL6e3Xn5X7dfOlDAtZ38h
764D9L3/TAMwzCUr39ofaI8pZ5RGu4/qfvYyYeuX7OntMC63X+7tY6u51OOA1VOCljjp5HT6G7KIwKE
765iDrlLjl1Uxs9vzLD/8weAzfx+8Jtj2Hr82Dz7pBff3x2unya58rLH4Pg+JLVchrWn0bM5cqFx6Fk
766F0q2mylkdgzzLzn6fcmsX7u/UdutctXxybyP+fN5Wc/a83+zqqmDUFhIqpJV73vt/jbYPG8PikRt
767973lTWz1/Im6vlwXbeVnyqndr9r3l1pnBKzpG/l558a/urrF25yRWX92Mq2uWbKh2QvHUy1VTu36
768q49rj0NK7XajHP2+5G8E+W0dtN1xSVdwA7rq+NSun6pn7fmf2XQ3+dRprn+qnK7yeDbsb5WS83a5
769C/vV1r/h/hNy3rouVldurn/tfhW+JPzz4qu8YZB795yUfVU937Tdwk/f8O1OCx/vvDs3dNXxOboO
770e+ypT8i5ceYBudvBL3R0tV0X1/rmfY91UhfhEX+o2e5znXl8Zn+9nbbdParqOdT00DWsX1ufWg31
771Obr8qP19yvkW5ej9/arr4iaErT1OClhXfci9qeXmTbwveW1/bZd/PLStf5za+hxa/rJLZed2v8fd
772Wraefl3wdC/pIiTQdHTLN/yJ9hqfLsvp6NT8+zhb/3JH1+du+8s5nn5dFHLfvqEvClgP7S7s+/78
773mn+u1XOGN9bu3bd132zWM7PC6vu4/4Tc8/ITCgwsP7Buq0WtjtO/4ZnZUKXL39anXxcNmu/bd6j8
774K105TcPHcT3ls79CmrNCbTlt203tV/nfUg3bnf3FM31JQ2v8Qe9Lav2j35eo82dW2sn1XL58c/1Z
775PQOPw+r5FnveLu3Z39lrU9ut2q9M+SGi7j+19Yy97+0v/0HXRWD55ft19HlI13W/uq72c/Tv43Na
776OLj2OHuX38H7CEtvvS7eul/H6X9OTpFYq+6QXt+CRd4l10ngX2ZcyPsIS2+9Lt66X88lYN3dJdeJ
777i/MdvI+w9Nbr4q379VxfNMgdAOAcAhYAQLAHByzfeij0+gP1+h1k1c4ZDY6Yb+JWp+KtKrOpvLap
7784xy7v886eiXutkd3u16O8OCAxaPd7dJqmI4rdZe/26690ufLH+WDTk6Ylqm2Ps6fBrXH+W6Oft+f
779cvI8/X0sJGDxeLf6HsDrbxmEOOH8aSvqKZ/QS4+49C68bzzi+LzMGd8i/GTV6Zxm06fGx1XLZ+dK
780yNdT+8XEvquzYkwXptbPbGK1npnyU7tcVX6XOHTNx79web6SywkGG97H1UKqzrfY+lSpfd9r6xNy
781Xi1nIyy5Lo6rf63M+9tVXhfNmz6inOUNZ3nLqr0uCt+U1XL23Of338/33wcy9clvtLz8WrWfF9MH
782q4e05Djf7fp9tJOmaZhd+Z/HqYBSsnz6zjUEnebK7ym/dn8zj2vrGX78C+u/avVVDeWMpS3/5q7a
78339j6lIt6v6LKz5hVYLwFX1L//AfJZuVTm9hTz9X6HH3fyJfcdl0UVrLkXAq/n+ff9/33gVR9Sg5C
784Sfm1asvPnOfd2vF5yvX7aCcFrPCDuHo5HbStg4z1zFR4z75MX3vEMbnzcS5MZvsLOcjRm350+fkP
785koai7lOfo0XVMFVOc/mZ+/ms8KrjfGh9ora101X39j3HtnvI9bLfxRONpk7iqpN7KP41q9uqvZgv
786kTnOT69/yt3264j6nBm27nY8U55Szzvb874fffyf8v7eqp4v+Jw938UBK+ovoWnb4+Pe/mVT6oWV
787yUsd56cc86rz5Ibvy1OOc8pT6v+UeoYYKgd6tm3i0PVrPeX9vVs9H/05e4lXfYtwGIaGpt3py2fd
788w6zaeZwv9/T6Q7jPRXF1LXgA989yNwpYVd2Fs0GR+WLLT4XPedPQPdxwtm3u107hF0Bhgbe98PZU
7897IY7dcMqVXlK/Z9Sz536/ylcec+Gqgq8pLsw6n4eKGQ4zREVIOPKLsJZCp4O+t5cnnrcLZoua7P2
790MlrV1idTckg5teXvqc+e5YVb31NO1RdSCs+Tkvcltd3A+py/fq1n1b98BEnUdjPlVJ0/m9fdcteq
791zsNlV3jVIQq5z5Tfz1O7MH3Qdt0dcT/vjnzfl+V3aydDbfm1+xu1/iv96rra3vG/jxtaei7RVs+n
7927B1As9qA5cbIK/U/J6dIrFV35l88yP0EVbcDiRv4Kloa4CDvD1hV9ws3F+DbuEnCEW40yB0A4B0E
793LACAYLcOWFUzLAAA3MR9A9ZncPqyv1/kAgBu7r4BCwDgoU76FuHmxGtdwZdTMrO0zV47Llkt//Ps
7946kR5vq4MAOx3RsBKTWSXWT4u6X7OYLt8VcmGlv9cfdwwozEAwNIF82CVTLHfReSbzMslJwDgOGcE
795rPJfAQtXMiI+1UUIANDmpBasad/faTFr2eW3+RItWwDAfqd+i/Az7YJWIgDg3c4IWHdIVA11mL3E
796rKcAQKFTx2CN/8wvLyxtWc7sqdlcDJvxyK/KAwAhfnVdXYyYpg4TGQAATzebvCmxVl3gMZM7AEAw
797AQsAIJiABQAQTMACAAgmYAEABBOwAACCCVgAAMEELACAYAIWAEAwAQsAIJiABQAQTMACAAgmYAEA
798BBOwAACCCVgAAMEELACAYAIWAEAwAQsAIJiABQAQTMACAAh2ZcDq+/7CrQfq+/41+1Liq3YWABqc
799FLD6iXO2eJq+74dhGIZhufyS+qQ8vT6pk+eVJxUAT3dGwBojyIePw6dbpskLN3pJZQAg7/fVFfjb
800kjH9pJyGsCOWb1ZmTznjyp8H4/qfoDlb87NktfzPs1XHp6o+teVkCqmqZ2x9yusJAKe5IGAtP5tn
801j2dBJHx5SkP545Lpfq2+qmRDmWOyZ79S9aktZyxt2QZZVc/Y+gDADV3cgnXEJ2hUmZvlbAap/Rt6
802SsIoTGb7Cyn3lEMHwCtd30W439imsnOkeaaco5XUM9WVdlsNx/MR+wUAm94QsLpJY1L38+O8Niql
803yjnUsmts8yVPaZ6pOp4NxwEA7umCebCO++CM+paibzvGuuR4mr4BgAu9YSb3ws/RzdXu8HncUIc7
804VHvVnorddqcAoMQZXYSz1ouSwc6r60ctj9puYWnLcmZPzeY42MwW4fUpLyczw0JtPfP1mb02M/NF
805qj5P6UUF4JV+dV3tKKW/j32RHgB4utlkQ4m16gLPG7oIAQBuRcACAAgmYAEABBOwAACCCVgAAMEE
806LACAYAIWAEAwAQsAIJiABQAQTMACAAgmYAEABBOwAACCCVgAAMEELACAYAIWAEAwAQsAIJiABQAQ
8077PfVFYA36PurawBxhuHqGsDzacECAAgmYAEABBOwINgw/PkvZLU91di5wjnVeD1HAL6TgAXx+n57
808VFbJOlNjIPuSD+z8bn7JQTiN4wnhDHKHxxgD2TAEDKs3MP8cjjN8JwELnqfvf2SsafPD7ON8fGp1
809eWrlbhHmUuWsym90+VSm/tM6zFZe7kJ4/UvKmYXd5T+XlUzVp3a745LZVtrKWT0lgGYCFjxb5gM+
8109bjrfnzW7iknX5/pJlLl5wPKas1LVgup/55yxtoue99Wy2nY7uyFY4SqKid1PIGdjMGC16r6yMys
8113PzR2/DCfGw6rRq3Kudu9QdKaMGCx4saoXz0SOfV8pc9XNP1L8kEVcdh2mjUUOEjdtCIdbgDAQse
812L+RDenXwUKxUPcd0Mltn2eF1jqe39Dy9/vAOugiBW/jMWzELdqtjmADuT8CC58m068zGlTeXHyJT
813zuzLaxn7M9ael5e89lPDe44TF0/hKroI4TFWv9s/yx+pp1a7/6a9crOVmz+YU+Wk6pmp/6zM1V0r
814KadqmoaS+hSqmgEhartt5WRGwgFtfnVd3X3056XbD/4+gkR82ZwOoGQ1drpnw9LNua/zbaZ5pk/e
815MuouDC1YEKy8zQCAtzIGC3gzQRa4hIAFABBMwAIACGYMFgQzyB0AAQviFf4McHezr2utfr0//+PB
8165esv91SyBF5MwAK6bitIbf5QYMlsCBIV8D2MwQKClc/SDvBWAhawIjNZPACbdBECwaa/u5L6bUTd
817hcC7CVjAD5lfPNyZioQq4HsIWMAPIV9vlKWAL2cMFlDESCyAcgIWPMkwrKec2uWbWwFgD12EQNf9
818bKBKNVZl1inpE5yVqRsReDEBC+KN36HbXKdWqsza5Zsrj49nJayuk9liqhyAdxOwIFhhkhA4AF7M
819GCwAgGACFgBAMAELACCYMVgQbHUm9ObV7qNk5D4AH1qwIF7fbweRknXONPtW4/Kfd6swwJ0JWAAA
820wXQRAl338+ecC3/XOTXRaO0EpADvI2ABOWNamo3BmoWwVDgrzGoALyNgAX+Mv36znK59MydJUQBT
821AhYQzG9FAwhYwB+1Y7BStGYB+BYhAEAwAQueZBjWO+Bql6+uObY8jYOxqipWtRzg3XQRAi1mISwV
822znQXAt9JwIJ4Jb8q09a0kyqzdvnmmvl/Rm0U4K0ELAhWGC+kEIAXMwYLACCYgAUAEEzAAgAIJmBB
823sM/MCJtj2AtX4yDmlQAOZZA7xCsZwD7OmX4fq9MrZH68uWr95Z7WfstyVuxmCdfyK9fw5QQsoOu2
824gtQyK2TWT6kNHJn1G6ZCBTiTgAUEy7RaHb3d0bK5a7l8+lTJ8obyxxW0ZsG3EbCAFdNA8GkuunlE
825yHRNlrTMbT5uKD+1BPgGAhYQbOy/m3Xk1f6ETtX6DfO7Vs1E3zZ/rHQFX0vAAn5Y7R0LacQKHIO1
826arVHcpr2dmr4AWzpCr6WgAX8EDJ86vxgseyqm1VmZ8zKlJ/yiK5V4CDmwQKKPP2Le31/wS48/aAB
827zQQseJLU3KS1yze38mipgV8NL69dYXX6rqcfT6CBLkKg637mgFQmyKxTO2i98CX5cqa9fqm6NdRz
8289vJ8mSXl6yuEL/Sr6+r+tvp5K+kHf5pBYlakwpnKfe5yN+7rfJtpnumTN+W6C0MLFgRr+z4/AG9i
829DBYAQDABCwAgmIAFABDMGCwIZpA7AAIWxCucC6C709e1Mj9mPMpPZV4YKFdXjvo1G4CbELCAuVnY
830Gh+nlhdaDXDjU/fJmgD7CVjAD5kpMU+eMLOk8Wwa/sYls/aw2olGAfYTsIC/7jPheKbLMtUSNlvh
8318yCzPsBxBCzgj9rwseencjbXj5qvVZwCLiFgAY32jMEqkf89xPLSjO4CzidgAX/c6jeJl117o+nX
832GzdrmykH4DgmGgX+etC3+fr+SbUFvo2ABU8yDOuRonZ5Ria1XNW+Na3PnkQljQGn0UUIzM36ClOT
833zufnDi03ljPt9ZvmvNTjko1mXgtwnF9dV3e/+Xlr6we3K0jM0uSncngo93W+zTTP9Mmbct2FoQUL
834gkXNLwDAcxmDBQAQTMACAAgmYAEABDMGC4K9dZD7feYgBbg/AQvilQSR6XTkN1H724IApAhYQNet
835/aTMLGOJXADlBCxg2/KH/z4JbNnRmVreJVrIlrOALp8qLB/gPgQsYMWy+WrZmzmb7T3/ONNCNlth
836jFCp9VOPAe7DtwiBRqlks7o8MAZJVMD9acECTnKrEf0AhxKwgDMsu/wAXkwXIbBCAALYQ8CCJxmG
8379ehTu/xaN6wSQCxdhEDXLb4nuNqdt5ysoa381e8kltcH4P5+dV3d35I/b3n94E9RSMSRl/1UDt/D
838fZ1vM80zffKmXHdhaMGCYIWBSa4CeDFjsAAAgglYAADBBCwAgGDGYEEwg9wBELAgXklmGn/Y+CYy
839P67crU3QsFrz1fkXJEjgCwlYwIYxbE1T1/hgFsU6iQrAGCxgNJtQFIBmAhaQM2u1kr0ASugiBP4Y
84089POIOUnbgAELGBDbdgSqgAELOCv1Wy0+eVBAGaMwQIACCZgwZMMw3obUu1yAA6lixAINot0hmQB
841X0jAgnjLec9T69RKlVm7fHPN5YSiqQLNMgqwJGBBsMKEIYgAvJgxWAAAwQQsAIBgAhYAQDBjsCDY
842OHq9cJC7wVgA7yNgQbySzPRZ5z6TVE1/1DmzfPxn6gcHl3skQQJfSMACGo3JaRbCJCoAY7CAnL7/
8432yiVauWargNAJ2ABAITTRQhsGBuoCvv+UsOzAL6HgAUEE6oAdBECGz5Drwy0AignYAEABBOw4EmG
844Yb0ZqXZ51RbHLr9UI1bq24UAX8sYLOCPWXjazEypyehrywF4HwEL4pV8566tYSlVZu3y5hKmrVk7
845twjwYgIWBCtMGIIIwIsZgwUAEEzAAgAIJmABAAQzBguCpb5b17YaAE+kBQvifeY937/OmVLfapwt
846n/7zM8nW6lRb5nwHvpwWLKDFbHJRc40CTGnBAnKms7eXpKixQWv/JPIAz6UFC4j0SWAatIAvJ2AB
847G8ZGLJkJoJAuQgCAYAIWsOHT3zcdjAVAnoAFtDOSHWCVgAVPkgo0tcurtjgOvZo1YmnZAkgxyB34
848Y5aT8kPaP7kqNR+9cfHAlxOwIF5Jtmhr9UmVWbu8uYTpP2cTjWaeBfg2AhYEKwwWL8sfL9sdgJ2M
849wQIACCZgAQAEE7AAAIIZgwXBUl+sa1ttTzWMiwK4ioAF8UqSzfijyAC8jy5CAIBgWrDgGZZdfuOS
850aTPYcp3V5alNrJazuvyz9WX5s3pO/1lVDsCjCVjwMJkE0y0CTSr3lBd7dPm15QA8gi5CeK09SaV8
851GNl+EhXwPlqw4PFCRspnfj2wpPzZD0KnWr/KywF4NAELHi+2Jem4XxUUnoDvoYsQ+KHvf4w6B6CB
852gAWvMg1GVSGpcOXCbr5h2BiuLsAB76aLEJ5hOkZq2os3a22ade2VT3+QKidTfpWocgAeQcCCeKnR
8534st1qkxDz+ry5cKqHJNaOVN+VVEN5QA8lIAFwQoTg2AB8GICFhxo6NZjVN8ZggTwZga5AwAEE7AA
854AILpIoRghV/c8/PGAC8mYEG88h/ya56qKvUTNKlfTfYjygBnErDgGVKBSZACuCEBC85y++zT0EK2
8557OjMBL6qcgAeTcCCgy1z1ZCavaFC1aSgJRpayFKPq8qvLQfgEQQsONinfWaeIKrnwZr9Qs7m8m7f
8567/2VDyPbT6IC3kfAguONIWhf+8x0XPzsNwczyz82w9bOoDb77cJU61d5OQCPJmDB8cZxRrPWrCar
8572SWzvKHkLh3U9hCegO9holE42CzyTEd0VxZTtbxZ3zfXEYA/BCw42LLd5pYtOYWJqrCbbxg22tIE
858OODddBHCWXb3DK5Oc5Ba/pTyAV5JwIJ4qdHiy3WqVE3NsDpC67jym18iaQGvJGBBsMLEIFgAvJiA
859BQfq6+e7AuAFDHIHAAgmYAEABBOwINhnhoLNMeyFq10lqmK33cHT1B6Bo9cHziFgQbzPXJ371ynn
860U/bjquPQkIqqXuL9hccRsAAOVDs5RW3s9nVUuCffIoST7P4RwvWJOseFy8m3UutP5/xcXX9Wz6hy
861UjLlT9dZ7nK37ziMSwrnLVutT2a7qYX5raQqX15+akJXE73CmQQsONYyV7UlrdQHfOo3nvMBZfk4
862lWCiyqndr9r1G47D7CVt70v+tbW/6rhcv7b8TBCsOs7ATroI4Vizj8CoD7aSMV4hr40qp5AOsnM4
863bnA0LVhwuDFj7UlXhT1ZU2d+E/C0/brwODzF6v42HDdgDwELDjcOVxr/32Y66GezkGWXUJuocjKq
8649qt5/e+R/01JMQvOoYsQjjULKLWDcpY+8zu8r1Vmtl/Tx6kmmVceh6M5bnAOAQuOtWwqaGs82POJ
865GDV35RFzYGbW+eSA2Ca0kGDxoHSSD6nAcXQRwkl2dsrMWh1mpS1H2KRag0rKL3lcW07J+t3aftWu
866nzkOqwUWyu/X6gin1AwLtcuryk/tb9RxAAr96rq6v2t+XqL94M8iaJoFqnA1PkwrcCb3db7NNM/0
867yXtN3YWhBQuClX8bjjwtLsBzCVgQwF/8R3OEgWcxyB0AIJiABQAQTMACAAgmYAEABBOwAACCCVgA
868AMEELACAYAIWAEAwAQsAIJiABQAQTMACAAgmYAEABBOwAACCCVgAAMEELACAYAIWAEAwAQsAIJiA
869BQAQTMACbq3v+6urAFDt99UVAJ5qGn2GYdhZ1M4SAG5FCxZQYQxVn0g0Oq6d6aDgpWEMOJQWLKBU
870YTvTasvW57XjU9Pl0wez8pcLM+UsV8vU51OIZjPgIAIWUCQfRwqDzvLx5/+pwlfbxlJlllR7+k8Z
871CziOLkJgW0gQiYoygZHo0M5N4JtpwQI2PL2ZJx+htGMBRxCwgA1PjyBVfYgAIXQRAts2u9Ie2tEm
872XQEHEbCAIg8arpSp5/Qp6Qo4ji5CoNS0r3CWt2ZfzVsuLym5W8zIMH2QL2o2d8Pq4y79bUeAWL+6
873ru4WM70juUMBAE+Xmjnvp7rAo4sQACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBA
874MAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmAB
875AAQTsAAAgglYAADBBCwAgGACFgBAsN87X9/3fUg9AABeY1fAGoYhqh4AAK+hixAAIJiABQAQTMAC
876AAgmYAEABBOwAACCCVgAAMEELACAYL+6LmouKzOOAgBvVZeXtGABAAQTsAAAgglYAADBBCwAgGAC
877FgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEOxX1w1X
8781wEA4FW0YAEABBOwAACCCVgAAMEELACAYAIWAEAwAQsAIJiABQAQTMACAAgmYAEABBOwAACCCVgA
879AMEELACAYAIWAEAwAQsAIJiABQAQTMACAAgmYAEABBOwAACCCVgAAMEELACAYAIWAEAwAQsAIJiA
880BQAQTMACAAgmYAEABBOwAACCCVgAAMEELACAYAIWAEAwAQsAIJiABQAQTMACAAgmYAEABBOwAACC
881CVgAAMEELACAYAIWAEAwAQsAIJiABQAQTMACAAgmYAEABBOwAACCCVgAAMEELACAYAIWAEAwAQsA
882IJiABQAQTMACAAgmYAEABBOwAACCCVgAAMEELACAYAIWAEAwAQsAIJiABQAQTMACAAgmYAEABBOw
883AACCCVgAAMEELACAYAIWAEAwAQsAIJiABQAQTMACAAgmYAEABBOwAACCCVgAAMEELACAYAIWAEAw
884AQsAIJiABQAQTMACAAgmYAEABBOwAACCCVgAAMEELACAYAIWAEAwAQsAIJiABQAQTMACAAgmYAEA
885BBOwAACCCVgAAMEELACAYAIWAEAwAQsAIJiABQAQTMACAAgmYAEABBOwAACCCVgAAMEELACAYAIW
886AEAwAQsAIJiABQAQ7PfVFQAAeK5+dakWLACAYAIWAECwyID1n//+K7A0IMTNL8ybVw+gTW4M1uqN
88775/f/z6sMu8xPXQvO2KfXdu/U//5779OPjLL87mkAufXs83R9bzbcUjV5271BL7WSsAa71DjfWrn
888PetLbnnjbs7297TdP2dD//z+97OaHKaH5ZLz8PLz/xuuPoC7mQeswg+DTAvN+NT0U63qM2Zawqy9
889ZHW7mUCTqudm/Ws/k0p28LPO8vg01HN1ee1xbthuSDnjwuWhvtX7UlvPVDlHv59d7LgAAAJbSURB
890VC+ZeqYqX3W9NLxfDS24q8d/tZ6p+kS9X231B5j5EbDK01XmBr36uPYzZtYUNN4Kq1qGMjfo2Bam
891fAmbx6q2npn6Vx3nqONTW87qsw3b3dR2KPbUM+T8jzqe003v2W7tcWh4H1PHbVWqPlHvV/h5CHyn
892vwGr/D5SGCaWT93zVrV6my63eqNPNbekPgIb6plZre04H/3W1JYf/r506ZaJqH0POf9jz4dyB50A
893gbsc7s51A57uT8Da04VR7qCMNS12+ddnav3uyJHa076MwkbB2u1mni08zpnjEFufQqe9L/uV7O9q
894vC5vJG6sWYHa6yXj6OvrEk+vP3ATfwLWzi6Mwo2d34KV2lxtAMqUn9mpfN/NqOF4VhW4Wc7yOOxs
895bWp2zvuyX1vJzV3wDdtqEHgeRr2PV3l6/YE7+DsPVvlYjTY37B/85/e/l3v9n//+q+o4rJYQU78m
896Dcd59Thc6KD35Vo3PP+PdrfzqtbT6w9c68dEow13k8JscfSny6fm+a2MddvsX2vbesmam6tlVsgc
8972+nj8vpH1blw/T373h38vuxRsonm87/hfCixeb00FF54fbVt7syUI1EBIebTNJT0rUw/t2afYbOn
898Pg+i0tVyW23r15ZTXrd//vetq8xg6uXxSR3P2vrXHueG4zP7EM3vb/44L0e6HP2+dIvPzpJN7K/n
899nvel5HxI1bNLvF+1202VH3h9VV0Xmf2tqmdJZQrrD7D0q+uGq+twL8c1tn1hJ1EgRw+AW+pXl/qx
9005zmf4vfkfQEAAAAAAAAAAAAAAAAAAAAAAAAAyPp/bzD23bYiiR0AAAAASUVORK5CYII=
901" id="image394" x="-1032.0272" y="264.93607" />
902 </g>
903 <g id="g557" transform="translate(1003.0351,-73.34192)" inkscape:export-filename="/home/m/Vault/projects/mitjafelicijan.com/dfd-rice/install-04.png" inkscape:export-xdpi="75" inkscape:export-ydpi="75">
904 <image width="169.38" height="127.035" preserveAspectRatio="none" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAyAAAAJYCAIAAAAVFBUnAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAg
905AElEQVR4nO3dO5bjOLYFUOVbadTw2tQQZfbw2mjjGdGlUvIDAeAhCUp7rzKiFBRwCfBzgpSYv263
906xw0AgJz/O7sAAIBPI2ABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
907AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
908AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
909AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
910AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
911AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
912AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
913AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
914AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
915AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
916AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
917AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
918AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
919AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
920AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGG/Uw09HqmWYF/3+/1he4Vt
9217Edc3f2+b/uuYAEAhAlYAABhAha8c7//77/IYh/v6iNw9fonPmx14Dpin8GCT7b4WZP7/Y/Xf35u
922Op9NFt7yiZZJMZVdz9+y9nqq3yav4/PsZW3QJpU8/zc4yB1S8wJcjYAF53kmgONPqI/HchZce/14
923a4Hpdlt9fU3r8icaZ/yBbQQsGMxPAnieZSfh4Gl+RWd+8WNx+WCda/2+/vawerKa6m+dl+5iWutZ
924m5Tb7Mrf2luAXrsErLu/wGCL16ssr7e6Fq/ErF0GK1wBiihcfmuqv6m7YzTV3zovW4ppref1UFwY
925/7Wf35fmUM/1HPZ4kb2uYHk+CsO6wFmhZvdpui92sL27br0S1rr8JQ5flStSs7X3rq/jPJdz5PHf
926LUK4iOfJsukT6EPpq2d+96r14tCFPoPVpHU89wxbwISABdfx+rW4tyfC+S2h0/WdvNe+nvmTOL82
927EHTM79eOFZzBc7Cg11mnq8fDd80ABidgQa+DI86W7gZMY1seGPa0U9AccLjK1gourMjl1hGuxi1C
928OE/TN/knYWKy8PwTWpPv3k++ULbYb8eTBeo/GVauv7x8TZAqtN/xIffFD34tttM6LwWL41/Tb+vP
929lfUAG/y63TK72Z9HM//KOuNq3j4rHxHkSUJ8E8d5ruh1u937Mq4rWPBOx1fVAPhuAhZfx5/dsJ39
930iOtbu4SV2bZ9yB0AIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgT
931sAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwjnO/38fs96zCWl2lzlZ7r9dO
9327X/qdJzOwO7qY46HV3G/3792SE8OWPc/TX51VlURqfpb27n6uO2tYzwX39J61Lj6vIxW/9WP2pcu
933/nad+q9SZ8op61s+jz8ej8fjcXxVIzg5YD2H/pvn4HRXGflT6lzrNFjM3ut1lflt8pEr9aNv1b4t
934SezngzetnTiPr/l9dgELnkeKnx9qJuz14PK6fNPrzxcfj8ek67V2Oup/7aWynspx6Oj37cKV/T5H
9357Fa3XvPuKtdu0nhrv4Wm5st36JjH+vEvrO/bkjbOb01TW8Yzsr6Trah+o6rvN7X86w9vt4ea9ps2
936hsX6J9311d96XO2os2l7WKvztj502/eXwvJN47O2vmvz1TEvHceTXbWex8c3YsB63bxqli9scE2v
937z7t+boJNB+5C/ZODV7me1nFo7ff5rsWLumv/u6hpvZpaLtTZ2u/a+HSs76K+eWwa/8I8rtk+v6nt
938eU12feu19ptavnV7qGm/dSeteUtwP1o8rnbU2bTKZx0PU+ed1PqeuH+9/tC9faaOz6cYMWBttPfo
939b2l/7ZC6oZz+foPvPWuLj9SWKn7wedyjzZH3tSP73Xu/HmHeRzirjbCrHjlul96/asL027df3ScE
940rMf6lef534Ll11vbT2mqZ2/B9T1lvTrqT9U51Dyu+bbtOahmvSZ/be9ZTpvWeT9xPxrKAfvL3lq3
94121N8wDjPfULAur2E5duf07M2VX1/hew0/fNLoNn2O6TW99wrEN2Xpvs6HXAe1+y6Pe/U5gia1mvv
9427eHR/gGa1nnvW/7z7L2/7O0qNV99nOc+6jlYj8djfgf9Qu2P5urre/X69/Zh4/O6Lh+zUm/9TGLH
943W17DWXncPmw76WYcjvFJ4/wJAatyJrpvFx450yNsVTvVcNiqbenoG+4VHlzbkd39HJe3fwy2puam
9449dpvEO5/21LD4rhtrHnkXaDJieOwx7mp/nR5iQPF8XU2OfkWYeGLBvV3ZCdp97l86+ut7Ve+q6n9
945eXLf9ZMTi+Pft76FSibtvFZYfxdvXmdrv/Pe58tP3rvW79txq5zHXcc/2/72/TG1/O3dcePt29/2
946u3j3bct6bdke1szz0Mb9onX5wn70tvjuOrtbO+x4mDrv3Cq2w5rtKjuei5q22zV94zb4ta5ft1vq
947exn//Lz9L0iALbqPQlc5fLUGrL5mOYuJqNQ6UPc/H06xslRm5D/kQ+4Ae/+lPpQ9rnRubAcONngM
948FbCADxE51I58vJ5IlXqhVf4eJqXG4KP0CR9yBwAYioAFABA2RMDa6VsAo33L9PQvO4z2jdahitnu
9496qtz9fonPmx1TjTmSNZXdUD9Yw4Rpxv3M1ijfXhtyxdQR/CpXzLq+ArJbWkeW+d313FY/NDx/PvY
950i5XcX/6R1MXlj5Gal9GMtv1zuvLXOdf2x9vfW/va6/Nf2fAuZ4iAdYntZvDnbVzRKfO+No/jzG/h
951eN36tfw9vsa/k3HGn4mRN5sa49S/Vkn59cH3XArOD1gbn7Y3ect8+fmD2taW73iuzGLjHW/pftDi
952Tu2UFy5MWWW/a40sPlhvrf1sPfXK22dkfk/UVH/rvHQX01rP2qTcZvt7/S6c2t4Kx5mm41JH/YvL
953l9sprOz8mZZN45w63nbU3zT+b0safI/mROcHrPlfrq2xvbzDzH/u2LHf9lv5x3eknvIBd/H11yK7
954D3Br89I3notXLJrGJ1tPvcL2ucf2duThu6n+1nnZUkxrPa+bVuvxYc3e21tf4Kivv7B8oZ3F/XQy
955FM+IExnnyuJr1mut/rftb6kTns4PWHGTveuwTmt24z3qeba51njqhHeAymS2vZGd7N1161/YrcuP
956v4Xc2v+NkY1Njay1/vIhYr9i4uP82P+ff9lD6xVZru4TAtb8SvXlVP6N9aOwvk3tdCx/io75HW29
957+uqZ3/Vozcqf+hf5Htv51QcnVf+WdkYY55o/wApXQ0+p7erbHms+IWDd/vw6xhU31r6/RN/e8ov3
958e5am+T34oFmjb5wnd3hfX/+ktNTqg7fzSxtwv2tlOyFriOdgpTwej/o77h/A+sLlvG7D37wxGwc+
9593icErD12zp3utdUs9naZSCORtxxjS2EDrlRTSWsL7xQ0BxyusrWCCysywjr+TF/HZciNxR+27pUd
960nTUONf02rcKWYvhgJ98inPwFs/jtj8p76q//27f848/v+k6+iDSvs7B8TdeL/e5Uf1M7le/qrv9W
961nPfWOsv11Mxjaz1r/fbVX15+4zx2fMi9fvtsnZeCt/vXWr+tP1fWUxDZ/hcXS+3X5U7n81vQvZ/W
96211k/HR3tB48z9Sr3x5ouOo5LDOXX7Zb6aOQ/P3/zB0QA6h12tBz8sDx4eWWXLv7b3Nef9/EiM5sf
9638iF3gKsIXlG7tI8Zh0sXz36aA5YNCWCLU87HA4aAAUuCoE/4kDsAwFAELACAsK8IWDs9c2HvMj7M
9644rf5AOAjfU7AGiRFHdbRpTOKh8cA8Nk+J2AVtH6U0kcvAYAtznxMw8/jKBYffLf49d215ctPY5u/
9652Lp8az3zdVxsquaBkGv9Fkpdq2F7v4V63ra/9lhFWRaAj7QpYG1/isnkkV+PlX/hfL7M68+L73ot
966bPH5ufXLt9az9sbW9V17vVz/oki/reNQ9zw3APhAW69gbf93J5raHO2Cx1VuPm7pt/KfWHm7gIwF
967wPcY9EnuNSfj0cLWxLD3vwr/Nla8fQD4TiMGrPmtqBOL+WzCEADs4Su+RXi8YS9fAQAHODlgvb06
968dcXLV4V0NfLqrNUWqXneyNoo3e/3kUcJAGqcfItw8ev9kxcrT7fPJSufyFC//KSGjR8YL69vzeuF
969+ruL2V5PuX0fcgfgq/y63Vq/B/fPz4WLEDVnfffRvpapB+B4dc8PypyefAaLE0hXAHy2M28ROssC
970AIPJXNlyBQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA
971wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACPuKgHW/388u4Q/3+320kr7B1cf86vV3
972+9oVLztrWOL9ftv8th7/s+PzbaN9rjMD1mSmP2ni73+a/OrxeDwej7NqG9wnbQZbfNs4XH19964/
9731X5rO1eZl471WnzL3n/9po7/B9S5X+Pf4yuuYPVtzVu2sOcuJEvBRsfvvxzplCPkWqcDHq4XSxqw
974TuZ+n13AsteD43NL+sn+z1+9ff21qdcXC8uvNbLYzt5+6lz838L4zJcvj89a1/P2C/0+X3kdpfJ8
975Ldb52mBNv63rdVuZ4qb1rWm8ss7yeC5uck3tROa9o/74+m7ff1vXd9JdX/1N+8vbIrdvD4V29uu3
976ppfW+b1tGP8OweNPffuvv9qyPd8a94sDxvN7jBiwyge4pp9vL0extS4mQWSxkdR6vf7Q3X5hfGre
9778nb5clBbXGyyQN+QLvZS7rd1yt7Oe+X6vm28ps615dfGobWdws+71h9c39ue+29qfju228JuMpfa
978Hmr62qPft710zG/NevXVMxfcv15/WHtjzfmrqc5JkW/b2Xs8v8r5AWueNt4ea+pfb20n+5bFFk7Z
979Lrf0eNZ792h/7RQe6atju211wHa+X7/BjWGP7eqssd1i73Fu6vfg9rfsjylNXawd/4/ckOrjGhHn
980B6xF9UGbVlcct723h8X2H3V3cN62c4Cz9pfWfoc6uLfO74dtD5fr98TxP+X4c2I7pJwcsF4vY85f
981fP7vMcU8QjfUidt1Ogrb2+vG2XHLKVzourM216Z+9x6fjv23aX67lz/YB2+HZ+2PZx1/WjltjeYr
982vkXY5PF4LG6m9/v94L8PXk8Y/jQ50c8mYQouYW3/ffuW13BW3u9sD+cy/lzFyQHreShcOyYevxfd
983/3Zwv4t+jiMdH9sK1r+lqbfv7Wh816mZXEmNtHOwPbquabOp3/3Gp37/LSyzuN9trPmUTeKTtsNB
9849sfDjj97NDXIee17jPgZrLW/JjusfXFjbeHytzl26rds/t7JmLyG1Mi41bS/WFi5qco655+06Oi3
985yVo9rf22jn+5/fpPnKTGp9DO23lsrbNm3m/R/bdcz7zx+v1urf7sdtu3PVSOc7zfyvab5nfL+E/e
986u9bv4utnHX9SdfadF44/Dn+kX7db6+X0f35eO4R1XHEZQesB+mCj1fPW5Qpm0VXmcaf99yqrD9S4
987Nz634k9th4IRr2CdZcCEPlo9MKzg/mu/A7YTsP4w2sF0tHqaXLp4ni40j6lSL7TKwLB8ixAAIEzA
988AgAIGyhgfcw3SPd4NkG2gM/wJas597Ur/mEGmcezyhhk9Z8clo/xVeMwUMCqlJqe0drZ29rDgSof
989GtTX44CtXWi+zi5hE6erPvvtj8cI7qdXeeLUfu4vFl9cfKbD5H/XlucA1wtYH2Dvj9Autr/Wqc/z
990Xk7flDm2jqZpP/02HzMO3fvdz9MEnibfbF18fU3r8qSc/28R/vww2Z0WvyZdeCrd2teqW9vpK36x
991nfKq1axvod/52ydrt8fhaf60usWnidQ8Gq11fV9/qBnn1LyvtTN5dl98+bfrO3/gU7n9yu2hUP+k
992u776y8tXPtMy1f4B87i2/GLxhfVter7X2vI19dSs19rrHcfntX4Lq7bWTr3g8eTtfjEvsnWXPEXr
993vBe2q7dddJ8XLuHMgLV2pF7bcF8PE2vt3GYHlPp2WhXamaza6wLzvyFaD6DlJXf9G2Wyys9dq1x/
994eYG369s6zql5Lx9A6/vN1rk4v2/br1nr1Im8dT+dv6XcdbD9Xeex8PNt5/10TU1tb9crOO9Nm2j3
995cXIidTypqbNy3evLPkDrvBd+rumie5wvYZTnYB1wuDlytrb0dbmtqumweEDXBwxgaxd717nHKkfW
996cXB7z+NoY7JWz651fsD4jNZ+65WeLVeGJn+llJdpbfPjjRKwJlrD1vF/CwY96u6MjGxt/NfS1d7z
997ddb2UNPv5K+0Pctp07oddmy3nzTvrfN43b17u9S8DLW/HGZ+N631YnzqytAn7b/HGDRgfVsifu4w
998twuuy/zS7vPnx+wG4vP1U+rZW9N67V3no/2DEa3bYd/y+zll3zlxe7uE4Phc4tjYsd+9bfC2NG5r
999R9edHLCdX2J+m/gW4UAej8cpn8zY1eet0bX8bFQdb3k9STx/XpzKj9xux/F2/BlQx37H5xklYBUO
1000HKnbhZXt3O/3g49in3TQXDsBB+d3ez3HNNvU9X6DcP/blhp+ZjD7J+wItxviNey0UovjH6znsEPQ
1001pKMt/c6bOvFAOu+6fr/ra//HAX/YLLZ/wL7/GafFM28Rrv2VPNloJseU+Sc/1pZvbWfxXfVr0fRh
1002w9e3lOss9zjperH9jtebFOZuskzf+k5arh+fxXr62pksv3gXoHse6+tsmq95Hiov/3Z/aV2+cj/t
1003E2n/gHlc1LE/1g9XRz1N47Bl3ufvnfd76zpO7nfcrhmHyVXGpv2upt+atSuMT/f2fKubx1aR/e4S
1004ft1urbcP/vl5bdPp3qQGcfX62dVVNo/Ugb7c7HVddEUuWvYBBhmZnfY7Ul5npD0mtk3loB9yP5H9
1005gc8Q/Ivw8/6yvBbj/9Y4x+2PvBJDHwFryv5A2YW2kFSpF1rlehdaqQuVepahhmioYjjRKB9yBwD4
1006GAIWAECYgHUBa1/3PfeLrJ/xNdoOp6/46QUA8Nb3BqxCahnqBPbz4c3r3tRvHc9THutyolQ9o60X
1007wJf73oC1FlkuFGXePgbpsEoKLjSeV2FIAcZ35rcI508tW3w6xeuLiw8oKzx3JPJ12Y7nmjQ98G1t
1008vWq6mCy89tS+xf8t9Pu2/o3n+LVxeP0hPm6t7Ve21jRut7r1fdvv26cyAnCukx/T8Hqmv72cMguB
1009aS1XzZ31wLdyoFlcbPHn8olz/izdpsEp9/u2/i2Xx9baX+y9sHzh50Ud7desQtO41axv2Xze+9oB
1010YFcj3iIsnCdaT0WJcraqKWNxmedHr/b7DFZ3s1vqCa7LWVM8yKYFwLAGfdCoT/4eb+2W1h5a269Z
1011XugBYBwjBqz5LZVz27mKjg9yFZpKVLSsY16EJwCuZcRbhKN5/PkvpZ9bzFuXfqYDAHyG0QNW6l7S
1012xmD0k7H6Pkd8cCa7/y1VzNrTwporq248/pa4EWqo1PocMgAiRrxFOLnV9fb0sLZ8oZ21L+gVvrhX
1013H60eK/+a+trrHRbrLHxbrXs81+qvaWetznI7j9kzO4Ljlmp/8W5s37zP6ykob58e0wAwjl+3W9vh
1014+PXovXZF57O/MT7s2p31WAoAuIRtzxtqO6WOeAVrQMErKPvJXukBALoJWFWuElauUicAfLbRP+QO
1015AHA5AhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY
1016AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgJV3v9/PLmGTq9c/8WGrc6IxR7K+qjHrBz7V73O7
1017nxzyHo/Hlqaa3v7T9fwta6+n+m3yOj7PXtYGbVLJ83+Dg9whNS+j2XXeGdPi/giw6OSA9UwAxx+t
1018Ho/H4l+0a68fby0w3f48uNeMXuvyJxpn/JkYebOpsbH+wv4IMHdywFr0c+R6nmUnB7Xnz/MrOvOL
1019H7v+xVno9/W3h9WT1VR/67x0F9Naz9qk3GZX/tbeUihm4/ZWOGEX6pwv31H/4vLldgor+3xXTf1r
1020/a4Ny9oqzIvsqL9p/AGabA1Y9Yf11mbnx9+1A+LaZbC9/+IsXH5rqr+pu2M01d86L1uKaa3n9UxZ
1021PqGune/n9t7e+gJHff2F5QvtLF5ZnAzFM+JExrmy+Jr1Wqv/bfuv/ytpAU02Baz9jjg1LTfdFzvY
10223l23/oXduvwlziWVK1JzWr3E+ha01r+2fGQcCo3Ex3kyv4fNo/uDwFsj3iJcM78T8dZon+bpq2d+
1023mbD14tCuV/JO1DqewtYx7YwwzjV/gBWuhhbe+El7ELCfKwWs20uwuFUcQJsOmsfoOy6/rvXk9W8+
10241nfM79eO1ZEG3O9a2U6A7S75HKzH41H/iQoY0+s2/M0b8+XGQfwCalwpYG05+A544G4qaW3hnYLm
1025gMNVtlZwYUVGWMef6eu4DLmx+MPWvbKjs8ahpt95FyNsOcD4RnnQaM1dv/IHWuef0Hr8+Z3tyRfK
1026Fvttqmet3776y8vXBKlC+x0fcl/84NdiO63zUrA4/jX9tv5cWU9BeXurb3++WOv6dlic34Lu/bS+
1027zvrp6Gg/eJwBqPTrdmv9/tH7Zb75g0HQ57C9ZvDdc/DygEsrPOelQtuh6WIfcodP4krJD+MAfJ7m
1028gLUW+BwVodUpYWLABDNgSQAbXelD7gAAlyBgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYA
1029QJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGG/zy4AAC7lfj+n38fjnH6/TmacXcEC
1030AAgTsAAAwgQsAICwL/0M1v3lDvqj9672/c/b8Fva6X4vAAN5PKaf0Jq/ckGT85TTVo0vuoL1zEM/
1031W8bTfcOmn2pnUbxBAHYRTxtjxJfX01DTKcn56/Y9V7Aq43bkylahnbftv9b5E9r8lQAwtNdrVPf7
1032H/87+fnpNX8svj5p5wxbzpvOX7cvCVjlaX7+KnUJdK2dt+3PX7GNAgytMgZNFnv+79rrt5MzVuX5
1033qHBec/76/FuEu07w/cXrVlXz3rfp6rmYa60AI1oMQD/BaO23ZZPln00dK3Xe/PLz14dfwSpvJc+J
1034796S1pJ76yb19hrbl/8dADCcQn5avPi0eAx/RqimpvZUON10nIy++fz14QGrPLXPO3fZTueXTN++
1035pVzn126dAONqjT6FCHW7rcasw+8SZiPRN5+/Pv8W4VUuUa7V+c1bJ8DQgrfw7veF1k76DFbhvNl0
1036Sv3y89fnB6xbcYPYO3sV2p//al7nl2+dAKPry1jPtxTee+q3CLdfm3D++vBbhE+v1zxft5u1n291
1037H8wqfD21r/3XOm2dABdQc69wksMmXxWcv372Mxpu6/cKa85rzl+32+1X6l+N/nMLMbIAfKizoo8T
103862Z1X0fLjPNX3CIEADjSt9wiBIAMV5Ko4AoWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEA
1039hAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEA
1040hAlYAABhAhYAQJiABQAQ9nundu/3+04tAwAMbpeA9Xg89mgWAOAS3CIEAAgTsAAAwgQsAIAwAQsA
1041IEzAAgAIE7AAAMIELACAsF+3297PrPLEUQDgKjK5yBUsAIAwAQsAIEzAAgAIE7AAAMIELACAMAEL
1042ACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAI+3W7Pc6uAQDgo7iC
1043BQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiA
1044BQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiA
1045BQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiA
1046BQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiA
1047BQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiA
1048BQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhGh1u2IAAAR7SURB
1049VAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEA
1050hAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEA
1051hAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEA
1052hAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEA
1053hAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEA
1054hAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEA
1055hAlYAABhv88uAADguu6Lr7qCBQAQJmABAIQlA9Z//vuvYGtAxOA75uDlAfQpfQZr8cD31+9/71bM
105653gdug8bsZ9V275S//nvvw4emfn2XFPA8XX22bvO0cZhrZ7R6gS+1kLAeh6hnsepjcesLznkPVdz
1057sr6Hrf4xHf31+9/XuuTwOiynbIenb//fsPcBjGYasCpPBoUrNM9fvZ7Vms4xry1Mrpcs9lsINGt1
1058vq2/9ZxUs4I/y8zHp6POxddbx7mj30g7zxfnQz3UvLTWudbO3vNSqHOt+Kb9pWO+Oq7gLo7/Yp1r
10599aTmq69+gIk/AlZ9uiocoBd/bj3HTC4FPQ+FTVeGCgfo7BWmcgtvx6q1zkL9TeOcGp/WdhZ/29Hv
1060W31DsaXOyPafGs/Xrrf02zoOHfO4Nm6L1upJzVd8OwS+0z8Bq/44Uhkm5r8a81C1eJiut3igX7vc
1061snYK7KizsFjfOO89Na3tx+fltn5lIrXuke0/uz3U22kDCK5y3Mi1AVf3v4C15RZGvZ0y1muz878+
106215a/7flJ7dd7GZUXBVv7Lfy2cpwL45Ctp9Jh87Jdzfouxuv6i8SdlVVo3V8K9t6/TnH1+oFB/C9g
1063bbyFUdnZ8Vew1rprDUCF9gsrVb5389Qxnk0Nvm1nPg4brzZ1O2ZetutrufsWfEdfHYLbYWoez3L1
1064+oER/PMcrPrPavQZ8P7gX7//PV/r//z3X03jsNhCpr4uHeO8OA4n2mlezjXg9r+30barVlevHzjX
1065Hw8a7TiaVGaLvc8uP5WXe3nW9vb+Wl/vNUu+XaywQGFsX3+urz9Vc+XyW9b9tvO8bFHTRff237E9
10661Hi7v3Q0Xrl/9XV3ZMqRqICI6WMaau6tvJ63Juewya9+fkilq3lffcu3tlNf219/f+uq8GHq+fis
1067jWdr/a3j3DE+k5NoeX3L4zz/pMve83KbnTtruthe55Z5qdke1uq8rcxXa79r7Qf3r6b9orC+TXXW
1068FFNZP8Dcr9vtcXYNY9nvYtsX3iQKMnoADOm++Kp/7HnKWXxM5gUAAAAAAAAAAAAAAAAAAAAAAAAA
1069oOj/AZvLm3jv9XPLAAAAAElFTkSuQmCC
1070" id="image539" x="-1160.9553" y="563.78479" />
1071 <image width="169.38" height="127.035" preserveAspectRatio="none" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAyAAAAJYCAIAAAAVFBUnAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAg
1072AElEQVR4nO3dzbajOJoFUEevGOTj1dCP6GE9Xg1q0IOb5SQAyRIcfr336tXrlgNLH0KGY8Dkr8fj
10739QAAIOf/ji4AAOBuBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAEL
1074ACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAEL
1075ACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAEL
1076ACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAEL
1077ACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAEL
1078ACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAEL
1079ACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAEL
1080ACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAEL
1081ACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAEL
1082ACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAEL
1083ACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAEL
1084ACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAEL
1085ACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAEL
1086ACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAEL
1087ACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIOx37xtery3KgP08n8+XeQzr
1088+BxxV89nph1nsAAAwgQsAIAwAQs+eT7//r/IYrd39RG4ev0jN1sduI7ue7DgG83ea/J8/vH6z99d
1089x7PRwmvuaBkV09j19C2l11P9dhmOz7uX0qCNKnn/z+AgL5DaLsDVCFhwnHcC2P+A+nrNZ8HS6/sr
1090BabHo/h6Se/yBzrP+APrCFhwMj8J4H2UHYWDt+kZnenJj9nlg3WW+h3+6271ZHXV37tdFhfTW09p
1091ozwmZ/5KbwGWWhWwnr5pwRaGZ1mGl7pmz8SUToNVzgBFVE6/ddXf1d0+uurv3S5riumtZ7iLrox/
10926e/PpTkEcB/xx46sPYPlOShczgWOCi0fq67rYjvbuuveM2G9y19it9a4Ii2zfen62v9zG1scF1wi
1093hIt4Hyy77kA/lWX1TK9e9Z4cutA9WF16x3PLsAWMCFhwHcOfxX08EE4vCR1u2cG79PPMn8T5tYFg
1094wfb92rGCI3gOFix11OHq9fJbM4CTE7BgqZ0jzpruTpjG1jww7G2joHnC4aorFVxZkcutI1yNS4Rw
1095nK5f8o/CxGjh6R1ao9/ej35QNtvvgicLtN8ZVq+/vnxLkKq0v+Am99kbv2bb6d0uFbPj39Jv79+N
10969QAr/Ho8+j5mf+61/NfUuZ7uedv4iCBPEuKb2P9zJ8P5nDq96wwWfLLgp2oAfDcBi6/jazes53PE
1097fZVOYfXNeTe5AwCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIW
1098AECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAlbR8/k8uoRj3H7F77GC91iLx3Er
1099cpt+rzITdq7zKsNScvX6R262Oo32CFjTkb3TWO+/Ltker7Itns/nqUrtLaZU/9nWq+QSRT5ydV5l
1100u6RcfT5v2ulzYPbF0euzhZWW30dq+9LFGSyu4fV6nbCp9Z0eUgwfXWi7XGU+L6vz8MP88/l8DQzr
1101Kb1e0rv8gS40/8/s9w59/Eym9wYb/T1cbLrA9H9O/Szwbmr03mn7La+3TK/hV5PG9uvtvNeiPj6j
1102967vd1r/ozAUve13bZfphq5v+t55Mux6+sauOitNTZdfIDI/S+1Uxi2yvpX53FLq4s/vsu2y7CPf
1103uHxLU4v3e8N2Tj6fF9e5cj9caiq4Xlvb9HOxuJjeekob5TGZ/727uJPbI2CVLNuhfGzq/Xep/ZbX
1104G7+OzJa9YL1GTb2nWr2d+gIf+y3V/+gcz4pl7ayZCR/NfnfsqjO43Wel5ueyLyrT/7lgfWfnc2PX
1105iz+/C+os/f2xyJblG5taOdvPP5/X1Llg59nVfmMX0+72sennYk0xvfUMN33q83gJOwWsd1zYaNTi
1106bc7uDnbWtbvfs+v929laS52NO/p9LJifveXtvDqHNH7U/Ny636vM5zOMwxq9Z8J6l7/E/rNxRdrP
1107WdzJfmewtktXFaWNenh4alSpf3Ykt16vVPuXGP9XzxWuH6can976D1zfrZ1quxzlxtu317L1ek6u
1108XvWeHAqeETyV3vH8nrB15CXCHZQ20iU23vRU6vvvUlq9yjfCS4z/Y7ADfTTUXNley/pdr6v+xcuf
11093Am3y1GOms9dXtvfiLOs2eHojV6/U1rqtWCefM9Y+RXhVZ3hIuaxhiOw6VC8Xq9Lj/ao/o/jdvX1
1110vSjzeeinyKOrgFXOHrCCe4Guy4Vn2/uUDoSVOr/hcuHPCGz09XFNYVvP25b2K8vMjtvKmk8yXF0d
1111BWv+Gc9l7337hvnc3mPXkK7paP3CGwXWsx2GPlpwT87l1rHLkZcIR5NyeGF79tv2Fu2v73d6Z0Op
1112/TX1l+oZnp1e1m/7nRlbrNdjbtymJY2+2Q+77iqj0k57ndNqp8uP3lvqd/b11Pz8WH9wfWcbbDd7
1113Vaj389tS5/S9s1ejurbLbMsL1nf2f9ZdYj731jnN/S1jst1+LPi56/28bPq5qIjsl1r+bqznun49
1114Hr2/Lfrn742+acECZuMyxi0lO5Jfu12WBSxY6Vl4rsSf+qbizW9y596+55tQlnGLi+QA2+XxZWc4
1115uDcBiwuz813GuMVFhtR2+WEcuIez3+QOAHA5AhYAQNidA9ZRv//cud/13Z3kh7InKYMf8c3xscFU
1116j2ebSGerh3M65zxZ//CRb+YerFapH7O0/1b2rkrPm9i/kjXOth3P9mOrs9XT62z199ZTmp9d83b2
1117ZvPR53f4+uyv/0rLf+z6VOMPCwhYe+t6Xs4+dt6RlfbI13LC7Xh1qclwtkl1SD2l+dk+byuPS+h9
1118jILHLrS4+rBcvf4t7BSwSt+EKg/ca2+n8S0tD3yrf2Obfvmr1LPpepUar4zzcJnpKrS0s6DOBbq2
1119V6mF0vr2jk9kfadHlNkv943ba7b94R9rtlfXvFpQz8cu1vSbaic4nqVGSvu94P7nulLrm9oP9B6n
1120SsvX26ms7PQZoV3H0wXPFStNzt76N92vXsIeAas+0O3nM5ZNlGn79Q/S9PXZfz1wvUozdcH4POa+
11210faOT1DX9lrTeEs78fX9mHSXtb9gfn4sb828KtUz7WK4QPs8rFvfTmo8S/U8Oud5tp7FdjsQbr2+
1122qePIguW75v9jMhTviBM57jQW37Jepfo/tr+mzks4+BJh18gu2AxH7XH23Bk1Tus1XWza/mn72rqY
1123M+9WNppXa1Y5NVxnGPbGZLa+kY30noG4+hmL3ppLy0fWfc/jzstDX9e52D1YW4eJXql6Nm1n+KVn
11245deFo8Y/0u+r57/GFez3wPYvbcH22rSdrZ1wfo56eRfWuzO50xmLMwT9lu1++PfDynHne/Z7VwpY
1125Z9tIwXrO8KE9Q/tb9/v+tLe0ufV8O9t8PqGu7bVDO1s71fycrWr0+tXT0hXdYL/xPXPmzs/Bglmv
112612uHS6uLDWs7bZF7Sm2vk2/3t6vUeXI+Rz+Mw4GuGrDa76fbupLZjtb02/XeysKja+fP53PZ181S
1127F9NV3vmCRe/CLW9sXNm4UftrttcW9Vy6hjOsS4vddhrB9k8eBBd/jlau1FHHnZKjxqGl3zPPn/X2
1128uESYulHu9edvRBuvQ8/eQDBbT73O6R0SlXpm+30MJtOwqd7xKfW7YJy76jnqhsetx6dl+dF7Z8ft
1129Yz2jKVSfzwvuq63Mz5YGg/Nqtp6KyOci2M5s/al6PvY4237X/qfU7+J6Wva3lfqPGv/ZxXr3AwuU
11309v8lm26X9jIWtx+c5zfz6/Ho3Y//8/eB37DhS/iUwXq7fY5O/oE9eXkHepafTzHQN3RXuskdvsT3
1131fMOD7fgc/TAORxGw4HTsBGG9Qz5HJ/zwnrCkL3HVm9wBAE5LwAIACNs7YN37N5kjvSu70eB81ZhP
11329T6p4XucczTaqzpn/dRNt1rl2Siz/1R6/ZxONZ8vNG73sOs9WM/qf+XxOXis/uiN9den/7TnJefe
1133H2Vc/ccsl/4Ryivx7OlpC5cek5Wuvu4LPr+PuT1M+zMpHn/urz7uxBr3k+1dX2J7leo8qv6rjFvF
1134DVbhck56k3tpHtRfP9sEWvAoo40qgamrz7ejbmGePQ3Q/kSiyvfMyvfPUjFdy5/TRcuOMw73s1/A
1135Os/n/6eS2QfBlb5Zzi5ff7ra9MXe5Xvrma7jbFMtDwCsf8Nu/LLeO84L6vnYfukxg2um4qiF0tNT
1136Pp6BKJk+5S/b/rCp6Ru7PheVpqbLt7zevl0Oqf/Sguu7ePmVZ/666tlnP1+vp3F+zjZe+VwvmJ+z
1137u4XFxxcanfQM1tZmD5D1CT39u37abPqNtnf53npKb+xd39LrC04TRvrtHYfSnmhry4LOrNGKvHd5
1138wTMWs2dcurZXaT6s2b7t22v/+jey2wEstb5rlp9ustn93vCPj0Fnzf6hZfne/V5lfSv77dn5/LH9
1139rsLa26kfX2h30oDV+w24VynidC1/oN56jqo/vo16l2nfbXV5x5099z47dBQZ85WNr9leqTmzuICV
1140tj6TFBGP9bPtTz9ZC77gHb6ffF3zPwtzlTrP76QBq7SBt97wLTv3k0++037hKAXlLdrfwc7p6see
1141J+TeXpMrlR+V6rx6/VnTqzC9GWLPM21Dh2zHit799hnqb/xyWDrrtm1xf5axW1/3c9KAdYgDJ/G3
11428aFd4PCdbHtMmV3mKvXvVuewqtHrp/2a9DjlfvLwM1U7u3r938ODRm/lzPtlNjK8DLHp0e71em10
1143yXUfV68fuJb9Atapdm0fKzlPqe0q6erMq7Pp5aT6fdCj13cYpVQXo3Z+PlwbxeuVNc++fc9riGva
11443HpKlNo/1d6yorfIE37ENi1pZeMtn+vGLq4yo27myEuElRsAp8ePelOlH5i0dD28AWL4Yu/Ena1/
1145+k/tywdvkPy4vi2vV+pfXMz6eurt77lbaal/TT31dro2R9fnpXc+9I7DgvHZrf7Re0v9Lq6nZX0b
114695Ptt201bq8t6m8czy5r6m/vtH2/d+x8bhc8vlDy6/HovXr9z98LvjGf4RrWGWrgEN+w6b9hHYEF
11477Bwqnn8+nKKwVN/o7X0Gy9blQHedfr6JAh/ZOezsG39FaJJxM6Y0wNn4FSEAQJiABQAQdquAtf8P
1148dP3wdQcnH+TZJ0EcUgkA53G9gHWqx5yc8OEiZ6tna/s8vwoAulwvYFV8238wgccpN+IJSwJgZ3v8
1149ivDn8RLTB10+Cj8vLy1ffxpb19M+6y821vP+n+sfLrKg30ojlaFobKd3e71fKT2Acbpeo+4+1tk+
1150DvV2Kgs31l8vpn1eAXBjOz2mYXQQfRX+C+Gzx+D337Pveis927p9+d56UlL9lta30n5LSS3ba7TA
1151O6J19ZsahwXr21V//Xl0XfMKgLva6RJhKeJ0LX+go+r5qn4vNB/eWgo7bfEAbOfgB4223J7s+PTj
1152DGErcjv58OTQ9OzO+vZv3A4AV3FkwNro4Mp2Ng15wfmQqjPSjnkO8IVu9StCAIAz2ClgffzWft2v
11539aV7lm//fKaVZ5h+xqd0imh6n/jivja9zLf+qWy3nycA32mnS4SzP/sfvdh4mJn+lv5RfUJB+/Kj
1154GlZeHlqwRtl+Z8d5Tfu97axZfvre+mMjttiOpXYqdX6sp31WAHBpvx6P3odz/vN34w/Ob/y79Pqq
11553XjFAeA26s/f+Z++A7p7sFaRrgCAqT0C1nfmjO9cawDg4QwWAECcgAUAECZgAQCECVgAAGECFgBA
1156mIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBA
1157mIAFABB2yYD1fD63bn+LLrYue2fbrc7NBurtrusFwNQeAes5sEN3Kz2fz9fr9Xq9ji7kg97BvMr4
1158p6TGp3fcvmqQASjZ6QzW638ih5/zp58TutCgHVJqqdNgMRfaBACs9Hvn/n4y1vtIM8xbwxeHh6Lp
1159/3xMjlWz7VRe71Wp8/1Pje3PLt9V//vF2aHo0jtupZWNj890ArSPW2V8tp4PpX7rL07bqYzb+o0O
1160wA72DlhD9SBVMj0NVmqnt/3SAbLSTunvShfT5Xvrn/3XBXr7LSXj4Pg85rZvqZ3e8Vk236aWbZf2
1161eVv5G4CrODJgbWTx0WhBcOnt6xJHysUxaFlTLRpLOk8x23VxiSkEwMEBa/YgPbyMuPLr+553HN/p
1162yLfgDvGPy8TH5x3y2ltOzQd3sgNQd3DA2jqU3Cn07Gb2pre6o8b5ncJbaliwXpu2A8CNXfI5WDAU
1163/IHq+X3b4zYALmrvgFW55Df6RdXPgWTBqZHS4ecMh6Uz1NBlwWDuto5rOnKtEIBN7XSJcPY356Oz
1164Di1ZavaHfqV2FrQ/K9XOqKmPddb77boDafG49f7dWE9XnSW941OpufID0unrlXZm+21p5+PK9i4G
1165wLF+PR69v4P7528/IAcArq70HKI/9QUe92ABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBA
1166mIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBA
1167mIAFABAmYHETz+fz8BYA4MfvowvgMqb54/V6tbyrZTE28rPVppug9DoAEQIWHe59PL7l2r1er9kz
1168c6XXAYgQsFjr5xzV+2j9jinvV6YnS4aH9uHys+3Uu55duNL+qOzRW1raqbz+schRL13jUKm/q55K
1169nZXxAaCLgEXA6GD/8/fP/58ep+tBoZQnPnba0n7F9IxOqZ0F7Y/e+I5Q8XForAeArQlYdCidKUkd
11700Re3s8MFr3hqqTTY1Zc4BXBCAhYdUsfyljC0pq/KXUel82rr279BOwCkCFgcYOuTLpdof/YmsAPb
1171ASDIc7CAx+PPy6xSGsBKAhYHixzLK42M7ht7Pp/Lrg+Wuti6/j2LWTM+AAy5REiH0fG769d574VH
1172N6RHbmwv/d3Y/uwTJUrtbF1/7/KVdkpPyqg8QUO0Aoj49Xj07U+Hu1/fdOGufLqB71F67s+f+naJ
1173zmABf4ucmQPgIWDRyl3PX2D0QNijyoBWvgZwYm5yBwAIE7AAAMIELNKOOmm/ab+uRLCSKbSeMeRS
11743IPFUq/XtrfpbN1+u65K1pc9beHnldHRZbjMnz/unW/nY2H15X+6KHU66re9yAVNrVyvR8N4NrY8
1175LbLUVOUtswvPDn5j4x/1zueVnbaMz7CkyvI/W+0kuwX4RMCC65gNFr2BY4FSX6V+S2Go/vrHhLc4
1176A5V8DJS9jbS88eN6jVrIbt+uk0Cl7d7rYwLuWh4uQsBikdLRqHKo6DoD0fgNvqvfZUrlTdt/v1g/
11772bPbwWP4df+o7/2lUw6RUxHbrdTsKa5H/3Yszc8FXdfbb6+nfb1Gibl0kmnlPO9a32klcGICFv0q
1178CWm4o1z8zbvxTEa830al9ktRpree6cHs2MNJ5UC7p/qo1t/YO56Nl+0+Xur6mEjqXdSXXzDPF69X
1179y/IL6jl8bsOWBCyiur6MLu6i3u/Wu+ze9oP19J4heA9Le7TdtJ4uleJTB+bdzixOPxfT6dqSbIbL
1180HxVNFvTbcib74/JwNQIWnRbcITtSv3Q1faU3JZT6DVoTRCovdp2B2OLbf+lyT2l9t77++G7/sc2B
1181dsEZl3jXjaP38VJ15cX4epWWL33eR8t8PIPbtTyclYDFllJ7xq4DbeX+rYje9hvvVxt6Z9CVR5fU
1182PVj19d36uuF0FXp7TI1n17WzBUpXuj9ejny0zauSrrdU5n9v15Ur+3B9AhY9tt4J1tvf+nwJp/Jx
1183Mlx0JpTKLp1Ou+hqfrT16Vg4mgeN0mzlNZTRN93Xq/Wu2JZTUF3XLLrU7ypLXVsp9Rs5ffX4tBbr
1184ldqvbNP1B9SulYoHsq7xPNs165amhsO74LM5fO+yAkr/KopxEc5gsdroBvPZvx8rLheW2mnpd4tg
1185UW9/esdYsJ6P4/BYMc5BpctVH18fDl3Leq2MTaX2F9czra3+d0s7j0nmmNbTOK9612v29sfe9Voz
1186bi3Lw1n9ejz6dvd/zvzna+tvZpzEl+/m7vS9ueVO5Cu663rxNv0YOgARMswzz+J+o2++OYMFDe50
1187nL7Tugzddb14s4m5FAGLNr4pAkAzN7kDAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAF
1188ABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBA2O+j
1189C9jW8/l8//16vdY3srKdxe8FAC7khgHrnWNGgWZNvkm1M0vwAoCbuVvAagwrkTNblXY+tj+s8/V6
1190yVgAcCe3Clj1mPL+p9SZrVI7H9ufviJjAcCd3CdgbRpQZs9INXb3MV29F5OxAOAebhKw6tHkHY/i
119192CN7n//6OM5NhkLAG7gJo9p+IkmlX/dIrX8hKG3lrfU65SuAOAebhKwHp+yy3mU6pSuAOA27hOw
1192HtWMtXX2qp+XGr0yrVO6AoA7uck9WG/D25iGOab096PtxqzSTe6L2x/WKV0BwM38ejz6Du3DJCAZ
1193AABX1/bztb7Ac6tLhAAAZyBgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmAB
1194AIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmAB
1195AIQJWAAAYQIWAEDY75Xvfz6fkToAAG5jVcB6vV6pOgAAbsMlQgCAMAELACBMwAIACBOwAADCBCwA
1196gDABCwAgTMACAAj79XiknmXliaMAwF315SVnsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAEL
1197ACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIOzX4/E6ugYAgFtxBgsAIEzA
1198AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA
1199AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA
1200AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA
1201AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA
1202AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA
1203AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA
1204AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA
1205AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA
1206AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA
1207AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA
1208AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA
1209AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwn4fXQAAwHU9Z191
1210BgsAIEzAAgAISwas//z3X8HWgIiTfzBPXh7AMrV7sGZ3fH/9/vdmxdzHcOhuNmI/q7Z+pf7z33/t
1211PDLT+dxSwP51LrN1nWcbh1I9Z6sT+FozAeu9h3rvp1bus75kl/dezdH67rb6+3T01+9/X+uUw3BY
1212DpmHh8//b/j0AZzNOGA1HgwqZ2je/zQ8qnUdY4YtjM6XzPZbCTSlOj/W33tMalnBn2Wm47OgztnX
1213e8d5Qb+Rdt4vTof6VNult85SO1tvl0qdpeK7Pi8LtteCM7iz4z9bZ6me1PZaVj/AyB8Bqz1dVXbQ
1214s3/3HmNGp4Leu8KuM0OVHXT2DFO9hY9j1Vtnpf6ucU6NT287s/+6oN+Plg3Fmjoj8z81nsOu1/Tb
1215Ow4LtmNp3GaV6kltr/g8BL7TPwGrfT/SGCam/3TOXdXsbrrd7I6+dLqldAhcUI+BqLYAAAHNSURB
1216VGdlsWXjvPWm6W0/vl0e5TMTqXWPzP/sfGi30QQIrnLcmWsDru7vgLXmEka7jTLWsNnpt8/S8o8t
121779QeXstoPCnY22/lXxvHuTIO2Xoa7bZd1mtZ39l43X6SeGFlDXo/LxVbf74OcfX6gZP4O2CtvITR
12182Nn+Z7BK3fUGoEr7lZWqX7t5WzCeXQ1+bGc6DivPNi22z3ZZb1nLiy/BL+hrgeA8TG3Ho1y9fuAM
1219/nkOVvu9Gsuc8PrgX7//PV3r//z3X13jMNtCpr5FFozz7DgcaKPtcqwTzv+tnW1e9bp6/cCx/njQ
12206IK9SWO22Pro8lN5vZd3bR+vry3rvWXJj4tVFqiM7fDv9vpTNTcuv2bdHxtvlzVaulg8/xfMhxYf
1221Py8LGm/8fC3rbs+UI1EBEePHNLRcWxket0bHsNE//fyRSlfTvpYt39tOe21//e9XV5WbqafjUxrP
12223vp7x3nB+IwOovX1rY/z9E6XrbfLY3LsbOlifZ1rtkvLfCjV+Shsr95+S+0HP19dn4vK+nbV2VJM
1223Y/0AU78ej9fRNZzLdifbvvAiUZDRA+CUnrOv+o89jzmKn5PtAgAAAAAAAAAAAAAAAAAAAAAAAABQ
12249f+dHPt315dAmAAAAABJRU5ErkJggg==
1225" id="image551" x="-991.57532" y="563.78479" />
1226 </g>
1227 <g inkscape:export-filename="/home/m/Vault/projects/mitjafelicijan.com/dfd-rice/install-05.png" inkscape:export-xdpi="75" inkscape:export-ydpi="75" id="g658" transform="translate(-4.0751145)">
1228 <image width="169.38" height="127.035" preserveAspectRatio="none" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAyAAAAJYCAIAAAAVFBUnAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAZ
12293klEQVR4nO3du7ajRrsFUPUZHfjx/lCPqNCP58DBCWTLbC6lqmIhQMw5HMgSqvoobmsDon/dbo8b
1230AAA5/7d3AQAA30bAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA
1231wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA
1232wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA
1233wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA
1234wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA
1235wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA
1236wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA
1237wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA
1238wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA
1239wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA
1240wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA
1241wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA
1242wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA
1243wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA
1244wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA
1245wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA
1246wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA
1247wgQsAIAwAQsAIEzAAgAIE7AAAMJ+pxp6PFItwbHc7/eH9ZtvZz3nau73bdt3BgsAIEzAAgAIE7Ag
12487X7/579dvj7b4BbTpyqMn6bf+rz/Xr51vuBLCViwgcdj5rbEpQPk6P3Z7xa8Alk8mW3h4OW9dKTS
12492a+0LpGzjA/wTuwmd2A35UDWeufy2e903qX+x2M+Gy2939cFcB4CFny159F9eGy+338c9UeH7en0
1250t5+nVZY+env4f01Z7mJU6lK/5V4q53e2/UKdHfUUiqzvt/zmtJ3C8gU+ZZOAdXeWGw5i9gzK8xg8
1251fT07/WiCpe+OJputZGmy2XYK/ZZ7qZzfpfaX6uyrZ6q136ftlsuPJu26+X4fexzJVmewPE+Fr3GC
1252o07rmZU1m+cojUVsvbuIjMlZZnZFF/bbfL1P7s9dIoTz2/S4+Dp38vmj76a7wo75OuwPJ4HjEbCA
1253d15Xr26fjVmfObNVOV/TS3J9Uu0Ax+YxDfApS4fws1yXeT4/4vsCwbfOF7ArAQs+pfI5WEdzkPIO
12549TxS1wqBd1wihO9V/uV/5fSjszsrz7fV3/nU0W/T/Jbbn9Y5evbB8LtL/b4dz+mZs9nx+cByAdJ+
12553W6ZzfLn3sC/ys73aF6fVz6CyBOM2IP9NlcwXM+3PoPsDBakrT/HA8DJCVjwhj/ruQLrOdezdAor
1256sy24yR0AIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQs
1257AIAwAQsAIEzAAgAIE7AAAMJ+t37h8diiDACA7+EMFgBAmIAFABAmYAGHcL/vXQFAjoAFp3G///hv
1258ZVMdXde/n+r3LIwDMCJgwWk8Hv/8yuT14pNdN70f7OIUTl08sIXmXxECh3K/3x6P/86IDI/0w9Mk
1259r/dfbz5fvJ2+r6SmfstvTttZmt+met7W+erl+VGq3w+MP3AEqwLWfbA/eNgfwE6ex/7R6+Gbw/+d
1260/bQw/Zpiavp9GmaXt/UsvW6qp9D+aILZr3T3u/X4Awex9gyWXAW7q9kK306T2pQ/sEtY08Ve3wWu
1261xiVC+E6jK1w1Undeu4P7qeOXBMDXELDga72uRt0qYtb0ElWfVDtfoPWMlzNk8E38ihC+3PMnh1cO
1262OgCfJ2DBd1qTqL74WuFew+JyIVyNS4RwGuUnHYyMzlqNJp7eoTV6BsHwu0v9zr5faGe235p2pvXX
1263W2qno/23j8Oor788/pX1AEf263Zr245/7lbus78iXHof4KQ8NwG+wDCf3BdPFGc2dZcIAQDCXCIE
1264eM/pK7iMzJktZ7AAAMIELACAMAFrQ8s30J2jfcpS43/x9WT38nYvAPhKOwes+08rm+rouv79VL9X
1265c7Xx3Kv+q/W75OJp9Wt8fpxHPb4t4DvWhO+Yi8PaOWA9Ho/nDyZfLz7ZddP7wS7O0n7EKYrsk5o1
126668m+jA+whSP+ivD5mIpXsh7u/oZxe/ooi+eLt9P3ldTUb/nNaTtL8/u2pJr23zYynb48v69qnx91
12671H+o5djXfqHI2UVT305rPa3r4dJyDPbbPZ6V7XRsj+V+R43Prs+p+R09JnDpqTyj/cN0+tbtrmO/
1268Ol2Xyr001V+Yfviie7/UYTi2b+dr9ouV00+/Pp2+Y7nvsv12H68r9z+t68+hHDFg3SaDOFyxptPM
1269flqYfk0xNf0+Dde5t/UsvS5oar9pvgrtjCaY/Up3v3stx772p+NfXh/q22mtp3U9nH7ltYuM9Nsx
1270nk3be9/2WJiL6fjM1rPX+ln5lfg4N1XSUX9wP1DYHa3XOj6pcaj8Svd+bK/td9p13/4ntd1t6qA3
1271uVce4dY3kirmgF20trmmhgOu2W+dpeaz1LnG0ebxaPUs+eQ23urItRVquN/vo0N102E+UkNkmk86
1272Wj3HcdAzWLMe7WeAp3+b9km1s6mO8dlL63hGxv8s47NjnadYz5m1Zm3ZZfvacX/eaqnfpXTVVOfK
12737X10Fqejhax4PcOTW9OzVuvb39SZAtZtcGrxVrE6phbGiRZq0/jsaK+/bs81Pp+v88hjwnb22r76
1274pt/UtIvC/n96YWupkZpO12/vR9t+t67naPM7ddBLhGWPx+Mxd+cET8an7Czjc5Y6aTJcpl+5cEfr
12757dv5PfV6Hqz81OPArDMFrDVr3hWuFa6sba/hXXm58HnPxBYd7eUgdX6yjIPM8sfM3utT4wMDteZM
1276/9JHs/P7mf1V/f6hu9NyKnrbe015HbNwtG1qTT0128vR5vdp50uEo79s3v7qYXR6dvbT4U8VZv+K
1277KvQ7+36hndl+a9p5O7NlkfaXpu+oczREa+osL8fC9E1F1rc/q7DeNt1REVxP6tfDty2s7De1/vQt
1278r/XjX1nqmvmdnaxmfrc4w/G238ohfbtcWqePjPN6NeP/GFwr3GI/XLPcd9x+I/VsPf0uft0a/3Xo
12794VwsJcqOv8w4r90X9+4FQLerrb1Xm1+O5v7zoRKN325bdU92kzuM2F9zOsf/yzvravMLTwIWa+27
1280x7S/5nSuttJebX7h6Uw3uQMAnIKABQAQdsSAFf+ZzDF/wLneMedrWtUx63zrpGW/7F7/7gU8HaQM
1281RvZaLtaHkQ8PyKXGf/+AdZbhbq1z6fkrrc9lOcv4nF1qnL91eW09X8Y/62jjIE71Oft2cfbxX2n/
1282gPUBu9xiudRpsJiz3Dp6ljrJstzh+Pq204snp0p7/oqw/JS/8oMrp9OXexk18vbBmMP3C3XGHxxa
12832W/5zWk7S/NbLmb6DLql+S00Xl9nh7f11LSfWg9bn1p5nzzYujzOhenLvVTWX+h3+CK+3aW2r633
1284Jx37jWkN5V5al3tkf1XY3peKTO0/by3LpXs/9vl+m8an0O9S/U11th5Haupv2vNsenw/uD0D1nME
1285Z3c6o53I7JSVB5jZZ+A2tb9UZ189U639Ls1XeUdc2O/PNn6bjMxS+0t7/I46m9TUU9N+aj0sL6/1
128687Wyqbf1Z+erfrtLbV8f2J/0tVMfhZvqCe6vZrf3yq7XrD+t49m0H9ur39b2g8uxaft6jVLH8bHj
1287INLUfmUXx3fQS4Rbj2xlMlvfSKqY43dR39FGxWzR7NIuKd7RRo5W6l71nGhT7e5r99o6CthrHlvr
1288/2Sda447Z1nPj7Zf2s7JHjQ6zdpBj7oz5FvUs+l8BR1qfjuWV8pZlhdlp16fd9xfjcqIt1/TzhZb
1289/S7js9FyPGOI+b796skC1meSdeXqPj2l2ddpqp0PiIx/cH6bllfKiZYXZUf7i791fe6bfiPx7frD
1290PrBdL83XLsedVo+WG9G6u9ii2R0d9BLhvh6Px+yVaY7ppMtrWPPpimc7o/X57Xpy0vWfkVMsx2eR
1291e1dxGicOWPEVcU2Dh7rW8BmzpbbWP3t/ZWUjRxirlTU896cdt3OeaIjOYvdNuPDF2fVkZcGbrhvB
1292xndZhz/QaeSPq88Pzv1fH+ho6y4+YP9LhPVXoEfpvuaYNFqJy18ptz+tc+mvzEK/s+8X2pntt6ad
1293tzPbYan91nGonN9IPbfqcehbDyuXV7m1Qvu3unGuLLW+/WlhTfPVtN0ttf/J5Vjffn07w0oi+5/W
12946SPjWS+1XWTrTG3X66W2u746648jS6b5vm+7fjvl63/fNn58v2631t9H/Pd6aYg7/iKHl2uuP9ec
1295a1pZT9hFX8A6oPvPh0Q0frttlvc/gwVD591uO3zfX2xswXrC7r7yDNPWBCyO5VLb7aVmlm7WE47A
1296etjqxDe5AwAck4AFABB2iID1HT/InPrW+QIAyg4RsCI6nsC09CSnpqakKABg5BABa5db55Y6DRbj
1297lkAAuKb9f0U4+/Sz2Qck3hZ+rlx4WlrqZ6Wt/ZbfnLazNL8AwBntH7Bmn0U7ehTY499/C3P2QWez
1298nxamb9Xa79J8FepZeg0AnNEhLhFOVT6Df30jqWKO3wUA8DH7n8Gq1/qvvN0O8A+4AgAXdKaAdRtc
1299lbtVxKzpJbm+TlPtAAAXcdBLhGWPx2OLf+0cACDiTAFrTaI677XC1udyAQC72/kSYflJByPlf817
1300eofW6NkHw+8u9Tv7fqGd2X5r2nk7swDAef263doO88NUsPRAAQ8aAACOZvRQpMZvtwWbM10iBAA4
1301BQELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACA
1302MAELACBMwAIACBOwAADCBCwAgLDfexcAAJd0v+9dwWc9HntX8FHOYAEAhAlYAABhAhYAXNXFLtt9
13030kXvwboPrnw/elev+8/L52va6f4uAN9peFxYebfW43G5+70O4EIB65VjRoFmTb5JtTNL8AK4llcS
1304GkWi7RLSRs2KdNcJWJVhJXJmq9DO2/aHdT4eDxkL4CoqQ8nsma3nd18fDd8fvhi1P32z0M5S4Jut
130559nItTPWJQJWOaa8Pkqd2Vpq523703dkLIBLKMeRyqAzfT17PmzY7PT4stRmTdnD/718xvr+gLVp
1306QJk9I1XZ3dt09ZpMxgL4ZpEgkooywUh07Yz15QGrHE1e8Sh+D9a9cX16e45NxgL4TmePIOVj04Uz
13071pcHrHI0eV25y3Y6vRT49ivlOqUrgK919gjSdA3xSr7/OVjP7LJ3Fe8t1SldAXy52Xuhhk56FLhw
1308urpdIWDdihlr6+xVaH/60bRO6QrgEt5mrOMo1Dn86Nrp6vb1lwhfhtfghjlm6fWt7saspZvcu9sf
13091ildAVzI8FrhKG+Nfpo3fb+m5dH05Sc4LLVQeD1s5PLp6na7/brd2g7hP0dyPgFIBgDwxtUiyAGC
1310wZqfo7XmpUtcIgQA+KSrXCIEgGM5wBkdtuMMFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQtvYx
1311DcPHlK8uBgDgG6wKWEIVAMCUS4QAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQ1vwcrH8f
1312LDrmkVgAAE/OYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYc2Paah0X3qcAwDAt9skYD08FAsA
1313uDCXCAEAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACDs1+229TOrPHEUADiLTC5yBgsAIEzA
1314AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA
1315AgAIE7AAAMJ+3W6PvWsAAPgqzmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm
1316YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm
1317YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm
1318YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm
1319YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm
1320YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm
1321YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm
1322YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm
1323YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm
1324YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm
1325YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm
1326YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm
1327YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm
1328YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm
1329YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm
1330YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm
1331YAEAhAlYAABhAhYAQNjvvQsAADiv++y7zmABAIQJWAAAYcmA9dff/wu2BkQcfMM8eHkAfUr3YM3u
1332+P74/edmxXyP4dB92Yg9Z239TP319/8+PDLT9bmmgM/X2WfrOo82Dkv1HK1O4LJmAtZrD/XaT63c
1333Z11kl/eazdH8fmz2P9PRH7//PNcph+Gw7LIe7r7+X2HrAziaccCqPBgUztC8Phoe1ZqOMcMWRudL
1334ZvstBJqlOt/W33pMqpnB5zTT8emoc/b91nHu6DfSzuvN6VAfarm01rnUztbLpVDnUvFN20vH8uo4
1335gzs7/rN1LtWTWl599QOM/AhY9emqsIOefd16jBmdCnrtCpvODBV20NkzTOUW3o5Va52F+pvGOTU+
1336re3MftrR71t9Q7Gmzsj6nxrPYddr+m0dh47luDRus5bqSS2v+HoIXNN/Aat+P1IZJqYfHXNXNbub
1337rje7o1863bJ0COyoszBZ3zhvvWha248vl9vymYnUvEfW/+z6UG+jFSA4y3FHrg04u38C1ppLGPU2
1338yljDZqd/fS5Nf9vyTu3htYzKk4Kt/RY+rRznwjhk66n0seWyXs38zsbr+pPEnZVVaN1eCrbevnZx
13399vqBg/gnYK28hFHZ2efPYC111xqACu0XZqp87ealYzybGnzbznQcVp5t6vaZ5bJeX8vdl+A7+uoQ
1340XA9Ty3EvZ68fOIL/noNVf69GnwNeH/zj95/Tuf7r7/81jcNsC5n6unSM8+w47Gij5bKvA67/Wzva
1341etXq7PUD+/rxoNGOvUllttj66PKsvNzLq7a319f6eq+Z8u1khQkKYzt8XV9/qubK6dfM+23j5bJG
1342TRfd63/H+lDj7fbS0Xjl9tXX3SdTjkQFRIwf01BzbWV43Bodw0YfPV+k0tW0r77pW9upr+2Pf391
1343VbiZejo+S+PZWn/rOHeMz+ggWp7f8jhP73TZerncJsfOmi7W17lmudSsD0t13haWV2u/S+0Ht6+m
13447aIwv0111hRTWT/A1K/b7bF3Dcey3cm2C14kCjJ6ABzSffZd/9jzmKP4MVkuAAAAAAAAAAAAAAAA
1345AAAAAAAAAABF/w+B/c/UXnPWXgAAAABJRU5ErkJggg==
1346" id="image640" x="-153.84512" y="683.60748" />
1347 <image width="169.38" height="127.035" preserveAspectRatio="none" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAyAAAAJYCAIAAAAVFBUnAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAI
1348CUlEQVR4nO3c0ZKjKhAAUHcq3+hH8pX7kHtTLGgLaoJmznlJVGxbmap0AeM0AQAAAAAAAAAAAAAA
1349AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwTVNK6WCDm/qO+zrefd/xHADgfX6maUqZ
13500flsWEy1SPu1uba/jhk3GG4z829y4s1+5fMB4BYez495np9fUkqv77sdj7CoyC3fPCXtTR+4RO2C
13511dWQ59BLdQXAQI9ie57nonDJD+UtX4cW9681nqpibi3OZ7RXZvV9reW/VggGBWKcXl0rrO2Pk5/a
1352+qXllHf0bzGUWP8R1vvjgluNBcBIvVNs8QxdcGJvnDhssb9Oe3OKsHEOMWi/mP/BKcvN6/ZGKJK8
1353bP/GzXZ0nwILgFF+9p3WNdoUNL7FZFOg9znkxceQe2+8qP4FgCPKKcLCWWMA544lLM46FZObLUE+
1354//P/qrEuUnlcs38B4O42CqxT6oB6rczBgK8lTQfjcM3+BYC72zlFeE3t65pHzdA9r2v99SmKKdex
1355yQBAriywgspjx4LlOMgRR+J8sroqHtrruqNqrOCil+rfRs/HOKpcBoA1/00RBqua8s3FQ4vTQ/lK
1356o6Lx7t/gljhBm5bf4CLm5psCdufZqPfNBV35XK1/iwjFTQX76yBdzwcAgGVmCQG4jj+jE4D9ekco
1357AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgPOklN7d4CLukicA
1358cC8/oxPollJSGAEAN3P9Aap9CQxPGwD4JR7Pj1fxMc9zfjgvStYOLe5viZNSmud5LU6XtTyD4HWe
1359cT6L9wUAsCyvTvIJuGLIJ99fnBIEPBKnJeE4fhy8PjE4xdQkANCoXIPVOELTNZATNL7agFCc6tWy
1360BQCu6REfPmvMxtgPAPB7bBRYp4zZPNc25ZvHY7Y4a4EXAECXjQLrC5xVWlnkDgA0KtdgBcNL+xak
1361t8d/k/S/D18XAPi1HlM1lbb4ffp38GZt9q34D77noSBmr834U/UaiPzc/FAdJ2bsCgBg420OAABv
13628md0Au8VvCgVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
1363AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
1364AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
1365AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
1366AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
1367AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
1368AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
1369AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
1370AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
1371AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
1372AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
1373AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
1374AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
1375AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
1376AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
1377AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
1378AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
1379AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
1380AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
1381AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
1382AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
1383AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
1384AAAAYJC/HlulbQuPF2AAAAAASUVORK5CYII=
1385" id="image652" x="15.534883" y="683.60748" />
1386 </g>
1387 </g>
1388</svg>
diff --git a/static/posts/dfd-rice/layout.png b/static/posts/dfd-rice/layout.png
deleted file mode 100755
index a44d2cd..0000000
--- a/static/posts/dfd-rice/layout.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/dfd-rice/layout.svg b/static/posts/dfd-rice/layout.svg
deleted file mode 100755
index 5a9031c..0000000
--- a/static/posts/dfd-rice/layout.svg
+++ /dev/null
@@ -1,28 +0,0 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<!-- Created with Inkscape (http://www.inkscape.org/) -->
3
4<svg width="210mm" height="297mm" viewBox="0 0 210 297" version="1.1" id="svg5" inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)" sodipodi:docname="layout.svg" 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">
5 <sodipodi:namedview id="namedview7" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageshadow="2" inkscape:pageopacity="0.0" inkscape:pagecheckerboard="0" inkscape:document-units="mm" showgrid="false" inkscape:zoom="0.08" inkscape:cx="1143.75" inkscape:cy="1893.75" inkscape:window-width="2305" inkscape:window-height="752" inkscape:window-x="873" inkscape:window-y="136" inkscape:window-maximized="0" inkscape:current-layer="layer1" />
6 <defs id="defs2" />
7 <g inkscape:label="Layer 1" inkscape:groupmode="layer" id="layer1">
8 <g id="g2012" inkscape:export-filename="/home/m/Vault/projects/mitjafelicijan.com/dfd-rice/layout.png" inkscape:export-xdpi="6.6072011" inkscape:export-ydpi="6.6072011">
9 <rect style="fill:#e6e6e6;stroke:#303030;stroke-width:0.447874;stroke-linecap:round;stroke-linejoin:miter;paint-order:stroke fill markers" id="rect1454" width="1360.1339" height="1074.3162" x="-360.50458" y="-265.69751" ry="0" />
10 <rect style="fill:#e6e6e6;stroke:#303030;stroke-width:0.261189;stroke-linecap:round;stroke-linejoin:miter;paint-order:stroke fill markers" id="rect1456" width="1058.4567" height="469.50305" x="1025.9943" y="-265.79086" ry="0" />
11 <text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:51.606px;line-height:1.25;font-family:sans-serif;fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:1.29015" x="1407.4224" y="-12.228849" id="text7667-3">
12 <tspan sodipodi:role="line" id="tspan7665-6" style="font-weight:bold;stroke-width:1.29015;fill:#4d4d4d" x="1407.4224" y="-12.228849">TERMINAL</tspan>
13 </text>
14 <rect style="fill:#e6e6e6;stroke:#303030;stroke-width:0.289748;stroke-linecap:round;stroke-linejoin:miter;paint-order:stroke fill markers" id="rect1458" width="1058.4564" height="577.78894" x="1028.7416" y="230.8085" ry="0" />
15 <rect style="fill:#e6e6e6;stroke:#303030;stroke-width:0.447874;stroke-linecap:round;stroke-linejoin:miter;paint-order:stroke fill markers" id="rect135" width="1360.1339" height="1074.3162" x="-1747.0968" y="-265.69751" ry="0" />
16 <text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:51.606px;line-height:1.25;font-family:sans-serif;fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:1.29015" x="-1214.8931" y="290.24585" id="text3280">
17 <tspan sodipodi:role="line" id="tspan3278" style="font-weight:bold;stroke-width:1.29015;fill:#4d4d4d" x="-1214.8931" y="290.24585">BROWSER</tspan>
18 </text>
19 <rect style="fill:none;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers" id="rect31" width="3834.2903" height="1074.2903" x="-1747.0922" y="-265.69287" ry="0" />
20 <text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:51.606px;line-height:1.25;font-family:sans-serif;fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:1.29015" x="121.84438" y="290.24585" id="text7667">
21 <tspan sodipodi:role="line" id="tspan7665" style="font-weight:bold;stroke-width:1.29015;fill:#4d4d4d" x="121.84438" y="290.24585">CODE EDITOR</tspan>
22 </text>
23 <text xml:space="preserve" style="font-style:normal;font-weight:normal;font-size:51.606px;line-height:1.25;font-family:sans-serif;fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:1.29015" x="1410.1696" y="538.51349" id="text12264">
24 <tspan sodipodi:role="line" id="tspan12262" style="font-weight:bold;stroke-width:1.29015;fill:#4d4d4d" x="1410.1696" y="538.51349">TERMINAL</tspan>
25 </text>
26 </g>
27 </g>
28</svg>
diff --git a/static/posts/dfd-rice/script.png b/static/posts/dfd-rice/script.png
deleted file mode 100755
index 09be37a..0000000
--- a/static/posts/dfd-rice/script.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/dna-sequence/benchmarks.csv b/static/posts/dna-sequence/benchmarks.csv
deleted file mode 100644
index 8645d5e..0000000
--- a/static/posts/dna-sequence/benchmarks.csv
+++ /dev/null
@@ -1,7 +0,0 @@
1Packages,Encode to FASTA (ms),FASTA file size (KB),FASTA gzipped (KB)
21KB,5.625224,4.1,1.4
310KB,32.679975,40.7,13
4100KB,112.864416,406.7,121
51MB,872.887675,4100,1200
610MB,8472.693202,40700,12000
7100MB,85525.178217,406700,118000
diff --git a/static/posts/dna-sequence/chart-size.py b/static/posts/dna-sequence/chart-size.py
deleted file mode 100644
index 4fc408d..0000000
--- a/static/posts/dna-sequence/chart-size.py
+++ /dev/null
@@ -1,28 +0,0 @@
1import csv
2
3import matplotlib.pyplot as plt
4import pandas as pd
5
6# Read the data
7df = pd.read_csv("benchmarks.csv")
8
9# Settings
10plt.title("Encode to FASTA out filesize")
11plt.tight_layout(pad=2)
12fig = plt.gcf()
13fig.set_size_inches(10, 4)
14
15# Plotting
16plt.plot(df["Packages"], df["FASTA file size (KB)"], label = "Raw", color="black", linestyle="-")
17plt.plot(df["Packages"], df["FASTA gzipped (KB)"], label = "Gzipped", color="black", linestyle="--")
18
19# Adding x and y axis labels
20plt.xlabel("Size of an input file", fontstyle="italic")
21plt.ylabel("File size (KB)", fontstyle="italic")
22
23# Legend
24legend = plt.legend()
25legend.get_frame().set_linewidth(0)
26
27# Export as SVG
28plt.savefig("chart-size.svg", format="svg")
diff --git a/static/posts/dna-sequence/chart-size.svg b/static/posts/dna-sequence/chart-size.svg
deleted file mode 100644
index 1a2d127..0000000
--- a/static/posts/dna-sequence/chart-size.svg
+++ /dev/null
@@ -1,1553 +0,0 @@
1<?xml version="1.0" encoding="utf-8" standalone="no"?>
2<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
3 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4<svg xmlns:xlink="http://www.w3.org/1999/xlink" width="720pt" height="288pt" viewBox="0 0 720 288" xmlns="http://www.w3.org/2000/svg" version="1.1">
5 <metadata>
6 <rdf:RDF xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
7 <cc:Work>
8 <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
9 <dc:date>2023-08-05T13:29:17.701350</dc:date>
10 <dc:format>image/svg+xml</dc:format>
11 <dc:creator>
12 <cc:Agent>
13 <dc:title>Matplotlib v3.5.2, https://matplotlib.org/</dc:title>
14 </cc:Agent>
15 </dc:creator>
16 </cc:Work>
17 </rdf:RDF>
18 </metadata>
19 <defs>
20 <style type="text/css">*{stroke-linejoin: round; stroke-linecap: butt}</style>
21 </defs>
22 <g id="figure_1">
23 <g id="patch_1">
24 <path d="M 0 288
25L 720 288
26L 720 0
27L 0 0
28z
29" style="fill: #ffffff"/>
30 </g>
31 <g id="axes_1">
32 <g id="patch_2">
33 <path d="M 67.078125 257.1
34L 676.304688 257.1
35L 676.304688 28.866667
36L 67.078125 28.866667
37z
38" style="fill: #ffffff"/>
39 </g>
40 <g id="matplotlib.axis_1">
41 <g id="xtick_1">
42 <g id="line2d_1">
43 <defs>
44 <path id="m07b8a304ba" d="M 0 0
45L 0 3.5
46" style="stroke: #000000; stroke-width: 0.8"/>
47 </defs>
48 <g>
49 <use xlink:href="#m07b8a304ba" x="94.770241" y="257.1" style="stroke: #000000; stroke-width: 0.8"/>
50 </g>
51 </g>
52 <g id="text_1">
53 <!-- 1KB -->
54 <g transform="translate(84.879616 271.698438)scale(0.1 -0.1)">
55 <defs>
56 <path id="DejaVuSans-31" d="M 794 531
57L 1825 531
58L 1825 4091
59L 703 3866
60L 703 4441
61L 1819 4666
62L 2450 4666
63L 2450 531
64L 3481 531
65L 3481 0
66L 794 0
67L 794 531
68z
69" transform="scale(0.015625)"/>
70 <path id="DejaVuSans-4b" d="M 628 4666
71L 1259 4666
72L 1259 2694
73L 3353 4666
74L 4166 4666
75L 1850 2491
76L 4331 0
77L 3500 0
78L 1259 2247
79L 1259 0
80L 628 0
81L 628 4666
82z
83" transform="scale(0.015625)"/>
84 <path id="DejaVuSans-42" d="M 1259 2228
85L 1259 519
86L 2272 519
87Q 2781 519 3026 730
88Q 3272 941 3272 1375
89Q 3272 1813 3026 2020
90Q 2781 2228 2272 2228
91L 1259 2228
92z
93M 1259 4147
94L 1259 2741
95L 2194 2741
96Q 2656 2741 2882 2914
97Q 3109 3088 3109 3444
98Q 3109 3797 2882 3972
99Q 2656 4147 2194 4147
100L 1259 4147
101z
102M 628 4666
103L 2241 4666
104Q 2963 4666 3353 4366
105Q 3744 4066 3744 3513
106Q 3744 3084 3544 2831
107Q 3344 2578 2956 2516
108Q 3422 2416 3680 2098
109Q 3938 1781 3938 1306
110Q 3938 681 3513 340
111Q 3088 0 2303 0
112L 628 0
113L 628 4666
114z
115" transform="scale(0.015625)"/>
116 </defs>
117 <use xlink:href="#DejaVuSans-31"/>
118 <use xlink:href="#DejaVuSans-4b" x="63.623047"/>
119 <use xlink:href="#DejaVuSans-42" x="129.199219"/>
120 </g>
121 </g>
122 </g>
123 <g id="xtick_2">
124 <g id="line2d_2">
125 <g>
126 <use xlink:href="#m07b8a304ba" x="205.538707" y="257.1" style="stroke: #000000; stroke-width: 0.8"/>
127 </g>
128 </g>
129 <g id="text_2">
130 <!-- 10KB -->
131 <g transform="translate(192.466832 271.698438)scale(0.1 -0.1)">
132 <defs>
133 <path id="DejaVuSans-30" d="M 2034 4250
134Q 1547 4250 1301 3770
135Q 1056 3291 1056 2328
136Q 1056 1369 1301 889
137Q 1547 409 2034 409
138Q 2525 409 2770 889
139Q 3016 1369 3016 2328
140Q 3016 3291 2770 3770
141Q 2525 4250 2034 4250
142z
143M 2034 4750
144Q 2819 4750 3233 4129
145Q 3647 3509 3647 2328
146Q 3647 1150 3233 529
147Q 2819 -91 2034 -91
148Q 1250 -91 836 529
149Q 422 1150 422 2328
150Q 422 3509 836 4129
151Q 1250 4750 2034 4750
152z
153" transform="scale(0.015625)"/>
154 </defs>
155 <use xlink:href="#DejaVuSans-31"/>
156 <use xlink:href="#DejaVuSans-30" x="63.623047"/>
157 <use xlink:href="#DejaVuSans-4b" x="127.246094"/>
158 <use xlink:href="#DejaVuSans-42" x="192.822266"/>
159 </g>
160 </g>
161 </g>
162 <g id="xtick_3">
163 <g id="line2d_3">
164 <g>
165 <use xlink:href="#m07b8a304ba" x="316.307173" y="257.1" style="stroke: #000000; stroke-width: 0.8"/>
166 </g>
167 </g>
168 <g id="text_3">
169 <!-- 100KB -->
170 <g transform="translate(300.054048 271.698438)scale(0.1 -0.1)">
171 <use xlink:href="#DejaVuSans-31"/>
172 <use xlink:href="#DejaVuSans-30" x="63.623047"/>
173 <use xlink:href="#DejaVuSans-30" x="127.246094"/>
174 <use xlink:href="#DejaVuSans-4b" x="190.869141"/>
175 <use xlink:href="#DejaVuSans-42" x="256.445312"/>
176 </g>
177 </g>
178 </g>
179 <g id="xtick_4">
180 <g id="line2d_4">
181 <g>
182 <use xlink:href="#m07b8a304ba" x="427.075639" y="257.1" style="stroke: #000000; stroke-width: 0.8"/>
183 </g>
184 </g>
185 <g id="text_4">
186 <!-- 1MB -->
187 <g transform="translate(416.149858 271.698438)scale(0.1 -0.1)">
188 <defs>
189 <path id="DejaVuSans-4d" d="M 628 4666
190L 1569 4666
191L 2759 1491
192L 3956 4666
193L 4897 4666
194L 4897 0
195L 4281 0
196L 4281 4097
197L 3078 897
198L 2444 897
199L 1241 4097
200L 1241 0
201L 628 0
202L 628 4666
203z
204" transform="scale(0.015625)"/>
205 </defs>
206 <use xlink:href="#DejaVuSans-31"/>
207 <use xlink:href="#DejaVuSans-4d" x="63.623047"/>
208 <use xlink:href="#DejaVuSans-42" x="149.902344"/>
209 </g>
210 </g>
211 </g>
212 <g id="xtick_5">
213 <g id="line2d_5">
214 <g>
215 <use xlink:href="#m07b8a304ba" x="537.844105" y="257.1" style="stroke: #000000; stroke-width: 0.8"/>
216 </g>
217 </g>
218 <g id="text_5">
219 <!-- 10MB -->
220 <g transform="translate(523.737074 271.698438)scale(0.1 -0.1)">
221 <use xlink:href="#DejaVuSans-31"/>
222 <use xlink:href="#DejaVuSans-30" x="63.623047"/>
223 <use xlink:href="#DejaVuSans-4d" x="127.246094"/>
224 <use xlink:href="#DejaVuSans-42" x="213.525391"/>
225 </g>
226 </g>
227 </g>
228 <g id="xtick_6">
229 <g id="line2d_6">
230 <g>
231 <use xlink:href="#m07b8a304ba" x="648.612571" y="257.1" style="stroke: #000000; stroke-width: 0.8"/>
232 </g>
233 </g>
234 <g id="text_6">
235 <!-- 100MB -->
236 <g transform="translate(631.32429 271.698438)scale(0.1 -0.1)">
237 <use xlink:href="#DejaVuSans-31"/>
238 <use xlink:href="#DejaVuSans-30" x="63.623047"/>
239 <use xlink:href="#DejaVuSans-30" x="127.246094"/>
240 <use xlink:href="#DejaVuSans-4d" x="190.869141"/>
241 <use xlink:href="#DejaVuSans-42" x="277.148438"/>
242 </g>
243 </g>
244 </g>
245 <g id="text_7">
246 <!-- Size of an input file -->
247 <g transform="translate(323.542969 285.376562)scale(0.1 -0.1)">
248 <defs>
249 <path id="DejaVuSans-Oblique-53" d="M 3859 4513
250L 3738 3897
251Q 3422 4066 3111 4152
252Q 2800 4238 2509 4238
253Q 1944 4238 1609 3991
254Q 1275 3744 1275 3334
255Q 1275 3109 1398 2989
256Q 1522 2869 2034 2731
257L 2413 2638
258Q 3053 2472 3303 2217
259Q 3553 1963 3553 1503
260Q 3553 797 2998 353
261Q 2444 -91 1538 -91
262Q 1166 -91 791 -17
263Q 416 56 38 206
264L 166 856
265Q 513 641 861 531
266Q 1209 422 1556 422
267Q 2147 422 2503 684
268Q 2859 947 2859 1369
269Q 2859 1650 2717 1795
270Q 2575 1941 2106 2059
271L 1728 2156
272Q 1081 2325 845 2545
273Q 609 2766 609 3163
274Q 609 3859 1145 4304
275Q 1681 4750 2541 4750
276Q 2875 4750 3203 4690
277Q 3531 4631 3859 4513
278z
279" transform="scale(0.015625)"/>
280 <path id="DejaVuSans-Oblique-69" d="M 1172 4863
281L 1747 4863
282L 1606 4134
283L 1031 4134
284L 1172 4863
285z
286M 909 3500
287L 1484 3500
288L 800 0
289L 225 0
290L 909 3500
291z
292" transform="scale(0.015625)"/>
293 <path id="DejaVuSans-Oblique-7a" d="M 744 3500
294L 3475 3500
295L 3372 2975
296L 738 459
297L 2913 459
298L 2822 0
299L -19 0
300L 84 525
301L 2719 3041
302L 653 3041
303L 744 3500
304z
305" transform="scale(0.015625)"/>
306 <path id="DejaVuSans-Oblique-65" d="M 3078 2063
307Q 3088 2113 3092 2166
308Q 3097 2219 3097 2272
309Q 3097 2653 2873 2875
310Q 2650 3097 2266 3097
311Q 1838 3097 1509 2826
312Q 1181 2556 1013 2059
313L 3078 2063
314z
315M 3578 1613
316L 903 1613
317Q 884 1494 878 1425
318Q 872 1356 872 1306
319Q 872 872 1139 634
320Q 1406 397 1894 397
321Q 2269 397 2603 481
322Q 2938 566 3225 728
323L 3116 159
324Q 2806 34 2476 -28
325Q 2147 -91 1806 -91
326Q 1078 -91 686 257
327Q 294 606 294 1247
328Q 294 1794 489 2264
329Q 684 2734 1063 3103
330Q 1306 3334 1642 3459
331Q 1978 3584 2356 3584
332Q 2950 3584 3301 3228
333Q 3653 2872 3653 2272
334Q 3653 2128 3634 1964
335Q 3616 1800 3578 1613
336z
337" transform="scale(0.015625)"/>
338 <path id="DejaVuSans-Oblique-20" transform="scale(0.015625)"/>
339 <path id="DejaVuSans-Oblique-6f" d="M 1625 -91
340Q 1009 -91 651 289
341Q 294 669 294 1325
342Q 294 1706 417 2101
343Q 541 2497 738 2766
344Q 1047 3184 1428 3384
345Q 1809 3584 2291 3584
346Q 2888 3584 3255 3212
347Q 3622 2841 3622 2241
348Q 3622 1825 3500 1412
349Q 3378 1000 3181 728
350Q 2875 309 2494 109
351Q 2113 -91 1625 -91
352z
353M 891 1344
354Q 891 869 1089 633
355Q 1288 397 1691 397
356Q 2269 397 2648 901
357Q 3028 1406 3028 2181
358Q 3028 2634 2825 2865
359Q 2622 3097 2228 3097
360Q 1903 3097 1650 2945
361Q 1397 2794 1197 2484
362Q 1050 2253 970 1956
363Q 891 1659 891 1344
364z
365" transform="scale(0.015625)"/>
366 <path id="DejaVuSans-Oblique-66" d="M 3059 4863
367L 2969 4384
368L 2419 4384
369Q 2106 4384 1964 4261
370Q 1822 4138 1753 3809
371L 1691 3500
372L 2638 3500
373L 2553 3053
374L 1606 3053
375L 1013 0
376L 434 0
377L 1031 3053
378L 481 3053
379L 563 3500
380L 1113 3500
381L 1159 3744
382Q 1278 4363 1576 4613
383Q 1875 4863 2516 4863
384L 3059 4863
385z
386" transform="scale(0.015625)"/>
387 <path id="DejaVuSans-Oblique-61" d="M 3438 1997
388L 3047 0
389L 2472 0
390L 2578 531
391Q 2325 219 2001 64
392Q 1678 -91 1281 -91
393Q 834 -91 548 182
394Q 263 456 263 884
395Q 263 1497 752 1853
396Q 1241 2209 2100 2209
397L 2900 2209
398L 2931 2363
399Q 2938 2388 2941 2417
400Q 2944 2447 2944 2509
401Q 2944 2788 2717 2942
402Q 2491 3097 2081 3097
403Q 1800 3097 1504 3025
404Q 1209 2953 897 2809
405L 997 3341
406Q 1322 3463 1633 3523
407Q 1944 3584 2234 3584
408Q 2853 3584 3176 3315
409Q 3500 3047 3500 2534
410Q 3500 2431 3484 2292
411Q 3469 2153 3438 1997
412z
413M 2816 1759
414L 2241 1759
415Q 1534 1759 1195 1570
416Q 856 1381 856 984
417Q 856 709 1029 553
418Q 1203 397 1509 397
419Q 1978 397 2328 733
420Q 2678 1069 2791 1631
421L 2816 1759
422z
423" transform="scale(0.015625)"/>
424 <path id="DejaVuSans-Oblique-6e" d="M 3566 2113
425L 3156 0
426L 2578 0
427L 2988 2091
428Q 3016 2238 3031 2350
429Q 3047 2463 3047 2528
430Q 3047 2791 2881 2937
431Q 2716 3084 2419 3084
432Q 1956 3084 1622 2776
433Q 1288 2469 1184 1941
434L 800 0
435L 225 0
436L 903 3500
437L 1478 3500
438L 1363 2950
439Q 1603 3253 1940 3418
440Q 2278 3584 2650 3584
441Q 3113 3584 3367 3334
442Q 3622 3084 3622 2631
443Q 3622 2519 3608 2391
444Q 3594 2263 3566 2113
445z
446" transform="scale(0.015625)"/>
447 <path id="DejaVuSans-Oblique-70" d="M 3175 2156
448Q 3175 2616 2975 2859
449Q 2775 3103 2400 3103
450Q 2144 3103 1911 2972
451Q 1678 2841 1497 2591
452Q 1319 2344 1212 1994
453Q 1106 1644 1106 1300
454Q 1106 863 1306 627
455Q 1506 391 1875 391
456Q 2147 391 2380 519
457Q 2613 647 2778 891
458Q 2956 1147 3065 1494
459Q 3175 1841 3175 2156
460z
461M 1394 2969
462Q 1625 3272 1939 3428
463Q 2253 3584 2638 3584
464Q 3175 3584 3472 3232
465Q 3769 2881 3769 2247
466Q 3769 1728 3584 1258
467Q 3400 788 3053 416
468Q 2822 169 2531 39
469Q 2241 -91 1919 -91
470Q 1547 -91 1294 64
471Q 1041 219 916 525
472L 556 -1331
473L -19 -1331
474L 922 3500
475L 1497 3500
476L 1394 2969
477z
478" transform="scale(0.015625)"/>
479 <path id="DejaVuSans-Oblique-75" d="M 428 1388
480L 838 3500
481L 1416 3500
482L 1006 1409
483Q 975 1256 961 1147
484Q 947 1038 947 966
485Q 947 700 1109 554
486Q 1272 409 1569 409
487Q 2031 409 2368 721
488Q 2706 1034 2809 1563
489L 3194 3500
490L 3769 3500
491L 3091 0
492L 2516 0
493L 2631 550
494Q 2388 244 2052 76
495Q 1716 -91 1338 -91
496Q 878 -91 622 161
497Q 366 413 366 863
498Q 366 956 381 1097
499Q 397 1238 428 1388
500z
501" transform="scale(0.015625)"/>
502 <path id="DejaVuSans-Oblique-74" d="M 2706 3500
503L 2619 3053
504L 1472 3053
505L 1100 1153
506Q 1081 1047 1072 975
507Q 1063 903 1063 863
508Q 1063 663 1183 572
509Q 1303 481 1569 481
510L 2150 481
511L 2053 0
512L 1503 0
513Q 991 0 739 200
514Q 488 400 488 806
515Q 488 878 497 964
516Q 506 1050 525 1153
517L 897 3053
518L 409 3053
519L 500 3500
520L 978 3500
521L 1172 4494
522L 1747 4494
523L 1556 3500
524L 2706 3500
525z
526" transform="scale(0.015625)"/>
527 <path id="DejaVuSans-Oblique-6c" d="M 1172 4863
528L 1747 4863
529L 800 0
530L 225 0
531L 1172 4863
532z
533" transform="scale(0.015625)"/>
534 </defs>
535 <use xlink:href="#DejaVuSans-Oblique-53"/>
536 <use xlink:href="#DejaVuSans-Oblique-69" x="63.476562"/>
537 <use xlink:href="#DejaVuSans-Oblique-7a" x="91.259766"/>
538 <use xlink:href="#DejaVuSans-Oblique-65" x="143.75"/>
539 <use xlink:href="#DejaVuSans-Oblique-20" x="205.273438"/>
540 <use xlink:href="#DejaVuSans-Oblique-6f" x="237.060547"/>
541 <use xlink:href="#DejaVuSans-Oblique-66" x="298.242188"/>
542 <use xlink:href="#DejaVuSans-Oblique-20" x="333.447266"/>
543 <use xlink:href="#DejaVuSans-Oblique-61" x="365.234375"/>
544 <use xlink:href="#DejaVuSans-Oblique-6e" x="426.513672"/>
545 <use xlink:href="#DejaVuSans-Oblique-20" x="489.892578"/>
546 <use xlink:href="#DejaVuSans-Oblique-69" x="521.679688"/>
547 <use xlink:href="#DejaVuSans-Oblique-6e" x="549.462891"/>
548 <use xlink:href="#DejaVuSans-Oblique-70" x="612.841797"/>
549 <use xlink:href="#DejaVuSans-Oblique-75" x="676.318359"/>
550 <use xlink:href="#DejaVuSans-Oblique-74" x="739.697266"/>
551 <use xlink:href="#DejaVuSans-Oblique-20" x="778.90625"/>
552 <use xlink:href="#DejaVuSans-Oblique-66" x="810.693359"/>
553 <use xlink:href="#DejaVuSans-Oblique-69" x="845.898438"/>
554 <use xlink:href="#DejaVuSans-Oblique-6c" x="873.681641"/>
555 <use xlink:href="#DejaVuSans-Oblique-65" x="901.464844"/>
556 </g>
557 </g>
558 </g>
559 <g id="matplotlib.axis_2">
560 <g id="ytick_1">
561 <g id="line2d_7">
562 <defs>
563 <path id="ma77a0d662c" d="M 0 0
564L -3.5 0
565" style="stroke: #000000; stroke-width: 0.8"/>
566 </defs>
567 <g>
568 <use xlink:href="#ma77a0d662c" x="67.078125" y="246.726472" style="stroke: #000000; stroke-width: 0.8"/>
569 </g>
570 </g>
571 <g id="text_8">
572 <!-- 0 -->
573 <g transform="translate(53.715625 250.525691)scale(0.1 -0.1)">
574 <use xlink:href="#DejaVuSans-30"/>
575 </g>
576 </g>
577 </g>
578 <g id="ytick_2">
579 <g id="line2d_8">
580 <g>
581 <use xlink:href="#ma77a0d662c" x="67.078125" y="221.218043" style="stroke: #000000; stroke-width: 0.8"/>
582 </g>
583 </g>
584 <g id="text_9">
585 <!-- 50000 -->
586 <g transform="translate(28.265625 225.017261)scale(0.1 -0.1)">
587 <defs>
588 <path id="DejaVuSans-35" d="M 691 4666
589L 3169 4666
590L 3169 4134
591L 1269 4134
592L 1269 2991
593Q 1406 3038 1543 3061
594Q 1681 3084 1819 3084
595Q 2600 3084 3056 2656
596Q 3513 2228 3513 1497
597Q 3513 744 3044 326
598Q 2575 -91 1722 -91
599Q 1428 -91 1123 -41
600Q 819 9 494 109
601L 494 744
602Q 775 591 1075 516
603Q 1375 441 1709 441
604Q 2250 441 2565 725
605Q 2881 1009 2881 1497
606Q 2881 1984 2565 2268
607Q 2250 2553 1709 2553
608Q 1456 2553 1204 2497
609Q 953 2441 691 2322
610L 691 4666
611z
612" transform="scale(0.015625)"/>
613 </defs>
614 <use xlink:href="#DejaVuSans-35"/>
615 <use xlink:href="#DejaVuSans-30" x="63.623047"/>
616 <use xlink:href="#DejaVuSans-30" x="127.246094"/>
617 <use xlink:href="#DejaVuSans-30" x="190.869141"/>
618 <use xlink:href="#DejaVuSans-30" x="254.492188"/>
619 </g>
620 </g>
621 </g>
622 <g id="ytick_3">
623 <g id="line2d_9">
624 <g>
625 <use xlink:href="#ma77a0d662c" x="67.078125" y="195.709614" style="stroke: #000000; stroke-width: 0.8"/>
626 </g>
627 </g>
628 <g id="text_10">
629 <!-- 100000 -->
630 <g transform="translate(21.903125 199.508832)scale(0.1 -0.1)">
631 <use xlink:href="#DejaVuSans-31"/>
632 <use xlink:href="#DejaVuSans-30" x="63.623047"/>
633 <use xlink:href="#DejaVuSans-30" x="127.246094"/>
634 <use xlink:href="#DejaVuSans-30" x="190.869141"/>
635 <use xlink:href="#DejaVuSans-30" x="254.492188"/>
636 <use xlink:href="#DejaVuSans-30" x="318.115234"/>
637 </g>
638 </g>
639 </g>
640 <g id="ytick_4">
641 <g id="line2d_10">
642 <g>
643 <use xlink:href="#ma77a0d662c" x="67.078125" y="170.201184" style="stroke: #000000; stroke-width: 0.8"/>
644 </g>
645 </g>
646 <g id="text_11">
647 <!-- 150000 -->
648 <g transform="translate(21.903125 174.000403)scale(0.1 -0.1)">
649 <use xlink:href="#DejaVuSans-31"/>
650 <use xlink:href="#DejaVuSans-35" x="63.623047"/>
651 <use xlink:href="#DejaVuSans-30" x="127.246094"/>
652 <use xlink:href="#DejaVuSans-30" x="190.869141"/>
653 <use xlink:href="#DejaVuSans-30" x="254.492188"/>
654 <use xlink:href="#DejaVuSans-30" x="318.115234"/>
655 </g>
656 </g>
657 </g>
658 <g id="ytick_5">
659 <g id="line2d_11">
660 <g>
661 <use xlink:href="#ma77a0d662c" x="67.078125" y="144.692755" style="stroke: #000000; stroke-width: 0.8"/>
662 </g>
663 </g>
664 <g id="text_12">
665 <!-- 200000 -->
666 <g transform="translate(21.903125 148.491974)scale(0.1 -0.1)">
667 <defs>
668 <path id="DejaVuSans-32" d="M 1228 531
669L 3431 531
670L 3431 0
671L 469 0
672L 469 531
673Q 828 903 1448 1529
674Q 2069 2156 2228 2338
675Q 2531 2678 2651 2914
676Q 2772 3150 2772 3378
677Q 2772 3750 2511 3984
678Q 2250 4219 1831 4219
679Q 1534 4219 1204 4116
680Q 875 4013 500 3803
681L 500 4441
682Q 881 4594 1212 4672
683Q 1544 4750 1819 4750
684Q 2544 4750 2975 4387
685Q 3406 4025 3406 3419
686Q 3406 3131 3298 2873
687Q 3191 2616 2906 2266
688Q 2828 2175 2409 1742
689Q 1991 1309 1228 531
690z
691" transform="scale(0.015625)"/>
692 </defs>
693 <use xlink:href="#DejaVuSans-32"/>
694 <use xlink:href="#DejaVuSans-30" x="63.623047"/>
695 <use xlink:href="#DejaVuSans-30" x="127.246094"/>
696 <use xlink:href="#DejaVuSans-30" x="190.869141"/>
697 <use xlink:href="#DejaVuSans-30" x="254.492188"/>
698 <use xlink:href="#DejaVuSans-30" x="318.115234"/>
699 </g>
700 </g>
701 </g>
702 <g id="ytick_6">
703 <g id="line2d_12">
704 <g>
705 <use xlink:href="#ma77a0d662c" x="67.078125" y="119.184326" style="stroke: #000000; stroke-width: 0.8"/>
706 </g>
707 </g>
708 <g id="text_13">
709 <!-- 250000 -->
710 <g transform="translate(21.903125 122.983545)scale(0.1 -0.1)">
711 <use xlink:href="#DejaVuSans-32"/>
712 <use xlink:href="#DejaVuSans-35" x="63.623047"/>
713 <use xlink:href="#DejaVuSans-30" x="127.246094"/>
714 <use xlink:href="#DejaVuSans-30" x="190.869141"/>
715 <use xlink:href="#DejaVuSans-30" x="254.492188"/>
716 <use xlink:href="#DejaVuSans-30" x="318.115234"/>
717 </g>
718 </g>
719 </g>
720 <g id="ytick_7">
721 <g id="line2d_13">
722 <g>
723 <use xlink:href="#ma77a0d662c" x="67.078125" y="93.675897" style="stroke: #000000; stroke-width: 0.8"/>
724 </g>
725 </g>
726 <g id="text_14">
727 <!-- 300000 -->
728 <g transform="translate(21.903125 97.475116)scale(0.1 -0.1)">
729 <defs>
730 <path id="DejaVuSans-33" d="M 2597 2516
731Q 3050 2419 3304 2112
732Q 3559 1806 3559 1356
733Q 3559 666 3084 287
734Q 2609 -91 1734 -91
735Q 1441 -91 1130 -33
736Q 819 25 488 141
737L 488 750
738Q 750 597 1062 519
739Q 1375 441 1716 441
740Q 2309 441 2620 675
741Q 2931 909 2931 1356
742Q 2931 1769 2642 2001
743Q 2353 2234 1838 2234
744L 1294 2234
745L 1294 2753
746L 1863 2753
747Q 2328 2753 2575 2939
748Q 2822 3125 2822 3475
749Q 2822 3834 2567 4026
750Q 2313 4219 1838 4219
751Q 1578 4219 1281 4162
752Q 984 4106 628 3988
753L 628 4550
754Q 988 4650 1302 4700
755Q 1616 4750 1894 4750
756Q 2613 4750 3031 4423
757Q 3450 4097 3450 3541
758Q 3450 3153 3228 2886
759Q 3006 2619 2597 2516
760z
761" transform="scale(0.015625)"/>
762 </defs>
763 <use xlink:href="#DejaVuSans-33"/>
764 <use xlink:href="#DejaVuSans-30" x="63.623047"/>
765 <use xlink:href="#DejaVuSans-30" x="127.246094"/>
766 <use xlink:href="#DejaVuSans-30" x="190.869141"/>
767 <use xlink:href="#DejaVuSans-30" x="254.492188"/>
768 <use xlink:href="#DejaVuSans-30" x="318.115234"/>
769 </g>
770 </g>
771 </g>
772 <g id="ytick_8">
773 <g id="line2d_14">
774 <g>
775 <use xlink:href="#ma77a0d662c" x="67.078125" y="68.167468" style="stroke: #000000; stroke-width: 0.8"/>
776 </g>
777 </g>
778 <g id="text_15">
779 <!-- 350000 -->
780 <g transform="translate(21.903125 71.966686)scale(0.1 -0.1)">
781 <use xlink:href="#DejaVuSans-33"/>
782 <use xlink:href="#DejaVuSans-35" x="63.623047"/>
783 <use xlink:href="#DejaVuSans-30" x="127.246094"/>
784 <use xlink:href="#DejaVuSans-30" x="190.869141"/>
785 <use xlink:href="#DejaVuSans-30" x="254.492188"/>
786 <use xlink:href="#DejaVuSans-30" x="318.115234"/>
787 </g>
788 </g>
789 </g>
790 <g id="ytick_9">
791 <g id="line2d_15">
792 <g>
793 <use xlink:href="#ma77a0d662c" x="67.078125" y="42.659039" style="stroke: #000000; stroke-width: 0.8"/>
794 </g>
795 </g>
796 <g id="text_16">
797 <!-- 400000 -->
798 <g transform="translate(21.903125 46.458257)scale(0.1 -0.1)">
799 <defs>
800 <path id="DejaVuSans-34" d="M 2419 4116
801L 825 1625
802L 2419 1625
803L 2419 4116
804z
805M 2253 4666
806L 3047 4666
807L 3047 1625
808L 3713 1625
809L 3713 1100
810L 3047 1100
811L 3047 0
812L 2419 0
813L 2419 1100
814L 313 1100
815L 313 1709
816L 2253 4666
817z
818" transform="scale(0.015625)"/>
819 </defs>
820 <use xlink:href="#DejaVuSans-34"/>
821 <use xlink:href="#DejaVuSans-30" x="63.623047"/>
822 <use xlink:href="#DejaVuSans-30" x="127.246094"/>
823 <use xlink:href="#DejaVuSans-30" x="190.869141"/>
824 <use xlink:href="#DejaVuSans-30" x="254.492188"/>
825 <use xlink:href="#DejaVuSans-30" x="318.115234"/>
826 </g>
827 </g>
828 </g>
829 <g id="text_17">
830 <!-- File size (KB) -->
831 <g transform="translate(15.823437 175.197396)rotate(-90)scale(0.1 -0.1)">
832 <defs>
833 <path id="DejaVuSans-Oblique-46" d="M 1081 4666
834L 3756 4666
835L 3653 4134
836L 1606 4134
837L 1338 2759
838L 3188 2759
839L 3084 2228
840L 1234 2228
841L 800 0
842L 172 0
843L 1081 4666
844z
845" transform="scale(0.015625)"/>
846 <path id="DejaVuSans-Oblique-73" d="M 3200 3397
847L 3091 2853
848Q 2863 2978 2609 3040
849Q 2356 3103 2088 3103
850Q 1634 3103 1373 2948
851Q 1113 2794 1113 2528
852Q 1113 2219 1719 2053
853Q 1766 2041 1788 2034
854L 1972 1978
855Q 2547 1819 2739 1644
856Q 2931 1469 2931 1166
857Q 2931 609 2489 259
858Q 2047 -91 1331 -91
859Q 1053 -91 747 -37
860Q 441 16 72 128
861L 184 722
862Q 500 559 806 475
863Q 1113 391 1394 391
864Q 1816 391 2080 572
865Q 2344 753 2344 1031
866Q 2344 1331 1650 1516
867L 1591 1531
868L 1394 1581
869Q 956 1697 753 1886
870Q 550 2075 550 2369
871Q 550 2928 970 3256
872Q 1391 3584 2113 3584
873Q 2397 3584 2667 3537
874Q 2938 3491 3200 3397
875z
876" transform="scale(0.015625)"/>
877 <path id="DejaVuSans-Oblique-28" d="M 2731 4856
878Q 1903 3822 1495 2892
879Q 1088 1963 1088 1100
880Q 1088 606 1206 120
881Q 1325 -366 1563 -844
882L 1063 -844
883Q 775 -306 634 201
884Q 494 709 494 1197
885Q 494 2125 923 3036
886Q 1353 3947 2222 4856
887L 2731 4856
888z
889" transform="scale(0.015625)"/>
890 <path id="DejaVuSans-Oblique-4b" d="M 1081 4666
891L 1716 4666
892L 1331 2700
893L 3781 4666
894L 4622 4666
895L 1850 2438
896L 3878 0
897L 3109 0
898L 1247 2272
899L 806 0
900L 172 0
901L 1081 4666
902z
903" transform="scale(0.015625)"/>
904 <path id="DejaVuSans-Oblique-42" d="M 1081 4666
905L 2694 4666
906Q 3350 4666 3675 4422
907Q 4000 4178 4000 3688
908Q 4000 3238 3720 2911
909Q 3441 2584 2988 2516
910Q 3375 2428 3569 2181
911Q 3763 1934 3763 1522
912Q 3763 819 3242 409
913Q 2722 0 1819 0
914L 172 0
915L 1081 4666
916z
917M 1234 2228
918L 903 519
919L 1919 519
920Q 2491 519 2800 781
921Q 3109 1044 3109 1522
922Q 3109 1891 2904 2059
923Q 2700 2228 2247 2228
924L 1234 2228
925z
926M 1606 4147
927L 1331 2741
928L 2272 2741
929Q 2775 2741 3058 2959
930Q 3341 3178 3341 3566
931Q 3341 3869 3150 4008
932Q 2959 4147 2541 4147
933L 1606 4147
934z
935" transform="scale(0.015625)"/>
936 <path id="DejaVuSans-Oblique-29" d="M -397 -844
937Q 434 191 840 1120
938Q 1247 2050 1247 2913
939Q 1247 3406 1130 3892
940Q 1013 4378 775 4856
941L 1275 4856
942Q 1563 4316 1703 3812
943Q 1844 3309 1844 2822
944Q 1844 1891 1411 973
945Q 978 56 116 -844
946L -397 -844
947z
948" transform="scale(0.015625)"/>
949 </defs>
950 <use xlink:href="#DejaVuSans-Oblique-46"/>
951 <use xlink:href="#DejaVuSans-Oblique-69" x="57.519531"/>
952 <use xlink:href="#DejaVuSans-Oblique-6c" x="85.302734"/>
953 <use xlink:href="#DejaVuSans-Oblique-65" x="113.085938"/>
954 <use xlink:href="#DejaVuSans-Oblique-20" x="174.609375"/>
955 <use xlink:href="#DejaVuSans-Oblique-73" x="206.396484"/>
956 <use xlink:href="#DejaVuSans-Oblique-69" x="258.496094"/>
957 <use xlink:href="#DejaVuSans-Oblique-7a" x="286.279297"/>
958 <use xlink:href="#DejaVuSans-Oblique-65" x="338.769531"/>
959 <use xlink:href="#DejaVuSans-Oblique-20" x="400.292969"/>
960 <use xlink:href="#DejaVuSans-Oblique-28" x="432.080078"/>
961 <use xlink:href="#DejaVuSans-Oblique-4b" x="471.09375"/>
962 <use xlink:href="#DejaVuSans-Oblique-42" x="536.669922"/>
963 <use xlink:href="#DejaVuSans-Oblique-29" x="605.273438"/>
964 </g>
965 </g>
966 </g>
967 <g id="line2d_16">
968 <path d="M 94.770241 246.72438
969L 205.538707 246.705708
970L 316.307173 246.518986
971L 427.075639 244.634781
972L 537.844105 225.96261
973L 648.612571 39.240909
974" clip-path="url(#p7aac08e103)" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/>
975 </g>
976 <g id="line2d_17">
977 <path d="M 94.770241 246.725758
978L 205.538707 246.71984
979L 316.307173 246.664741
980L 427.075639 246.11427
981L 537.844105 240.604449
982L 648.612571 186.526579
983" clip-path="url(#p7aac08e103)" style="fill: none; stroke-dasharray: 5.55,2.4; stroke-dashoffset: 0; stroke: #000000; stroke-width: 1.5"/>
984 </g>
985 <g id="patch_3">
986 <path d="M 67.078125 257.1
987L 67.078125 28.866667
988" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/>
989 </g>
990 <g id="patch_4">
991 <path d="M 676.304688 257.1
992L 676.304688 28.866667
993" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/>
994 </g>
995 <g id="patch_5">
996 <path d="M 67.078125 257.1
997L 676.304688 257.1
998" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/>
999 </g>
1000 <g id="patch_6">
1001 <path d="M 67.078125 28.866667
1002L 676.304688 28.866667
1003" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/>
1004 </g>
1005 <g id="text_18">
1006 <!-- Encode to FASTA out filesize -->
1007 <g transform="translate(287.257344 22.866667)scale(0.12 -0.12)">
1008 <defs>
1009 <path id="DejaVuSans-45" d="M 628 4666
1010L 3578 4666
1011L 3578 4134
1012L 1259 4134
1013L 1259 2753
1014L 3481 2753
1015L 3481 2222
1016L 1259 2222
1017L 1259 531
1018L 3634 531
1019L 3634 0
1020L 628 0
1021L 628 4666
1022z
1023" transform="scale(0.015625)"/>
1024 <path id="DejaVuSans-6e" d="M 3513 2113
1025L 3513 0
1026L 2938 0
1027L 2938 2094
1028Q 2938 2591 2744 2837
1029Q 2550 3084 2163 3084
1030Q 1697 3084 1428 2787
1031Q 1159 2491 1159 1978
1032L 1159 0
1033L 581 0
1034L 581 3500
1035L 1159 3500
1036L 1159 2956
1037Q 1366 3272 1645 3428
1038Q 1925 3584 2291 3584
1039Q 2894 3584 3203 3211
1040Q 3513 2838 3513 2113
1041z
1042" transform="scale(0.015625)"/>
1043 <path id="DejaVuSans-63" d="M 3122 3366
1044L 3122 2828
1045Q 2878 2963 2633 3030
1046Q 2388 3097 2138 3097
1047Q 1578 3097 1268 2742
1048Q 959 2388 959 1747
1049Q 959 1106 1268 751
1050Q 1578 397 2138 397
1051Q 2388 397 2633 464
1052Q 2878 531 3122 666
1053L 3122 134
1054Q 2881 22 2623 -34
1055Q 2366 -91 2075 -91
1056Q 1284 -91 818 406
1057Q 353 903 353 1747
1058Q 353 2603 823 3093
1059Q 1294 3584 2113 3584
1060Q 2378 3584 2631 3529
1061Q 2884 3475 3122 3366
1062z
1063" transform="scale(0.015625)"/>
1064 <path id="DejaVuSans-6f" d="M 1959 3097
1065Q 1497 3097 1228 2736
1066Q 959 2375 959 1747
1067Q 959 1119 1226 758
1068Q 1494 397 1959 397
1069Q 2419 397 2687 759
1070Q 2956 1122 2956 1747
1071Q 2956 2369 2687 2733
1072Q 2419 3097 1959 3097
1073z
1074M 1959 3584
1075Q 2709 3584 3137 3096
1076Q 3566 2609 3566 1747
1077Q 3566 888 3137 398
1078Q 2709 -91 1959 -91
1079Q 1206 -91 779 398
1080Q 353 888 353 1747
1081Q 353 2609 779 3096
1082Q 1206 3584 1959 3584
1083z
1084" transform="scale(0.015625)"/>
1085 <path id="DejaVuSans-64" d="M 2906 2969
1086L 2906 4863
1087L 3481 4863
1088L 3481 0
1089L 2906 0
1090L 2906 525
1091Q 2725 213 2448 61
1092Q 2172 -91 1784 -91
1093Q 1150 -91 751 415
1094Q 353 922 353 1747
1095Q 353 2572 751 3078
1096Q 1150 3584 1784 3584
1097Q 2172 3584 2448 3432
1098Q 2725 3281 2906 2969
1099z
1100M 947 1747
1101Q 947 1113 1208 752
1102Q 1469 391 1925 391
1103Q 2381 391 2643 752
1104Q 2906 1113 2906 1747
1105Q 2906 2381 2643 2742
1106Q 2381 3103 1925 3103
1107Q 1469 3103 1208 2742
1108Q 947 2381 947 1747
1109z
1110" transform="scale(0.015625)"/>
1111 <path id="DejaVuSans-65" d="M 3597 1894
1112L 3597 1613
1113L 953 1613
1114Q 991 1019 1311 708
1115Q 1631 397 2203 397
1116Q 2534 397 2845 478
1117Q 3156 559 3463 722
1118L 3463 178
1119Q 3153 47 2828 -22
1120Q 2503 -91 2169 -91
1121Q 1331 -91 842 396
1122Q 353 884 353 1716
1123Q 353 2575 817 3079
1124Q 1281 3584 2069 3584
1125Q 2775 3584 3186 3129
1126Q 3597 2675 3597 1894
1127z
1128M 3022 2063
1129Q 3016 2534 2758 2815
1130Q 2500 3097 2075 3097
1131Q 1594 3097 1305 2825
1132Q 1016 2553 972 2059
1133L 3022 2063
1134z
1135" transform="scale(0.015625)"/>
1136 <path id="DejaVuSans-20" transform="scale(0.015625)"/>
1137 <path id="DejaVuSans-74" d="M 1172 4494
1138L 1172 3500
1139L 2356 3500
1140L 2356 3053
1141L 1172 3053
1142L 1172 1153
1143Q 1172 725 1289 603
1144Q 1406 481 1766 481
1145L 2356 481
1146L 2356 0
1147L 1766 0
1148Q 1100 0 847 248
1149Q 594 497 594 1153
1150L 594 3053
1151L 172 3053
1152L 172 3500
1153L 594 3500
1154L 594 4494
1155L 1172 4494
1156z
1157" transform="scale(0.015625)"/>
1158 <path id="DejaVuSans-46" d="M 628 4666
1159L 3309 4666
1160L 3309 4134
1161L 1259 4134
1162L 1259 2759
1163L 3109 2759
1164L 3109 2228
1165L 1259 2228
1166L 1259 0
1167L 628 0
1168L 628 4666
1169z
1170" transform="scale(0.015625)"/>
1171 <path id="DejaVuSans-41" d="M 2188 4044
1172L 1331 1722
1173L 3047 1722
1174L 2188 4044
1175z
1176M 1831 4666
1177L 2547 4666
1178L 4325 0
1179L 3669 0
1180L 3244 1197
1181L 1141 1197
1182L 716 0
1183L 50 0
1184L 1831 4666
1185z
1186" transform="scale(0.015625)"/>
1187 <path id="DejaVuSans-53" d="M 3425 4513
1188L 3425 3897
1189Q 3066 4069 2747 4153
1190Q 2428 4238 2131 4238
1191Q 1616 4238 1336 4038
1192Q 1056 3838 1056 3469
1193Q 1056 3159 1242 3001
1194Q 1428 2844 1947 2747
1195L 2328 2669
1196Q 3034 2534 3370 2195
1197Q 3706 1856 3706 1288
1198Q 3706 609 3251 259
1199Q 2797 -91 1919 -91
1200Q 1588 -91 1214 -16
1201Q 841 59 441 206
1202L 441 856
1203Q 825 641 1194 531
1204Q 1563 422 1919 422
1205Q 2459 422 2753 634
1206Q 3047 847 3047 1241
1207Q 3047 1584 2836 1778
1208Q 2625 1972 2144 2069
1209L 1759 2144
1210Q 1053 2284 737 2584
1211Q 422 2884 422 3419
1212Q 422 4038 858 4394
1213Q 1294 4750 2059 4750
1214Q 2388 4750 2728 4690
1215Q 3069 4631 3425 4513
1216z
1217" transform="scale(0.015625)"/>
1218 <path id="DejaVuSans-54" d="M -19 4666
1219L 3928 4666
1220L 3928 4134
1221L 2272 4134
1222L 2272 0
1223L 1638 0
1224L 1638 4134
1225L -19 4134
1226L -19 4666
1227z
1228" transform="scale(0.015625)"/>
1229 <path id="DejaVuSans-75" d="M 544 1381
1230L 544 3500
1231L 1119 3500
1232L 1119 1403
1233Q 1119 906 1312 657
1234Q 1506 409 1894 409
1235Q 2359 409 2629 706
1236Q 2900 1003 2900 1516
1237L 2900 3500
1238L 3475 3500
1239L 3475 0
1240L 2900 0
1241L 2900 538
1242Q 2691 219 2414 64
1243Q 2138 -91 1772 -91
1244Q 1169 -91 856 284
1245Q 544 659 544 1381
1246z
1247M 1991 3584
1248L 1991 3584
1249z
1250" transform="scale(0.015625)"/>
1251 <path id="DejaVuSans-66" d="M 2375 4863
1252L 2375 4384
1253L 1825 4384
1254Q 1516 4384 1395 4259
1255Q 1275 4134 1275 3809
1256L 1275 3500
1257L 2222 3500
1258L 2222 3053
1259L 1275 3053
1260L 1275 0
1261L 697 0
1262L 697 3053
1263L 147 3053
1264L 147 3500
1265L 697 3500
1266L 697 3744
1267Q 697 4328 969 4595
1268Q 1241 4863 1831 4863
1269L 2375 4863
1270z
1271" transform="scale(0.015625)"/>
1272 <path id="DejaVuSans-69" d="M 603 3500
1273L 1178 3500
1274L 1178 0
1275L 603 0
1276L 603 3500
1277z
1278M 603 4863
1279L 1178 4863
1280L 1178 4134
1281L 603 4134
1282L 603 4863
1283z
1284" transform="scale(0.015625)"/>
1285 <path id="DejaVuSans-6c" d="M 603 4863
1286L 1178 4863
1287L 1178 0
1288L 603 0
1289L 603 4863
1290z
1291" transform="scale(0.015625)"/>
1292 <path id="DejaVuSans-73" d="M 2834 3397
1293L 2834 2853
1294Q 2591 2978 2328 3040
1295Q 2066 3103 1784 3103
1296Q 1356 3103 1142 2972
1297Q 928 2841 928 2578
1298Q 928 2378 1081 2264
1299Q 1234 2150 1697 2047
1300L 1894 2003
1301Q 2506 1872 2764 1633
1302Q 3022 1394 3022 966
1303Q 3022 478 2636 193
1304Q 2250 -91 1575 -91
1305Q 1294 -91 989 -36
1306Q 684 19 347 128
1307L 347 722
1308Q 666 556 975 473
1309Q 1284 391 1588 391
1310Q 1994 391 2212 530
1311Q 2431 669 2431 922
1312Q 2431 1156 2273 1281
1313Q 2116 1406 1581 1522
1314L 1381 1569
1315Q 847 1681 609 1914
1316Q 372 2147 372 2553
1317Q 372 3047 722 3315
1318Q 1072 3584 1716 3584
1319Q 2034 3584 2315 3537
1320Q 2597 3491 2834 3397
1321z
1322" transform="scale(0.015625)"/>
1323 <path id="DejaVuSans-7a" d="M 353 3500
1324L 3084 3500
1325L 3084 2975
1326L 922 459
1327L 3084 459
1328L 3084 0
1329L 275 0
1330L 275 525
1331L 2438 3041
1332L 353 3041
1333L 353 3500
1334z
1335" transform="scale(0.015625)"/>
1336 </defs>
1337 <use xlink:href="#DejaVuSans-45"/>
1338 <use xlink:href="#DejaVuSans-6e" x="63.183594"/>
1339 <use xlink:href="#DejaVuSans-63" x="126.5625"/>
1340 <use xlink:href="#DejaVuSans-6f" x="181.542969"/>
1341 <use xlink:href="#DejaVuSans-64" x="242.724609"/>
1342 <use xlink:href="#DejaVuSans-65" x="306.201172"/>
1343 <use xlink:href="#DejaVuSans-20" x="367.724609"/>
1344 <use xlink:href="#DejaVuSans-74" x="399.511719"/>
1345 <use xlink:href="#DejaVuSans-6f" x="438.720703"/>
1346 <use xlink:href="#DejaVuSans-20" x="499.902344"/>
1347 <use xlink:href="#DejaVuSans-46" x="531.689453"/>
1348 <use xlink:href="#DejaVuSans-41" x="580.083984"/>
1349 <use xlink:href="#DejaVuSans-53" x="648.492188"/>
1350 <use xlink:href="#DejaVuSans-54" x="711.96875"/>
1351 <use xlink:href="#DejaVuSans-41" x="765.302734"/>
1352 <use xlink:href="#DejaVuSans-20" x="833.710938"/>
1353 <use xlink:href="#DejaVuSans-6f" x="865.498047"/>
1354 <use xlink:href="#DejaVuSans-75" x="926.679688"/>
1355 <use xlink:href="#DejaVuSans-74" x="990.058594"/>
1356 <use xlink:href="#DejaVuSans-20" x="1029.267578"/>
1357 <use xlink:href="#DejaVuSans-66" x="1061.054688"/>
1358 <use xlink:href="#DejaVuSans-69" x="1096.259766"/>
1359 <use xlink:href="#DejaVuSans-6c" x="1124.042969"/>
1360 <use xlink:href="#DejaVuSans-65" x="1151.826172"/>
1361 <use xlink:href="#DejaVuSans-73" x="1213.349609"/>
1362 <use xlink:href="#DejaVuSans-69" x="1265.449219"/>
1363 <use xlink:href="#DejaVuSans-7a" x="1293.232422"/>
1364 <use xlink:href="#DejaVuSans-65" x="1345.722656"/>
1365 </g>
1366 </g>
1367 <g id="legend_1">
1368 <g id="patch_7">
1369 <path d="M 74.078125 66.222917
1370L 147.051562 66.222917
1371Q 149.051562 66.222917 149.051562 64.222917
1372L 149.051562 35.866667
1373Q 149.051562 33.866667 147.051562 33.866667
1374L 74.078125 33.866667
1375Q 72.078125 33.866667 72.078125 35.866667
1376L 72.078125 64.222917
1377Q 72.078125 66.222917 74.078125 66.222917
1378z
1379" style="fill: #ffffff; opacity: 0.8"/>
1380 </g>
1381 <g id="line2d_18">
1382 <path d="M 76.078125 41.965104
1383L 86.078125 41.965104
1384L 96.078125 41.965104
1385" style="fill: none; stroke: #000000; stroke-width: 1.5; stroke-linecap: square"/>
1386 </g>
1387 <g id="text_19">
1388 <!-- Raw -->
1389 <g transform="translate(104.078125 45.465104)scale(0.1 -0.1)">
1390 <defs>
1391 <path id="DejaVuSans-52" d="M 2841 2188
1392Q 3044 2119 3236 1894
1393Q 3428 1669 3622 1275
1394L 4263 0
1395L 3584 0
1396L 2988 1197
1397Q 2756 1666 2539 1819
1398Q 2322 1972 1947 1972
1399L 1259 1972
1400L 1259 0
1401L 628 0
1402L 628 4666
1403L 2053 4666
1404Q 2853 4666 3247 4331
1405Q 3641 3997 3641 3322
1406Q 3641 2881 3436 2590
1407Q 3231 2300 2841 2188
1408z
1409M 1259 4147
1410L 1259 2491
1411L 2053 2491
1412Q 2509 2491 2742 2702
1413Q 2975 2913 2975 3322
1414Q 2975 3731 2742 3939
1415Q 2509 4147 2053 4147
1416L 1259 4147
1417z
1418" transform="scale(0.015625)"/>
1419 <path id="DejaVuSans-61" d="M 2194 1759
1420Q 1497 1759 1228 1600
1421Q 959 1441 959 1056
1422Q 959 750 1161 570
1423Q 1363 391 1709 391
1424Q 2188 391 2477 730
1425Q 2766 1069 2766 1631
1426L 2766 1759
1427L 2194 1759
1428z
1429M 3341 1997
1430L 3341 0
1431L 2766 0
1432L 2766 531
1433Q 2569 213 2275 61
1434Q 1981 -91 1556 -91
1435Q 1019 -91 701 211
1436Q 384 513 384 1019
1437Q 384 1609 779 1909
1438Q 1175 2209 1959 2209
1439L 2766 2209
1440L 2766 2266
1441Q 2766 2663 2505 2880
1442Q 2244 3097 1772 3097
1443Q 1472 3097 1187 3025
1444Q 903 2953 641 2809
1445L 641 3341
1446Q 956 3463 1253 3523
1447Q 1550 3584 1831 3584
1448Q 2591 3584 2966 3190
1449Q 3341 2797 3341 1997
1450z
1451" transform="scale(0.015625)"/>
1452 <path id="DejaVuSans-77" d="M 269 3500
1453L 844 3500
1454L 1563 769
1455L 2278 3500
1456L 2956 3500
1457L 3675 769
1458L 4391 3500
1459L 4966 3500
1460L 4050 0
1461L 3372 0
1462L 2619 2869
1463L 1863 0
1464L 1184 0
1465L 269 3500
1466z
1467" transform="scale(0.015625)"/>
1468 </defs>
1469 <use xlink:href="#DejaVuSans-52"/>
1470 <use xlink:href="#DejaVuSans-61" x="67.232422"/>
1471 <use xlink:href="#DejaVuSans-77" x="128.511719"/>
1472 </g>
1473 </g>
1474 <g id="line2d_19">
1475 <path d="M 76.078125 56.643229
1476L 86.078125 56.643229
1477L 96.078125 56.643229
1478" style="fill: none; stroke-dasharray: 5.55,2.4; stroke-dashoffset: 0; stroke: #000000; stroke-width: 1.5"/>
1479 </g>
1480 <g id="text_20">
1481 <!-- Gzipped -->
1482 <g transform="translate(104.078125 60.143229)scale(0.1 -0.1)">
1483 <defs>
1484 <path id="DejaVuSans-47" d="M 3809 666
1485L 3809 1919
1486L 2778 1919
1487L 2778 2438
1488L 4434 2438
1489L 4434 434
1490Q 4069 175 3628 42
1491Q 3188 -91 2688 -91
1492Q 1594 -91 976 548
1493Q 359 1188 359 2328
1494Q 359 3472 976 4111
1495Q 1594 4750 2688 4750
1496Q 3144 4750 3555 4637
1497Q 3966 4525 4313 4306
1498L 4313 3634
1499Q 3963 3931 3569 4081
1500Q 3175 4231 2741 4231
1501Q 1884 4231 1454 3753
1502Q 1025 3275 1025 2328
1503Q 1025 1384 1454 906
1504Q 1884 428 2741 428
1505Q 3075 428 3337 486
1506Q 3600 544 3809 666
1507z
1508" transform="scale(0.015625)"/>
1509 <path id="DejaVuSans-70" d="M 1159 525
1510L 1159 -1331
1511L 581 -1331
1512L 581 3500
1513L 1159 3500
1514L 1159 2969
1515Q 1341 3281 1617 3432
1516Q 1894 3584 2278 3584
1517Q 2916 3584 3314 3078
1518Q 3713 2572 3713 1747
1519Q 3713 922 3314 415
1520Q 2916 -91 2278 -91
1521Q 1894 -91 1617 61
1522Q 1341 213 1159 525
1523z
1524M 3116 1747
1525Q 3116 2381 2855 2742
1526Q 2594 3103 2138 3103
1527Q 1681 3103 1420 2742
1528Q 1159 2381 1159 1747
1529Q 1159 1113 1420 752
1530Q 1681 391 2138 391
1531Q 2594 391 2855 752
1532Q 3116 1113 3116 1747
1533z
1534" transform="scale(0.015625)"/>
1535 </defs>
1536 <use xlink:href="#DejaVuSans-47"/>
1537 <use xlink:href="#DejaVuSans-7a" x="77.490234"/>
1538 <use xlink:href="#DejaVuSans-69" x="129.980469"/>
1539 <use xlink:href="#DejaVuSans-70" x="157.763672"/>
1540 <use xlink:href="#DejaVuSans-70" x="221.240234"/>
1541 <use xlink:href="#DejaVuSans-65" x="284.716797"/>
1542 <use xlink:href="#DejaVuSans-64" x="346.240234"/>
1543 </g>
1544 </g>
1545 </g>
1546 </g>
1547 </g>
1548 <defs>
1549 <clipPath id="p7aac08e103">
1550 <rect x="67.078125" y="28.866667" width="609.226562" height="228.233333"/>
1551 </clipPath>
1552 </defs>
1553</svg>
diff --git a/static/posts/dna-sequence/chart-speed.py b/static/posts/dna-sequence/chart-speed.py
deleted file mode 100644
index c07b057..0000000
--- a/static/posts/dna-sequence/chart-speed.py
+++ /dev/null
@@ -1,23 +0,0 @@
1import csv
2
3import matplotlib.pyplot as plt
4import pandas as pd
5
6# Read the data
7df = pd.read_csv("benchmarks.csv")
8
9# Settings
10plt.title("Encode to FASTA speed over time")
11plt.tight_layout(pad=2)
12fig = plt.gcf()
13fig.set_size_inches(10, 4)
14
15# Plotting
16plt.plot(df["Packages"], df["Encode to FASTA (ms)"], label = "ALB", color="black", linestyle="--")
17
18# Adding x and y axis labels
19plt.xlabel("Size of an input file", fontstyle="italic")
20plt.ylabel("Encoding time (ms)", fontstyle="italic")
21
22# Export as SVG
23plt.savefig("chart-speed.svg", format="svg")
diff --git a/static/posts/dna-sequence/chart-speed.svg b/static/posts/dna-sequence/chart-speed.svg
deleted file mode 100644
index 7bb0c29..0000000
--- a/static/posts/dna-sequence/chart-speed.svg
+++ /dev/null
@@ -1,1416 +0,0 @@
1<?xml version="1.0" encoding="utf-8" standalone="no"?>
2<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
3 "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
4<svg xmlns:xlink="http://www.w3.org/1999/xlink" width="720pt" height="288pt" viewBox="0 0 720 288" xmlns="http://www.w3.org/2000/svg" version="1.1">
5 <metadata>
6 <rdf:RDF xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
7 <cc:Work>
8 <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
9 <dc:date>2023-08-05T13:29:20.420382</dc:date>
10 <dc:format>image/svg+xml</dc:format>
11 <dc:creator>
12 <cc:Agent>
13 <dc:title>Matplotlib v3.5.2, https://matplotlib.org/</dc:title>
14 </cc:Agent>
15 </dc:creator>
16 </cc:Work>
17 </rdf:RDF>
18 </metadata>
19 <defs>
20 <style type="text/css">*{stroke-linejoin: round; stroke-linecap: butt}</style>
21 </defs>
22 <g id="figure_1">
23 <g id="patch_1">
24 <path d="M 0 288
25L 720 288
26L 720 0
27L 0 0
28z
29" style="fill: #ffffff"/>
30 </g>
31 <g id="axes_1">
32 <g id="patch_2">
33 <path d="M 67.078125 257.1
34L 676.304688 257.1
35L 676.304688 28.866667
36L 67.078125 28.866667
37z
38" style="fill: #ffffff"/>
39 </g>
40 <g id="matplotlib.axis_1">
41 <g id="xtick_1">
42 <g id="line2d_1">
43 <defs>
44 <path id="md9204da613" d="M 0 0
45L 0 3.5
46" style="stroke: #000000; stroke-width: 0.8"/>
47 </defs>
48 <g>
49 <use xlink:href="#md9204da613" x="94.770241" y="257.1" style="stroke: #000000; stroke-width: 0.8"/>
50 </g>
51 </g>
52 <g id="text_1">
53 <!-- 1KB -->
54 <g transform="translate(84.879616 271.698438)scale(0.1 -0.1)">
55 <defs>
56 <path id="DejaVuSans-31" d="M 794 531
57L 1825 531
58L 1825 4091
59L 703 3866
60L 703 4441
61L 1819 4666
62L 2450 4666
63L 2450 531
64L 3481 531
65L 3481 0
66L 794 0
67L 794 531
68z
69" transform="scale(0.015625)"/>
70 <path id="DejaVuSans-4b" d="M 628 4666
71L 1259 4666
72L 1259 2694
73L 3353 4666
74L 4166 4666
75L 1850 2491
76L 4331 0
77L 3500 0
78L 1259 2247
79L 1259 0
80L 628 0
81L 628 4666
82z
83" transform="scale(0.015625)"/>
84 <path id="DejaVuSans-42" d="M 1259 2228
85L 1259 519
86L 2272 519
87Q 2781 519 3026 730
88Q 3272 941 3272 1375
89Q 3272 1813 3026 2020
90Q 2781 2228 2272 2228
91L 1259 2228
92z
93M 1259 4147
94L 1259 2741
95L 2194 2741
96Q 2656 2741 2882 2914
97Q 3109 3088 3109 3444
98Q 3109 3797 2882 3972
99Q 2656 4147 2194 4147
100L 1259 4147
101z
102M 628 4666
103L 2241 4666
104Q 2963 4666 3353 4366
105Q 3744 4066 3744 3513
106Q 3744 3084 3544 2831
107Q 3344 2578 2956 2516
108Q 3422 2416 3680 2098
109Q 3938 1781 3938 1306
110Q 3938 681 3513 340
111Q 3088 0 2303 0
112L 628 0
113L 628 4666
114z
115" transform="scale(0.015625)"/>
116 </defs>
117 <use xlink:href="#DejaVuSans-31"/>
118 <use xlink:href="#DejaVuSans-4b" x="63.623047"/>
119 <use xlink:href="#DejaVuSans-42" x="129.199219"/>
120 </g>
121 </g>
122 </g>
123 <g id="xtick_2">
124 <g id="line2d_2">
125 <g>
126 <use xlink:href="#md9204da613" x="205.538707" y="257.1" style="stroke: #000000; stroke-width: 0.8"/>
127 </g>
128 </g>
129 <g id="text_2">
130 <!-- 10KB -->
131 <g transform="translate(192.466832 271.698438)scale(0.1 -0.1)">
132 <defs>
133 <path id="DejaVuSans-30" d="M 2034 4250
134Q 1547 4250 1301 3770
135Q 1056 3291 1056 2328
136Q 1056 1369 1301 889
137Q 1547 409 2034 409
138Q 2525 409 2770 889
139Q 3016 1369 3016 2328
140Q 3016 3291 2770 3770
141Q 2525 4250 2034 4250
142z
143M 2034 4750
144Q 2819 4750 3233 4129
145Q 3647 3509 3647 2328
146Q 3647 1150 3233 529
147Q 2819 -91 2034 -91
148Q 1250 -91 836 529
149Q 422 1150 422 2328
150Q 422 3509 836 4129
151Q 1250 4750 2034 4750
152z
153" transform="scale(0.015625)"/>
154 </defs>
155 <use xlink:href="#DejaVuSans-31"/>
156 <use xlink:href="#DejaVuSans-30" x="63.623047"/>
157 <use xlink:href="#DejaVuSans-4b" x="127.246094"/>
158 <use xlink:href="#DejaVuSans-42" x="192.822266"/>
159 </g>
160 </g>
161 </g>
162 <g id="xtick_3">
163 <g id="line2d_3">
164 <g>
165 <use xlink:href="#md9204da613" x="316.307173" y="257.1" style="stroke: #000000; stroke-width: 0.8"/>
166 </g>
167 </g>
168 <g id="text_3">
169 <!-- 100KB -->
170 <g transform="translate(300.054048 271.698438)scale(0.1 -0.1)">
171 <use xlink:href="#DejaVuSans-31"/>
172 <use xlink:href="#DejaVuSans-30" x="63.623047"/>
173 <use xlink:href="#DejaVuSans-30" x="127.246094"/>
174 <use xlink:href="#DejaVuSans-4b" x="190.869141"/>
175 <use xlink:href="#DejaVuSans-42" x="256.445312"/>
176 </g>
177 </g>
178 </g>
179 <g id="xtick_4">
180 <g id="line2d_4">
181 <g>
182 <use xlink:href="#md9204da613" x="427.075639" y="257.1" style="stroke: #000000; stroke-width: 0.8"/>
183 </g>
184 </g>
185 <g id="text_4">
186 <!-- 1MB -->
187 <g transform="translate(416.149858 271.698438)scale(0.1 -0.1)">
188 <defs>
189 <path id="DejaVuSans-4d" d="M 628 4666
190L 1569 4666
191L 2759 1491
192L 3956 4666
193L 4897 4666
194L 4897 0
195L 4281 0
196L 4281 4097
197L 3078 897
198L 2444 897
199L 1241 4097
200L 1241 0
201L 628 0
202L 628 4666
203z
204" transform="scale(0.015625)"/>
205 </defs>
206 <use xlink:href="#DejaVuSans-31"/>
207 <use xlink:href="#DejaVuSans-4d" x="63.623047"/>
208 <use xlink:href="#DejaVuSans-42" x="149.902344"/>
209 </g>
210 </g>
211 </g>
212 <g id="xtick_5">
213 <g id="line2d_5">
214 <g>
215 <use xlink:href="#md9204da613" x="537.844105" y="257.1" style="stroke: #000000; stroke-width: 0.8"/>
216 </g>
217 </g>
218 <g id="text_5">
219 <!-- 10MB -->
220 <g transform="translate(523.737074 271.698438)scale(0.1 -0.1)">
221 <use xlink:href="#DejaVuSans-31"/>
222 <use xlink:href="#DejaVuSans-30" x="63.623047"/>
223 <use xlink:href="#DejaVuSans-4d" x="127.246094"/>
224 <use xlink:href="#DejaVuSans-42" x="213.525391"/>
225 </g>
226 </g>
227 </g>
228 <g id="xtick_6">
229 <g id="line2d_6">
230 <g>
231 <use xlink:href="#md9204da613" x="648.612571" y="257.1" style="stroke: #000000; stroke-width: 0.8"/>
232 </g>
233 </g>
234 <g id="text_6">
235 <!-- 100MB -->
236 <g transform="translate(631.32429 271.698438)scale(0.1 -0.1)">
237 <use xlink:href="#DejaVuSans-31"/>
238 <use xlink:href="#DejaVuSans-30" x="63.623047"/>
239 <use xlink:href="#DejaVuSans-30" x="127.246094"/>
240 <use xlink:href="#DejaVuSans-4d" x="190.869141"/>
241 <use xlink:href="#DejaVuSans-42" x="277.148438"/>
242 </g>
243 </g>
244 </g>
245 <g id="text_7">
246 <!-- Size of an input file -->
247 <g transform="translate(323.542969 285.376562)scale(0.1 -0.1)">
248 <defs>
249 <path id="DejaVuSans-Oblique-53" d="M 3859 4513
250L 3738 3897
251Q 3422 4066 3111 4152
252Q 2800 4238 2509 4238
253Q 1944 4238 1609 3991
254Q 1275 3744 1275 3334
255Q 1275 3109 1398 2989
256Q 1522 2869 2034 2731
257L 2413 2638
258Q 3053 2472 3303 2217
259Q 3553 1963 3553 1503
260Q 3553 797 2998 353
261Q 2444 -91 1538 -91
262Q 1166 -91 791 -17
263Q 416 56 38 206
264L 166 856
265Q 513 641 861 531
266Q 1209 422 1556 422
267Q 2147 422 2503 684
268Q 2859 947 2859 1369
269Q 2859 1650 2717 1795
270Q 2575 1941 2106 2059
271L 1728 2156
272Q 1081 2325 845 2545
273Q 609 2766 609 3163
274Q 609 3859 1145 4304
275Q 1681 4750 2541 4750
276Q 2875 4750 3203 4690
277Q 3531 4631 3859 4513
278z
279" transform="scale(0.015625)"/>
280 <path id="DejaVuSans-Oblique-69" d="M 1172 4863
281L 1747 4863
282L 1606 4134
283L 1031 4134
284L 1172 4863
285z
286M 909 3500
287L 1484 3500
288L 800 0
289L 225 0
290L 909 3500
291z
292" transform="scale(0.015625)"/>
293 <path id="DejaVuSans-Oblique-7a" d="M 744 3500
294L 3475 3500
295L 3372 2975
296L 738 459
297L 2913 459
298L 2822 0
299L -19 0
300L 84 525
301L 2719 3041
302L 653 3041
303L 744 3500
304z
305" transform="scale(0.015625)"/>
306 <path id="DejaVuSans-Oblique-65" d="M 3078 2063
307Q 3088 2113 3092 2166
308Q 3097 2219 3097 2272
309Q 3097 2653 2873 2875
310Q 2650 3097 2266 3097
311Q 1838 3097 1509 2826
312Q 1181 2556 1013 2059
313L 3078 2063
314z
315M 3578 1613
316L 903 1613
317Q 884 1494 878 1425
318Q 872 1356 872 1306
319Q 872 872 1139 634
320Q 1406 397 1894 397
321Q 2269 397 2603 481
322Q 2938 566 3225 728
323L 3116 159
324Q 2806 34 2476 -28
325Q 2147 -91 1806 -91
326Q 1078 -91 686 257
327Q 294 606 294 1247
328Q 294 1794 489 2264
329Q 684 2734 1063 3103
330Q 1306 3334 1642 3459
331Q 1978 3584 2356 3584
332Q 2950 3584 3301 3228
333Q 3653 2872 3653 2272
334Q 3653 2128 3634 1964
335Q 3616 1800 3578 1613
336z
337" transform="scale(0.015625)"/>
338 <path id="DejaVuSans-Oblique-20" transform="scale(0.015625)"/>
339 <path id="DejaVuSans-Oblique-6f" d="M 1625 -91
340Q 1009 -91 651 289
341Q 294 669 294 1325
342Q 294 1706 417 2101
343Q 541 2497 738 2766
344Q 1047 3184 1428 3384
345Q 1809 3584 2291 3584
346Q 2888 3584 3255 3212
347Q 3622 2841 3622 2241
348Q 3622 1825 3500 1412
349Q 3378 1000 3181 728
350Q 2875 309 2494 109
351Q 2113 -91 1625 -91
352z
353M 891 1344
354Q 891 869 1089 633
355Q 1288 397 1691 397
356Q 2269 397 2648 901
357Q 3028 1406 3028 2181
358Q 3028 2634 2825 2865
359Q 2622 3097 2228 3097
360Q 1903 3097 1650 2945
361Q 1397 2794 1197 2484
362Q 1050 2253 970 1956
363Q 891 1659 891 1344
364z
365" transform="scale(0.015625)"/>
366 <path id="DejaVuSans-Oblique-66" d="M 3059 4863
367L 2969 4384
368L 2419 4384
369Q 2106 4384 1964 4261
370Q 1822 4138 1753 3809
371L 1691 3500
372L 2638 3500
373L 2553 3053
374L 1606 3053
375L 1013 0
376L 434 0
377L 1031 3053
378L 481 3053
379L 563 3500
380L 1113 3500
381L 1159 3744
382Q 1278 4363 1576 4613
383Q 1875 4863 2516 4863
384L 3059 4863
385z
386" transform="scale(0.015625)"/>
387 <path id="DejaVuSans-Oblique-61" d="M 3438 1997
388L 3047 0
389L 2472 0
390L 2578 531
391Q 2325 219 2001 64
392Q 1678 -91 1281 -91
393Q 834 -91 548 182
394Q 263 456 263 884
395Q 263 1497 752 1853
396Q 1241 2209 2100 2209
397L 2900 2209
398L 2931 2363
399Q 2938 2388 2941 2417
400Q 2944 2447 2944 2509
401Q 2944 2788 2717 2942
402Q 2491 3097 2081 3097
403Q 1800 3097 1504 3025
404Q 1209 2953 897 2809
405L 997 3341
406Q 1322 3463 1633 3523
407Q 1944 3584 2234 3584
408Q 2853 3584 3176 3315
409Q 3500 3047 3500 2534
410Q 3500 2431 3484 2292
411Q 3469 2153 3438 1997
412z
413M 2816 1759
414L 2241 1759
415Q 1534 1759 1195 1570
416Q 856 1381 856 984
417Q 856 709 1029 553
418Q 1203 397 1509 397
419Q 1978 397 2328 733
420Q 2678 1069 2791 1631
421L 2816 1759
422z
423" transform="scale(0.015625)"/>
424 <path id="DejaVuSans-Oblique-6e" d="M 3566 2113
425L 3156 0
426L 2578 0
427L 2988 2091
428Q 3016 2238 3031 2350
429Q 3047 2463 3047 2528
430Q 3047 2791 2881 2937
431Q 2716 3084 2419 3084
432Q 1956 3084 1622 2776
433Q 1288 2469 1184 1941
434L 800 0
435L 225 0
436L 903 3500
437L 1478 3500
438L 1363 2950
439Q 1603 3253 1940 3418
440Q 2278 3584 2650 3584
441Q 3113 3584 3367 3334
442Q 3622 3084 3622 2631
443Q 3622 2519 3608 2391
444Q 3594 2263 3566 2113
445z
446" transform="scale(0.015625)"/>
447 <path id="DejaVuSans-Oblique-70" d="M 3175 2156
448Q 3175 2616 2975 2859
449Q 2775 3103 2400 3103
450Q 2144 3103 1911 2972
451Q 1678 2841 1497 2591
452Q 1319 2344 1212 1994
453Q 1106 1644 1106 1300
454Q 1106 863 1306 627
455Q 1506 391 1875 391
456Q 2147 391 2380 519
457Q 2613 647 2778 891
458Q 2956 1147 3065 1494
459Q 3175 1841 3175 2156
460z
461M 1394 2969
462Q 1625 3272 1939 3428
463Q 2253 3584 2638 3584
464Q 3175 3584 3472 3232
465Q 3769 2881 3769 2247
466Q 3769 1728 3584 1258
467Q 3400 788 3053 416
468Q 2822 169 2531 39
469Q 2241 -91 1919 -91
470Q 1547 -91 1294 64
471Q 1041 219 916 525
472L 556 -1331
473L -19 -1331
474L 922 3500
475L 1497 3500
476L 1394 2969
477z
478" transform="scale(0.015625)"/>
479 <path id="DejaVuSans-Oblique-75" d="M 428 1388
480L 838 3500
481L 1416 3500
482L 1006 1409
483Q 975 1256 961 1147
484Q 947 1038 947 966
485Q 947 700 1109 554
486Q 1272 409 1569 409
487Q 2031 409 2368 721
488Q 2706 1034 2809 1563
489L 3194 3500
490L 3769 3500
491L 3091 0
492L 2516 0
493L 2631 550
494Q 2388 244 2052 76
495Q 1716 -91 1338 -91
496Q 878 -91 622 161
497Q 366 413 366 863
498Q 366 956 381 1097
499Q 397 1238 428 1388
500z
501" transform="scale(0.015625)"/>
502 <path id="DejaVuSans-Oblique-74" d="M 2706 3500
503L 2619 3053
504L 1472 3053
505L 1100 1153
506Q 1081 1047 1072 975
507Q 1063 903 1063 863
508Q 1063 663 1183 572
509Q 1303 481 1569 481
510L 2150 481
511L 2053 0
512L 1503 0
513Q 991 0 739 200
514Q 488 400 488 806
515Q 488 878 497 964
516Q 506 1050 525 1153
517L 897 3053
518L 409 3053
519L 500 3500
520L 978 3500
521L 1172 4494
522L 1747 4494
523L 1556 3500
524L 2706 3500
525z
526" transform="scale(0.015625)"/>
527 <path id="DejaVuSans-Oblique-6c" d="M 1172 4863
528L 1747 4863
529L 800 0
530L 225 0
531L 1172 4863
532z
533" transform="scale(0.015625)"/>
534 </defs>
535 <use xlink:href="#DejaVuSans-Oblique-53"/>
536 <use xlink:href="#DejaVuSans-Oblique-69" x="63.476562"/>
537 <use xlink:href="#DejaVuSans-Oblique-7a" x="91.259766"/>
538 <use xlink:href="#DejaVuSans-Oblique-65" x="143.75"/>
539 <use xlink:href="#DejaVuSans-Oblique-20" x="205.273438"/>
540 <use xlink:href="#DejaVuSans-Oblique-6f" x="237.060547"/>
541 <use xlink:href="#DejaVuSans-Oblique-66" x="298.242188"/>
542 <use xlink:href="#DejaVuSans-Oblique-20" x="333.447266"/>
543 <use xlink:href="#DejaVuSans-Oblique-61" x="365.234375"/>
544 <use xlink:href="#DejaVuSans-Oblique-6e" x="426.513672"/>
545 <use xlink:href="#DejaVuSans-Oblique-20" x="489.892578"/>
546 <use xlink:href="#DejaVuSans-Oblique-69" x="521.679688"/>
547 <use xlink:href="#DejaVuSans-Oblique-6e" x="549.462891"/>
548 <use xlink:href="#DejaVuSans-Oblique-70" x="612.841797"/>
549 <use xlink:href="#DejaVuSans-Oblique-75" x="676.318359"/>
550 <use xlink:href="#DejaVuSans-Oblique-74" x="739.697266"/>
551 <use xlink:href="#DejaVuSans-Oblique-20" x="778.90625"/>
552 <use xlink:href="#DejaVuSans-Oblique-66" x="810.693359"/>
553 <use xlink:href="#DejaVuSans-Oblique-69" x="845.898438"/>
554 <use xlink:href="#DejaVuSans-Oblique-6c" x="873.681641"/>
555 <use xlink:href="#DejaVuSans-Oblique-65" x="901.464844"/>
556 </g>
557 </g>
558 </g>
559 <g id="matplotlib.axis_2">
560 <g id="ytick_1">
561 <g id="line2d_7">
562 <defs>
563 <path id="mc301ada271" d="M 0 0
564L -3.5 0
565" style="stroke: #000000; stroke-width: 0.8"/>
566 </defs>
567 <g>
568 <use xlink:href="#mc301ada271" x="67.078125" y="246.739405" style="stroke: #000000; stroke-width: 0.8"/>
569 </g>
570 </g>
571 <g id="text_8">
572 <!-- 0 -->
573 <g transform="translate(53.715625 250.538624)scale(0.1 -0.1)">
574 <use xlink:href="#DejaVuSans-30"/>
575 </g>
576 </g>
577 </g>
578 <g id="ytick_2">
579 <g id="line2d_8">
580 <g>
581 <use xlink:href="#mc301ada271" x="67.078125" y="198.216035" style="stroke: #000000; stroke-width: 0.8"/>
582 </g>
583 </g>
584 <g id="text_9">
585 <!-- 20000 -->
586 <g transform="translate(28.265625 202.015253)scale(0.1 -0.1)">
587 <defs>
588 <path id="DejaVuSans-32" d="M 1228 531
589L 3431 531
590L 3431 0
591L 469 0
592L 469 531
593Q 828 903 1448 1529
594Q 2069 2156 2228 2338
595Q 2531 2678 2651 2914
596Q 2772 3150 2772 3378
597Q 2772 3750 2511 3984
598Q 2250 4219 1831 4219
599Q 1534 4219 1204 4116
600Q 875 4013 500 3803
601L 500 4441
602Q 881 4594 1212 4672
603Q 1544 4750 1819 4750
604Q 2544 4750 2975 4387
605Q 3406 4025 3406 3419
606Q 3406 3131 3298 2873
607Q 3191 2616 2906 2266
608Q 2828 2175 2409 1742
609Q 1991 1309 1228 531
610z
611" transform="scale(0.015625)"/>
612 </defs>
613 <use xlink:href="#DejaVuSans-32"/>
614 <use xlink:href="#DejaVuSans-30" x="63.623047"/>
615 <use xlink:href="#DejaVuSans-30" x="127.246094"/>
616 <use xlink:href="#DejaVuSans-30" x="190.869141"/>
617 <use xlink:href="#DejaVuSans-30" x="254.492188"/>
618 </g>
619 </g>
620 </g>
621 <g id="ytick_3">
622 <g id="line2d_9">
623 <g>
624 <use xlink:href="#mc301ada271" x="67.078125" y="149.692664" style="stroke: #000000; stroke-width: 0.8"/>
625 </g>
626 </g>
627 <g id="text_10">
628 <!-- 40000 -->
629 <g transform="translate(28.265625 153.491883)scale(0.1 -0.1)">
630 <defs>
631 <path id="DejaVuSans-34" d="M 2419 4116
632L 825 1625
633L 2419 1625
634L 2419 4116
635z
636M 2253 4666
637L 3047 4666
638L 3047 1625
639L 3713 1625
640L 3713 1100
641L 3047 1100
642L 3047 0
643L 2419 0
644L 2419 1100
645L 313 1100
646L 313 1709
647L 2253 4666
648z
649" transform="scale(0.015625)"/>
650 </defs>
651 <use xlink:href="#DejaVuSans-34"/>
652 <use xlink:href="#DejaVuSans-30" x="63.623047"/>
653 <use xlink:href="#DejaVuSans-30" x="127.246094"/>
654 <use xlink:href="#DejaVuSans-30" x="190.869141"/>
655 <use xlink:href="#DejaVuSans-30" x="254.492188"/>
656 </g>
657 </g>
658 </g>
659 <g id="ytick_4">
660 <g id="line2d_10">
661 <g>
662 <use xlink:href="#mc301ada271" x="67.078125" y="101.169293" style="stroke: #000000; stroke-width: 0.8"/>
663 </g>
664 </g>
665 <g id="text_11">
666 <!-- 60000 -->
667 <g transform="translate(28.265625 104.968512)scale(0.1 -0.1)">
668 <defs>
669 <path id="DejaVuSans-36" d="M 2113 2584
670Q 1688 2584 1439 2293
671Q 1191 2003 1191 1497
672Q 1191 994 1439 701
673Q 1688 409 2113 409
674Q 2538 409 2786 701
675Q 3034 994 3034 1497
676Q 3034 2003 2786 2293
677Q 2538 2584 2113 2584
678z
679M 3366 4563
680L 3366 3988
681Q 3128 4100 2886 4159
682Q 2644 4219 2406 4219
683Q 1781 4219 1451 3797
684Q 1122 3375 1075 2522
685Q 1259 2794 1537 2939
686Q 1816 3084 2150 3084
687Q 2853 3084 3261 2657
688Q 3669 2231 3669 1497
689Q 3669 778 3244 343
690Q 2819 -91 2113 -91
691Q 1303 -91 875 529
692Q 447 1150 447 2328
693Q 447 3434 972 4092
694Q 1497 4750 2381 4750
695Q 2619 4750 2861 4703
696Q 3103 4656 3366 4563
697z
698" transform="scale(0.015625)"/>
699 </defs>
700 <use xlink:href="#DejaVuSans-36"/>
701 <use xlink:href="#DejaVuSans-30" x="63.623047"/>
702 <use xlink:href="#DejaVuSans-30" x="127.246094"/>
703 <use xlink:href="#DejaVuSans-30" x="190.869141"/>
704 <use xlink:href="#DejaVuSans-30" x="254.492188"/>
705 </g>
706 </g>
707 </g>
708 <g id="ytick_5">
709 <g id="line2d_11">
710 <g>
711 <use xlink:href="#mc301ada271" x="67.078125" y="52.645923" style="stroke: #000000; stroke-width: 0.8"/>
712 </g>
713 </g>
714 <g id="text_12">
715 <!-- 80000 -->
716 <g transform="translate(28.265625 56.445141)scale(0.1 -0.1)">
717 <defs>
718 <path id="DejaVuSans-38" d="M 2034 2216
719Q 1584 2216 1326 1975
720Q 1069 1734 1069 1313
721Q 1069 891 1326 650
722Q 1584 409 2034 409
723Q 2484 409 2743 651
724Q 3003 894 3003 1313
725Q 3003 1734 2745 1975
726Q 2488 2216 2034 2216
727z
728M 1403 2484
729Q 997 2584 770 2862
730Q 544 3141 544 3541
731Q 544 4100 942 4425
732Q 1341 4750 2034 4750
733Q 2731 4750 3128 4425
734Q 3525 4100 3525 3541
735Q 3525 3141 3298 2862
736Q 3072 2584 2669 2484
737Q 3125 2378 3379 2068
738Q 3634 1759 3634 1313
739Q 3634 634 3220 271
740Q 2806 -91 2034 -91
741Q 1263 -91 848 271
742Q 434 634 434 1313
743Q 434 1759 690 2068
744Q 947 2378 1403 2484
745z
746M 1172 3481
747Q 1172 3119 1398 2916
748Q 1625 2713 2034 2713
749Q 2441 2713 2670 2916
750Q 2900 3119 2900 3481
751Q 2900 3844 2670 4047
752Q 2441 4250 2034 4250
753Q 1625 4250 1398 4047
754Q 1172 3844 1172 3481
755z
756" transform="scale(0.015625)"/>
757 </defs>
758 <use xlink:href="#DejaVuSans-38"/>
759 <use xlink:href="#DejaVuSans-30" x="63.623047"/>
760 <use xlink:href="#DejaVuSans-30" x="127.246094"/>
761 <use xlink:href="#DejaVuSans-30" x="190.869141"/>
762 <use xlink:href="#DejaVuSans-30" x="254.492188"/>
763 </g>
764 </g>
765 </g>
766 <g id="text_13">
767 <!-- Encoding time (ms) -->
768 <g transform="translate(22.185937 191.877083)rotate(-90)scale(0.1 -0.1)">
769 <defs>
770 <path id="DejaVuSans-Oblique-45" d="M 1081 4666
771L 4031 4666
772L 3928 4134
773L 1606 4134
774L 1338 2753
775L 3566 2753
776L 3463 2222
777L 1234 2222
778L 909 531
779L 3284 531
780L 3181 0
781L 172 0
782L 1081 4666
783z
784" transform="scale(0.015625)"/>
785 <path id="DejaVuSans-Oblique-63" d="M 3431 3366
786L 3316 2797
787Q 3109 2947 2876 3022
788Q 2644 3097 2394 3097
789Q 2119 3097 1870 3000
790Q 1622 2903 1453 2725
791Q 1184 2453 1037 2087
792Q 891 1722 891 1331
793Q 891 859 1127 628
794Q 1363 397 1844 397
795Q 2081 397 2348 469
796Q 2616 541 2906 684
797L 2797 116
798Q 2547 13 2283 -39
799Q 2019 -91 1741 -91
800Q 1044 -91 669 257
801Q 294 606 294 1253
802Q 294 1797 489 2255
803Q 684 2713 1069 3078
804Q 1331 3328 1684 3456
805Q 2038 3584 2456 3584
806Q 2700 3584 2940 3529
807Q 3181 3475 3431 3366
808z
809" transform="scale(0.015625)"/>
810 <path id="DejaVuSans-Oblique-64" d="M 2675 525
811Q 2444 222 2128 65
812Q 1813 -91 1428 -91
813Q 903 -91 598 267
814Q 294 625 294 1247
815Q 294 1766 478 2236
816Q 663 2706 1013 3078
817Q 1244 3325 1534 3454
818Q 1825 3584 2144 3584
819Q 2481 3584 2739 3421
820Q 2997 3259 3138 2956
821L 3513 4863
822L 4091 4863
823L 3144 0
824L 2566 0
825L 2675 525
826z
827M 891 1350
828Q 891 897 1095 644
829Q 1300 391 1663 391
830Q 1931 391 2161 520
831Q 2391 650 2566 903
832Q 2750 1166 2856 1509
833Q 2963 1853 2963 2188
834Q 2963 2622 2758 2865
835Q 2553 3109 2194 3109
836Q 1922 3109 1687 2981
837Q 1453 2853 1288 2613
838Q 1106 2353 998 2009
839Q 891 1666 891 1350
840z
841" transform="scale(0.015625)"/>
842 <path id="DejaVuSans-Oblique-67" d="M 3816 3500
843L 3219 434
844Q 3047 -456 2561 -893
845Q 2075 -1331 1253 -1331
846Q 950 -1331 690 -1286
847Q 431 -1241 206 -1147
848L 313 -588
849Q 525 -725 762 -790
850Q 1000 -856 1269 -856
851Q 1816 -856 2167 -557
852Q 2519 -259 2631 300
853L 2681 563
854Q 2441 288 2122 144
855Q 1803 0 1434 0
856Q 903 0 598 351
857Q 294 703 294 1319
858Q 294 1803 478 2267
859Q 663 2731 997 3091
860Q 1219 3328 1514 3456
861Q 1809 3584 2131 3584
862Q 2484 3584 2746 3420
863Q 3009 3256 3138 2956
864L 3238 3500
865L 3816 3500
866z
867M 2950 2216
868Q 2950 2641 2750 2872
869Q 2550 3103 2181 3103
870Q 1953 3103 1747 3012
871Q 1541 2922 1394 2759
872Q 1156 2491 1023 2127
873Q 891 1763 891 1375
874Q 891 944 1092 712
875Q 1294 481 1672 481
876Q 2219 481 2584 976
877Q 2950 1472 2950 2216
878z
879" transform="scale(0.015625)"/>
880 <path id="DejaVuSans-Oblique-6d" d="M 5747 2113
881L 5338 0
882L 4763 0
883L 5166 2094
884Q 5191 2228 5203 2325
885Q 5216 2422 5216 2491
886Q 5216 2772 5059 2928
887Q 4903 3084 4622 3084
888Q 4203 3084 3875 2770
889Q 3547 2456 3450 1953
890L 3066 0
891L 2491 0
892L 2900 2094
893Q 2925 2209 2937 2307
894Q 2950 2406 2950 2484
895Q 2950 2769 2794 2926
896Q 2638 3084 2363 3084
897Q 1938 3084 1609 2770
898Q 1281 2456 1184 1953
899L 800 0
900L 225 0
901L 909 3500
902L 1484 3500
903L 1375 2956
904Q 1609 3263 1923 3423
905Q 2238 3584 2597 3584
906Q 2978 3584 3223 3384
907Q 3469 3184 3519 2828
908Q 3781 3197 4126 3390
909Q 4472 3584 4856 3584
910Q 5306 3584 5551 3325
911Q 5797 3066 5797 2591
912Q 5797 2488 5784 2364
913Q 5772 2241 5747 2113
914z
915" transform="scale(0.015625)"/>
916 <path id="DejaVuSans-Oblique-28" d="M 2731 4856
917Q 1903 3822 1495 2892
918Q 1088 1963 1088 1100
919Q 1088 606 1206 120
920Q 1325 -366 1563 -844
921L 1063 -844
922Q 775 -306 634 201
923Q 494 709 494 1197
924Q 494 2125 923 3036
925Q 1353 3947 2222 4856
926L 2731 4856
927z
928" transform="scale(0.015625)"/>
929 <path id="DejaVuSans-Oblique-73" d="M 3200 3397
930L 3091 2853
931Q 2863 2978 2609 3040
932Q 2356 3103 2088 3103
933Q 1634 3103 1373 2948
934Q 1113 2794 1113 2528
935Q 1113 2219 1719 2053
936Q 1766 2041 1788 2034
937L 1972 1978
938Q 2547 1819 2739 1644
939Q 2931 1469 2931 1166
940Q 2931 609 2489 259
941Q 2047 -91 1331 -91
942Q 1053 -91 747 -37
943Q 441 16 72 128
944L 184 722
945Q 500 559 806 475
946Q 1113 391 1394 391
947Q 1816 391 2080 572
948Q 2344 753 2344 1031
949Q 2344 1331 1650 1516
950L 1591 1531
951L 1394 1581
952Q 956 1697 753 1886
953Q 550 2075 550 2369
954Q 550 2928 970 3256
955Q 1391 3584 2113 3584
956Q 2397 3584 2667 3537
957Q 2938 3491 3200 3397
958z
959" transform="scale(0.015625)"/>
960 <path id="DejaVuSans-Oblique-29" d="M -397 -844
961Q 434 191 840 1120
962Q 1247 2050 1247 2913
963Q 1247 3406 1130 3892
964Q 1013 4378 775 4856
965L 1275 4856
966Q 1563 4316 1703 3812
967Q 1844 3309 1844 2822
968Q 1844 1891 1411 973
969Q 978 56 116 -844
970L -397 -844
971z
972" transform="scale(0.015625)"/>
973 </defs>
974 <use xlink:href="#DejaVuSans-Oblique-45"/>
975 <use xlink:href="#DejaVuSans-Oblique-6e" x="63.183594"/>
976 <use xlink:href="#DejaVuSans-Oblique-63" x="126.5625"/>
977 <use xlink:href="#DejaVuSans-Oblique-6f" x="181.542969"/>
978 <use xlink:href="#DejaVuSans-Oblique-64" x="242.724609"/>
979 <use xlink:href="#DejaVuSans-Oblique-69" x="306.201172"/>
980 <use xlink:href="#DejaVuSans-Oblique-6e" x="333.984375"/>
981 <use xlink:href="#DejaVuSans-Oblique-67" x="397.363281"/>
982 <use xlink:href="#DejaVuSans-Oblique-20" x="460.839844"/>
983 <use xlink:href="#DejaVuSans-Oblique-74" x="492.626953"/>
984 <use xlink:href="#DejaVuSans-Oblique-69" x="531.835938"/>
985 <use xlink:href="#DejaVuSans-Oblique-6d" x="559.619141"/>
986 <use xlink:href="#DejaVuSans-Oblique-65" x="657.03125"/>
987 <use xlink:href="#DejaVuSans-Oblique-20" x="718.554688"/>
988 <use xlink:href="#DejaVuSans-Oblique-28" x="750.341797"/>
989 <use xlink:href="#DejaVuSans-Oblique-6d" x="789.355469"/>
990 <use xlink:href="#DejaVuSans-Oblique-73" x="886.767578"/>
991 <use xlink:href="#DejaVuSans-Oblique-29" x="938.867188"/>
992 </g>
993 </g>
994 </g>
995 <g id="line2d_12">
996 <path d="M 94.770241 246.725758
997L 205.538707 246.660118
998L 316.307173 246.465577
999L 427.075639 244.621633
1000L 537.844105 226.183224
1001L 648.612571 39.240909
1002" clip-path="url(#p6e18296699)" style="fill: none; stroke-dasharray: 5.55,2.4; stroke-dashoffset: 0; stroke: #000000; stroke-width: 1.5"/>
1003 </g>
1004 <g id="patch_3">
1005 <path d="M 67.078125 257.1
1006L 67.078125 28.866667
1007" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/>
1008 </g>
1009 <g id="patch_4">
1010 <path d="M 676.304688 257.1
1011L 676.304688 28.866667
1012" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/>
1013 </g>
1014 <g id="patch_5">
1015 <path d="M 67.078125 257.1
1016L 676.304688 257.1
1017" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/>
1018 </g>
1019 <g id="patch_6">
1020 <path d="M 67.078125 28.866667
1021L 676.304688 28.866667
1022" style="fill: none; stroke: #000000; stroke-width: 0.8; stroke-linejoin: miter; stroke-linecap: square"/>
1023 </g>
1024 <g id="text_14">
1025 <!-- Encode to FASTA speed over time -->
1026 <g transform="translate(270.883906 22.866667)scale(0.12 -0.12)">
1027 <defs>
1028 <path id="DejaVuSans-45" d="M 628 4666
1029L 3578 4666
1030L 3578 4134
1031L 1259 4134
1032L 1259 2753
1033L 3481 2753
1034L 3481 2222
1035L 1259 2222
1036L 1259 531
1037L 3634 531
1038L 3634 0
1039L 628 0
1040L 628 4666
1041z
1042" transform="scale(0.015625)"/>
1043 <path id="DejaVuSans-6e" d="M 3513 2113
1044L 3513 0
1045L 2938 0
1046L 2938 2094
1047Q 2938 2591 2744 2837
1048Q 2550 3084 2163 3084
1049Q 1697 3084 1428 2787
1050Q 1159 2491 1159 1978
1051L 1159 0
1052L 581 0
1053L 581 3500
1054L 1159 3500
1055L 1159 2956
1056Q 1366 3272 1645 3428
1057Q 1925 3584 2291 3584
1058Q 2894 3584 3203 3211
1059Q 3513 2838 3513 2113
1060z
1061" transform="scale(0.015625)"/>
1062 <path id="DejaVuSans-63" d="M 3122 3366
1063L 3122 2828
1064Q 2878 2963 2633 3030
1065Q 2388 3097 2138 3097
1066Q 1578 3097 1268 2742
1067Q 959 2388 959 1747
1068Q 959 1106 1268 751
1069Q 1578 397 2138 397
1070Q 2388 397 2633 464
1071Q 2878 531 3122 666
1072L 3122 134
1073Q 2881 22 2623 -34
1074Q 2366 -91 2075 -91
1075Q 1284 -91 818 406
1076Q 353 903 353 1747
1077Q 353 2603 823 3093
1078Q 1294 3584 2113 3584
1079Q 2378 3584 2631 3529
1080Q 2884 3475 3122 3366
1081z
1082" transform="scale(0.015625)"/>
1083 <path id="DejaVuSans-6f" d="M 1959 3097
1084Q 1497 3097 1228 2736
1085Q 959 2375 959 1747
1086Q 959 1119 1226 758
1087Q 1494 397 1959 397
1088Q 2419 397 2687 759
1089Q 2956 1122 2956 1747
1090Q 2956 2369 2687 2733
1091Q 2419 3097 1959 3097
1092z
1093M 1959 3584
1094Q 2709 3584 3137 3096
1095Q 3566 2609 3566 1747
1096Q 3566 888 3137 398
1097Q 2709 -91 1959 -91
1098Q 1206 -91 779 398
1099Q 353 888 353 1747
1100Q 353 2609 779 3096
1101Q 1206 3584 1959 3584
1102z
1103" transform="scale(0.015625)"/>
1104 <path id="DejaVuSans-64" d="M 2906 2969
1105L 2906 4863
1106L 3481 4863
1107L 3481 0
1108L 2906 0
1109L 2906 525
1110Q 2725 213 2448 61
1111Q 2172 -91 1784 -91
1112Q 1150 -91 751 415
1113Q 353 922 353 1747
1114Q 353 2572 751 3078
1115Q 1150 3584 1784 3584
1116Q 2172 3584 2448 3432
1117Q 2725 3281 2906 2969
1118z
1119M 947 1747
1120Q 947 1113 1208 752
1121Q 1469 391 1925 391
1122Q 2381 391 2643 752
1123Q 2906 1113 2906 1747
1124Q 2906 2381 2643 2742
1125Q 2381 3103 1925 3103
1126Q 1469 3103 1208 2742
1127Q 947 2381 947 1747
1128z
1129" transform="scale(0.015625)"/>
1130 <path id="DejaVuSans-65" d="M 3597 1894
1131L 3597 1613
1132L 953 1613
1133Q 991 1019 1311 708
1134Q 1631 397 2203 397
1135Q 2534 397 2845 478
1136Q 3156 559 3463 722
1137L 3463 178
1138Q 3153 47 2828 -22
1139Q 2503 -91 2169 -91
1140Q 1331 -91 842 396
1141Q 353 884 353 1716
1142Q 353 2575 817 3079
1143Q 1281 3584 2069 3584
1144Q 2775 3584 3186 3129
1145Q 3597 2675 3597 1894
1146z
1147M 3022 2063
1148Q 3016 2534 2758 2815
1149Q 2500 3097 2075 3097
1150Q 1594 3097 1305 2825
1151Q 1016 2553 972 2059
1152L 3022 2063
1153z
1154" transform="scale(0.015625)"/>
1155 <path id="DejaVuSans-20" transform="scale(0.015625)"/>
1156 <path id="DejaVuSans-74" d="M 1172 4494
1157L 1172 3500
1158L 2356 3500
1159L 2356 3053
1160L 1172 3053
1161L 1172 1153
1162Q 1172 725 1289 603
1163Q 1406 481 1766 481
1164L 2356 481
1165L 2356 0
1166L 1766 0
1167Q 1100 0 847 248
1168Q 594 497 594 1153
1169L 594 3053
1170L 172 3053
1171L 172 3500
1172L 594 3500
1173L 594 4494
1174L 1172 4494
1175z
1176" transform="scale(0.015625)"/>
1177 <path id="DejaVuSans-46" d="M 628 4666
1178L 3309 4666
1179L 3309 4134
1180L 1259 4134
1181L 1259 2759
1182L 3109 2759
1183L 3109 2228
1184L 1259 2228
1185L 1259 0
1186L 628 0
1187L 628 4666
1188z
1189" transform="scale(0.015625)"/>
1190 <path id="DejaVuSans-41" d="M 2188 4044
1191L 1331 1722
1192L 3047 1722
1193L 2188 4044
1194z
1195M 1831 4666
1196L 2547 4666
1197L 4325 0
1198L 3669 0
1199L 3244 1197
1200L 1141 1197
1201L 716 0
1202L 50 0
1203L 1831 4666
1204z
1205" transform="scale(0.015625)"/>
1206 <path id="DejaVuSans-53" d="M 3425 4513
1207L 3425 3897
1208Q 3066 4069 2747 4153
1209Q 2428 4238 2131 4238
1210Q 1616 4238 1336 4038
1211Q 1056 3838 1056 3469
1212Q 1056 3159 1242 3001
1213Q 1428 2844 1947 2747
1214L 2328 2669
1215Q 3034 2534 3370 2195
1216Q 3706 1856 3706 1288
1217Q 3706 609 3251 259
1218Q 2797 -91 1919 -91
1219Q 1588 -91 1214 -16
1220Q 841 59 441 206
1221L 441 856
1222Q 825 641 1194 531
1223Q 1563 422 1919 422
1224Q 2459 422 2753 634
1225Q 3047 847 3047 1241
1226Q 3047 1584 2836 1778
1227Q 2625 1972 2144 2069
1228L 1759 2144
1229Q 1053 2284 737 2584
1230Q 422 2884 422 3419
1231Q 422 4038 858 4394
1232Q 1294 4750 2059 4750
1233Q 2388 4750 2728 4690
1234Q 3069 4631 3425 4513
1235z
1236" transform="scale(0.015625)"/>
1237 <path id="DejaVuSans-54" d="M -19 4666
1238L 3928 4666
1239L 3928 4134
1240L 2272 4134
1241L 2272 0
1242L 1638 0
1243L 1638 4134
1244L -19 4134
1245L -19 4666
1246z
1247" transform="scale(0.015625)"/>
1248 <path id="DejaVuSans-73" d="M 2834 3397
1249L 2834 2853
1250Q 2591 2978 2328 3040
1251Q 2066 3103 1784 3103
1252Q 1356 3103 1142 2972
1253Q 928 2841 928 2578
1254Q 928 2378 1081 2264
1255Q 1234 2150 1697 2047
1256L 1894 2003
1257Q 2506 1872 2764 1633
1258Q 3022 1394 3022 966
1259Q 3022 478 2636 193
1260Q 2250 -91 1575 -91
1261Q 1294 -91 989 -36
1262Q 684 19 347 128
1263L 347 722
1264Q 666 556 975 473
1265Q 1284 391 1588 391
1266Q 1994 391 2212 530
1267Q 2431 669 2431 922
1268Q 2431 1156 2273 1281
1269Q 2116 1406 1581 1522
1270L 1381 1569
1271Q 847 1681 609 1914
1272Q 372 2147 372 2553
1273Q 372 3047 722 3315
1274Q 1072 3584 1716 3584
1275Q 2034 3584 2315 3537
1276Q 2597 3491 2834 3397
1277z
1278" transform="scale(0.015625)"/>
1279 <path id="DejaVuSans-70" d="M 1159 525
1280L 1159 -1331
1281L 581 -1331
1282L 581 3500
1283L 1159 3500
1284L 1159 2969
1285Q 1341 3281 1617 3432
1286Q 1894 3584 2278 3584
1287Q 2916 3584 3314 3078
1288Q 3713 2572 3713 1747
1289Q 3713 922 3314 415
1290Q 2916 -91 2278 -91
1291Q 1894 -91 1617 61
1292Q 1341 213 1159 525
1293z
1294M 3116 1747
1295Q 3116 2381 2855 2742
1296Q 2594 3103 2138 3103
1297Q 1681 3103 1420 2742
1298Q 1159 2381 1159 1747
1299Q 1159 1113 1420 752
1300Q 1681 391 2138 391
1301Q 2594 391 2855 752
1302Q 3116 1113 3116 1747
1303z
1304" transform="scale(0.015625)"/>
1305 <path id="DejaVuSans-76" d="M 191 3500
1306L 800 3500
1307L 1894 563
1308L 2988 3500
1309L 3597 3500
1310L 2284 0
1311L 1503 0
1312L 191 3500
1313z
1314" transform="scale(0.015625)"/>
1315 <path id="DejaVuSans-72" d="M 2631 2963
1316Q 2534 3019 2420 3045
1317Q 2306 3072 2169 3072
1318Q 1681 3072 1420 2755
1319Q 1159 2438 1159 1844
1320L 1159 0
1321L 581 0
1322L 581 3500
1323L 1159 3500
1324L 1159 2956
1325Q 1341 3275 1631 3429
1326Q 1922 3584 2338 3584
1327Q 2397 3584 2469 3576
1328Q 2541 3569 2628 3553
1329L 2631 2963
1330z
1331" transform="scale(0.015625)"/>
1332 <path id="DejaVuSans-69" d="M 603 3500
1333L 1178 3500
1334L 1178 0
1335L 603 0
1336L 603 3500
1337z
1338M 603 4863
1339L 1178 4863
1340L 1178 4134
1341L 603 4134
1342L 603 4863
1343z
1344" transform="scale(0.015625)"/>
1345 <path id="DejaVuSans-6d" d="M 3328 2828
1346Q 3544 3216 3844 3400
1347Q 4144 3584 4550 3584
1348Q 5097 3584 5394 3201
1349Q 5691 2819 5691 2113
1350L 5691 0
1351L 5113 0
1352L 5113 2094
1353Q 5113 2597 4934 2840
1354Q 4756 3084 4391 3084
1355Q 3944 3084 3684 2787
1356Q 3425 2491 3425 1978
1357L 3425 0
1358L 2847 0
1359L 2847 2094
1360Q 2847 2600 2669 2842
1361Q 2491 3084 2119 3084
1362Q 1678 3084 1418 2786
1363Q 1159 2488 1159 1978
1364L 1159 0
1365L 581 0
1366L 581 3500
1367L 1159 3500
1368L 1159 2956
1369Q 1356 3278 1631 3431
1370Q 1906 3584 2284 3584
1371Q 2666 3584 2933 3390
1372Q 3200 3197 3328 2828
1373z
1374" transform="scale(0.015625)"/>
1375 </defs>
1376 <use xlink:href="#DejaVuSans-45"/>
1377 <use xlink:href="#DejaVuSans-6e" x="63.183594"/>
1378 <use xlink:href="#DejaVuSans-63" x="126.5625"/>
1379 <use xlink:href="#DejaVuSans-6f" x="181.542969"/>
1380 <use xlink:href="#DejaVuSans-64" x="242.724609"/>
1381 <use xlink:href="#DejaVuSans-65" x="306.201172"/>
1382 <use xlink:href="#DejaVuSans-20" x="367.724609"/>
1383 <use xlink:href="#DejaVuSans-74" x="399.511719"/>
1384 <use xlink:href="#DejaVuSans-6f" x="438.720703"/>
1385 <use xlink:href="#DejaVuSans-20" x="499.902344"/>
1386 <use xlink:href="#DejaVuSans-46" x="531.689453"/>
1387 <use xlink:href="#DejaVuSans-41" x="580.083984"/>
1388 <use xlink:href="#DejaVuSans-53" x="648.492188"/>
1389 <use xlink:href="#DejaVuSans-54" x="711.96875"/>
1390 <use xlink:href="#DejaVuSans-41" x="765.302734"/>
1391 <use xlink:href="#DejaVuSans-20" x="833.710938"/>
1392 <use xlink:href="#DejaVuSans-73" x="865.498047"/>
1393 <use xlink:href="#DejaVuSans-70" x="917.597656"/>
1394 <use xlink:href="#DejaVuSans-65" x="981.074219"/>
1395 <use xlink:href="#DejaVuSans-65" x="1042.597656"/>
1396 <use xlink:href="#DejaVuSans-64" x="1104.121094"/>
1397 <use xlink:href="#DejaVuSans-20" x="1167.597656"/>
1398 <use xlink:href="#DejaVuSans-6f" x="1199.384766"/>
1399 <use xlink:href="#DejaVuSans-76" x="1260.566406"/>
1400 <use xlink:href="#DejaVuSans-65" x="1319.746094"/>
1401 <use xlink:href="#DejaVuSans-72" x="1381.269531"/>
1402 <use xlink:href="#DejaVuSans-20" x="1422.382812"/>
1403 <use xlink:href="#DejaVuSans-74" x="1454.169922"/>
1404 <use xlink:href="#DejaVuSans-69" x="1493.378906"/>
1405 <use xlink:href="#DejaVuSans-6d" x="1521.162109"/>
1406 <use xlink:href="#DejaVuSans-65" x="1618.574219"/>
1407 </g>
1408 </g>
1409 </g>
1410 </g>
1411 <defs>
1412 <clipPath id="p6e18296699">
1413 <rect x="67.078125" y="28.866667" width="609.226562" height="228.233333"/>
1414 </clipPath>
1415 </defs>
1416</svg>
diff --git a/static/posts/dna-sequence/dna-basics.jpg b/static/posts/dna-sequence/dna-basics.jpg
deleted file mode 100755
index c2e7f52..0000000
--- a/static/posts/dna-sequence/dna-basics.jpg
+++ /dev/null
Binary files differ
diff --git a/static/posts/dna-sequence/quote.png b/static/posts/dna-sequence/quote.png
deleted file mode 100755
index 09fb01c..0000000
--- a/static/posts/dna-sequence/quote.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/dna-sequence/sample-binary-file.png b/static/posts/dna-sequence/sample-binary-file.png
deleted file mode 100755
index 1e4622a..0000000
--- a/static/posts/dna-sequence/sample-binary-file.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/dna-sequence/sample.png b/static/posts/dna-sequence/sample.png
deleted file mode 100755
index 30f12da..0000000
--- a/static/posts/dna-sequence/sample.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/dna-synthesized/bison/in.txt b/static/posts/dna-synthesized/bison/in.txt
deleted file mode 100755
index fd1eea6..0000000
--- a/static/posts/dna-synthesized/bison/in.txt
+++ /dev/null
@@ -1,11 +0,0 @@
1GGTCAGCCCAAATCCGCACCCTCGGTCACCCTGTTTCCGCCCTCCACGGAGGAGCTCACT
2GCCAACAAGGCCACCCTGGTGTGTCTCATCAGCGACTTCTACCCGGGTAGCGTGACCGTG
3GCCTGGAAGGCAGACGGCAGCACCATCACCCGCAACGTGGAGACCACCCGGGCCTCCAAA
4CAGAGCAACAGCAAGTACGCGAAAAGCGGTTACAGCTGCGAGGTCACGCACGAGGGGAGC
5ACCGTGACGAAGACAGTGAAGCCCTCAGCGTGTCAGCCCAAGTCCGCACCCTTGGTCACC
6CTGTTCCCGCCCTCCAAGGAGGAGCTCAGCGCCAACAAGGCCACCCTGGTGTGTCTCATC
7AGCGACTTCTACCCGGGTAGCGTGACCGTGGTCTGGAAGGCAGACGGCAGCACCATCACC
8CGCAACGTGGAGACCACCCGGGCCTCCAAACAGAGCAACAGCAAGTACGCGGCCAGCAGC
9TACCTGAGCCTGACGGGCAGCGACTGGAAATCGAAAGGCAGTTACAGCTGCGAGGTCACG
10CACGAGGGGAGCACCGTGACGAAGACAGTGAAGGTCTCAGAGTGTCAGCCCAAGTCCGCA
11
diff --git a/static/posts/dna-synthesized/bison/out.mp3 b/static/posts/dna-synthesized/bison/out.mp3
deleted file mode 100755
index d6408ca..0000000
--- a/static/posts/dna-synthesized/bison/out.mp3
+++ /dev/null
Binary files differ
diff --git a/static/posts/dna-synthesized/bison/spectogram.png b/static/posts/dna-synthesized/bison/spectogram.png
deleted file mode 100755
index 959902b..0000000
--- a/static/posts/dna-synthesized/bison/spectogram.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/dna-synthesized/elektron/IMG_0619.jpg b/static/posts/dna-synthesized/elektron/IMG_0619.jpg
deleted file mode 100755
index ebf60b0..0000000
--- a/static/posts/dna-synthesized/elektron/IMG_0619.jpg
+++ /dev/null
Binary files differ
diff --git a/static/posts/dna-synthesized/elektron/IMG_0620.jpg b/static/posts/dna-synthesized/elektron/IMG_0620.jpg
deleted file mode 100755
index c9aa398..0000000
--- a/static/posts/dna-synthesized/elektron/IMG_0620.jpg
+++ /dev/null
Binary files differ
diff --git a/static/posts/dna-synthesized/elektron/IMG_0622.jpg b/static/posts/dna-synthesized/elektron/IMG_0622.jpg
deleted file mode 100755
index 98acee4..0000000
--- a/static/posts/dna-synthesized/elektron/IMG_0622.jpg
+++ /dev/null
Binary files differ
diff --git a/static/posts/dna-synthesized/elektron/elektron.mp4 b/static/posts/dna-synthesized/elektron/elektron.mp4
deleted file mode 100755
index f8e39b9..0000000
--- a/static/posts/dna-synthesized/elektron/elektron.mp4
+++ /dev/null
Binary files differ
diff --git a/static/posts/dna-synthesized/elektron/midi-studio.jpg b/static/posts/dna-synthesized/elektron/midi-studio.jpg
deleted file mode 100755
index 59075cd..0000000
--- a/static/posts/dna-synthesized/elektron/midi-studio.jpg
+++ /dev/null
Binary files differ
diff --git a/static/posts/dna-synthesized/mouse/in.txt b/static/posts/dna-synthesized/mouse/in.txt
deleted file mode 100755
index abd34a2..0000000
--- a/static/posts/dna-synthesized/mouse/in.txt
+++ /dev/null
@@ -1,9 +0,0 @@
1GAATTCTCAGGGCCTGTGATGGTCTATACTGCATGGCATATCAGTGTAGAGAAAATAAAT
2AGACACAAGCTCCAATCCCAAACCCAGAAACTATTAATAACAAACGAAAAATTAGTTCTC
3TCAAATGAAGTCTCCCTGAGGATACAGATCCCATTCAGATGGGCAGGTCTGCAGGCCAAC
4ACAAAATGAACTCAGGGGCCTCTTTGGAGGTCTTAGGTCTCATAATGTTTTGTCAGGCCT
5TTTATCTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTGCTTATTTATCTTAAAACCCACTA
6GCTGTTCTCTCCAGGGTCACACCCTAGCACACTCCGTCTAGGTGCCTTCTTACCATCTCC
7TCTAAGTGAGTGGAGGCTCCCTGTGTATTTCCACACCCTTGTACTTTAAGTATTTTCAAG
8GCAGGGCATATCCTCTCTCACTGAGTCCAGACAAAGCAGCTCAAATAGAAGAACATGTCC
9CACATACAGGCAACAGATTTTGAAGGAGGCCTCCACTCCAGCTGTTAGGGGACCCACATG
diff --git a/static/posts/dna-synthesized/mouse/out.mp3 b/static/posts/dna-synthesized/mouse/out.mp3
deleted file mode 100755
index e66e87b..0000000
--- a/static/posts/dna-synthesized/mouse/out.mp3
+++ /dev/null
Binary files differ
diff --git a/static/posts/dna-synthesized/mouse/spectogram.png b/static/posts/dna-synthesized/mouse/spectogram.png
deleted file mode 100755
index 8b7f63f..0000000
--- a/static/posts/dna-synthesized/mouse/spectogram.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/dna-synthesized/quote/in.txt b/static/posts/dna-synthesized/quote/in.txt
deleted file mode 100755
index 81e8eb9..0000000
--- a/static/posts/dna-synthesized/quote/in.txt
+++ /dev/null
@@ -1,8 +0,0 @@
1GACAGCTTGTGTACAAGTGTGCTTGCTCGCGAGCGGGTACGCGCGTGGGCTAACAAGTGA
2GCCAGCAGGTGAACAAGTGTGCGGACAAGCCAGCAGGTGCGCGGACAAGCTGGCGGGTGA
3ACAAGTGTGCCGGTGAGCCAACAAGCAGACAAGTAAGCAGGTACGCAGGCGAGCTTGTCA
4ACTCACAAGATCGCTTGTGTACAAGTGTGCGGACAAGCCAGCAGGTGCGCGGACAAGTAT
5GCTTGCTGGCGGACAAGCCAGCTTGTAAGCGGACAAGCTTGCGCACAAGCTGGCAGGCCT
6GCCGGCTCGCGTACAAATTCACAAGTAAGTACGCTTGCGTGTACGCGGGTATGTATACTC
7AACCTCACCAAACGGGACAAGATCGCCGGCGGGCTAGTATACAAGAACGCTTGCCAGTAC
8AACC \ No newline at end of file
diff --git a/static/posts/dna-synthesized/quote/out.mp3 b/static/posts/dna-synthesized/quote/out.mp3
deleted file mode 100755
index 985871d..0000000
--- a/static/posts/dna-synthesized/quote/out.mp3
+++ /dev/null
Binary files differ
diff --git a/static/posts/dna-synthesized/quote/spectogram.png b/static/posts/dna-synthesized/quote/spectogram.png
deleted file mode 100755
index c460ffd..0000000
--- a/static/posts/dna-synthesized/quote/spectogram.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/dna-synthesized/symphony-no6-1st-movement.mp3 b/static/posts/dna-synthesized/symphony-no6-1st-movement.mp3
deleted file mode 100755
index 8c5a609..0000000
--- a/static/posts/dna-synthesized/symphony-no6-1st-movement.mp3
+++ /dev/null
Binary files differ
diff --git a/static/posts/dna-synthesized/symphony-no6-1st-movement.png b/static/posts/dna-synthesized/symphony-no6-1st-movement.png
deleted file mode 100755
index 8269f08..0000000
--- a/static/posts/dna-synthesized/symphony-no6-1st-movement.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/dna-synthesized/taurus/in.txt b/static/posts/dna-synthesized/taurus/in.txt
deleted file mode 100755
index 8c5bddb..0000000
--- a/static/posts/dna-synthesized/taurus/in.txt
+++ /dev/null
@@ -1,11 +0,0 @@
1GGTCAGCCCAAGTCCCCACCCTCGGTCACCCTGTTCCCGCCCTCCAAGGAGGAGCTCAGC
2GCCAACAAGGCCACCCTGGTGTGTCTCATCAGCGACTTCTACCCGGGTAGCGTGACCGTG
3GCCTGGAAGGCAGACGGCAGCACCATCACCCGCAACGTGGAGACCACCCGGGCCTCCAAA
4CAGAGCAACAGCAAGTACGCGGCCAGCAGCTACCTGAGCCTGACGAGCAGCGACTGGAAA
5TCGAAAGGCAGTTACAGCTGCGAGGTCACGCACGAGGGGAGCACCGTGACGAAGACAGTG
6AAGACCTCAGCGTGTCAGCCCAAGTCCCCACCCTCGGTCACCCTGTTCCCGCCCTCCACG
7GAGGAGCTCAACGGCAACAAGGCCACCCTGGTGTGTCTCATCAGCGACTTCTACCCGGGT
8AGCGTGACCGTGGTCTGGAAGGCAGACGGCAGCACCATCACCCGCAACGTGGAGACCACC
9CGGGCCTCCAAACAGAGCAACAGCAAGTACGCGGCCAGCAGCTACCTGAGCCTGACGAGC
10AGCGACTGGAAATCGAAAGGCAGTTACAGCTGCGAGGTCACGCACGAGGGGAGCACCGTG
11ACGAAGACAGTGAAGCCCTCAGAGTGGCCCTGGGCCCCCACCGCCGTCCCCACCCTCGTC
diff --git a/static/posts/dna-synthesized/taurus/out.mp3 b/static/posts/dna-synthesized/taurus/out.mp3
deleted file mode 100755
index ea7ae1a..0000000
--- a/static/posts/dna-synthesized/taurus/out.mp3
+++ /dev/null
Binary files differ
diff --git a/static/posts/dna-synthesized/taurus/spectogram.png b/static/posts/dna-synthesized/taurus/spectogram.png
deleted file mode 100755
index 3be9b58..0000000
--- a/static/posts/dna-synthesized/taurus/spectogram.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/do-fuse/copy-benchmarks.tsv b/static/posts/do-fuse/copy-benchmarks.tsv
deleted file mode 100755
index c7a7af4..0000000
--- a/static/posts/do-fuse/copy-benchmarks.tsv
+++ /dev/null
@@ -1,101 +0,0 @@
110KB 100KB 1MB 10MB
20.15 0.187 0.317 0.653
30.158 0.237 0.192 0.659
40.134 0.359 0.236 0.604
50.136 0.292 0.196 0.501
64.411 4.479 4.376 0.649
70.134 0.481 0.265 0.608
80.146 0.266 0.28 0.516
94.282 0.307 4.549 0.562
100.152 0.28 0.229 0.512
110.162 0.37 0.315 0.652
120.13 4.735 0.222 5.171
134.29 8.767 0.283 5.076
144.555 4.682 0.318 4.941
154.658 4.691 0.177 9.624
164.778 4.791 4.415 5.114
178.794 8.604 0.311 5.223
184.582 4.727 0.234 9.28
194.596 4.638 0.212 5.064
204.7 4.65 4.458 5.221
218.822 9.159 0.191 5.032
224.628 4.641 0.324 9.226
234.6 4.921 0.197 5.22
248.85 4.58 4.405 5.245
254.65 9.142 0.215 5.168
264.884 6.67 0.248 9.273
274.581 4.594 0.248 5.082
288.864 4.844 4.502 5.121
294.704 4.656 0.177 5.173
304.616 8.883 0.209 9.334
314.729 4.962 4.366 4.966
328.918 4.682 0.186 6.702
334.686 4.58 0.168 5.111
345.123 8.84 4.747 5.084
354.846 4.732 8.85 5.065
368.887 4.639 4.824 9.286
374.681 8.897 4.791 5.104
384.649 4.682 4.835 5.194
398.847 4.663 8.929 5.271
404.568 4.604 4.762 9.444
414.657 8.74 4.772 5.076
424.636 4.724 4.838 5.168
438.778 4.846 9.065 5.057
444.995 4.571 5.074 9.314
452.343 9.222 4.818 5.732
464.742 4.646 8.909 5.32
474.82 4.842 4.778 5.167
488.791 4.66 4.759 5.157
494.835 8.944 4.804 9.323
504.599 5.594 8.952 5.299
514.809 4.628 1.567 5.294
528.744 4.771 5.59 5.018
534.71 8.919 4.771 9.257
544.704 4.7 9.003 5.064
554.765 4.605 4.781 5.185
568.866 4.669 4.844 5.392
574.897 8.925 4.786 9.279
584.568 5.168 8.893 5.1
594.679 4.757 5.41 5.232
608.922 4.702 4.7 1.984
614.669 8.721 4.906 5.366
624.707 4.555 8.96 5.245
638.938 4.615 4.89 5.216
644.608 4.621 4.677 9.237
654.58 8.954 4.908 5.194
664.707 4.575 8.968 5.017
678.822 4.781 4.882 9.714
684.674 8.833 4.834 5.02
695.005 4.689 4.762 5.312
704.732 4.799 9.111 5.286
718.894 4.675 4.936 5.185
724.747 8.764 4.739 9.312
734.785 4.749 4.845 5.34
744.656 4.705 9.181 5.256
758.899 4.601 4.739 5.261
764.594 8.813 4.576 9.329
774.585 4.716 8.813 5.343
788.718 4.723 4.819 5.092
794.725 4.757 4.83 5.061
804.737 8.899 4.772 9.488
814.692 4.717 8.831 5.13
828.841 4.951 4.787 5.309
834.66 8.895 4.746 5.228
844.749 4.595 4.833 5.26
854.715 4.615 8.928 9.381
868.849 4.651 4.826 5.289
874.66 8.897 4.802 5.197
884.588 4.844 4.883 9.311
894.753 4.888 9.053 5.072
908.841 4.737 4.75 5.157
914.794 8.976 5.063 5.196
924.544 4.673 9.036 9.335
938.74 4.654 6.377 5.29
944.729 4.752 5.001 5.048
954.654 8.98 4.873 5.544
964.9 4.606 4.723 5.192
978.757 4.802 5.427 9.056
984.859 8.969 4.816 5.3
994.701 4.662 9.002 5.138
1004.943 4.813 4.894 5.15
1018.772 4.721 4.785 9.168
diff --git a/static/posts/do-fuse/fuse-droplets.png b/static/posts/do-fuse/fuse-droplets.png
deleted file mode 100755
index d7ce243..0000000
--- a/static/posts/do-fuse/fuse-droplets.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/do-fuse/fuse-spaces.png b/static/posts/do-fuse/fuse-spaces.png
deleted file mode 100755
index 4dcc1c5..0000000
--- a/static/posts/do-fuse/fuse-spaces.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/do-fuse/sqlite-benchmarks.tsv b/static/posts/do-fuse/sqlite-benchmarks.tsv
deleted file mode 100755
index daa2c21..0000000
--- a/static/posts/do-fuse/sqlite-benchmarks.tsv
+++ /dev/null
@@ -1,1001 +0,0 @@
1DROPTABLE CREATETABLE INSERTMANY FETCHALL COMMIT
20.000732 0.000400 0.008133 0.000065 0.000166
30.000200 0.000214 0.003105 0.000043 0.000171
40.000246 0.000170 0.006594 0.000044 0.000101
50.000182 0.000166 0.003892 0.000043 0.000112
60.000248 0.000654 0.002308 0.000041 0.000090
70.000240 0.000184 0.002253 0.000053 0.000110
80.000698 0.000483 0.003737 0.000041 0.000165
90.000217 0.000179 0.002470 0.000049 0.000107
100.000243 0.000160 0.002668 0.000054 0.000340
110.000196 0.000169 0.002247 0.000040 0.000096
120.000191 0.000162 0.003522 0.000260 0.000102
130.000195 0.000188 0.002325 0.000041 0.000132
140.000194 0.000202 0.002291 0.000039 0.000091
150.000195 0.000196 0.004114 0.000042 0.000108
160.000204 0.000200 0.002971 0.000040 0.000106
170.000227 0.000159 0.002208 0.000039 0.000117
180.000207 0.000176 0.003558 0.000040 0.000124
190.000255 0.000179 0.002870 0.000040 0.000125
200.000209 0.000176 0.002248 0.000040 0.000176
210.000211 0.000174 0.002661 0.000039 0.000180
220.000208 0.000219 0.002321 0.000039 0.000151
230.000212 0.000178 0.002609 0.000040 0.000132
240.000205 0.000209 0.002666 0.000039 0.000126
250.000205 0.000176 0.002501 0.000041 0.000133
260.000243 0.000183 0.002220 0.000037 0.000117
270.000504 0.000173 0.002230 0.000121 0.000414
280.000270 0.000200 0.002325 0.000040 0.000154
290.000208 0.000176 0.002386 0.000038 0.000123
300.000229 0.000182 0.002245 0.000039 0.000127
310.000211 0.000176 0.002544 0.000039 0.000136
320.000204 0.000180 0.002133 0.000037 0.000129
330.000205 0.000178 0.002330 0.000048 0.000146
340.000210 0.000178 0.002242 0.000039 0.000109
350.000210 0.000259 0.002766 0.000039 0.000118
360.000317 0.000495 0.002237 0.000039 0.000195
370.000454 0.000246 0.002447 0.000040 0.000172
380.000936 0.000200 0.002305 0.000057 0.000173
390.000263 0.000178 0.002251 0.000038 0.000166
400.000240 0.000183 0.002169 0.000068 0.000176
410.000251 0.000189 0.002221 0.000038 0.000141
420.000268 0.000215 0.002322 0.000039 0.000226
430.000287 0.000223 0.002696 0.000045 0.000247
440.000362 0.000229 0.002551 0.000043 0.000133
450.000239 0.000200 0.002621 0.000045 0.000133
460.000634 0.000208 0.002619 0.000046 0.000138
470.000236 0.000205 0.002589 0.000046 0.000137
480.000262 0.000205 0.002607 0.000045 0.000142
490.000239 0.000198 0.002754 0.000044 0.000185
500.000238 0.000198 0.002593 0.000057 0.000160
510.000242 0.000221 0.003784 0.000122 0.000174
520.000242 0.000201 0.002625 0.000054 0.000148
530.000296 0.000225 0.002934 0.000044 0.000134
540.000239 0.000245 0.003428 0.000046 0.000158
550.000261 0.000251 0.002569 0.000046 0.000139
560.000260 0.000230 0.002603 0.000045 0.000145
570.000302 0.000212 0.002580 0.000045 0.000176
580.000794 0.000197 0.002856 0.000046 0.000141
590.000273 0.000209 0.003173 0.000045 0.000217
600.000240 0.000201 0.002844 0.000043 0.000167
610.000389 0.000175 0.004315 0.000055 0.000091
620.000275 0.000534 0.004991 0.000053 0.000092
630.000229 0.000215 0.004084 0.000045 0.000074
640.000172 0.000474 0.002611 0.000043 0.000069
650.000201 0.000174 0.002485 0.000043 0.000069
660.000173 0.000220 0.002541 0.000045 0.000068
670.000167 0.000161 0.002827 0.000043 0.000071
680.000168 0.000160 0.003512 0.000068 0.000075
690.000211 0.000167 0.002530 0.000044 0.000069
700.000193 0.000230 0.003664 0.000046 0.000074
710.000171 0.000161 0.002575 0.000076 0.000075
720.000169 0.000161 0.002595 0.000044 0.000076
730.000981 0.000174 0.002556 0.000045 0.000072
740.000168 0.000163 0.002568 0.000043 0.000072
750.000163 0.000158 0.002579 0.000043 0.000386
760.000168 0.000160 0.002579 0.000059 0.000088
770.000176 0.000163 0.002559 0.000044 0.000075
780.000167 0.000161 0.002558 0.000043 0.000075
790.000169 0.000161 0.002599 0.000043 0.000095
800.000174 0.000163 0.002633 0.000046 0.000076
810.000170 0.000165 0.002576 0.000858 0.000079
820.000169 0.000162 0.002611 0.000044 0.000075
830.000170 0.000199 0.002621 0.000043 0.000074
840.000170 0.000167 0.003611 0.000043 0.000073
850.000171 0.000159 0.002764 0.000046 0.000076
860.000171 0.000165 0.002639 0.000044 0.000073
870.000168 0.000162 0.003131 0.000046 0.000075
880.000170 0.000162 0.002858 0.000044 0.000074
890.000171 0.000164 0.002841 0.000043 0.000075
900.000167 0.000161 0.002971 0.000043 0.000074
910.000170 0.000226 0.002842 0.000044 0.000074
920.000171 0.000165 0.002822 0.000044 0.000075
930.000173 0.000160 0.002895 0.000045 0.000073
940.000167 0.000217 0.002697 0.000044 0.000076
950.000170 0.000197 0.002699 0.000044 0.000075
960.000171 0.000163 0.003230 0.000045 0.000097
970.000170 0.000164 0.003167 0.000046 0.000082
980.000172 0.000196 0.002559 0.000043 0.000075
990.000168 0.000165 0.003006 0.000045 0.000075
1000.000176 0.000160 0.002567 0.000043 0.000075
1010.000167 0.000163 0.002757 0.000045 0.000076
1020.000171 0.000162 0.002802 0.000045 0.000076
1030.000169 0.000162 0.003102 0.000043 0.000072
1040.000167 0.000162 0.002624 0.000043 0.000075
1050.000170 0.000161 0.002589 0.000043 0.000072
1060.000222 0.000253 0.002657 0.000045 0.000075
1070.000172 0.000162 0.002586 0.000044 0.000084
1080.000172 0.000165 0.002933 0.000044 0.000075
1090.000169 0.000192 0.002609 0.000044 0.000074
1100.000194 0.000162 0.003020 0.000045 0.000081
1110.000170 0.000164 0.002908 0.000045 0.000076
1120.000169 0.000163 0.002567 0.000042 0.000073
1130.000167 0.000159 0.003071 0.000042 0.000074
1140.000222 0.000163 0.003175 0.000043 0.000076
1150.000167 0.000160 0.002641 0.000046 0.000099
1160.000171 0.000168 0.002586 0.000057 0.000075
1170.000170 0.000168 0.003148 0.000046 0.000075
1180.000171 0.000159 0.002770 0.000041 0.000074
1190.000173 0.000158 0.002643 0.000055 0.000077
1200.000313 0.000174 0.002920 0.000045 0.000075
1210.000170 0.000163 0.002551 0.000044 0.000072
1220.000173 0.000161 0.002599 0.000045 0.000073
1230.000167 0.000160 0.003505 0.000046 0.000075
1240.000171 0.000161 0.002894 0.000045 0.000074
1250.000171 0.000166 0.002572 0.000042 0.000073
1260.000166 0.000160 0.004099 0.000044 0.000102
1270.000181 0.000160 0.002499 0.000046 0.000071
1280.000174 0.000175 0.002560 0.000043 0.000068
1290.000165 0.000168 0.003083 0.000044 0.000070
1300.000210 0.000163 0.002535 0.000040 0.000068
1310.000164 0.000177 0.002906 0.000044 0.000075
1320.000175 0.000227 0.002971 0.000043 0.000073
1330.000167 0.000175 0.003409 0.000046 0.000078
1340.000172 0.000166 0.002640 0.000046 0.000074
1350.000177 0.000164 0.002574 0.000046 0.000076
1360.000170 0.000163 0.002631 0.000046 0.000075
1370.000216 0.000168 0.002596 0.000046 0.000076
1380.000170 0.000163 0.002659 0.000045 0.000074
1390.000172 0.000162 0.002677 0.000046 0.000075
1400.000170 0.000159 0.002604 0.000044 0.000081
1410.000171 0.000161 0.003163 0.000046 0.000076
1420.000171 0.000162 0.002574 0.000313 0.000075
1430.000170 0.000186 0.002988 0.000046 0.000074
1440.000171 0.000162 0.002596 0.000043 0.000077
1450.000168 0.000160 0.002640 0.000055 0.000074
1460.000169 0.000161 0.002567 0.000043 0.000371
1470.000170 0.000162 0.002704 0.000057 0.000078
1480.000255 0.000185 0.002453 0.000293 0.000066
1490.000148 0.000143 0.002169 0.000037 0.000066
1500.000173 0.000141 0.002238 0.000039 0.000085
1510.000154 0.000174 0.002679 0.000041 0.000065
1520.000149 0.000144 0.002187 0.000037 0.000065
1530.000146 0.000140 0.002760 0.000039 0.000071
1540.000147 0.000151 0.002193 0.000039 0.000065
1550.000150 0.000172 0.002207 0.000039 0.000067
1560.000147 0.000141 0.002126 0.000037 0.000060
1570.000191 0.000141 0.002119 0.000036 0.000086
1580.000149 0.000144 0.002440 0.000039 0.000065
1590.000148 0.000143 0.003287 0.000041 0.000068
1600.000152 0.000149 0.002555 0.000040 0.000069
1610.000148 0.000141 0.002203 0.000038 0.000065
1620.000147 0.000139 0.002371 0.000052 0.000075
1630.000148 0.000143 0.002201 0.000037 0.000066
1640.000149 0.000140 0.002186 0.000038 0.000062
1650.000152 0.000154 0.002215 0.000038 0.000062
1660.000149 0.000144 0.002505 0.000039 0.000067
1670.000148 0.000140 0.002216 0.000038 0.000101
1680.000160 0.000144 0.002574 0.000039 0.000067
1690.000150 0.000144 0.002266 0.000040 0.000068
1700.000151 0.000142 0.003640 0.000040 0.000068
1710.000150 0.000142 0.002207 0.000038 0.000066
1720.000148 0.000140 0.002337 0.000041 0.000068
1730.000151 0.000144 0.002138 0.000038 0.000063
1740.000146 0.000178 0.002369 0.000039 0.000060
1750.000150 0.000141 0.002290 0.000039 0.000067
1760.000149 0.000143 0.002569 0.000050 0.000070
1770.000149 0.000143 0.002797 0.000040 0.000068
1780.000149 0.000143 0.002720 0.000039 0.000066
1790.000273 0.000154 0.002255 0.000039 0.000066
1800.000147 0.000141 0.002180 0.000037 0.000065
1810.000884 0.000142 0.002164 0.000036 0.000060
1820.000188 0.000143 0.002248 0.000039 0.000062
1830.000148 0.000142 0.002178 0.000038 0.000064
1840.000151 0.000140 0.002705 0.000038 0.000063
1850.000145 0.000144 0.002588 0.000039 0.000064
1860.000147 0.000142 0.002196 0.000037 0.000064
1870.000147 0.000139 0.002169 0.000035 0.000060
1880.000151 0.000894 0.002267 0.000039 0.000061
1890.000152 0.000145 0.002178 0.000038 0.000061
1900.000185 0.000142 0.002148 0.000036 0.000062
1910.000147 0.000141 0.002845 0.000040 0.000065
1920.000159 0.000178 0.002193 0.000039 0.000063
1930.000145 0.000141 0.002571 0.000039 0.000066
1940.000149 0.000141 0.003380 0.000038 0.000065
1950.000200 0.000149 0.002439 0.000039 0.000066
1960.000152 0.000140 0.002193 0.000037 0.000065
1970.000147 0.000139 0.002239 0.000037 0.000066
1980.000200 0.000143 0.002190 0.000039 0.000066
1990.000147 0.000139 0.002243 0.000038 0.000062
2000.000421 0.000144 0.002229 0.000038 0.000062
2010.000147 0.000149 0.002715 0.000038 0.000063
2020.000151 0.000176 0.002144 0.000036 0.000060
2030.000145 0.000138 0.002184 0.000038 0.000064
2040.000146 0.000207 0.002526 0.000040 0.000067
2050.000163 0.000142 0.002366 0.000038 0.000070
2060.000149 0.000143 0.002143 0.000038 0.000065
2070.000150 0.000142 0.002146 0.000035 0.000059
2080.000162 0.000147 0.002736 0.000038 0.000067
2090.000149 0.000146 0.002383 0.000040 0.000071
2100.000147 0.000139 0.002485 0.000038 0.000065
2110.000147 0.000143 0.002811 0.000039 0.000098
2120.000181 0.000142 0.002503 0.000039 0.000066
2130.000150 0.000143 0.002227 0.000039 0.000065
2140.000149 0.000143 0.002182 0.000036 0.000061
2150.000148 0.000387 0.002159 0.000036 0.000059
2160.000147 0.000173 0.002267 0.000039 0.000063
2170.000147 0.000143 0.002729 0.000039 0.000066
2180.000149 0.000142 0.002574 0.000040 0.000069
2190.000149 0.000143 0.002560 0.000040 0.000068
2200.000152 0.000141 0.002203 0.000038 0.000066
2210.000151 0.000139 0.002234 0.000038 0.000087
2220.000148 0.000140 0.002152 0.000036 0.000060
2230.000185 0.000140 0.002274 0.000039 0.000063
2240.000148 0.000144 0.002211 0.000038 0.000066
2250.000149 0.000141 0.002692 0.000039 0.000066
2260.000148 0.000145 0.002519 0.000039 0.000066
2270.000147 0.000143 0.002188 0.000038 0.000066
2280.000149 0.000171 0.002171 0.000038 0.000093
2290.000150 0.000182 0.002185 0.000038 0.000068
2300.000191 0.000154 0.002172 0.000037 0.000061
2310.000145 0.000140 0.002253 0.000043 0.000065
2320.000147 0.000139 0.002673 0.000038 0.000066
2330.000191 0.000144 0.002740 0.000038 0.000066
2340.000147 0.000142 0.002187 0.000038 0.000064
2350.000146 0.000181 0.002180 0.000038 0.000066
2360.000176 0.000142 0.002152 0.000039 0.000061
2370.000149 0.000142 0.002164 0.000037 0.000064
2380.000245 0.000150 0.002771 0.000055 0.000084
2390.000149 0.000145 0.003006 0.000040 0.000069
2400.000153 0.000144 0.002701 0.000040 0.000067
2410.000149 0.000144 0.002192 0.000038 0.000065
2420.000148 0.000143 0.002220 0.000038 0.000063
2430.000146 0.000140 0.002210 0.000038 0.000062
2440.000157 0.000144 0.002174 0.000038 0.000060
2450.000148 0.000171 0.002208 0.000039 0.000061
2460.000146 0.000141 0.002685 0.000039 0.000064
2470.000146 0.000139 0.002811 0.000038 0.000064
2480.000147 0.000140 0.002234 0.000037 0.000063
2490.000143 0.000143 0.002209 0.000040 0.000066
2500.000149 0.000144 0.002162 0.000037 0.000091
2510.000408 0.000141 0.002140 0.000036 0.000060
2520.000142 0.000149 0.002208 0.000132 0.000061
2530.000148 0.000142 0.002706 0.000040 0.000066
2540.000148 0.000142 0.002502 0.000039 0.000065
2550.000176 0.000144 0.002265 0.000039 0.000066
2560.000150 0.000142 0.002199 0.000039 0.000065
2570.000147 0.000154 0.002201 0.000040 0.000067
2580.000150 0.000142 0.002164 0.000036 0.000094
2590.000183 0.000177 0.002253 0.000039 0.000063
2600.000189 0.000143 0.002480 0.000039 0.000066
2610.000148 0.000141 0.002212 0.000037 0.000064
2620.000150 0.000137 0.002192 0.000037 0.000065
2630.000144 0.000140 0.002271 0.000039 0.000062
2640.000190 0.000171 0.002145 0.000037 0.000061
2650.000146 0.000141 0.005865 0.000099 0.000083
2660.000178 0.000165 0.002792 0.000040 0.000066
2670.000148 0.000233 0.002742 0.000039 0.000079
2680.000157 0.000151 0.002225 0.000039 0.000066
2690.000149 0.000142 0.002215 0.000039 0.000081
2700.000165 0.000141 0.002239 0.000039 0.000081
2710.000150 0.000154 0.002154 0.000036 0.000060
2720.000152 0.000151 0.002216 0.000039 0.000075
2730.000172 0.000141 0.004471 0.000060 0.000092
2740.000250 0.000210 0.002881 0.000040 0.000066
2750.000176 0.000152 0.002262 0.000038 0.000337
2760.000164 0.000154 0.002485 0.000039 0.000074
2770.000149 0.000180 0.002148 0.000039 0.000078
2780.000194 0.000145 0.002345 0.000044 0.000064
2790.000164 0.000201 0.002483 0.000040 0.000062
2800.000148 0.000140 0.002249 0.000038 0.000076
2810.000155 0.000144 0.002504 0.000039 0.000067
2820.000166 0.000150 0.002780 0.000040 0.000079
2830.000150 0.000142 0.002194 0.000038 0.000086
2840.000178 0.000153 0.002360 0.000039 0.000079
2850.000160 0.000154 0.002159 0.000036 0.000079
2860.000195 0.000445 0.002203 0.000038 0.000074
2870.000171 0.000161 0.002220 0.000038 0.000087
2880.000165 0.000151 0.002231 0.000038 0.000088
2890.000149 0.000141 0.003445 0.000040 0.000068
2900.000148 0.000143 0.002465 0.000039 0.000081
2910.000165 0.000150 0.002228 0.000038 0.000067
2920.000160 0.000142 0.003231 0.000039 0.000066
2930.000149 0.000141 0.002215 0.000038 0.000078
2940.000146 0.000152 0.002152 0.000038 0.000077
2950.000168 0.000140 0.002258 0.000040 0.000076
2960.000193 0.000142 0.002266 0.000039 0.000085
2970.000261 0.000164 0.002160 0.000037 0.000061
2980.000151 0.000419 0.002217 0.000037 0.000073
2990.000163 0.000148 0.002856 0.000038 0.000106
3000.000258 0.000204 0.002267 0.000040 0.000075
3010.000178 0.000159 0.002266 0.000038 0.000070
3020.000158 0.000149 0.002665 0.000039 0.000085
3030.000164 0.000154 0.002478 0.000039 0.000077
3040.000148 0.000140 0.002459 0.000038 0.000066
3050.000161 0.000142 0.002206 0.000038 0.000074
3060.000155 0.000151 0.002230 0.000039 0.000083
3070.000161 0.000142 0.002225 0.000037 0.000072
3080.000161 0.000187 0.002450 0.000038 0.000063
3090.000145 0.000155 0.002438 0.000039 0.000079
3100.000166 0.000138 0.002296 0.000039 0.000076
3110.000170 0.000156 0.002446 0.000038 0.000078
3120.000160 0.000159 0.002211 0.000038 0.000078
3130.000159 0.000142 0.002190 0.000036 0.000110
3140.000157 0.000150 0.002336 0.000039 0.000073
3150.000165 0.000182 0.002132 0.000038 0.000072
3160.000160 0.000140 0.002641 0.000066 0.000066
3170.000147 0.000153 0.002153 0.000039 0.000080
3180.000148 0.000156 0.002165 0.000037 0.000077
3190.000147 0.000151 0.002201 0.000038 0.000067
3200.000162 0.000143 0.002216 0.000040 0.000080
3210.000165 0.000148 0.002223 0.000055 0.000080
3220.000193 0.000143 0.002155 0.000037 0.000078
3230.000165 0.000143 0.003005 0.000040 0.000067
3240.000151 0.000145 0.002511 0.000039 0.000070
3250.000149 0.000173 0.002246 0.000039 0.000066
3260.000148 0.000143 0.002808 0.000040 0.000067
3270.000148 0.000142 0.002513 0.000038 0.000066
3280.000148 0.000143 0.002203 0.000037 0.000065
3290.000146 0.000138 0.002123 0.000038 0.000061
3300.000170 0.000149 0.002165 0.000036 0.000062
3310.000144 0.000145 0.002186 0.000037 0.000059
3320.000144 0.000139 0.002520 0.000037 0.000065
3330.000146 0.000139 0.002559 0.000038 0.000066
3340.000153 0.000142 0.002537 0.000038 0.000067
3350.000168 0.000144 0.002217 0.000048 0.000066
3360.000147 0.000141 0.002120 0.000037 0.000063
3370.000188 0.001725 0.002541 0.000040 0.000067
3380.000149 0.000143 0.002229 0.000038 0.000076
3390.000147 0.000143 0.002233 0.000037 0.000062
3400.000182 0.000142 0.002150 0.000037 0.000061
3410.000148 0.000140 0.002196 0.000037 0.000065
3420.000145 0.000140 0.002473 0.000037 0.000065
3430.000147 0.000139 0.002725 0.000040 0.000067
3440.000149 0.000142 0.002217 0.000039 0.000065
3450.000146 0.000140 0.002167 0.000037 0.000061
3460.000176 0.000144 0.002415 0.000039 0.000064
3470.000171 0.000144 0.002925 0.000040 0.000068
3480.000152 0.000167 0.002190 0.000039 0.000066
3490.000149 0.000142 0.002530 0.000039 0.000067
3500.000150 0.000142 0.003059 0.000040 0.000068
3510.000149 0.000142 0.002417 0.000038 0.000072
3520.000149 0.000143 0.002569 0.000038 0.000068
3530.000148 0.000141 0.002262 0.000040 0.000068
3540.000152 0.000144 0.002253 0.000038 0.000066
3550.000149 0.000142 0.002134 0.000037 0.000061
3560.000277 0.000427 0.002186 0.000036 0.000060
3570.000145 0.000139 0.002791 0.000039 0.000065
3580.000149 0.000144 0.002238 0.000039 0.000066
3590.000147 0.000144 0.002514 0.000039 0.000066
3600.000148 0.000143 0.002683 0.000038 0.000063
3610.000147 0.000139 0.002214 0.000037 0.000068
3620.000145 0.000139 0.002149 0.000036 0.000059
3630.000185 0.000139 0.002214 0.000037 0.000060
3640.000145 0.000140 0.003549 0.000039 0.000066
3650.000187 0.000142 0.002160 0.000037 0.000059
3660.000147 0.000158 0.002212 0.000038 0.000065
3670.000148 0.000140 0.002483 0.000039 0.000067
3680.000147 0.000142 0.003034 0.000039 0.000066
3690.000148 0.000142 0.002228 0.000039 0.000066
3700.000145 0.000151 0.002225 0.000040 0.000067
3710.000149 0.000142 0.002858 0.000048 0.000083
3720.000203 0.000185 0.004022 0.000049 0.000086
3730.000212 0.000188 0.005086 0.000056 0.000093
3740.000220 0.000203 0.004209 0.000051 0.000085
3750.000208 0.000247 0.009261 0.000098 0.000089
3760.000211 0.000262 0.002546 0.000041 0.000066
3770.000198 0.000150 0.002534 0.000039 0.000079
3780.000159 0.000143 0.002207 0.000038 0.000094
3790.000157 0.000143 0.002173 0.000038 0.000062
3800.000198 0.000505 0.002157 0.000039 0.000079
3810.000164 0.000143 0.002172 0.000038 0.000076
3820.000156 0.000148 0.002259 0.000039 0.000080
3830.000161 0.000142 0.002219 0.000039 0.000076
3840.000161 0.000143 0.002266 0.000039 0.000085
3850.000161 0.000141 0.002150 0.000036 0.000077
3860.000179 0.000140 0.002140 0.000036 0.000071
3870.000157 0.000151 0.002316 0.000040 0.000079
3880.000149 0.000143 0.002269 0.000039 0.000066
3890.000161 0.000142 0.002206 0.000040 0.000091
3900.000172 0.000143 0.002244 0.000039 0.000067
3910.000168 0.000142 0.002189 0.000039 0.000083
3920.000163 0.000188 0.002156 0.000037 0.000077
3930.000168 0.000143 0.002266 0.000039 0.000084
3940.000166 0.000147 0.002205 0.000325 0.000078
3950.000175 0.000140 0.002173 0.000037 0.000106
3960.000170 0.000153 0.002158 0.000036 0.000083
3970.000168 0.000147 0.002825 0.000039 0.000108
3980.000172 0.000151 0.002483 0.000038 0.000085
3990.000160 0.000143 0.002163 0.000038 0.000066
4000.000161 0.000154 0.002493 0.000039 0.000084
4010.000167 0.000153 0.002564 0.000040 0.000082
4020.000159 0.000151 0.002185 0.000046 0.000088
4030.000157 0.000156 0.002175 0.000039 0.000076
4040.000150 0.000144 0.002151 0.000038 0.000063
4050.000160 0.000140 0.002429 0.000038 0.000064
4060.000160 0.000154 0.002184 0.000048 0.000077
4070.000168 0.000142 0.002686 0.000040 0.000119
4080.000164 0.000152 0.002279 0.000039 0.000075
4090.000161 0.000143 0.002192 0.000068 0.000067
4100.000161 0.000154 0.002190 0.000040 0.000092
4110.000246 0.000146 0.003064 0.000038 0.000072
4120.000163 0.000158 0.002171 0.000037 0.000073
4130.000216 0.000144 0.002209 0.000039 0.000115
4140.000159 0.000141 0.003338 0.000039 0.000079
4150.000277 0.000158 0.002464 0.000039 0.000082
4160.000168 0.000150 0.002227 0.000037 0.000079
4170.000168 0.000146 0.002775 0.000038 0.000077
4180.000146 0.000147 0.002694 0.000042 0.000084
4190.000160 0.000145 0.002807 0.000039 0.000066
4200.000162 0.000177 0.002187 0.000063 0.000066
4210.000147 0.000141 0.002220 0.000038 0.000085
4220.000160 0.000142 0.002216 0.000037 0.000077
4230.000166 0.000159 0.002224 0.000039 0.000108
4240.000147 0.000141 0.002746 0.000039 0.000078
4250.000159 0.000141 0.002194 0.000037 0.000063
4260.000164 0.000143 0.002164 0.000039 0.000067
4270.000169 0.000152 0.002278 0.000074 0.000088
4280.000157 0.000157 0.002155 0.000068 0.000076
4290.000159 0.000140 0.002170 0.000035 0.000078
4300.000156 0.000141 0.002299 0.000040 0.000066
4310.000192 0.000160 0.002241 0.000039 0.000082
4320.000149 0.000143 0.002288 0.000039 0.000079
4330.000161 0.000142 0.002185 0.000049 0.000077
4340.000147 0.000149 0.002284 0.000039 0.000063
4350.000456 0.000144 0.002203 0.000046 0.000064
4360.000187 0.000144 0.002147 0.000037 0.000061
4370.000147 0.000140 0.002238 0.000040 0.000067
4380.000147 0.000140 0.003077 0.000041 0.000068
4390.000151 0.000142 0.002226 0.000038 0.000065
4400.000146 0.000142 0.002188 0.000039 0.000065
4410.000145 0.000141 0.002156 0.000036 0.000061
4420.000143 0.000172 0.002379 0.000037 0.000060
4430.000152 0.000231 0.002172 0.000038 0.000065
4440.000153 0.000142 0.002181 0.000039 0.000065
4450.000148 0.000142 0.002567 0.000039 0.000067
4460.000150 0.000142 0.002177 0.000038 0.000072
4470.000147 0.000146 0.002328 0.000038 0.000063
4480.000146 0.000150 0.002211 0.000038 0.000063
4490.000149 0.000143 0.002222 0.000040 0.000072
4500.000150 0.000144 0.002455 0.000039 0.000065
4510.000147 0.000144 0.002206 0.000039 0.000066
4520.000145 0.000141 0.002153 0.000055 0.000070
4530.000443 0.000144 0.002139 0.000036 0.000069
4540.000147 0.000182 0.002188 0.000037 0.000061
4550.000146 0.000138 0.002248 0.000038 0.000067
4560.000147 0.000142 0.002817 0.000039 0.000067
4570.000148 0.000144 0.002230 0.000038 0.000066
4580.000148 0.000142 0.002239 0.000039 0.000067
4590.000149 0.000142 0.002197 0.000038 0.000063
4600.000181 0.000674 0.002170 0.000038 0.000061
4610.000146 0.000195 0.002204 0.000037 0.000061
4620.000146 0.000141 0.002260 0.000039 0.000067
4630.000150 0.000142 0.002193 0.000045 0.000065
4640.000147 0.000140 0.002229 0.000036 0.000066
4650.000146 0.000137 0.002197 0.000037 0.000062
4660.000152 0.000159 0.002187 0.000036 0.000060
4670.000145 0.000139 0.002224 0.000037 0.000064
4680.000149 0.000144 0.002175 0.000038 0.000066
4690.000150 0.000143 0.002187 0.000038 0.000066
4700.000148 0.000141 0.002152 0.000036 0.000061
4710.000185 0.000141 0.002176 0.000036 0.000064
4720.000169 0.000145 0.002483 0.000038 0.000067
4730.000149 0.000141 0.002225 0.000036 0.000064
4740.000244 0.000149 0.002538 0.000038 0.000065
4750.000156 0.000143 0.002317 0.000039 0.000297
4760.000228 0.000172 0.002222 0.000039 0.000300
4770.000149 0.000145 0.002173 0.000040 0.000066
4780.000154 0.000145 0.002155 0.000038 0.000093
4790.000161 0.000145 0.002178 0.000039 0.000063
4800.000147 0.000170 0.002299 0.000039 0.000066
4810.000149 0.000142 0.003494 0.000040 0.000066
4820.000149 0.000178 0.002237 0.000038 0.000062
4830.000148 0.000143 0.002150 0.000037 0.000064
4840.000146 0.000139 0.002315 0.000038 0.000065
4850.000147 0.000141 0.002269 0.000039 0.000067
4860.000173 0.000145 0.002191 0.000037 0.000065
4870.000166 0.000144 0.002247 0.000038 0.000061
4880.000146 0.000140 0.002551 0.000038 0.000065
4890.000148 0.000175 0.002202 0.000037 0.000064
4900.000145 0.000141 0.002217 0.000038 0.000063
4910.000146 0.000138 0.002164 0.000132 0.000547
4920.000148 0.000144 0.008140 0.000160 0.000893
4930.000311 0.000221 0.004526 0.000058 0.000109
4940.000238 0.000225 0.003475 0.000044 0.000094
4950.000178 0.000177 0.002537 0.000041 0.000087
4960.000172 0.000161 0.002194 0.000048 0.000084
4970.000172 0.000163 0.002177 0.000040 0.000084
4980.001177 0.000156 0.002351 0.000041 0.000325
4990.000167 0.000163 0.002273 0.000040 0.000088
5000.000170 0.000151 0.002245 0.000040 0.000077
5010.000172 0.000896 0.002181 0.000038 0.000080
5020.000202 0.000164 0.002449 0.000038 0.000076
5030.000162 0.000161 0.002188 0.000037 0.000078
5040.000165 0.000154 0.002440 0.000074 0.000091
5050.000167 0.000149 0.002185 0.000039 0.000081
5060.000176 0.000154 0.002427 0.000040 0.000093
5070.000168 0.000154 0.002304 0.000038 0.000105
5080.000672 0.000160 0.002260 0.000038 0.000088
5090.000686 0.000159 0.002207 0.000038 0.000084
5100.000163 0.000154 0.002186 0.000037 0.000077
5110.000173 0.000153 0.002399 0.000038 0.000082
5120.000166 0.000157 0.002709 0.000039 0.000077
5130.000155 0.000149 0.002143 0.000038 0.000097
5140.000166 0.000154 0.003454 0.000051 0.000106
5150.000166 0.000160 0.002539 0.000039 0.000128
5160.000169 0.000149 0.002307 0.000039 0.000085
5170.000170 0.000158 0.002225 0.000040 0.000088
5180.000170 0.000180 0.002165 0.000036 0.000103
5190.000203 0.000160 0.002345 0.000039 0.000075
5200.000173 0.000191 0.002160 0.000038 0.000074
5210.000165 0.000156 0.002243 0.000039 0.000085
5220.000172 0.000154 0.002260 0.000040 0.000090
5230.000163 0.000164 0.002258 0.000040 0.000085
5240.000168 0.000143 0.002755 0.000039 0.000086
5250.000178 0.000155 0.002202 0.000039 0.000075
5260.000164 0.000153 0.002267 0.000038 0.000081
5270.000161 0.000154 0.002158 0.000036 0.000090
5280.000169 0.000158 0.002454 0.000037 0.000061
5290.000162 0.000154 0.002543 0.000038 0.000091
5300.000170 0.000154 0.002168 0.000037 0.000085
5310.000166 0.000151 0.002852 0.000038 0.000087
5320.000167 0.000165 0.002484 0.000039 0.000089
5330.000374 0.000197 0.002217 0.000038 0.000082
5340.000156 0.000150 0.002213 0.000038 0.000112
5350.000683 0.000155 0.002131 0.000038 0.000077
5360.000162 0.000164 0.002199 0.000038 0.000076
5370.000176 0.000154 0.002345 0.000038 0.000089
5380.000175 0.000150 0.002928 0.000039 0.000082
5390.000161 0.000140 0.002528 0.000039 0.000066
5400.000159 0.000151 0.002256 0.000039 0.000075
5410.000155 0.000156 0.002233 0.000040 0.000066
5420.000171 0.000156 0.002149 0.000066 0.000084
5430.000182 0.000154 0.002233 0.000037 0.000117
5440.000166 0.000160 0.002460 0.000037 0.000088
5450.000159 0.000165 0.002891 0.000043 0.000075
5460.000169 0.000143 0.002383 0.000038 0.000084
5470.000162 0.000149 0.002313 0.000039 0.000078
5480.000166 0.000161 0.003837 0.000041 0.000092
5490.000166 0.000144 0.002389 0.000038 0.000078
5500.000185 0.000153 0.002548 0.000040 0.000090
5510.000166 0.000152 0.002943 0.000037 0.000063
5520.000147 0.000140 0.002284 0.000038 0.000066
5530.000145 0.000141 0.002555 0.000038 0.000071
5540.000189 0.000143 0.002235 0.000038 0.000359
5550.000149 0.000140 0.002779 0.000053 0.000089
5560.000211 0.000206 0.002744 0.000040 0.000067
5570.000150 0.000144 0.002471 0.000039 0.000065
5580.000151 0.000140 0.002563 0.000040 0.000064
5590.000148 0.000138 0.002305 0.000039 0.000066
5600.000148 0.000141 0.002162 0.000036 0.000060
5610.000182 0.000145 0.002403 0.000042 0.000063
5620.000152 0.000141 0.002311 0.000039 0.000065
5630.000148 0.000180 0.002192 0.000038 0.000065
5640.000149 0.000141 0.002516 0.000039 0.000066
5650.000147 0.000142 0.002193 0.000040 0.000064
5660.000146 0.000138 0.002194 0.000036 0.000060
5670.000197 0.000142 0.002291 0.000038 0.000063
5680.000148 0.000142 0.002440 0.000039 0.000066
5690.000148 0.000143 0.002228 0.000039 0.000066
5700.000149 0.000140 0.002216 0.000038 0.000067
5710.000148 0.000145 0.002196 0.000038 0.000066
5720.000148 0.000141 0.002157 0.000036 0.000061
5730.000144 0.000175 0.002491 0.000039 0.000063
5740.000147 0.000141 0.002290 0.000039 0.000066
5750.000149 0.000143 0.002508 0.000039 0.000067
5760.000149 0.000142 0.002536 0.000039 0.000067
5770.000150 0.000141 0.003132 0.000046 0.000070
5780.000153 0.000145 0.002202 0.000039 0.000067
5790.000149 0.000143 0.002102 0.000037 0.000067
5800.000989 0.000142 0.002188 0.000063 0.000068
5810.000151 0.000142 0.002229 0.000038 0.000068
5820.001481 0.000141 0.002238 0.000039 0.000070
5830.000148 0.000142 0.002204 0.000037 0.000093
5840.000160 0.000141 0.002138 0.000038 0.000062
5850.000145 0.000141 0.002708 0.000039 0.000065
5860.000147 0.000142 0.002218 0.000039 0.000067
5870.000148 0.000140 0.002759 0.000038 0.000066
5880.000148 0.000139 0.003156 0.000037 0.000067
5890.000185 0.000141 0.002259 0.000040 0.000066
5900.000148 0.000142 0.002226 0.000047 0.000068
5910.000148 0.000142 0.002305 0.000040 0.000090
5920.001000 0.000155 0.002217 0.000064 0.000068
5930.000154 0.000144 0.002554 0.000038 0.000065
5940.000148 0.000141 0.002151 0.000038 0.000066
5950.000146 0.000181 0.003031 0.000039 0.000062
5960.000146 0.000180 0.002254 0.000039 0.000061
5970.000147 0.000143 0.002188 0.000039 0.000065
5980.000147 0.000140 0.002259 0.000039 0.000063
5990.000146 0.000141 0.002238 0.000038 0.000076
6000.000148 0.000141 0.002163 0.000038 0.000061
6010.000153 0.000143 0.002195 0.000043 0.000072
6020.000149 0.000177 0.003291 0.000039 0.000063
6030.000258 0.000153 0.002150 0.000039 0.000066
6040.000157 0.000144 0.002155 0.000037 0.000060
6050.000160 0.001194 0.002269 0.000040 0.000100
6060.000164 0.000151 0.002162 0.000038 0.000078
6070.000163 0.000424 0.002178 0.000036 0.000069
6080.001333 0.000389 0.002249 0.000039 0.000066
6090.000175 0.000142 0.002208 0.000037 0.000102
6100.000443 0.000156 0.002249 0.000040 0.000062
6110.000244 0.001562 0.003049 0.000041 0.000083
6120.000208 0.000183 0.002483 0.000040 0.000068
6130.000164 0.000156 0.002220 0.000040 0.000078
6140.000169 0.000142 0.002694 0.000040 0.000083
6150.000162 0.000152 0.002453 0.000038 0.000077
6160.000157 0.000189 0.002306 0.000040 0.000077
6170.000162 0.000151 0.002200 0.000039 0.000325
6180.000150 0.000142 0.002251 0.000039 0.000066
6190.000172 0.000157 0.002184 0.000039 0.000073
6200.000160 0.000150 0.002678 0.000038 0.000326
6210.000165 0.000151 0.002292 0.000038 0.000094
6220.000162 0.000156 0.002203 0.000037 0.000083
6230.000170 0.000141 0.002175 0.000037 0.000074
6240.000149 0.000166 0.002235 0.000039 0.000071
6250.000161 0.000143 0.002423 0.000036 0.000180
6260.000164 0.000152 0.003095 0.000039 0.000076
6270.000172 0.000153 0.002466 0.000039 0.000115
6280.000151 0.000153 0.002274 0.000039 0.000066
6290.000150 0.000142 0.003179 0.000040 0.000080
6300.000172 0.000159 0.002421 0.000039 0.000083
6310.000159 0.000142 0.002165 0.000037 0.000068
6320.000155 0.000150 0.002233 0.000041 0.000123
6330.000153 0.000158 0.002253 0.000039 0.000571
6340.000203 0.000145 0.002269 0.000041 0.000077
6350.000164 0.000158 0.002176 0.000038 0.000086
6360.000197 0.000144 0.002220 0.000041 0.000080
6370.000174 0.000403 0.002224 0.000039 0.000063
6380.000218 0.000144 0.002150 0.000036 0.000069
6390.000149 0.000141 0.002479 0.000040 0.000079
6400.000163 0.000145 0.002664 0.000039 0.000082
6410.000150 0.000152 0.002446 0.000040 0.000069
6420.000203 0.000154 0.002205 0.000043 0.000077
6430.000160 0.000143 0.002210 0.000039 0.000087
6440.000194 0.000145 0.002167 0.000038 0.000069
6450.000151 0.000154 0.002137 0.000036 0.000079
6460.000162 0.000140 0.002697 0.000037 0.000085
6470.000162 0.000143 0.002233 0.000039 0.000076
6480.000148 0.000144 0.002210 0.000039 0.000065
6490.000151 0.000152 0.003015 0.000041 0.000084
6500.000158 0.000156 0.002730 0.000039 0.000079
6510.000312 0.000165 0.002207 0.000038 0.000076
6520.000167 0.000139 0.002297 0.000040 0.000065
6530.000172 0.000154 0.002205 0.000037 0.000080
6540.000146 0.000149 0.002286 0.000039 0.000076
6550.000164 0.000151 0.002214 0.000038 0.000073
6560.000162 0.000169 0.003110 0.000038 0.000067
6570.000293 0.000144 0.002182 0.000038 0.000060
6580.000157 0.000153 0.003778 0.000049 0.000095
6590.001735 0.000210 0.004360 0.000050 0.000083
6600.000297 0.000198 0.002532 0.000039 0.000072
6610.000185 0.000163 0.002173 0.000039 0.000070
6620.000183 0.000142 0.002122 0.000038 0.000062
6630.000147 0.000145 0.002443 0.000039 0.000066
6640.000149 0.000144 0.002473 0.000040 0.000066
6650.000147 0.000139 0.002949 0.000038 0.000063
6660.000147 0.000139 0.002737 0.000039 0.000066
6670.000199 0.000142 0.002927 0.000038 0.000066
6680.000149 0.000141 0.002188 0.000038 0.000065
6690.000147 0.000144 0.002203 0.000038 0.000066
6700.000149 0.000141 0.002154 0.000037 0.000062
6710.000144 0.000137 0.003526 0.000037 0.000066
6720.000151 0.000153 0.002150 0.000036 0.000060
6730.000145 0.000138 0.002202 0.000037 0.000065
6740.000272 0.000187 0.002477 0.000038 0.000306
6750.000148 0.000141 0.002421 0.000038 0.000067
6760.000147 0.000141 0.002252 0.000039 0.000065
6770.000150 0.000140 0.002144 0.000037 0.000061
6780.000191 0.000144 0.002229 0.000038 0.000060
6790.000145 0.000145 0.002202 0.000038 0.000061
6800.000146 0.000142 0.002418 0.000038 0.000065
6810.000189 0.000171 0.002568 0.000040 0.000066
6820.000150 0.000141 0.002300 0.000039 0.000067
6830.000151 0.000141 0.002199 0.000038 0.000347
6840.000147 0.000140 0.002165 0.000035 0.000061
6850.000151 0.000646 0.002310 0.000040 0.000062
6860.000161 0.000410 0.002195 0.000038 0.000061
6870.000147 0.000141 0.002466 0.000039 0.000066
6880.000147 0.000141 0.003026 0.000038 0.000066
6890.000148 0.000142 0.002223 0.000038 0.000065
6900.000147 0.000142 0.002196 0.000038 0.000067
6910.000147 0.000141 0.002155 0.000044 0.000064
6920.000146 0.000140 0.002354 0.000039 0.000067
6930.000149 0.000143 0.002186 0.000037 0.000062
6940.000150 0.000144 0.002498 0.000040 0.000063
6950.000178 0.000212 0.002453 0.000039 0.000062
6960.000149 0.000177 0.002463 0.000038 0.000063
6970.000147 0.000142 0.002507 0.000038 0.000067
6980.000149 0.000142 0.002717 0.000038 0.000066
6990.000148 0.000141 0.002452 0.000037 0.000065
7000.000147 0.000140 0.002266 0.000039 0.000066
7010.000149 0.000141 0.002183 0.000037 0.000066
7020.000153 0.000142 0.002203 0.000039 0.000067
7030.000152 0.000419 0.002245 0.000040 0.000062
7040.000149 0.000181 0.002181 0.000038 0.000063
7050.000147 0.000142 0.002224 0.000039 0.000066
7060.000147 0.000142 0.002204 0.000038 0.000066
7070.000146 0.000141 0.002250 0.000038 0.000065
7080.000148 0.000141 0.002142 0.000038 0.000063
7090.000156 0.000139 0.002176 0.000036 0.000060
7100.000243 0.000148 0.002768 0.000039 0.000069
7110.000146 0.000204 0.002194 0.000037 0.000065
7120.000147 0.000143 0.003071 0.000039 0.000066
7130.000148 0.000144 0.003489 0.000042 0.000073
7140.000151 0.000151 0.002173 0.000039 0.000064
7150.000146 0.000140 0.003509 0.000038 0.000067
7160.000148 0.000142 0.002191 0.000038 0.000064
7170.000146 0.000139 0.002441 0.000039 0.000117
7180.000174 0.000141 0.002133 0.000038 0.000065
7190.000151 0.000142 0.002257 0.000039 0.000073
7200.000163 0.000147 0.002187 0.000038 0.000061
7210.000146 0.000222 0.002193 0.000038 0.000062
7220.000145 0.000143 0.002434 0.000037 0.000064
7230.000145 0.000139 0.002933 0.000041 0.000066
7240.000146 0.000140 0.002680 0.000037 0.000065
7250.000143 0.000139 0.002217 0.001029 0.000065
7260.000145 0.000139 0.002361 0.000039 0.000067
7270.000150 0.000143 0.002186 0.000068 0.000066
7280.000148 0.000142 0.002149 0.000037 0.000061
7290.000147 0.000181 0.002183 0.000037 0.000061
7300.000146 0.000455 0.002305 0.000038 0.000074
7310.000148 0.000143 0.002223 0.000038 0.000066
7320.000148 0.000141 0.002547 0.000038 0.000066
7330.000148 0.000143 0.002180 0.000038 0.000336
7340.000146 0.000141 0.002102 0.000037 0.000063
7350.000150 0.000145 0.002170 0.000037 0.000067
7360.000152 0.000138 0.002982 0.000038 0.000067
7370.000149 0.000143 0.002419 0.000037 0.000064
7380.000145 0.000195 0.002228 0.000040 0.000067
7390.000148 0.000143 0.002193 0.000038 0.000064
7400.000155 0.000141 0.002166 0.000067 0.000066
7410.000454 0.000176 0.002193 0.000038 0.000063
7420.000186 0.000142 0.002165 0.000035 0.000066
7430.000144 0.000138 0.002542 0.000038 0.000066
7440.000148 0.000143 0.002733 0.000039 0.000066
7450.000147 0.000141 0.002227 0.000038 0.000067
7460.000145 0.000142 0.002764 0.000037 0.000064
7470.000144 0.000138 0.002207 0.000037 0.000065
7480.000147 0.000185 0.002262 0.000038 0.000062
7490.000154 0.000160 0.002163 0.000038 0.000063
7500.000150 0.000145 0.002719 0.000038 0.000065
7510.000145 0.000139 0.002226 0.000037 0.000074
7520.000148 0.000140 0.002517 0.000038 0.000067
7530.000148 0.000142 0.003734 0.000039 0.000067
7540.000147 0.000143 0.002508 0.000039 0.000067
7550.000146 0.000143 0.002288 0.000038 0.000067
7560.000149 0.000143 0.002899 0.000039 0.000067
7570.000150 0.000145 0.002232 0.000037 0.000065
7580.000148 0.000142 0.002169 0.000039 0.000067
7590.000161 0.000141 0.002196 0.000036 0.000060
7600.000145 0.000137 0.002467 0.000040 0.000064
7610.000147 0.000141 0.002168 0.000037 0.000063
7620.000147 0.000139 0.002165 0.000037 0.000064
7630.000146 0.000138 0.002167 0.000036 0.000060
7640.000150 0.000141 0.002326 0.000039 0.000063
7650.000149 0.000179 0.002197 0.000039 0.000063
7660.000148 0.000142 0.002538 0.000039 0.000067
7670.000148 0.000148 0.002555 0.000039 0.000067
7680.000150 0.000144 0.002180 0.000038 0.000066
7690.000245 0.000152 0.002203 0.000038 0.000065
7700.000146 0.000142 0.002118 0.000036 0.000091
7710.000648 0.000141 0.002173 0.000035 0.000058
7720.000142 0.000149 0.002137 0.000037 0.000059
7730.000144 0.000138 0.002191 0.000037 0.000063
7740.000143 0.000137 0.002795 0.000039 0.000065
7750.000147 0.000256 0.002250 0.000038 0.000064
7760.000148 0.000142 0.002231 0.000040 0.000075
7770.000149 0.000143 0.002174 0.000038 0.000061
7780.000182 0.000708 0.002255 0.000038 0.000061
7790.000181 0.000170 0.002222 0.000038 0.000060
7800.000148 0.000141 0.002177 0.000038 0.000065
7810.000147 0.000141 0.002478 0.000039 0.000065
7820.000148 0.000141 0.002191 0.000039 0.000065
7830.000146 0.000139 0.002161 0.000067 0.000063
7840.000157 0.000138 0.002174 0.000036 0.000059
7850.000143 0.000165 0.002396 0.000040 0.000067
7860.000148 0.000141 0.002302 0.000044 0.000067
7870.000148 0.000142 0.002226 0.000043 0.000065
7880.000149 0.000142 0.002198 0.000038 0.000087
7890.000147 0.000143 0.002221 0.000039 0.000066
7900.000146 0.000142 0.002376 0.000065 0.000063
7910.000152 0.000154 0.002201 0.000038 0.000062
7920.000150 0.000142 0.002705 0.000039 0.000067
7930.000149 0.000142 0.002267 0.000039 0.000067
7940.000194 0.000149 0.002347 0.000039 0.000066
7950.000155 0.000141 0.002594 0.000038 0.000066
7960.000148 0.000141 0.002189 0.000038 0.000064
7970.000202 0.000142 0.002155 0.000039 0.000062
7980.000182 0.000146 0.002204 0.000037 0.000061
7990.000146 0.000139 0.002466 0.000037 0.000065
8000.000146 0.000140 0.002463 0.000036 0.000065
8010.000146 0.000139 0.002209 0.000037 0.000063
8020.000145 0.000138 0.002146 0.000036 0.000060
8030.000181 0.000142 0.003356 0.000038 0.000068
8040.000161 0.000142 0.002169 0.000038 0.000062
8050.000146 0.000175 0.002538 0.000039 0.000061
8060.000148 0.000141 0.002482 0.000039 0.000067
8070.000148 0.000144 0.002450 0.000040 0.000066
8080.000149 0.000143 0.002466 0.000043 0.000068
8090.000148 0.000144 0.003551 0.000038 0.000068
8100.000149 0.000142 0.002482 0.000039 0.000066
8110.000149 0.000142 0.002220 0.000039 0.000066
8120.000151 0.000140 0.002199 0.000038 0.000064
8130.000148 0.000184 0.002185 0.000038 0.000066
8140.000145 0.000140 0.002158 0.000036 0.000092
8150.000158 0.000140 0.002262 0.000038 0.000062
8160.000148 0.000143 0.002674 0.000039 0.000066
8170.000148 0.000140 0.002421 0.000039 0.000066
8180.000149 0.000149 0.002433 0.000038 0.000065
8190.000146 0.000172 0.002187 0.000038 0.000065
8200.000146 0.000140 0.002311 0.000039 0.000323
8210.000149 0.000142 0.002180 0.000038 0.000091
8220.000420 0.000143 0.002483 0.000038 0.000063
8230.000685 0.000145 0.002136 0.000035 0.000064
8240.000146 0.000145 0.002433 0.000038 0.000062
8250.000146 0.000139 0.002496 0.000039 0.000066
8260.000149 0.000139 0.003626 0.000041 0.000068
8270.000153 0.000147 0.002272 0.000042 0.000067
8280.000248 0.000155 0.002208 0.000038 0.000063
8290.000146 0.000138 0.002524 0.000038 0.000068
8300.000147 0.000140 0.002176 0.000210 0.000065
8310.000147 0.000140 0.002166 0.000036 0.000060
8320.000144 0.000146 0.002169 0.000036 0.000057
8330.000144 0.000138 0.002207 0.000037 0.000063
8340.000145 0.000138 0.002183 0.000037 0.000062
8350.000145 0.000137 0.002167 0.000036 0.000059
8360.000148 0.000453 0.002310 0.000038 0.000061
8370.000183 0.000855 0.002326 0.000037 0.000061
8380.000146 0.000175 0.002672 0.000036 0.000060
8390.000143 0.000140 0.002238 0.000039 0.000065
8400.000146 0.000139 0.002473 0.000037 0.000064
8410.000146 0.000139 0.002196 0.000039 0.000065
8420.000145 0.000139 0.002141 0.000036 0.000061
8430.000174 0.000397 0.002175 0.000036 0.000059
8440.000143 0.000139 0.002647 0.000037 0.000065
8450.000147 0.000138 0.002196 0.000037 0.000064
8460.000146 0.000138 0.002199 0.000037 0.000063
8470.000146 0.000138 0.002167 0.000036 0.000066
8480.000169 0.000141 0.002156 0.000036 0.000060
8490.000143 0.000139 0.002180 0.000037 0.000065
8500.000144 0.000136 0.002756 0.000039 0.000066
8510.000150 0.000141 0.002919 0.000039 0.000066
8520.000147 0.000140 0.002184 0.000036 0.000065
8530.000145 0.000138 0.002168 0.000036 0.000091
8540.000156 0.000139 0.002169 0.000036 0.000059
8550.000143 0.000139 0.002741 0.000038 0.000065
8560.000147 0.000140 0.002429 0.000037 0.000063
8570.000145 0.000139 0.002226 0.000037 0.000064
8580.000145 0.000139 0.003381 0.000040 0.000066
8590.000153 0.000141 0.002262 0.000038 0.000064
8600.000145 0.000140 0.002137 0.000036 0.000062
8610.000154 0.000650 0.002217 0.000038 0.000063
8620.000184 0.000143 0.002209 0.000038 0.000062
8630.000153 0.000142 0.002907 0.000039 0.000066
8640.000147 0.000142 0.002158 0.000038 0.000064
8650.000146 0.000140 0.002953 0.000039 0.000068
8660.000148 0.000143 0.002208 0.000039 0.000065
8670.000149 0.000139 0.002187 0.000036 0.000065
8680.000144 0.000139 0.002157 0.000036 0.000061
8690.000154 0.000926 0.002139 0.000036 0.000059
8700.000183 0.000140 0.002526 0.000038 0.000062
8710.000148 0.000142 0.002207 0.000038 0.000066
8720.000147 0.000139 0.002790 0.000039 0.000069
8730.000149 0.000144 0.002251 0.000038 0.000066
8740.000151 0.000140 0.002220 0.000039 0.000066
8750.000148 0.000142 0.002523 0.000038 0.000064
8760.000151 0.000138 0.002151 0.000037 0.000065
8770.000147 0.000140 0.002251 0.000037 0.000062
8780.000149 0.000139 0.002607 0.000037 0.000065
8790.000147 0.000141 0.003380 0.000037 0.000066
8800.000147 0.000139 0.002285 0.000069 0.000066
8810.000149 0.000142 0.002566 0.000038 0.000067
8820.000147 0.000142 0.002523 0.000038 0.000067
8830.000152 0.000143 0.002215 0.000038 0.000067
8840.000150 0.000144 0.002243 0.000038 0.000075
8850.000149 0.000141 0.002148 0.000036 0.000063
8860.000182 0.000144 0.002167 0.000036 0.000062
8870.000278 0.000155 0.002631 0.000036 0.000061
8880.000149 0.000139 0.003175 0.000040 0.000066
8890.000156 0.000140 0.002660 0.000038 0.000065
8900.000148 0.000141 0.006171 0.000067 0.000069
8910.000164 0.000142 0.002713 0.000038 0.000064
8920.000161 0.000150 0.002270 0.000038 0.000081
8930.000160 0.000283 0.002276 0.000038 0.000083
8940.000168 0.000150 0.002207 0.000037 0.000072
8950.000151 0.000669 0.002160 0.000038 0.000062
8960.000196 0.000156 0.002363 0.000036 0.000061
8970.000162 0.000141 0.002160 0.000037 0.000077
8980.000147 0.000141 0.002676 0.000038 0.000096
8990.000162 0.000143 0.002263 0.000037 0.000065
9000.000162 0.000141 0.002206 0.000036 0.000080
9010.000146 0.000139 0.002149 0.000036 0.000060
9020.000169 0.000884 0.002163 0.000036 0.000076
9030.000187 0.000140 0.002222 0.000036 0.000061
9040.000145 0.000140 0.002192 0.000037 0.000084
9050.000145 0.000138 0.002619 0.000039 0.000116
9060.000158 0.000149 0.002213 0.000038 0.000089
9070.000145 0.000183 0.002154 0.000038 0.000089
9080.000162 0.000142 0.002142 0.000037 0.000061
9090.000146 0.000178 0.002401 0.000038 0.000062
9100.000145 0.000150 0.002741 0.000037 0.000081
9110.000147 0.000139 0.002360 0.000040 0.000067
9120.000151 0.000153 0.002459 0.000039 0.000075
9130.000148 0.000155 0.002459 0.000037 0.000091
9140.000153 0.000152 0.002174 0.000036 0.000064
9150.000424 0.000149 0.002116 0.000036 0.000068
9160.000166 0.000168 0.002625 0.000038 0.000076
9170.000146 0.000141 0.002957 0.000038 0.000067
9180.000160 0.000142 0.002501 0.000039 0.000079
9190.000147 0.000143 0.002219 0.000038 0.000066
9200.000160 0.000143 0.002771 0.000040 0.000079
9210.000148 0.000150 0.002426 0.000037 0.000082
9220.000146 0.000138 0.002134 0.000036 0.000103
9230.000659 0.000143 0.002197 0.000036 0.000073
9240.000179 0.000153 0.002301 0.000038 0.000074
9250.000147 0.000142 0.002258 0.000038 0.000066
9260.000146 0.000141 0.002210 0.000038 0.000066
9270.000161 0.000141 0.002235 0.000038 0.000084
9280.000145 0.000138 0.002131 0.000036 0.000060
9290.000151 0.000211 0.002265 0.000038 0.000062
9300.000147 0.000142 0.002254 0.000038 0.000067
9310.000148 0.000143 0.002217 0.000038 0.000079
9320.000160 0.000155 0.002229 0.000038 0.000066
9330.000145 0.000142 0.002129 0.000038 0.000065
9340.000165 0.000140 0.002140 0.000036 0.000076
9350.000162 0.000142 0.002452 0.000039 0.000079
9360.000148 0.000143 0.002253 0.000059 0.000068
9370.000164 0.000142 0.003378 0.000039 0.000096
9380.000150 0.000194 0.002192 0.000039 0.000067
9390.000161 0.000152 0.002202 0.000037 0.000077
9400.000160 0.000141 0.002258 0.000039 0.000067
9410.000167 0.000143 0.002706 0.000039 0.000067
9420.000149 0.000155 0.002280 0.000037 0.000100
9430.000174 0.000144 0.002134 0.000037 0.000090
9440.001167 0.000154 0.002224 0.000038 0.000067
9450.000162 0.000155 0.002181 0.000035 0.000065
9460.000773 0.000153 0.002145 0.000036 0.000060
9470.000149 0.000161 0.002160 0.000036 0.000071
9480.000208 0.000144 0.002164 0.000035 0.000060
9490.000143 0.000138 0.002156 0.000036 0.000064
9500.000143 0.000138 0.002225 0.000055 0.000066
9510.000147 0.000141 0.002734 0.000038 0.000065
9520.000145 0.000147 0.002173 0.000037 0.000064
9530.000146 0.000139 0.002112 0.000037 0.000060
9540.000144 0.000137 0.002708 0.000038 0.000064
9550.000144 0.000139 0.002421 0.000037 0.000064
9560.000145 0.000140 0.002449 0.000037 0.000063
9570.000143 0.000138 0.002278 0.000038 0.000064
9580.000145 0.000140 0.002427 0.000040 0.000130
9590.000151 0.000142 0.002155 0.000036 0.000064
9600.000181 0.000139 0.002435 0.000036 0.000060
9610.000145 0.000138 0.003527 0.000038 0.000065
9620.000146 0.000178 0.002178 0.000036 0.000060
9630.000145 0.000138 0.002139 0.000037 0.000065
9640.000145 0.000137 0.003006 0.000037 0.000064
9650.000146 0.000139 0.002204 0.000037 0.000065
9660.000145 0.000139 0.002211 0.000038 0.000062
9670.000182 0.000140 0.002221 0.000036 0.000061
9680.000145 0.000139 0.003169 0.000038 0.000068
9690.000149 0.000174 0.002414 0.000038 0.000066
9700.000147 0.000142 0.002234 0.000038 0.000066
9710.000149 0.000143 0.002678 0.000038 0.000065
9720.000148 0.000141 0.002886 0.000038 0.000066
9730.000145 0.000140 0.002250 0.000038 0.000065
9740.000148 0.000139 0.002181 0.000035 0.000065
9750.000718 0.000142 0.002141 0.000035 0.000059
9760.000189 0.000140 0.002383 0.000036 0.000059
9770.000145 0.000139 0.002206 0.000039 0.000065
9780.000154 0.000186 0.002457 0.000038 0.000066
9790.000190 0.000141 0.002224 0.000038 0.000066
9800.000149 0.000141 0.002151 0.000037 0.000066
9810.000215 0.000143 0.002151 0.000035 0.000061
9820.000144 0.000138 0.002822 0.000039 0.000065
9830.000147 0.000139 0.002275 0.000038 0.000065
9840.000148 0.000141 0.002211 0.000036 0.000064
9850.000146 0.000138 0.002201 0.000037 0.000066
9860.000148 0.000140 0.002273 0.000038 0.000068
9870.000150 0.000144 0.002188 0.000037 0.000063
9880.000152 0.000151 0.002190 0.000037 0.000062
9890.000146 0.000142 0.003145 0.000039 0.000067
9900.000151 0.000139 0.002218 0.000037 0.000065
9910.000145 0.000138 0.002264 0.000037 0.000066
9920.000148 0.000142 0.003011 0.000039 0.000067
9930.000149 0.000141 0.002196 0.000038 0.000065
9940.000146 0.000141 0.002188 0.000036 0.000060
9950.000149 0.000140 0.002190 0.000035 0.000060
9960.000144 0.000137 0.002641 0.000038 0.000064
9970.000146 0.000138 0.002182 0.000043 0.000065
9980.000146 0.000141 0.002216 0.000036 0.000064
9990.000147 0.000139 0.002294 0.000039 0.000068
10000.000657 0.000145 0.002143 0.000037 0.000062
10010.000154 0.000415 0.002237 0.000040 0.000084
diff --git a/static/posts/dropbox-sync/dropbox-spaces.png b/static/posts/dropbox-sync/dropbox-spaces.png
deleted file mode 100755
index c90f99f..0000000
--- a/static/posts/dropbox-sync/dropbox-spaces.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/esp8366-micropython/boards.jpg b/static/posts/esp8366-micropython/boards.jpg
deleted file mode 100755
index 89e2b30..0000000
--- a/static/posts/esp8366-micropython/boards.jpg
+++ /dev/null
Binary files differ
diff --git a/static/posts/go-profiling/golang-profiling-cpu.pdf b/static/posts/go-profiling/golang-profiling-cpu.pdf
deleted file mode 100755
index 15241cb..0000000
--- a/static/posts/go-profiling/golang-profiling-cpu.pdf
+++ /dev/null
Binary files differ
diff --git a/static/posts/go-profiling/golang-profiling-mem.pdf b/static/posts/go-profiling/golang-profiling-mem.pdf
deleted file mode 100755
index 822e445..0000000
--- a/static/posts/go-profiling/golang-profiling-mem.pdf
+++ /dev/null
Binary files differ
diff --git a/static/posts/goaccess/goaccess-dash-html.png b/static/posts/goaccess/goaccess-dash-html.png
deleted file mode 100755
index 917d959..0000000
--- a/static/posts/goaccess/goaccess-dash-html.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/goaccess/goaccess-dash-term.png b/static/posts/goaccess/goaccess-dash-term.png
deleted file mode 100755
index e3f6357..0000000
--- a/static/posts/goaccess/goaccess-dash-term.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/godot-dynamic-tile-loading/2d-player-movement.webm b/static/posts/godot-dynamic-tile-loading/2d-player-movement.webm
deleted file mode 100644
index 579f2f3..0000000
--- a/static/posts/godot-dynamic-tile-loading/2d-player-movement.webm
+++ /dev/null
Binary files differ
diff --git a/static/posts/godot-dynamic-tile-loading/cellular-automata.png b/static/posts/godot-dynamic-tile-loading/cellular-automata.png
deleted file mode 100644
index 1b28242..0000000
--- a/static/posts/godot-dynamic-tile-loading/cellular-automata.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/godot-dynamic-tile-loading/example1/index.apple-touch-icon.png b/static/posts/godot-dynamic-tile-loading/example1/index.apple-touch-icon.png
deleted file mode 100644
index 880ae2d..0000000
--- a/static/posts/godot-dynamic-tile-loading/example1/index.apple-touch-icon.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/godot-dynamic-tile-loading/example1/index.audio.worklet.js b/static/posts/godot-dynamic-tile-loading/example1/index.audio.worklet.js
deleted file mode 100644
index ea4d8cb..0000000
--- a/static/posts/godot-dynamic-tile-loading/example1/index.audio.worklet.js
+++ /dev/null
@@ -1,211 +0,0 @@
1/*************************************************************************/
2/* audio.worklet.js */
3/*************************************************************************/
4/* This file is part of: */
5/* GODOT ENGINE */
6/* https://godotengine.org */
7/*************************************************************************/
8/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
9/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
10/* */
11/* Permission is hereby granted, free of charge, to any person obtaining */
12/* a copy of this software and associated documentation files (the */
13/* "Software"), to deal in the Software without restriction, including */
14/* without limitation the rights to use, copy, modify, merge, publish, */
15/* distribute, sublicense, and/or sell copies of the Software, and to */
16/* permit persons to whom the Software is furnished to do so, subject to */
17/* the following conditions: */
18/* */
19/* The above copyright notice and this permission notice shall be */
20/* included in all copies or substantial portions of the Software. */
21/* */
22/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
25/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29/*************************************************************************/
30
31class RingBuffer {
32 constructor(p_buffer, p_state, p_threads) {
33 this.buffer = p_buffer;
34 this.avail = p_state;
35 this.threads = p_threads;
36 this.rpos = 0;
37 this.wpos = 0;
38 }
39
40 data_left() {
41 return this.threads ? Atomics.load(this.avail, 0) : this.avail;
42 }
43
44 space_left() {
45 return this.buffer.length - this.data_left();
46 }
47
48 read(output) {
49 const size = this.buffer.length;
50 let from = 0;
51 let to_write = output.length;
52 if (this.rpos + to_write > size) {
53 const high = size - this.rpos;
54 output.set(this.buffer.subarray(this.rpos, size));
55 from = high;
56 to_write -= high;
57 this.rpos = 0;
58 }
59 if (to_write) {
60 output.set(this.buffer.subarray(this.rpos, this.rpos + to_write), from);
61 }
62 this.rpos += to_write;
63 if (this.threads) {
64 Atomics.add(this.avail, 0, -output.length);
65 Atomics.notify(this.avail, 0);
66 } else {
67 this.avail -= output.length;
68 }
69 }
70
71 write(p_buffer) {
72 const to_write = p_buffer.length;
73 const mw = this.buffer.length - this.wpos;
74 if (mw >= to_write) {
75 this.buffer.set(p_buffer, this.wpos);
76 this.wpos += to_write;
77 if (mw === to_write) {
78 this.wpos = 0;
79 }
80 } else {
81 const high = p_buffer.subarray(0, mw);
82 const low = p_buffer.subarray(mw);
83 this.buffer.set(high, this.wpos);
84 this.buffer.set(low);
85 this.wpos = low.length;
86 }
87 if (this.threads) {
88 Atomics.add(this.avail, 0, to_write);
89 Atomics.notify(this.avail, 0);
90 } else {
91 this.avail += to_write;
92 }
93 }
94}
95
96class GodotProcessor extends AudioWorkletProcessor {
97 constructor() {
98 super();
99 this.threads = false;
100 this.running = true;
101 this.lock = null;
102 this.notifier = null;
103 this.output = null;
104 this.output_buffer = new Float32Array();
105 this.input = null;
106 this.input_buffer = new Float32Array();
107 this.port.onmessage = (event) => {
108 const cmd = event.data['cmd'];
109 const data = event.data['data'];
110 this.parse_message(cmd, data);
111 };
112 }
113
114 process_notify() {
115 if (this.notifier) {
116 Atomics.add(this.notifier, 0, 1);
117 Atomics.notify(this.notifier, 0);
118 }
119 }
120
121 parse_message(p_cmd, p_data) {
122 if (p_cmd === 'start' && p_data) {
123 const state = p_data[0];
124 let idx = 0;
125 this.threads = true;
126 this.lock = state.subarray(idx, ++idx);
127 this.notifier = state.subarray(idx, ++idx);
128 const avail_in = state.subarray(idx, ++idx);
129 const avail_out = state.subarray(idx, ++idx);
130 this.input = new RingBuffer(p_data[1], avail_in, true);
131 this.output = new RingBuffer(p_data[2], avail_out, true);
132 } else if (p_cmd === 'stop') {
133 this.running = false;
134 this.output = null;
135 this.input = null;
136 } else if (p_cmd === 'start_nothreads') {
137 this.output = new RingBuffer(p_data[0], p_data[0].length, false);
138 } else if (p_cmd === 'chunk') {
139 this.output.write(p_data);
140 }
141 }
142
143 static array_has_data(arr) {
144 return arr.length && arr[0].length && arr[0][0].length;
145 }
146
147 process(inputs, outputs, parameters) {
148 if (!this.running) {
149 return false; // Stop processing.
150 }
151 if (this.output === null) {
152 return true; // Not ready yet, keep processing.
153 }
154 const process_input = GodotProcessor.array_has_data(inputs);
155 if (process_input) {
156 const input = inputs[0];
157 const chunk = input[0].length * input.length;
158 if (this.input_buffer.length !== chunk) {
159 this.input_buffer = new Float32Array(chunk);
160 }
161 if (!this.threads) {
162 GodotProcessor.write_input(this.input_buffer, input);
163 this.port.postMessage({ 'cmd': 'input', 'data': this.input_buffer });
164 } else if (this.input.space_left() >= chunk) {
165 GodotProcessor.write_input(this.input_buffer, input);
166 this.input.write(this.input_buffer);
167 } else {
168 this.port.postMessage('Input buffer is full! Skipping input frame.');
169 }
170 }
171 const process_output = GodotProcessor.array_has_data(outputs);
172 if (process_output) {
173 const output = outputs[0];
174 const chunk = output[0].length * output.length;
175 if (this.output_buffer.length !== chunk) {
176 this.output_buffer = new Float32Array(chunk);
177 }
178 if (this.output.data_left() >= chunk) {
179 this.output.read(this.output_buffer);
180 GodotProcessor.write_output(output, this.output_buffer);
181 if (!this.threads) {
182 this.port.postMessage({ 'cmd': 'read', 'data': chunk });
183 }
184 } else {
185 this.port.postMessage('Output buffer has not enough frames! Skipping output frame.');
186 }
187 }
188 this.process_notify();
189 return true;
190 }
191
192 static write_output(dest, source) {
193 const channels = dest.length;
194 for (let ch = 0; ch < channels; ch++) {
195 for (let sample = 0; sample < dest[ch].length; sample++) {
196 dest[ch][sample] = source[sample * channels + ch];
197 }
198 }
199 }
200
201 static write_input(dest, source) {
202 const channels = source.length;
203 for (let ch = 0; ch < channels; ch++) {
204 for (let sample = 0; sample < source[ch].length; sample++) {
205 dest[sample * channels + ch] = source[ch][sample];
206 }
207 }
208 }
209}
210
211registerProcessor('godot-processor', GodotProcessor);
diff --git a/static/posts/godot-dynamic-tile-loading/example1/index.html b/static/posts/godot-dynamic-tile-loading/example1/index.html
deleted file mode 100644
index e96af24..0000000
--- a/static/posts/godot-dynamic-tile-loading/example1/index.html
+++ /dev/null
@@ -1,248 +0,0 @@
1<!DOCTYPE html>
2<html xmlns='http://www.w3.org/1999/xhtml' lang='' xml:lang=''>
3<head>
4 <meta charset='utf-8' />
5 <meta name='viewport' content='width=device-width, user-scalable=no' />
6 <title>html1</title>
7 <style type='text/css'>
8
9 body {
10 touch-action: none;
11 margin: 0;
12 border: 0 none;
13 padding: 0;
14 text-align: center;
15 background-color: black;
16 }
17
18 #canvas {
19 display: block;
20 margin: 0;
21 color: white;
22 }
23
24 #canvas:focus {
25 outline: none;
26 }
27
28 .godot {
29 font-family: 'Noto Sans', 'Droid Sans', Arial, sans-serif;
30 color: #e0e0e0;
31 background-color: #3b3943;
32 background-image: linear-gradient(to bottom, #403e48, #35333c);
33 border: 1px solid #45434e;
34 box-shadow: 0 0 1px 1px #2f2d35;
35 }
36
37
38 /* Status display
39 * ============== */
40
41 #status {
42 position: absolute;
43 left: 0;
44 top: 0;
45 right: 0;
46 bottom: 0;
47 display: flex;
48 justify-content: center;
49 align-items: center;
50 /* don't consume click events - make children visible explicitly */
51 visibility: hidden;
52 }
53
54 #status-progress {
55 width: 366px;
56 height: 7px;
57 background-color: #38363A;
58 border: 1px solid #444246;
59 padding: 1px;
60 box-shadow: 0 0 2px 1px #1B1C22;
61 border-radius: 2px;
62 visibility: visible;
63 }
64
65 @media only screen and (orientation:portrait) {
66 #status-progress {
67 width: 61.8%;
68 }
69 }
70
71 #status-progress-inner {
72 height: 100%;
73 width: 0;
74 box-sizing: border-box;
75 transition: width 0.5s linear;
76 background-color: #202020;
77 border: 1px solid #222223;
78 box-shadow: 0 0 1px 1px #27282E;
79 border-radius: 3px;
80 }
81
82 #status-indeterminate {
83 height: 42px;
84 visibility: visible;
85 position: relative;
86 }
87
88 #status-indeterminate > div {
89 width: 4.5px;
90 height: 0;
91 border-style: solid;
92 border-width: 9px 3px 0 3px;
93 border-color: #2b2b2b transparent transparent transparent;
94 transform-origin: center 21px;
95 position: absolute;
96 }
97
98 #status-indeterminate > div:nth-child(1) { transform: rotate( 22.5deg); }
99 #status-indeterminate > div:nth-child(2) { transform: rotate( 67.5deg); }
100 #status-indeterminate > div:nth-child(3) { transform: rotate(112.5deg); }
101 #status-indeterminate > div:nth-child(4) { transform: rotate(157.5deg); }
102 #status-indeterminate > div:nth-child(5) { transform: rotate(202.5deg); }
103 #status-indeterminate > div:nth-child(6) { transform: rotate(247.5deg); }
104 #status-indeterminate > div:nth-child(7) { transform: rotate(292.5deg); }
105 #status-indeterminate > div:nth-child(8) { transform: rotate(337.5deg); }
106
107 #status-notice {
108 margin: 0 100px;
109 line-height: 1.3;
110 visibility: visible;
111 padding: 4px 6px;
112 visibility: visible;
113 }
114 </style>
115<link id='-gd-engine-icon' rel='icon' type='image/png' href='index.icon.png' />
116<link rel='apple-touch-icon' href='index.apple-touch-icon.png'/>
117
118</head>
119<body>
120 <canvas id='canvas'>
121 HTML5 canvas appears to be unsupported in the current browser.<br />
122 Please try updating or use a different browser.
123 </canvas>
124 <div id='status'>
125 <div id='status-progress' style='display: none;' oncontextmenu='event.preventDefault();'><div id ='status-progress-inner'></div></div>
126 <div id='status-indeterminate' style='display: none;' oncontextmenu='event.preventDefault();'>
127 <div></div>
128 <div></div>
129 <div></div>
130 <div></div>
131 <div></div>
132 <div></div>
133 <div></div>
134 <div></div>
135 </div>
136 <div id='status-notice' class='godot' style='display: none;'></div>
137 </div>
138
139 <script type='text/javascript' src='index.js'></script>
140 <script type='text/javascript'>//<![CDATA[
141
142 const GODOT_CONFIG = {"args":[],"canvasResizePolicy":2,"executable":"index","experimentalVK":false,"fileSizes":{"index.pck":7056,"index.wasm":13789463},"focusCanvas":true,"gdnativeLibs":[]};
143 var engine = new Engine(GODOT_CONFIG);
144
145 (function() {
146 const INDETERMINATE_STATUS_STEP_MS = 100;
147 var statusProgress = document.getElementById('status-progress');
148 var statusProgressInner = document.getElementById('status-progress-inner');
149 var statusIndeterminate = document.getElementById('status-indeterminate');
150 var statusNotice = document.getElementById('status-notice');
151
152 var initializing = true;
153 var statusMode = 'hidden';
154
155 var animationCallbacks = [];
156 function animate(time) {
157 animationCallbacks.forEach(callback => callback(time));
158 requestAnimationFrame(animate);
159 }
160 requestAnimationFrame(animate);
161
162 function setStatusMode(mode) {
163
164 if (statusMode === mode || !initializing)
165 return;
166 [statusProgress, statusIndeterminate, statusNotice].forEach(elem => {
167 elem.style.display = 'none';
168 });
169 animationCallbacks = animationCallbacks.filter(function(value) {
170 return (value != animateStatusIndeterminate);
171 });
172 switch (mode) {
173 case 'progress':
174 statusProgress.style.display = 'block';
175 break;
176 case 'indeterminate':
177 statusIndeterminate.style.display = 'block';
178 animationCallbacks.push(animateStatusIndeterminate);
179 break;
180 case 'notice':
181 statusNotice.style.display = 'block';
182 break;
183 case 'hidden':
184 break;
185 default:
186 throw new Error('Invalid status mode');
187 }
188 statusMode = mode;
189 }
190
191 function animateStatusIndeterminate(ms) {
192 var i = Math.floor(ms / INDETERMINATE_STATUS_STEP_MS % 8);
193 if (statusIndeterminate.children[i].style.borderTopColor == '') {
194 Array.prototype.slice.call(statusIndeterminate.children).forEach(child => {
195 child.style.borderTopColor = '';
196 });
197 statusIndeterminate.children[i].style.borderTopColor = '#dfdfdf';
198 }
199 }
200
201 function setStatusNotice(text) {
202 while (statusNotice.lastChild) {
203 statusNotice.removeChild(statusNotice.lastChild);
204 }
205 var lines = text.split('\n');
206 lines.forEach((line) => {
207 statusNotice.appendChild(document.createTextNode(line));
208 statusNotice.appendChild(document.createElement('br'));
209 });
210 };
211
212 function displayFailureNotice(err) {
213 var msg = err.message || err;
214 console.error(msg);
215 setStatusNotice(msg);
216 setStatusMode('notice');
217 initializing = false;
218 };
219
220 if (!Engine.isWebGLAvailable()) {
221 displayFailureNotice('WebGL not available');
222 } else {
223 setStatusMode('indeterminate');
224 engine.startGame({
225 'onProgress': function (current, total) {
226 if (total > 0) {
227 statusProgressInner.style.width = current/total * 100 + '%';
228 setStatusMode('progress');
229 if (current === total) {
230 // wait for progress bar animation
231 setTimeout(() => {
232 setStatusMode('indeterminate');
233 }, 500);
234 }
235 } else {
236 setStatusMode('indeterminate');
237 }
238 },
239 }).then(() => {
240 setStatusMode('hidden');
241 initializing = false;
242 }, displayFailureNotice);
243 }
244 })();
245 //]]></script>
246</body>
247</html>
248
diff --git a/static/posts/godot-dynamic-tile-loading/example1/index.icon.png b/static/posts/godot-dynamic-tile-loading/example1/index.icon.png
deleted file mode 100644
index c98fbb6..0000000
--- a/static/posts/godot-dynamic-tile-loading/example1/index.icon.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/godot-dynamic-tile-loading/example1/index.js b/static/posts/godot-dynamic-tile-loading/example1/index.js
deleted file mode 100644
index 1c18e52..0000000
--- a/static/posts/godot-dynamic-tile-loading/example1/index.js
+++ /dev/null
@@ -1,796 +0,0 @@
1
2var Godot = (() => {
3 var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined;
4
5 return (
6function(Godot) {
7 Godot = Godot || {};
8
9var Module=typeof Godot!="undefined"?Godot:{};var readyPromiseResolve,readyPromiseReject;Module["ready"]=new Promise(function(resolve,reject){readyPromiseResolve=resolve;readyPromiseReject=reject});var moduleOverrides=Object.assign({},Module);var arguments_=[];var thisProgram="./this.program";var quit_=(status,toThrow)=>{throw toThrow};var ENVIRONMENT_IS_WEB=typeof window=="object";var ENVIRONMENT_IS_WORKER=typeof importScripts=="function";var ENVIRONMENT_IS_NODE=typeof process=="object"&&typeof process.versions=="object"&&typeof process.versions.node=="string";var scriptDirectory="";function locateFile(path){if(Module["locateFile"]){return Module["locateFile"](path,scriptDirectory)}return scriptDirectory+path}var read_,readAsync,readBinary,setWindowTitle;if(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER){if(ENVIRONMENT_IS_WORKER){scriptDirectory=self.location.href}else if(typeof document!="undefined"&&document.currentScript){scriptDirectory=document.currentScript.src}if(_scriptDir){scriptDirectory=_scriptDir}if(scriptDirectory.indexOf("blob:")!==0){scriptDirectory=scriptDirectory.substr(0,scriptDirectory.replace(/[?#].*/,"").lastIndexOf("/")+1)}else{scriptDirectory=""}{read_=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.send(null);return xhr.responseText};if(ENVIRONMENT_IS_WORKER){readBinary=url=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,false);xhr.responseType="arraybuffer";xhr.send(null);return new Uint8Array(xhr.response)}}readAsync=(url,onload,onerror)=>{var xhr=new XMLHttpRequest;xhr.open("GET",url,true);xhr.responseType="arraybuffer";xhr.onload=()=>{if(xhr.status==200||xhr.status==0&&xhr.response){onload(xhr.response);return}onerror()};xhr.onerror=onerror;xhr.send(null)}}setWindowTitle=title=>document.title=title}else{}var out=Module["print"]||console.log.bind(console);var err=Module["printErr"]||console.warn.bind(console);Object.assign(Module,moduleOverrides);moduleOverrides=null;if(Module["arguments"])arguments_=Module["arguments"];if(Module["thisProgram"])thisProgram=Module["thisProgram"];if(Module["quit"])quit_=Module["quit"];function warnOnce(text){if(!warnOnce.shown)warnOnce.shown={};if(!warnOnce.shown[text]){warnOnce.shown[text]=1;err(text)}}var tempRet0=0;var setTempRet0=value=>{tempRet0=value};var getTempRet0=()=>tempRet0;var wasmBinary;if(Module["wasmBinary"])wasmBinary=Module["wasmBinary"];var noExitRuntime=Module["noExitRuntime"]||false;if(typeof WebAssembly!="object"){abort("no native wasm support detected")}var wasmMemory;var ABORT=false;var EXITSTATUS;function assert(condition,text){if(!condition){abort(text)}}function getCFunc(ident){var func=Module["_"+ident];return func}function ccall(ident,returnType,argTypes,args,opts){var toC={"string":function(str){var ret=0;if(str!==null&&str!==undefined&&str!==0){var len=(str.length<<2)+1;ret=stackAlloc(len);stringToUTF8(str,ret,len)}return ret},"array":function(arr){var ret=stackAlloc(arr.length);writeArrayToMemory(arr,ret);return ret}};function convertReturnValue(ret){if(returnType==="string"){return UTF8ToString(ret)}if(returnType==="boolean")return Boolean(ret);return ret}var func=getCFunc(ident);var cArgs=[];var stack=0;if(args){for(var i=0;i<args.length;i++){var converter=toC[argTypes[i]];if(converter){if(stack===0)stack=stackSave();cArgs[i]=converter(args[i])}else{cArgs[i]=args[i]}}}var ret=func.apply(null,cArgs);function onDone(ret){if(stack!==0)stackRestore(stack);return convertReturnValue(ret)}ret=onDone(ret);return ret}function cwrap(ident,returnType,argTypes,opts){argTypes=argTypes||[];var numericArgs=argTypes.every(function(type){return type==="number"});var numericRet=returnType!=="string";if(numericRet&&numericArgs&&!opts){return getCFunc(ident)}return function(){return ccall(ident,returnType,argTypes,arguments,opts)}}var UTF8Decoder=typeof TextDecoder!="undefined"?new TextDecoder("utf8"):undefined;function UTF8ArrayToString(heapOrArray,idx,maxBytesToRead){var endIdx=idx+maxBytesToRead;var endPtr=idx;while(heapOrArray[endPtr]&&!(endPtr>=endIdx))++endPtr;if(endPtr-idx>16&&heapOrArray.buffer&&UTF8Decoder){return UTF8Decoder.decode(heapOrArray.subarray(idx,endPtr))}else{var str="";while(idx<endPtr){var u0=heapOrArray[idx++];if(!(u0&128)){str+=String.fromCharCode(u0);continue}var u1=heapOrArray[idx++]&63;if((u0&224)==192){str+=String.fromCharCode((u0&31)<<6|u1);continue}var u2=heapOrArray[idx++]&63;if((u0&240)==224){u0=(u0&15)<<12|u1<<6|u2}else{u0=(u0&7)<<18|u1<<12|u2<<6|heapOrArray[idx++]&63}if(u0<65536){str+=String.fromCharCode(u0)}else{var ch=u0-65536;str+=String.fromCharCode(55296|ch>>10,56320|ch&1023)}}}return str}function UTF8ToString(ptr,maxBytesToRead){return ptr?UTF8ArrayToString(HEAPU8,ptr,maxBytesToRead):""}function stringToUTF8Array(str,heap,outIdx,maxBytesToWrite){if(!(maxBytesToWrite>0))return 0;var startIdx=outIdx;var endIdx=outIdx+maxBytesToWrite-1;for(var i=0;i<str.length;++i){var u=str.charCodeAt(i);if(u>=55296&&u<=57343){var u1=str.charCodeAt(++i);u=65536+((u&1023)<<10)|u1&1023}if(u<=127){if(outIdx>=endIdx)break;heap[outIdx++]=u}else if(u<=2047){if(outIdx+1>=endIdx)break;heap[outIdx++]=192|u>>6;heap[outIdx++]=128|u&63}else if(u<=65535){if(outIdx+2>=endIdx)break;heap[outIdx++]=224|u>>12;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}else{if(outIdx+3>=endIdx)break;heap[outIdx++]=240|u>>18;heap[outIdx++]=128|u>>12&63;heap[outIdx++]=128|u>>6&63;heap[outIdx++]=128|u&63}}heap[outIdx]=0;return outIdx-startIdx}function stringToUTF8(str,outPtr,maxBytesToWrite){return stringToUTF8Array(str,HEAPU8,outPtr,maxBytesToWrite)}function lengthBytesUTF8(str){var len=0;for(var i=0;i<str.length;++i){var u=str.charCodeAt(i);if(u>=55296&&u<=57343)u=65536+((u&1023)<<10)|str.charCodeAt(++i)&1023;if(u<=127)++len;else if(u<=2047)len+=2;else if(u<=65535)len+=3;else len+=4}return len}function allocateUTF8(str){var size=lengthBytesUTF8(str)+1;var ret=_malloc(size);if(ret)stringToUTF8Array(str,HEAP8,ret,size);return ret}function allocateUTF8OnStack(str){var size=lengthBytesUTF8(str)+1;var ret=stackAlloc(size);stringToUTF8Array(str,HEAP8,ret,size);return ret}function writeArrayToMemory(array,buffer){HEAP8.set(array,buffer)}function writeAsciiToMemory(str,buffer,dontAddNull){for(var i=0;i<str.length;++i){HEAP8[buffer++>>0]=str.charCodeAt(i)}if(!dontAddNull)HEAP8[buffer>>0]=0}var buffer,HEAP8,HEAPU8,HEAP16,HEAPU16,HEAP32,HEAPU32,HEAPF32,HEAPF64;function updateGlobalBufferAndViews(buf){buffer=buf;Module["HEAP8"]=HEAP8=new Int8Array(buf);Module["HEAP16"]=HEAP16=new Int16Array(buf);Module["HEAP32"]=HEAP32=new Int32Array(buf);Module["HEAPU8"]=HEAPU8=new Uint8Array(buf);Module["HEAPU16"]=HEAPU16=new Uint16Array(buf);Module["HEAPU32"]=HEAPU32=new Uint32Array(buf);Module["HEAPF32"]=HEAPF32=new Float32Array(buf);Module["HEAPF64"]=HEAPF64=new Float64Array(buf)}var INITIAL_MEMORY=Module["INITIAL_MEMORY"]||33554432;var wasmTable;var __ATPRERUN__=[];var __ATINIT__=[];var __ATMAIN__=[];var __ATEXIT__=[];var __ATPOSTRUN__=[];var runtimeInitialized=false;var runtimeExited=false;var runtimeKeepaliveCounter=0;function keepRuntimeAlive(){return noExitRuntime||runtimeKeepaliveCounter>0}function preRun(){if(Module["preRun"]){if(typeof Module["preRun"]=="function")Module["preRun"]=[Module["preRun"]];while(Module["preRun"].length){addOnPreRun(Module["preRun"].shift())}}callRuntimeCallbacks(__ATPRERUN__)}function initRuntime(){runtimeInitialized=true;if(!Module["noFSInit"]&&!FS.init.initialized)FS.init();FS.ignorePermissions=false;TTY.init();SOCKFS.root=FS.mount(SOCKFS,{},null);callRuntimeCallbacks(__ATINIT__)}function preMain(){callRuntimeCallbacks(__ATMAIN__)}function exitRuntime(){___funcs_on_exit();callRuntimeCallbacks(__ATEXIT__);FS.quit();TTY.shutdown();IDBFS.quit();runtimeExited=true}function postRun(){if(Module["postRun"]){if(typeof Module["postRun"]=="function")Module["postRun"]=[Module["postRun"]];while(Module["postRun"].length){addOnPostRun(Module["postRun"].shift())}}callRuntimeCallbacks(__ATPOSTRUN__)}function addOnPreRun(cb){__ATPRERUN__.unshift(cb)}function addOnInit(cb){__ATINIT__.unshift(cb)}function addOnPostRun(cb){__ATPOSTRUN__.unshift(cb)}var runDependencies=0;var runDependencyWatcher=null;var dependenciesFulfilled=null;function getUniqueRunDependency(id){return id}function addRunDependency(id){runDependencies++;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}}function removeRunDependency(id){runDependencies--;if(Module["monitorRunDependencies"]){Module["monitorRunDependencies"](runDependencies)}if(runDependencies==0){if(runDependencyWatcher!==null){clearInterval(runDependencyWatcher);runDependencyWatcher=null}if(dependenciesFulfilled){var callback=dependenciesFulfilled;dependenciesFulfilled=null;callback()}}}function abort(what){{if(Module["onAbort"]){Module["onAbort"](what)}}what="Aborted("+what+")";err(what);ABORT=true;EXITSTATUS=1;what+=". Build with -sASSERTIONS for more info.";var e=new WebAssembly.RuntimeError(what);readyPromiseReject(e);throw e}var dataURIPrefix="data:application/octet-stream;base64,";function isDataURI(filename){return filename.startsWith(dataURIPrefix)}var wasmBinaryFile;wasmBinaryFile="godot.javascript.opt.wasm";if(!isDataURI(wasmBinaryFile)){wasmBinaryFile=locateFile(wasmBinaryFile)}function getBinary(file){try{if(file==wasmBinaryFile&&wasmBinary){return new Uint8Array(wasmBinary)}if(readBinary){return readBinary(file)}else{throw"both async and sync fetching of the wasm failed"}}catch(err){abort(err)}}function getBinaryPromise(){if(!wasmBinary&&(ENVIRONMENT_IS_WEB||ENVIRONMENT_IS_WORKER)){if(typeof fetch=="function"){return fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){if(!response["ok"]){throw"failed to load wasm binary file at '"+wasmBinaryFile+"'"}return response["arrayBuffer"]()}).catch(function(){return getBinary(wasmBinaryFile)})}}return Promise.resolve().then(function(){return getBinary(wasmBinaryFile)})}function createWasm(){var info={"a":asmLibraryArg};function receiveInstance(instance,module){var exports=instance.exports;Module["asm"]=exports;wasmMemory=Module["asm"]["dk"];updateGlobalBufferAndViews(wasmMemory.buffer);wasmTable=Module["asm"]["rk"];addOnInit(Module["asm"]["ek"]);removeRunDependency("wasm-instantiate")}addRunDependency("wasm-instantiate");function receiveInstantiationResult(result){receiveInstance(result["instance"])}function instantiateArrayBuffer(receiver){return getBinaryPromise().then(function(binary){return WebAssembly.instantiate(binary,info)}).then(function(instance){return instance}).then(receiver,function(reason){err("failed to asynchronously prepare wasm: "+reason);abort(reason)})}function instantiateAsync(){if(!wasmBinary&&typeof WebAssembly.instantiateStreaming=="function"&&!isDataURI(wasmBinaryFile)&&typeof fetch=="function"){return fetch(wasmBinaryFile,{credentials:"same-origin"}).then(function(response){var result=WebAssembly.instantiateStreaming(response,info);return result.then(receiveInstantiationResult,function(reason){err("wasm streaming compile failed: "+reason);err("falling back to ArrayBuffer instantiation");return instantiateArrayBuffer(receiveInstantiationResult)})})}else{return instantiateArrayBuffer(receiveInstantiationResult)}}if(Module["instantiateWasm"]){try{var exports=Module["instantiateWasm"](info,receiveInstance);return exports}catch(e){err("Module.instantiateWasm callback failed with error: "+e);return false}}instantiateAsync().catch(readyPromiseReject);return{}}var tempDouble;var tempI64;function callRuntimeCallbacks(callbacks){while(callbacks.length>0){var callback=callbacks.shift();if(typeof callback=="function"){callback(Module);continue}var func=callback.func;if(typeof func=="number"){if(callback.arg===undefined){getWasmTableEntry(func)()}else{getWasmTableEntry(func)(callback.arg)}}else{func(callback.arg===undefined?null:callback.arg)}}}function getValue(ptr,type="i8"){if(type.endsWith("*"))type="i32";switch(type){case"i1":return HEAP8[ptr>>0];case"i8":return HEAP8[ptr>>0];case"i16":return HEAP16[ptr>>1];case"i32":return HEAP32[ptr>>2];case"i64":return HEAP32[ptr>>2];case"float":return HEAPF32[ptr>>2];case"double":return Number(HEAPF64[ptr>>3]);default:abort("invalid type for getValue: "+type)}return null}function getWasmTableEntry(funcPtr){return wasmTable.get(funcPtr)}function handleException(e){if(e instanceof ExitStatus||e=="unwind"){return EXITSTATUS}quit_(1,e)}function setValue(ptr,value,type="i8"){if(type.endsWith("*"))type="i32";switch(type){case"i1":HEAP8[ptr>>0]=value;break;case"i8":HEAP8[ptr>>0]=value;break;case"i16":HEAP16[ptr>>1]=value;break;case"i32":HEAP32[ptr>>2]=value;break;case"i64":tempI64=[value>>>0,(tempDouble=value,+Math.abs(tempDouble)>=1?tempDouble>0?(Math.min(+Math.floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[ptr>>2]=tempI64[0],HEAP32[ptr+4>>2]=tempI64[1];break;case"float":HEAPF32[ptr>>2]=value;break;case"double":HEAPF64[ptr>>3]=value;break;default:abort("invalid type for setValue: "+type)}}function ___call_sighandler(fp,sig){getWasmTableEntry(fp)(sig)}var PATH={isAbs:path=>path.charAt(0)==="/",splitPath:filename=>{var splitPathRe=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;return splitPathRe.exec(filename).slice(1)},normalizeArray:(parts,allowAboveRoot)=>{var up=0;for(var i=parts.length-1;i>=0;i--){var last=parts[i];if(last==="."){parts.splice(i,1)}else if(last===".."){parts.splice(i,1);up++}else if(up){parts.splice(i,1);up--}}if(allowAboveRoot){for(;up;up--){parts.unshift("..")}}return parts},normalize:path=>{var isAbsolute=PATH.isAbs(path),trailingSlash=path.substr(-1)==="/";path=PATH.normalizeArray(path.split("/").filter(p=>!!p),!isAbsolute).join("/");if(!path&&!isAbsolute){path="."}if(path&&trailingSlash){path+="/"}return(isAbsolute?"/":"")+path},dirname:path=>{var result=PATH.splitPath(path),root=result[0],dir=result[1];if(!root&&!dir){return"."}if(dir){dir=dir.substr(0,dir.length-1)}return root+dir},basename:path=>{if(path==="/")return"/";path=PATH.normalize(path);path=path.replace(/\/$/,"");var lastSlash=path.lastIndexOf("/");if(lastSlash===-1)return path;return path.substr(lastSlash+1)},join:function(){var paths=Array.prototype.slice.call(arguments,0);return PATH.normalize(paths.join("/"))},join2:(l,r)=>{return PATH.normalize(l+"/"+r)}};function getRandomDevice(){if(typeof crypto=="object"&&typeof crypto["getRandomValues"]=="function"){var randomBuffer=new Uint8Array(1);return function(){crypto.getRandomValues(randomBuffer);return randomBuffer[0]}}else return function(){abort("randomDevice")}}var PATH_FS={resolve:function(){var resolvedPath="",resolvedAbsolute=false;for(var i=arguments.length-1;i>=-1&&!resolvedAbsolute;i--){var path=i>=0?arguments[i]:FS.cwd();if(typeof path!="string"){throw new TypeError("Arguments to path.resolve must be strings")}else if(!path){return""}resolvedPath=path+"/"+resolvedPath;resolvedAbsolute=PATH.isAbs(path)}resolvedPath=PATH.normalizeArray(resolvedPath.split("/").filter(p=>!!p),!resolvedAbsolute).join("/");return(resolvedAbsolute?"/":"")+resolvedPath||"."},relative:(from,to)=>{from=PATH_FS.resolve(from).substr(1);to=PATH_FS.resolve(to).substr(1);function trim(arr){var start=0;for(;start<arr.length;start++){if(arr[start]!=="")break}var end=arr.length-1;for(;end>=0;end--){if(arr[end]!=="")break}if(start>end)return[];return arr.slice(start,end-start+1)}var fromParts=trim(from.split("/"));var toParts=trim(to.split("/"));var length=Math.min(fromParts.length,toParts.length);var samePartsLength=length;for(var i=0;i<length;i++){if(fromParts[i]!==toParts[i]){samePartsLength=i;break}}var outputParts=[];for(var i=samePartsLength;i<fromParts.length;i++){outputParts.push("..")}outputParts=outputParts.concat(toParts.slice(samePartsLength));return outputParts.join("/")}};var TTY={ttys:[],init:function(){},shutdown:function(){},register:function(dev,ops){TTY.ttys[dev]={input:[],output:[],ops:ops};FS.registerDevice(dev,TTY.stream_ops)},stream_ops:{open:function(stream){var tty=TTY.ttys[stream.node.rdev];if(!tty){throw new FS.ErrnoError(43)}stream.tty=tty;stream.seekable=false},close:function(stream){stream.tty.ops.flush(stream.tty)},flush:function(stream){stream.tty.ops.flush(stream.tty)},read:function(stream,buffer,offset,length,pos){if(!stream.tty||!stream.tty.ops.get_char){throw new FS.ErrnoError(60)}var bytesRead=0;for(var i=0;i<length;i++){var result;try{result=stream.tty.ops.get_char(stream.tty)}catch(e){throw new FS.ErrnoError(29)}if(result===undefined&&bytesRead===0){throw new FS.ErrnoError(6)}if(result===null||result===undefined)break;bytesRead++;buffer[offset+i]=result}if(bytesRead){stream.node.timestamp=Date.now()}return bytesRead},write:function(stream,buffer,offset,length,pos){if(!stream.tty||!stream.tty.ops.put_char){throw new FS.ErrnoError(60)}try{for(var i=0;i<length;i++){stream.tty.ops.put_char(stream.tty,buffer[offset+i])}}catch(e){throw new FS.ErrnoError(29)}if(length){stream.node.timestamp=Date.now()}return i}},default_tty_ops:{get_char:function(tty){if(!tty.input.length){var result=null;if(typeof window!="undefined"&&typeof window.prompt=="function"){result=window.prompt("Input: ");if(result!==null){result+="\n"}}else if(typeof readline=="function"){result=readline();if(result!==null){result+="\n"}}if(!result){return null}tty.input=intArrayFromString(result,true)}return tty.input.shift()},put_char:function(tty,val){if(val===null||val===10){out(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},flush:function(tty){if(tty.output&&tty.output.length>0){out(UTF8ArrayToString(tty.output,0));tty.output=[]}}},default_tty1_ops:{put_char:function(tty,val){if(val===null||val===10){err(UTF8ArrayToString(tty.output,0));tty.output=[]}else{if(val!=0)tty.output.push(val)}},flush:function(tty){if(tty.output&&tty.output.length>0){err(UTF8ArrayToString(tty.output,0));tty.output=[]}}}};function zeroMemory(address,size){HEAPU8.fill(0,address,address+size)}function mmapAlloc(size){abort()}var MEMFS={ops_table:null,mount:function(mount){return MEMFS.createNode(null,"/",16384|511,0)},createNode:function(parent,name,mode,dev){if(FS.isBlkdev(mode)||FS.isFIFO(mode)){throw new FS.ErrnoError(63)}if(!MEMFS.ops_table){MEMFS.ops_table={dir:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,lookup:MEMFS.node_ops.lookup,mknod:MEMFS.node_ops.mknod,rename:MEMFS.node_ops.rename,unlink:MEMFS.node_ops.unlink,rmdir:MEMFS.node_ops.rmdir,readdir:MEMFS.node_ops.readdir,symlink:MEMFS.node_ops.symlink},stream:{llseek:MEMFS.stream_ops.llseek}},file:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:{llseek:MEMFS.stream_ops.llseek,read:MEMFS.stream_ops.read,write:MEMFS.stream_ops.write,allocate:MEMFS.stream_ops.allocate,mmap:MEMFS.stream_ops.mmap,msync:MEMFS.stream_ops.msync}},link:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr,readlink:MEMFS.node_ops.readlink},stream:{}},chrdev:{node:{getattr:MEMFS.node_ops.getattr,setattr:MEMFS.node_ops.setattr},stream:FS.chrdev_stream_ops}}}var node=FS.createNode(parent,name,mode,dev);if(FS.isDir(node.mode)){node.node_ops=MEMFS.ops_table.dir.node;node.stream_ops=MEMFS.ops_table.dir.stream;node.contents={}}else if(FS.isFile(node.mode)){node.node_ops=MEMFS.ops_table.file.node;node.stream_ops=MEMFS.ops_table.file.stream;node.usedBytes=0;node.contents=null}else if(FS.isLink(node.mode)){node.node_ops=MEMFS.ops_table.link.node;node.stream_ops=MEMFS.ops_table.link.stream}else if(FS.isChrdev(node.mode)){node.node_ops=MEMFS.ops_table.chrdev.node;node.stream_ops=MEMFS.ops_table.chrdev.stream}node.timestamp=Date.now();if(parent){parent.contents[name]=node;parent.timestamp=node.timestamp}return node},getFileDataAsTypedArray:function(node){if(!node.contents)return new Uint8Array(0);if(node.contents.subarray)return node.contents.subarray(0,node.usedBytes);return new Uint8Array(node.contents)},expandFileStorage:function(node,newCapacity){var prevCapacity=node.contents?node.contents.length:0;if(prevCapacity>=newCapacity)return;var CAPACITY_DOUBLING_MAX=1024*1024;newCapacity=Math.max(newCapacity,prevCapacity*(prevCapacity<CAPACITY_DOUBLING_MAX?2:1.125)>>>0);if(prevCapacity!=0)newCapacity=Math.max(newCapacity,256);var oldContents=node.contents;node.contents=new Uint8Array(newCapacity);if(node.usedBytes>0)node.contents.set(oldContents.subarray(0,node.usedBytes),0)},resizeFileStorage:function(node,newSize){if(node.usedBytes==newSize)return;if(newSize==0){node.contents=null;node.usedBytes=0}else{var oldContents=node.contents;node.contents=new Uint8Array(newSize);if(oldContents){node.contents.set(oldContents.subarray(0,Math.min(newSize,node.usedBytes)))}node.usedBytes=newSize}},node_ops:{getattr:function(node){var attr={};attr.dev=FS.isChrdev(node.mode)?node.id:1;attr.ino=node.id;attr.mode=node.mode;attr.nlink=1;attr.uid=0;attr.gid=0;attr.rdev=node.rdev;if(FS.isDir(node.mode)){attr.size=4096}else if(FS.isFile(node.mode)){attr.size=node.usedBytes}else if(FS.isLink(node.mode)){attr.size=node.link.length}else{attr.size=0}attr.atime=new Date(node.timestamp);attr.mtime=new Date(node.timestamp);attr.ctime=new Date(node.timestamp);attr.blksize=4096;attr.blocks=Math.ceil(attr.size/attr.blksize);return attr},setattr:function(node,attr){if(attr.mode!==undefined){node.mode=attr.mode}if(attr.timestamp!==undefined){node.timestamp=attr.timestamp}if(attr.size!==undefined){MEMFS.resizeFileStorage(node,attr.size)}},lookup:function(parent,name){throw FS.genericErrors[44]},mknod:function(parent,name,mode,dev){return MEMFS.createNode(parent,name,mode,dev)},rename:function(old_node,new_dir,new_name){if(FS.isDir(old_node.mode)){var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(new_node){for(var i in new_node.contents){throw new FS.ErrnoError(55)}}}delete old_node.parent.contents[old_node.name];old_node.parent.timestamp=Date.now();old_node.name=new_name;new_dir.contents[new_name]=old_node;new_dir.timestamp=old_node.parent.timestamp;old_node.parent=new_dir},unlink:function(parent,name){delete parent.contents[name];parent.timestamp=Date.now()},rmdir:function(parent,name){var node=FS.lookupNode(parent,name);for(var i in node.contents){throw new FS.ErrnoError(55)}delete parent.contents[name];parent.timestamp=Date.now()},readdir:function(node){var entries=[".",".."];for(var key in node.contents){if(!node.contents.hasOwnProperty(key)){continue}entries.push(key)}return entries},symlink:function(parent,newname,oldpath){var node=MEMFS.createNode(parent,newname,511|40960,0);node.link=oldpath;return node},readlink:function(node){if(!FS.isLink(node.mode)){throw new FS.ErrnoError(28)}return node.link}},stream_ops:{read:function(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=stream.node.usedBytes)return 0;var size=Math.min(stream.node.usedBytes-position,length);if(size>8&&contents.subarray){buffer.set(contents.subarray(position,position+size),offset)}else{for(var i=0;i<size;i++)buffer[offset+i]=contents[position+i]}return size},write:function(stream,buffer,offset,length,position,canOwn){if(buffer.buffer===HEAP8.buffer){canOwn=false}if(!length)return 0;var node=stream.node;node.timestamp=Date.now();if(buffer.subarray&&(!node.contents||node.contents.subarray)){if(canOwn){node.contents=buffer.subarray(offset,offset+length);node.usedBytes=length;return length}else if(node.usedBytes===0&&position===0){node.contents=buffer.slice(offset,offset+length);node.usedBytes=length;return length}else if(position+length<=node.usedBytes){node.contents.set(buffer.subarray(offset,offset+length),position);return length}}MEMFS.expandFileStorage(node,position+length);if(node.contents.subarray&&buffer.subarray){node.contents.set(buffer.subarray(offset,offset+length),position)}else{for(var i=0;i<length;i++){node.contents[position+i]=buffer[offset+i]}}node.usedBytes=Math.max(node.usedBytes,position+length);return length},llseek:function(stream,offset,whence){var position=offset;if(whence===1){position+=stream.position}else if(whence===2){if(FS.isFile(stream.node.mode)){position+=stream.node.usedBytes}}if(position<0){throw new FS.ErrnoError(28)}return position},allocate:function(stream,offset,length){MEMFS.expandFileStorage(stream.node,offset+length);stream.node.usedBytes=Math.max(stream.node.usedBytes,offset+length)},mmap:function(stream,length,position,prot,flags){if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}var ptr;var allocated;var contents=stream.node.contents;if(!(flags&2)&&contents.buffer===buffer){allocated=false;ptr=contents.byteOffset}else{if(position>0||position+length<contents.length){if(contents.subarray){contents=contents.subarray(position,position+length)}else{contents=Array.prototype.slice.call(contents,position,position+length)}}allocated=true;ptr=mmapAlloc(length);if(!ptr){throw new FS.ErrnoError(48)}HEAP8.set(contents,ptr)}return{ptr:ptr,allocated:allocated}},msync:function(stream,buffer,offset,length,mmapFlags){if(!FS.isFile(stream.node.mode)){throw new FS.ErrnoError(43)}if(mmapFlags&2){return 0}var bytesWritten=MEMFS.stream_ops.write(stream,buffer,0,length,offset,false);return 0}}};function asyncLoad(url,onload,onerror,noRunDep){var dep=!noRunDep?getUniqueRunDependency("al "+url):"";readAsync(url,function(arrayBuffer){assert(arrayBuffer,'Loading data file "'+url+'" failed (no arrayBuffer).');onload(new Uint8Array(arrayBuffer));if(dep)removeRunDependency(dep)},function(event){if(onerror){onerror()}else{throw'Loading data file "'+url+'" failed.'}});if(dep)addRunDependency(dep)}var IDBFS={dbs:{},indexedDB:()=>{if(typeof indexedDB!="undefined")return indexedDB;var ret=null;if(typeof window=="object")ret=window.indexedDB||window.mozIndexedDB||window.webkitIndexedDB||window.msIndexedDB;assert(ret,"IDBFS used, but indexedDB not supported");return ret},DB_VERSION:21,DB_STORE_NAME:"FILE_DATA",mount:function(mount){return MEMFS.mount.apply(null,arguments)},syncfs:(mount,populate,callback)=>{IDBFS.getLocalSet(mount,(err,local)=>{if(err)return callback(err);IDBFS.getRemoteSet(mount,(err,remote)=>{if(err)return callback(err);var src=populate?remote:local;var dst=populate?local:remote;IDBFS.reconcile(src,dst,callback)})})},quit:()=>{Object.values(IDBFS.dbs).forEach(value=>value.close());IDBFS.dbs={}},getDB:(name,callback)=>{var db=IDBFS.dbs[name];if(db){return callback(null,db)}var req;try{req=IDBFS.indexedDB().open(name,IDBFS.DB_VERSION)}catch(e){return callback(e)}if(!req){return callback("Unable to connect to IndexedDB")}req.onupgradeneeded=e=>{var db=e.target.result;var transaction=e.target.transaction;var fileStore;if(db.objectStoreNames.contains(IDBFS.DB_STORE_NAME)){fileStore=transaction.objectStore(IDBFS.DB_STORE_NAME)}else{fileStore=db.createObjectStore(IDBFS.DB_STORE_NAME)}if(!fileStore.indexNames.contains("timestamp")){fileStore.createIndex("timestamp","timestamp",{unique:false})}};req.onsuccess=()=>{db=req.result;IDBFS.dbs[name]=db;callback(null,db)};req.onerror=e=>{callback(this.error);e.preventDefault()}},getLocalSet:(mount,callback)=>{var entries={};function isRealDir(p){return p!=="."&&p!==".."}function toAbsolute(root){return p=>{return PATH.join2(root,p)}}var check=FS.readdir(mount.mountpoint).filter(isRealDir).map(toAbsolute(mount.mountpoint));while(check.length){var path=check.pop();var stat;try{stat=FS.stat(path)}catch(e){return callback(e)}if(FS.isDir(stat.mode)){check.push.apply(check,FS.readdir(path).filter(isRealDir).map(toAbsolute(path)))}entries[path]={"timestamp":stat.mtime}}return callback(null,{type:"local",entries:entries})},getRemoteSet:(mount,callback)=>{var entries={};IDBFS.getDB(mount.mountpoint,(err,db)=>{if(err)return callback(err);try{var transaction=db.transaction([IDBFS.DB_STORE_NAME],"readonly");transaction.onerror=e=>{callback(this.error);e.preventDefault()};var store=transaction.objectStore(IDBFS.DB_STORE_NAME);var index=store.index("timestamp");index.openKeyCursor().onsuccess=event=>{var cursor=event.target.result;if(!cursor){return callback(null,{type:"remote",db:db,entries:entries})}entries[cursor.primaryKey]={"timestamp":cursor.key};cursor.continue()}}catch(e){return callback(e)}})},loadLocalEntry:(path,callback)=>{var stat,node;try{var lookup=FS.lookupPath(path);node=lookup.node;stat=FS.stat(path)}catch(e){return callback(e)}if(FS.isDir(stat.mode)){return callback(null,{"timestamp":stat.mtime,"mode":stat.mode})}else if(FS.isFile(stat.mode)){node.contents=MEMFS.getFileDataAsTypedArray(node);return callback(null,{"timestamp":stat.mtime,"mode":stat.mode,"contents":node.contents})}else{return callback(new Error("node type not supported"))}},storeLocalEntry:(path,entry,callback)=>{try{if(FS.isDir(entry["mode"])){FS.mkdirTree(path,entry["mode"])}else if(FS.isFile(entry["mode"])){FS.writeFile(path,entry["contents"],{canOwn:true})}else{return callback(new Error("node type not supported"))}FS.chmod(path,entry["mode"]);FS.utime(path,entry["timestamp"],entry["timestamp"])}catch(e){return callback(e)}callback(null)},removeLocalEntry:(path,callback)=>{try{var stat=FS.stat(path);if(FS.isDir(stat.mode)){FS.rmdir(path)}else if(FS.isFile(stat.mode)){FS.unlink(path)}}catch(e){return callback(e)}callback(null)},loadRemoteEntry:(store,path,callback)=>{var req=store.get(path);req.onsuccess=event=>{callback(null,event.target.result)};req.onerror=e=>{callback(this.error);e.preventDefault()}},storeRemoteEntry:(store,path,entry,callback)=>{try{var req=store.put(entry,path)}catch(e){callback(e);return}req.onsuccess=()=>{callback(null)};req.onerror=e=>{callback(this.error);e.preventDefault()}},removeRemoteEntry:(store,path,callback)=>{var req=store.delete(path);req.onsuccess=()=>{callback(null)};req.onerror=e=>{callback(this.error);e.preventDefault()}},reconcile:(src,dst,callback)=>{var total=0;var create=[];Object.keys(src.entries).forEach(function(key){var e=src.entries[key];var e2=dst.entries[key];if(!e2||e["timestamp"].getTime()!=e2["timestamp"].getTime()){create.push(key);total++}});var remove=[];Object.keys(dst.entries).forEach(function(key){if(!src.entries[key]){remove.push(key);total++}});if(!total){return callback(null)}var errored=false;var db=src.type==="remote"?src.db:dst.db;var transaction=db.transaction([IDBFS.DB_STORE_NAME],"readwrite");var store=transaction.objectStore(IDBFS.DB_STORE_NAME);function done(err){if(err&&!errored){errored=true;return callback(err)}}transaction.onerror=e=>{done(this.error);e.preventDefault()};transaction.oncomplete=e=>{if(!errored){callback(null)}};create.sort().forEach(path=>{if(dst.type==="local"){IDBFS.loadRemoteEntry(store,path,(err,entry)=>{if(err)return done(err);IDBFS.storeLocalEntry(path,entry,done)})}else{IDBFS.loadLocalEntry(path,(err,entry)=>{if(err)return done(err);IDBFS.storeRemoteEntry(store,path,entry,done)})}});remove.sort().reverse().forEach(path=>{if(dst.type==="local"){IDBFS.removeLocalEntry(path,done)}else{IDBFS.removeRemoteEntry(store,path,done)}})}};var FS={root:null,mounts:[],devices:{},streams:[],nextInode:1,nameTable:null,currentPath:"/",initialized:false,ignorePermissions:true,ErrnoError:null,genericErrors:{},filesystems:null,syncFSRequests:0,lookupPath:(path,opts={})=>{path=PATH_FS.resolve(FS.cwd(),path);if(!path)return{path:"",node:null};var defaults={follow_mount:true,recurse_count:0};opts=Object.assign(defaults,opts);if(opts.recurse_count>8){throw new FS.ErrnoError(32)}var parts=PATH.normalizeArray(path.split("/").filter(p=>!!p),false);var current=FS.root;var current_path="/";for(var i=0;i<parts.length;i++){var islast=i===parts.length-1;if(islast&&opts.parent){break}current=FS.lookupNode(current,parts[i]);current_path=PATH.join2(current_path,parts[i]);if(FS.isMountpoint(current)){if(!islast||islast&&opts.follow_mount){current=current.mounted.root}}if(!islast||opts.follow){var count=0;while(FS.isLink(current.mode)){var link=FS.readlink(current_path);current_path=PATH_FS.resolve(PATH.dirname(current_path),link);var lookup=FS.lookupPath(current_path,{recurse_count:opts.recurse_count+1});current=lookup.node;if(count++>40){throw new FS.ErrnoError(32)}}}}return{path:current_path,node:current}},getPath:node=>{var path;while(true){if(FS.isRoot(node)){var mount=node.mount.mountpoint;if(!path)return mount;return mount[mount.length-1]!=="/"?mount+"/"+path:mount+path}path=path?node.name+"/"+path:node.name;node=node.parent}},hashName:(parentid,name)=>{var hash=0;for(var i=0;i<name.length;i++){hash=(hash<<5)-hash+name.charCodeAt(i)|0}return(parentid+hash>>>0)%FS.nameTable.length},hashAddNode:node=>{var hash=FS.hashName(node.parent.id,node.name);node.name_next=FS.nameTable[hash];FS.nameTable[hash]=node},hashRemoveNode:node=>{var hash=FS.hashName(node.parent.id,node.name);if(FS.nameTable[hash]===node){FS.nameTable[hash]=node.name_next}else{var current=FS.nameTable[hash];while(current){if(current.name_next===node){current.name_next=node.name_next;break}current=current.name_next}}},lookupNode:(parent,name)=>{var errCode=FS.mayLookup(parent);if(errCode){throw new FS.ErrnoError(errCode,parent)}var hash=FS.hashName(parent.id,name);for(var node=FS.nameTable[hash];node;node=node.name_next){var nodeName=node.name;if(node.parent.id===parent.id&&nodeName===name){return node}}return FS.lookup(parent,name)},createNode:(parent,name,mode,rdev)=>{var node=new FS.FSNode(parent,name,mode,rdev);FS.hashAddNode(node);return node},destroyNode:node=>{FS.hashRemoveNode(node)},isRoot:node=>{return node===node.parent},isMountpoint:node=>{return!!node.mounted},isFile:mode=>{return(mode&61440)===32768},isDir:mode=>{return(mode&61440)===16384},isLink:mode=>{return(mode&61440)===40960},isChrdev:mode=>{return(mode&61440)===8192},isBlkdev:mode=>{return(mode&61440)===24576},isFIFO:mode=>{return(mode&61440)===4096},isSocket:mode=>{return(mode&49152)===49152},flagModes:{"r":0,"r+":2,"w":577,"w+":578,"a":1089,"a+":1090},modeStringToFlags:str=>{var flags=FS.flagModes[str];if(typeof flags=="undefined"){throw new Error("Unknown file open mode: "+str)}return flags},flagsToPermissionString:flag=>{var perms=["r","w","rw"][flag&3];if(flag&512){perms+="w"}return perms},nodePermissions:(node,perms)=>{if(FS.ignorePermissions){return 0}if(perms.includes("r")&&!(node.mode&292)){return 2}else if(perms.includes("w")&&!(node.mode&146)){return 2}else if(perms.includes("x")&&!(node.mode&73)){return 2}return 0},mayLookup:dir=>{var errCode=FS.nodePermissions(dir,"x");if(errCode)return errCode;if(!dir.node_ops.lookup)return 2;return 0},mayCreate:(dir,name)=>{try{var node=FS.lookupNode(dir,name);return 20}catch(e){}return FS.nodePermissions(dir,"wx")},mayDelete:(dir,name,isdir)=>{var node;try{node=FS.lookupNode(dir,name)}catch(e){return e.errno}var errCode=FS.nodePermissions(dir,"wx");if(errCode){return errCode}if(isdir){if(!FS.isDir(node.mode)){return 54}if(FS.isRoot(node)||FS.getPath(node)===FS.cwd()){return 10}}else{if(FS.isDir(node.mode)){return 31}}return 0},mayOpen:(node,flags)=>{if(!node){return 44}if(FS.isLink(node.mode)){return 32}else if(FS.isDir(node.mode)){if(FS.flagsToPermissionString(flags)!=="r"||flags&512){return 31}}return FS.nodePermissions(node,FS.flagsToPermissionString(flags))},MAX_OPEN_FDS:4096,nextfd:(fd_start=0,fd_end=FS.MAX_OPEN_FDS)=>{for(var fd=fd_start;fd<=fd_end;fd++){if(!FS.streams[fd]){return fd}}throw new FS.ErrnoError(33)},getStream:fd=>FS.streams[fd],createStream:(stream,fd_start,fd_end)=>{if(!FS.FSStream){FS.FSStream=function(){this.shared={}};FS.FSStream.prototype={};Object.defineProperties(FS.FSStream.prototype,{object:{get:function(){return this.node},set:function(val){this.node=val}},isRead:{get:function(){return(this.flags&2097155)!==1}},isWrite:{get:function(){return(this.flags&2097155)!==0}},isAppend:{get:function(){return this.flags&1024}},flags:{get:function(){return this.shared.flags},set:function(val){this.shared.flags=val}},position:{get:function(){return this.shared.position},set:function(val){this.shared.position=val}}})}stream=Object.assign(new FS.FSStream,stream);var fd=FS.nextfd(fd_start,fd_end);stream.fd=fd;FS.streams[fd]=stream;return stream},closeStream:fd=>{FS.streams[fd]=null},chrdev_stream_ops:{open:stream=>{var device=FS.getDevice(stream.node.rdev);stream.stream_ops=device.stream_ops;if(stream.stream_ops.open){stream.stream_ops.open(stream)}},llseek:()=>{throw new FS.ErrnoError(70)}},major:dev=>dev>>8,minor:dev=>dev&255,makedev:(ma,mi)=>ma<<8|mi,registerDevice:(dev,ops)=>{FS.devices[dev]={stream_ops:ops}},getDevice:dev=>FS.devices[dev],getMounts:mount=>{var mounts=[];var check=[mount];while(check.length){var m=check.pop();mounts.push(m);check.push.apply(check,m.mounts)}return mounts},syncfs:(populate,callback)=>{if(typeof populate=="function"){callback=populate;populate=false}FS.syncFSRequests++;if(FS.syncFSRequests>1){err("warning: "+FS.syncFSRequests+" FS.syncfs operations in flight at once, probably just doing extra work")}var mounts=FS.getMounts(FS.root.mount);var completed=0;function doCallback(errCode){FS.syncFSRequests--;return callback(errCode)}function done(errCode){if(errCode){if(!done.errored){done.errored=true;return doCallback(errCode)}return}if(++completed>=mounts.length){doCallback(null)}}mounts.forEach(mount=>{if(!mount.type.syncfs){return done(null)}mount.type.syncfs(mount,populate,done)})},mount:(type,opts,mountpoint)=>{var root=mountpoint==="/";var pseudo=!mountpoint;var node;if(root&&FS.root){throw new FS.ErrnoError(10)}else if(!root&&!pseudo){var lookup=FS.lookupPath(mountpoint,{follow_mount:false});mountpoint=lookup.path;node=lookup.node;if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}if(!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}}var mount={type:type,opts:opts,mountpoint:mountpoint,mounts:[]};var mountRoot=type.mount(mount);mountRoot.mount=mount;mount.root=mountRoot;if(root){FS.root=mountRoot}else if(node){node.mounted=mount;if(node.mount){node.mount.mounts.push(mount)}}return mountRoot},unmount:mountpoint=>{var lookup=FS.lookupPath(mountpoint,{follow_mount:false});if(!FS.isMountpoint(lookup.node)){throw new FS.ErrnoError(28)}var node=lookup.node;var mount=node.mounted;var mounts=FS.getMounts(mount);Object.keys(FS.nameTable).forEach(hash=>{var current=FS.nameTable[hash];while(current){var next=current.name_next;if(mounts.includes(current.mount)){FS.destroyNode(current)}current=next}});node.mounted=null;var idx=node.mount.mounts.indexOf(mount);node.mount.mounts.splice(idx,1)},lookup:(parent,name)=>{return parent.node_ops.lookup(parent,name)},mknod:(path,mode,dev)=>{var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);if(!name||name==="."||name===".."){throw new FS.ErrnoError(28)}var errCode=FS.mayCreate(parent,name);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.mknod){throw new FS.ErrnoError(63)}return parent.node_ops.mknod(parent,name,mode,dev)},create:(path,mode)=>{mode=mode!==undefined?mode:438;mode&=4095;mode|=32768;return FS.mknod(path,mode,0)},mkdir:(path,mode)=>{mode=mode!==undefined?mode:511;mode&=511|512;mode|=16384;return FS.mknod(path,mode,0)},mkdirTree:(path,mode)=>{var dirs=path.split("/");var d="";for(var i=0;i<dirs.length;++i){if(!dirs[i])continue;d+="/"+dirs[i];try{FS.mkdir(d,mode)}catch(e){if(e.errno!=20)throw e}}},mkdev:(path,mode,dev)=>{if(typeof dev=="undefined"){dev=mode;mode=438}mode|=8192;return FS.mknod(path,mode,dev)},symlink:(oldpath,newpath)=>{if(!PATH_FS.resolve(oldpath)){throw new FS.ErrnoError(44)}var lookup=FS.lookupPath(newpath,{parent:true});var parent=lookup.node;if(!parent){throw new FS.ErrnoError(44)}var newname=PATH.basename(newpath);var errCode=FS.mayCreate(parent,newname);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.symlink){throw new FS.ErrnoError(63)}return parent.node_ops.symlink(parent,newname,oldpath)},rename:(old_path,new_path)=>{var old_dirname=PATH.dirname(old_path);var new_dirname=PATH.dirname(new_path);var old_name=PATH.basename(old_path);var new_name=PATH.basename(new_path);var lookup,old_dir,new_dir;lookup=FS.lookupPath(old_path,{parent:true});old_dir=lookup.node;lookup=FS.lookupPath(new_path,{parent:true});new_dir=lookup.node;if(!old_dir||!new_dir)throw new FS.ErrnoError(44);if(old_dir.mount!==new_dir.mount){throw new FS.ErrnoError(75)}var old_node=FS.lookupNode(old_dir,old_name);var relative=PATH_FS.relative(old_path,new_dirname);if(relative.charAt(0)!=="."){throw new FS.ErrnoError(28)}relative=PATH_FS.relative(new_path,old_dirname);if(relative.charAt(0)!=="."){throw new FS.ErrnoError(55)}var new_node;try{new_node=FS.lookupNode(new_dir,new_name)}catch(e){}if(old_node===new_node){return}var isdir=FS.isDir(old_node.mode);var errCode=FS.mayDelete(old_dir,old_name,isdir);if(errCode){throw new FS.ErrnoError(errCode)}errCode=new_node?FS.mayDelete(new_dir,new_name,isdir):FS.mayCreate(new_dir,new_name);if(errCode){throw new FS.ErrnoError(errCode)}if(!old_dir.node_ops.rename){throw new FS.ErrnoError(63)}if(FS.isMountpoint(old_node)||new_node&&FS.isMountpoint(new_node)){throw new FS.ErrnoError(10)}if(new_dir!==old_dir){errCode=FS.nodePermissions(old_dir,"w");if(errCode){throw new FS.ErrnoError(errCode)}}FS.hashRemoveNode(old_node);try{old_dir.node_ops.rename(old_node,new_dir,new_name)}catch(e){throw e}finally{FS.hashAddNode(old_node)}},rmdir:path=>{var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;var name=PATH.basename(path);var node=FS.lookupNode(parent,name);var errCode=FS.mayDelete(parent,name,true);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.rmdir){throw new FS.ErrnoError(63)}if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}parent.node_ops.rmdir(parent,name);FS.destroyNode(node)},readdir:path=>{var lookup=FS.lookupPath(path,{follow:true});var node=lookup.node;if(!node.node_ops.readdir){throw new FS.ErrnoError(54)}return node.node_ops.readdir(node)},unlink:path=>{var lookup=FS.lookupPath(path,{parent:true});var parent=lookup.node;if(!parent){throw new FS.ErrnoError(44)}var name=PATH.basename(path);var node=FS.lookupNode(parent,name);var errCode=FS.mayDelete(parent,name,false);if(errCode){throw new FS.ErrnoError(errCode)}if(!parent.node_ops.unlink){throw new FS.ErrnoError(63)}if(FS.isMountpoint(node)){throw new FS.ErrnoError(10)}parent.node_ops.unlink(parent,name);FS.destroyNode(node)},readlink:path=>{var lookup=FS.lookupPath(path);var link=lookup.node;if(!link){throw new FS.ErrnoError(44)}if(!link.node_ops.readlink){throw new FS.ErrnoError(28)}return PATH_FS.resolve(FS.getPath(link.parent),link.node_ops.readlink(link))},stat:(path,dontFollow)=>{var lookup=FS.lookupPath(path,{follow:!dontFollow});var node=lookup.node;if(!node){throw new FS.ErrnoError(44)}if(!node.node_ops.getattr){throw new FS.ErrnoError(63)}return node.node_ops.getattr(node)},lstat:path=>{return FS.stat(path,true)},chmod:(path,mode,dontFollow)=>{var node;if(typeof path=="string"){var lookup=FS.lookupPath(path,{follow:!dontFollow});node=lookup.node}else{node=path}if(!node.node_ops.setattr){throw new FS.ErrnoError(63)}node.node_ops.setattr(node,{mode:mode&4095|node.mode&~4095,timestamp:Date.now()})},lchmod:(path,mode)=>{FS.chmod(path,mode,true)},fchmod:(fd,mode)=>{var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}FS.chmod(stream.node,mode)},chown:(path,uid,gid,dontFollow)=>{var node;if(typeof path=="string"){var lookup=FS.lookupPath(path,{follow:!dontFollow});node=lookup.node}else{node=path}if(!node.node_ops.setattr){throw new FS.ErrnoError(63)}node.node_ops.setattr(node,{timestamp:Date.now()})},lchown:(path,uid,gid)=>{FS.chown(path,uid,gid,true)},fchown:(fd,uid,gid)=>{var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}FS.chown(stream.node,uid,gid)},truncate:(path,len)=>{if(len<0){throw new FS.ErrnoError(28)}var node;if(typeof path=="string"){var lookup=FS.lookupPath(path,{follow:true});node=lookup.node}else{node=path}if(!node.node_ops.setattr){throw new FS.ErrnoError(63)}if(FS.isDir(node.mode)){throw new FS.ErrnoError(31)}if(!FS.isFile(node.mode)){throw new FS.ErrnoError(28)}var errCode=FS.nodePermissions(node,"w");if(errCode){throw new FS.ErrnoError(errCode)}node.node_ops.setattr(node,{size:len,timestamp:Date.now()})},ftruncate:(fd,len)=>{var stream=FS.getStream(fd);if(!stream){throw new FS.ErrnoError(8)}if((stream.flags&2097155)===0){throw new FS.ErrnoError(28)}FS.truncate(stream.node,len)},utime:(path,atime,mtime)=>{var lookup=FS.lookupPath(path,{follow:true});var node=lookup.node;node.node_ops.setattr(node,{timestamp:Math.max(atime,mtime)})},open:(path,flags,mode)=>{if(path===""){throw new FS.ErrnoError(44)}flags=typeof flags=="string"?FS.modeStringToFlags(flags):flags;mode=typeof mode=="undefined"?438:mode;if(flags&64){mode=mode&4095|32768}else{mode=0}var node;if(typeof path=="object"){node=path}else{path=PATH.normalize(path);try{var lookup=FS.lookupPath(path,{follow:!(flags&131072)});node=lookup.node}catch(e){}}var created=false;if(flags&64){if(node){if(flags&128){throw new FS.ErrnoError(20)}}else{node=FS.mknod(path,mode,0);created=true}}if(!node){throw new FS.ErrnoError(44)}if(FS.isChrdev(node.mode)){flags&=~512}if(flags&65536&&!FS.isDir(node.mode)){throw new FS.ErrnoError(54)}if(!created){var errCode=FS.mayOpen(node,flags);if(errCode){throw new FS.ErrnoError(errCode)}}if(flags&512&&!created){FS.truncate(node,0)}flags&=~(128|512|131072);var stream=FS.createStream({node:node,path:FS.getPath(node),flags:flags,seekable:true,position:0,stream_ops:node.stream_ops,ungotten:[],error:false});if(stream.stream_ops.open){stream.stream_ops.open(stream)}if(Module["logReadFiles"]&&!(flags&1)){if(!FS.readFiles)FS.readFiles={};if(!(path in FS.readFiles)){FS.readFiles[path]=1}}return stream},close:stream=>{if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if(stream.getdents)stream.getdents=null;try{if(stream.stream_ops.close){stream.stream_ops.close(stream)}}catch(e){throw e}finally{FS.closeStream(stream.fd)}stream.fd=null},isClosed:stream=>{return stream.fd===null},llseek:(stream,offset,whence)=>{if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if(!stream.seekable||!stream.stream_ops.llseek){throw new FS.ErrnoError(70)}if(whence!=0&&whence!=1&&whence!=2){throw new FS.ErrnoError(28)}stream.position=stream.stream_ops.llseek(stream,offset,whence);stream.ungotten=[];return stream.position},read:(stream,buffer,offset,length,position)=>{if(length<0||position<0){throw new FS.ErrnoError(28)}if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if((stream.flags&2097155)===1){throw new FS.ErrnoError(8)}if(FS.isDir(stream.node.mode)){throw new FS.ErrnoError(31)}if(!stream.stream_ops.read){throw new FS.ErrnoError(28)}var seeking=typeof position!="undefined";if(!seeking){position=stream.position}else if(!stream.seekable){throw new FS.ErrnoError(70)}var bytesRead=stream.stream_ops.read(stream,buffer,offset,length,position);if(!seeking)stream.position+=bytesRead;return bytesRead},write:(stream,buffer,offset,length,position,canOwn)=>{if(length<0||position<0){throw new FS.ErrnoError(28)}if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if((stream.flags&2097155)===0){throw new FS.ErrnoError(8)}if(FS.isDir(stream.node.mode)){throw new FS.ErrnoError(31)}if(!stream.stream_ops.write){throw new FS.ErrnoError(28)}if(stream.seekable&&stream.flags&1024){FS.llseek(stream,0,2)}var seeking=typeof position!="undefined";if(!seeking){position=stream.position}else if(!stream.seekable){throw new FS.ErrnoError(70)}var bytesWritten=stream.stream_ops.write(stream,buffer,offset,length,position,canOwn);if(!seeking)stream.position+=bytesWritten;return bytesWritten},allocate:(stream,offset,length)=>{if(FS.isClosed(stream)){throw new FS.ErrnoError(8)}if(offset<0||length<=0){throw new FS.ErrnoError(28)}if((stream.flags&2097155)===0){throw new FS.ErrnoError(8)}if(!FS.isFile(stream.node.mode)&&!FS.isDir(stream.node.mode)){throw new FS.ErrnoError(43)}if(!stream.stream_ops.allocate){throw new FS.ErrnoError(138)}stream.stream_ops.allocate(stream,offset,length)},mmap:(stream,length,position,prot,flags)=>{if((prot&2)!==0&&(flags&2)===0&&(stream.flags&2097155)!==2){throw new FS.ErrnoError(2)}if((stream.flags&2097155)===1){throw new FS.ErrnoError(2)}if(!stream.stream_ops.mmap){throw new FS.ErrnoError(43)}return stream.stream_ops.mmap(stream,length,position,prot,flags)},msync:(stream,buffer,offset,length,mmapFlags)=>{if(!stream||!stream.stream_ops.msync){return 0}return stream.stream_ops.msync(stream,buffer,offset,length,mmapFlags)},munmap:stream=>0,ioctl:(stream,cmd,arg)=>{if(!stream.stream_ops.ioctl){throw new FS.ErrnoError(59)}return stream.stream_ops.ioctl(stream,cmd,arg)},readFile:(path,opts={})=>{opts.flags=opts.flags||0;opts.encoding=opts.encoding||"binary";if(opts.encoding!=="utf8"&&opts.encoding!=="binary"){throw new Error('Invalid encoding type "'+opts.encoding+'"')}var ret;var stream=FS.open(path,opts.flags);var stat=FS.stat(path);var length=stat.size;var buf=new Uint8Array(length);FS.read(stream,buf,0,length,0);if(opts.encoding==="utf8"){ret=UTF8ArrayToString(buf,0)}else if(opts.encoding==="binary"){ret=buf}FS.close(stream);return ret},writeFile:(path,data,opts={})=>{opts.flags=opts.flags||577;var stream=FS.open(path,opts.flags,opts.mode);if(typeof data=="string"){var buf=new Uint8Array(lengthBytesUTF8(data)+1);var actualNumBytes=stringToUTF8Array(data,buf,0,buf.length);FS.write(stream,buf,0,actualNumBytes,undefined,opts.canOwn)}else if(ArrayBuffer.isView(data)){FS.write(stream,data,0,data.byteLength,undefined,opts.canOwn)}else{throw new Error("Unsupported data type")}FS.close(stream)},cwd:()=>FS.currentPath,chdir:path=>{var lookup=FS.lookupPath(path,{follow:true});if(lookup.node===null){throw new FS.ErrnoError(44)}if(!FS.isDir(lookup.node.mode)){throw new FS.ErrnoError(54)}var errCode=FS.nodePermissions(lookup.node,"x");if(errCode){throw new FS.ErrnoError(errCode)}FS.currentPath=lookup.path},createDefaultDirectories:()=>{FS.mkdir("/tmp");FS.mkdir("/home");FS.mkdir("/home/web_user")},createDefaultDevices:()=>{FS.mkdir("/dev");FS.registerDevice(FS.makedev(1,3),{read:()=>0,write:(stream,buffer,offset,length,pos)=>length});FS.mkdev("/dev/null",FS.makedev(1,3));TTY.register(FS.makedev(5,0),TTY.default_tty_ops);TTY.register(FS.makedev(6,0),TTY.default_tty1_ops);FS.mkdev("/dev/tty",FS.makedev(5,0));FS.mkdev("/dev/tty1",FS.makedev(6,0));var random_device=getRandomDevice();FS.createDevice("/dev","random",random_device);FS.createDevice("/dev","urandom",random_device);FS.mkdir("/dev/shm");FS.mkdir("/dev/shm/tmp")},createSpecialDirectories:()=>{FS.mkdir("/proc");var proc_self=FS.mkdir("/proc/self");FS.mkdir("/proc/self/fd");FS.mount({mount:()=>{var node=FS.createNode(proc_self,"fd",16384|511,73);node.node_ops={lookup:(parent,name)=>{var fd=+name;var stream=FS.getStream(fd);if(!stream)throw new FS.ErrnoError(8);var ret={parent:null,mount:{mountpoint:"fake"},node_ops:{readlink:()=>stream.path}};ret.parent=ret;return ret}};return node}},{},"/proc/self/fd")},createStandardStreams:()=>{if(Module["stdin"]){FS.createDevice("/dev","stdin",Module["stdin"])}else{FS.symlink("/dev/tty","/dev/stdin")}if(Module["stdout"]){FS.createDevice("/dev","stdout",null,Module["stdout"])}else{FS.symlink("/dev/tty","/dev/stdout")}if(Module["stderr"]){FS.createDevice("/dev","stderr",null,Module["stderr"])}else{FS.symlink("/dev/tty1","/dev/stderr")}var stdin=FS.open("/dev/stdin",0);var stdout=FS.open("/dev/stdout",1);var stderr=FS.open("/dev/stderr",1)},ensureErrnoError:()=>{if(FS.ErrnoError)return;FS.ErrnoError=function ErrnoError(errno,node){this.node=node;this.setErrno=function(errno){this.errno=errno};this.setErrno(errno);this.message="FS error"};FS.ErrnoError.prototype=new Error;FS.ErrnoError.prototype.constructor=FS.ErrnoError;[44].forEach(code=>{FS.genericErrors[code]=new FS.ErrnoError(code);FS.genericErrors[code].stack="<generic error, no stack>"})},staticInit:()=>{FS.ensureErrnoError();FS.nameTable=new Array(4096);FS.mount(MEMFS,{},"/");FS.createDefaultDirectories();FS.createDefaultDevices();FS.createSpecialDirectories();FS.filesystems={"MEMFS":MEMFS,"IDBFS":IDBFS}},init:(input,output,error)=>{FS.init.initialized=true;FS.ensureErrnoError();Module["stdin"]=input||Module["stdin"];Module["stdout"]=output||Module["stdout"];Module["stderr"]=error||Module["stderr"];FS.createStandardStreams()},quit:()=>{FS.init.initialized=false;_fflush(0);for(var i=0;i<FS.streams.length;i++){var stream=FS.streams[i];if(!stream){continue}FS.close(stream)}},getMode:(canRead,canWrite)=>{var mode=0;if(canRead)mode|=292|73;if(canWrite)mode|=146;return mode},findObject:(path,dontResolveLastLink)=>{var ret=FS.analyzePath(path,dontResolveLastLink);if(ret.exists){return ret.object}else{return null}},analyzePath:(path,dontResolveLastLink)=>{try{var lookup=FS.lookupPath(path,{follow:!dontResolveLastLink});path=lookup.path}catch(e){}var ret={isRoot:false,exists:false,error:0,name:null,path:null,object:null,parentExists:false,parentPath:null,parentObject:null};try{var lookup=FS.lookupPath(path,{parent:true});ret.parentExists=true;ret.parentPath=lookup.path;ret.parentObject=lookup.node;ret.name=PATH.basename(path);lookup=FS.lookupPath(path,{follow:!dontResolveLastLink});ret.exists=true;ret.path=lookup.path;ret.object=lookup.node;ret.name=lookup.node.name;ret.isRoot=lookup.path==="/"}catch(e){ret.error=e.errno}return ret},createPath:(parent,path,canRead,canWrite)=>{parent=typeof parent=="string"?parent:FS.getPath(parent);var parts=path.split("/").reverse();while(parts.length){var part=parts.pop();if(!part)continue;var current=PATH.join2(parent,part);try{FS.mkdir(current)}catch(e){}parent=current}return current},createFile:(parent,name,properties,canRead,canWrite)=>{var path=PATH.join2(typeof parent=="string"?parent:FS.getPath(parent),name);var mode=FS.getMode(canRead,canWrite);return FS.create(path,mode)},createDataFile:(parent,name,data,canRead,canWrite,canOwn)=>{var path=name;if(parent){parent=typeof parent=="string"?parent:FS.getPath(parent);path=name?PATH.join2(parent,name):parent}var mode=FS.getMode(canRead,canWrite);var node=FS.create(path,mode);if(data){if(typeof data=="string"){var arr=new Array(data.length);for(var i=0,len=data.length;i<len;++i)arr[i]=data.charCodeAt(i);data=arr}FS.chmod(node,mode|146);var stream=FS.open(node,577);FS.write(stream,data,0,data.length,0,canOwn);FS.close(stream);FS.chmod(node,mode)}return node},createDevice:(parent,name,input,output)=>{var path=PATH.join2(typeof parent=="string"?parent:FS.getPath(parent),name);var mode=FS.getMode(!!input,!!output);if(!FS.createDevice.major)FS.createDevice.major=64;var dev=FS.makedev(FS.createDevice.major++,0);FS.registerDevice(dev,{open:stream=>{stream.seekable=false},close:stream=>{if(output&&output.buffer&&output.buffer.length){output(10)}},read:(stream,buffer,offset,length,pos)=>{var bytesRead=0;for(var i=0;i<length;i++){var result;try{result=input()}catch(e){throw new FS.ErrnoError(29)}if(result===undefined&&bytesRead===0){throw new FS.ErrnoError(6)}if(result===null||result===undefined)break;bytesRead++;buffer[offset+i]=result}if(bytesRead){stream.node.timestamp=Date.now()}return bytesRead},write:(stream,buffer,offset,length,pos)=>{for(var i=0;i<length;i++){try{output(buffer[offset+i])}catch(e){throw new FS.ErrnoError(29)}}if(length){stream.node.timestamp=Date.now()}return i}});return FS.mkdev(path,mode,dev)},forceLoadFile:obj=>{if(obj.isDevice||obj.isFolder||obj.link||obj.contents)return true;if(typeof XMLHttpRequest!="undefined"){throw new Error("Lazy loading should have been performed (contents set) in createLazyFile, but it was not. Lazy loading only works in web workers. Use --embed-file or --preload-file in emcc on the main thread.")}else if(read_){try{obj.contents=intArrayFromString(read_(obj.url),true);obj.usedBytes=obj.contents.length}catch(e){throw new FS.ErrnoError(29)}}else{throw new Error("Cannot load without read() or XMLHttpRequest.")}},createLazyFile:(parent,name,url,canRead,canWrite)=>{function LazyUint8Array(){this.lengthKnown=false;this.chunks=[]}LazyUint8Array.prototype.get=function LazyUint8Array_get(idx){if(idx>this.length-1||idx<0){return undefined}var chunkOffset=idx%this.chunkSize;var chunkNum=idx/this.chunkSize|0;return this.getter(chunkNum)[chunkOffset]};LazyUint8Array.prototype.setDataGetter=function LazyUint8Array_setDataGetter(getter){this.getter=getter};LazyUint8Array.prototype.cacheLength=function LazyUint8Array_cacheLength(){var xhr=new XMLHttpRequest;xhr.open("HEAD",url,false);xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);var datalength=Number(xhr.getResponseHeader("Content-length"));var header;var hasByteServing=(header=xhr.getResponseHeader("Accept-Ranges"))&&header==="bytes";var usesGzip=(header=xhr.getResponseHeader("Content-Encoding"))&&header==="gzip";var chunkSize=1024*1024;if(!hasByteServing)chunkSize=datalength;var doXHR=(from,to)=>{if(from>to)throw new Error("invalid range ("+from+", "+to+") or no bytes requested!");if(to>datalength-1)throw new Error("only "+datalength+" bytes available! programmer error!");var xhr=new XMLHttpRequest;xhr.open("GET",url,false);if(datalength!==chunkSize)xhr.setRequestHeader("Range","bytes="+from+"-"+to);xhr.responseType="arraybuffer";if(xhr.overrideMimeType){xhr.overrideMimeType("text/plain; charset=x-user-defined")}xhr.send(null);if(!(xhr.status>=200&&xhr.status<300||xhr.status===304))throw new Error("Couldn't load "+url+". Status: "+xhr.status);if(xhr.response!==undefined){return new Uint8Array(xhr.response||[])}else{return intArrayFromString(xhr.responseText||"",true)}};var lazyArray=this;lazyArray.setDataGetter(chunkNum=>{var start=chunkNum*chunkSize;var end=(chunkNum+1)*chunkSize-1;end=Math.min(end,datalength-1);if(typeof lazyArray.chunks[chunkNum]=="undefined"){lazyArray.chunks[chunkNum]=doXHR(start,end)}if(typeof lazyArray.chunks[chunkNum]=="undefined")throw new Error("doXHR failed!");return lazyArray.chunks[chunkNum]});if(usesGzip||!datalength){chunkSize=datalength=1;datalength=this.getter(0).length;chunkSize=datalength;out("LazyFiles on gzip forces download of the whole file when length is accessed")}this._length=datalength;this._chunkSize=chunkSize;this.lengthKnown=true};if(typeof XMLHttpRequest!="undefined"){if(!ENVIRONMENT_IS_WORKER)throw"Cannot do synchronous binary XHRs outside webworkers in modern browsers. Use --embed-file or --preload-file in emcc";var lazyArray=new LazyUint8Array;Object.defineProperties(lazyArray,{length:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._length}},chunkSize:{get:function(){if(!this.lengthKnown){this.cacheLength()}return this._chunkSize}}});var properties={isDevice:false,contents:lazyArray}}else{var properties={isDevice:false,url:url}}var node=FS.createFile(parent,name,properties,canRead,canWrite);if(properties.contents){node.contents=properties.contents}else if(properties.url){node.contents=null;node.url=properties.url}Object.defineProperties(node,{usedBytes:{get:function(){return this.contents.length}}});var stream_ops={};var keys=Object.keys(node.stream_ops);keys.forEach(key=>{var fn=node.stream_ops[key];stream_ops[key]=function forceLoadLazyFile(){FS.forceLoadFile(node);return fn.apply(null,arguments)}});function writeChunks(stream,buffer,offset,length,position){var contents=stream.node.contents;if(position>=contents.length)return 0;var size=Math.min(contents.length-position,length);if(contents.slice){for(var i=0;i<size;i++){buffer[offset+i]=contents[position+i]}}else{for(var i=0;i<size;i++){buffer[offset+i]=contents.get(position+i)}}return size}stream_ops.read=(stream,buffer,offset,length,position)=>{FS.forceLoadFile(node);return writeChunks(stream,buffer,offset,length,position)};stream_ops.mmap=(stream,length,position,prot,flags)=>{FS.forceLoadFile(node);var ptr=mmapAlloc(length);if(!ptr){throw new FS.ErrnoError(48)}writeChunks(stream,HEAP8,ptr,length,position);return{ptr:ptr,allocated:true}};node.stream_ops=stream_ops;return node},createPreloadedFile:(parent,name,url,canRead,canWrite,onload,onerror,dontCreateFile,canOwn,preFinish)=>{var fullname=name?PATH_FS.resolve(PATH.join2(parent,name)):parent;var dep=getUniqueRunDependency("cp "+fullname);function processData(byteArray){function finish(byteArray){if(preFinish)preFinish();if(!dontCreateFile){FS.createDataFile(parent,name,byteArray,canRead,canWrite,canOwn)}if(onload)onload();removeRunDependency(dep)}if(Browser.handledByPreloadPlugin(byteArray,fullname,finish,()=>{if(onerror)onerror();removeRunDependency(dep)})){return}finish(byteArray)}addRunDependency(dep);if(typeof url=="string"){asyncLoad(url,byteArray=>processData(byteArray),onerror)}else{processData(url)}},indexedDB:()=>{return window.indexedDB||window.mozIndexedDB||window.webkitIndexedDB||window.msIndexedDB},DB_NAME:()=>{return"EM_FS_"+window.location.pathname},DB_VERSION:20,DB_STORE_NAME:"FILE_DATA",saveFilesToDB:(paths,onload,onerror)=>{onload=onload||(()=>{});onerror=onerror||(()=>{});var indexedDB=FS.indexedDB();try{var openRequest=indexedDB.open(FS.DB_NAME(),FS.DB_VERSION)}catch(e){return onerror(e)}openRequest.onupgradeneeded=()=>{out("creating db");var db=openRequest.result;db.createObjectStore(FS.DB_STORE_NAME)};openRequest.onsuccess=()=>{var db=openRequest.result;var transaction=db.transaction([FS.DB_STORE_NAME],"readwrite");var files=transaction.objectStore(FS.DB_STORE_NAME);var ok=0,fail=0,total=paths.length;function finish(){if(fail==0)onload();else onerror()}paths.forEach(path=>{var putRequest=files.put(FS.analyzePath(path).object.contents,path);putRequest.onsuccess=()=>{ok++;if(ok+fail==total)finish()};putRequest.onerror=()=>{fail++;if(ok+fail==total)finish()}});transaction.onerror=onerror};openRequest.onerror=onerror},loadFilesFromDB:(paths,onload,onerror)=>{onload=onload||(()=>{});onerror=onerror||(()=>{});var indexedDB=FS.indexedDB();try{var openRequest=indexedDB.open(FS.DB_NAME(),FS.DB_VERSION)}catch(e){return onerror(e)}openRequest.onupgradeneeded=onerror;openRequest.onsuccess=()=>{var db=openRequest.result;try{var transaction=db.transaction([FS.DB_STORE_NAME],"readonly")}catch(e){onerror(e);return}var files=transaction.objectStore(FS.DB_STORE_NAME);var ok=0,fail=0,total=paths.length;function finish(){if(fail==0)onload();else onerror()}paths.forEach(path=>{var getRequest=files.get(path);getRequest.onsuccess=()=>{if(FS.analyzePath(path).exists){FS.unlink(path)}FS.createDataFile(PATH.dirname(path),PATH.basename(path),getRequest.result,true,true,true);ok++;if(ok+fail==total)finish()};getRequest.onerror=()=>{fail++;if(ok+fail==total)finish()}});transaction.onerror=onerror};openRequest.onerror=onerror}};var SYSCALLS={DEFAULT_POLLMASK:5,calculateAt:function(dirfd,path,allowEmpty){if(PATH.isAbs(path)){return path}var dir;if(dirfd===-100){dir=FS.cwd()}else{var dirstream=FS.getStream(dirfd);if(!dirstream)throw new FS.ErrnoError(8);dir=dirstream.path}if(path.length==0){if(!allowEmpty){throw new FS.ErrnoError(44)}return dir}return PATH.join2(dir,path)},doStat:function(func,path,buf){try{var stat=func(path)}catch(e){if(e&&e.node&&PATH.normalize(path)!==PATH.normalize(FS.getPath(e.node))){return-54}throw e}HEAP32[buf>>2]=stat.dev;HEAP32[buf+4>>2]=0;HEAP32[buf+8>>2]=stat.ino;HEAP32[buf+12>>2]=stat.mode;HEAP32[buf+16>>2]=stat.nlink;HEAP32[buf+20>>2]=stat.uid;HEAP32[buf+24>>2]=stat.gid;HEAP32[buf+28>>2]=stat.rdev;HEAP32[buf+32>>2]=0;tempI64=[stat.size>>>0,(tempDouble=stat.size,+Math.abs(tempDouble)>=1?tempDouble>0?(Math.min(+Math.floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+40>>2]=tempI64[0],HEAP32[buf+44>>2]=tempI64[1];HEAP32[buf+48>>2]=4096;HEAP32[buf+52>>2]=stat.blocks;HEAP32[buf+56>>2]=stat.atime.getTime()/1e3|0;HEAP32[buf+60>>2]=0;HEAP32[buf+64>>2]=stat.mtime.getTime()/1e3|0;HEAP32[buf+68>>2]=0;HEAP32[buf+72>>2]=stat.ctime.getTime()/1e3|0;HEAP32[buf+76>>2]=0;tempI64=[stat.ino>>>0,(tempDouble=stat.ino,+Math.abs(tempDouble)>=1?tempDouble>0?(Math.min(+Math.floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[buf+80>>2]=tempI64[0],HEAP32[buf+84>>2]=tempI64[1];return 0},doMsync:function(addr,stream,len,flags,offset){var buffer=HEAPU8.slice(addr,addr+len);FS.msync(stream,buffer,offset,len,flags)},varargs:undefined,get:function(){SYSCALLS.varargs+=4;var ret=HEAP32[SYSCALLS.varargs-4>>2];return ret},getStr:function(ptr){var ret=UTF8ToString(ptr);return ret},getStreamFromFD:function(fd){var stream=FS.getStream(fd);if(!stream)throw new FS.ErrnoError(8);return stream}};function ___syscall__newselect(nfds,readfds,writefds,exceptfds,timeout){try{var total=0;var srcReadLow=readfds?HEAP32[readfds>>2]:0,srcReadHigh=readfds?HEAP32[readfds+4>>2]:0;var srcWriteLow=writefds?HEAP32[writefds>>2]:0,srcWriteHigh=writefds?HEAP32[writefds+4>>2]:0;var srcExceptLow=exceptfds?HEAP32[exceptfds>>2]:0,srcExceptHigh=exceptfds?HEAP32[exceptfds+4>>2]:0;var dstReadLow=0,dstReadHigh=0;var dstWriteLow=0,dstWriteHigh=0;var dstExceptLow=0,dstExceptHigh=0;var allLow=(readfds?HEAP32[readfds>>2]:0)|(writefds?HEAP32[writefds>>2]:0)|(exceptfds?HEAP32[exceptfds>>2]:0);var allHigh=(readfds?HEAP32[readfds+4>>2]:0)|(writefds?HEAP32[writefds+4>>2]:0)|(exceptfds?HEAP32[exceptfds+4>>2]:0);var check=function(fd,low,high,val){return fd<32?low&val:high&val};for(var fd=0;fd<nfds;fd++){var mask=1<<fd%32;if(!check(fd,allLow,allHigh,mask)){continue}var stream=FS.getStream(fd);if(!stream)throw new FS.ErrnoError(8);var flags=SYSCALLS.DEFAULT_POLLMASK;if(stream.stream_ops.poll){flags=stream.stream_ops.poll(stream)}if(flags&1&&check(fd,srcReadLow,srcReadHigh,mask)){fd<32?dstReadLow=dstReadLow|mask:dstReadHigh=dstReadHigh|mask;total++}if(flags&4&&check(fd,srcWriteLow,srcWriteHigh,mask)){fd<32?dstWriteLow=dstWriteLow|mask:dstWriteHigh=dstWriteHigh|mask;total++}if(flags&2&&check(fd,srcExceptLow,srcExceptHigh,mask)){fd<32?dstExceptLow=dstExceptLow|mask:dstExceptHigh=dstExceptHigh|mask;total++}}if(readfds){HEAP32[readfds>>2]=dstReadLow;HEAP32[readfds+4>>2]=dstReadHigh}if(writefds){HEAP32[writefds>>2]=dstWriteLow;HEAP32[writefds+4>>2]=dstWriteHigh}if(exceptfds){HEAP32[exceptfds>>2]=dstExceptLow;HEAP32[exceptfds+4>>2]=dstExceptHigh}return total}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}var SOCKFS={mount:function(mount){Module["websocket"]=Module["websocket"]&&"object"===typeof Module["websocket"]?Module["websocket"]:{};Module["websocket"]._callbacks={};Module["websocket"]["on"]=function(event,callback){if("function"===typeof callback){this._callbacks[event]=callback}return this};Module["websocket"].emit=function(event,param){if("function"===typeof this._callbacks[event]){this._callbacks[event].call(this,param)}};return FS.createNode(null,"/",16384|511,0)},createSocket:function(family,type,protocol){type&=~526336;var streaming=type==1;if(streaming&&protocol&&protocol!=6){throw new FS.ErrnoError(66)}var sock={family:family,type:type,protocol:protocol,server:null,error:null,peers:{},pending:[],recv_queue:[],sock_ops:SOCKFS.websocket_sock_ops};var name=SOCKFS.nextname();var node=FS.createNode(SOCKFS.root,name,49152,0);node.sock=sock;var stream=FS.createStream({path:name,node:node,flags:2,seekable:false,stream_ops:SOCKFS.stream_ops});sock.stream=stream;return sock},getSocket:function(fd){var stream=FS.getStream(fd);if(!stream||!FS.isSocket(stream.node.mode)){return null}return stream.node.sock},stream_ops:{poll:function(stream){var sock=stream.node.sock;return sock.sock_ops.poll(sock)},ioctl:function(stream,request,varargs){var sock=stream.node.sock;return sock.sock_ops.ioctl(sock,request,varargs)},read:function(stream,buffer,offset,length,position){var sock=stream.node.sock;var msg=sock.sock_ops.recvmsg(sock,length);if(!msg){return 0}buffer.set(msg.buffer,offset);return msg.buffer.length},write:function(stream,buffer,offset,length,position){var sock=stream.node.sock;return sock.sock_ops.sendmsg(sock,buffer,offset,length)},close:function(stream){var sock=stream.node.sock;sock.sock_ops.close(sock)}},nextname:function(){if(!SOCKFS.nextname.current){SOCKFS.nextname.current=0}return"socket["+SOCKFS.nextname.current+++"]"},websocket_sock_ops:{createPeer:function(sock,addr,port){var ws;if(typeof addr=="object"){ws=addr;addr=null;port=null}if(ws){if(ws._socket){addr=ws._socket.remoteAddress;port=ws._socket.remotePort}else{var result=/ws[s]?:\/\/([^:]+):(\d+)/.exec(ws.url);if(!result){throw new Error("WebSocket URL must be in the format ws(s)://address:port")}addr=result[1];port=parseInt(result[2],10)}}else{try{var runtimeConfig=Module["websocket"]&&"object"===typeof Module["websocket"];var url="ws:#".replace("#","//");if(runtimeConfig){if("string"===typeof Module["websocket"]["url"]){url=Module["websocket"]["url"]}}if(url==="ws://"||url==="wss://"){var parts=addr.split("/");url=url+parts[0]+":"+port+"/"+parts.slice(1).join("/")}var subProtocols="binary";if(runtimeConfig){if("string"===typeof Module["websocket"]["subprotocol"]){subProtocols=Module["websocket"]["subprotocol"]}}var opts=undefined;if(subProtocols!=="null"){subProtocols=subProtocols.replace(/^ +| +$/g,"").split(/ *, */);opts=subProtocols}if(runtimeConfig&&null===Module["websocket"]["subprotocol"]){subProtocols="null";opts=undefined}var WebSocketConstructor;{WebSocketConstructor=WebSocket}ws=new WebSocketConstructor(url,opts);ws.binaryType="arraybuffer"}catch(e){throw new FS.ErrnoError(23)}}var peer={addr:addr,port:port,socket:ws,dgram_send_queue:[]};SOCKFS.websocket_sock_ops.addPeer(sock,peer);SOCKFS.websocket_sock_ops.handlePeerEvents(sock,peer);if(sock.type===2&&typeof sock.sport!="undefined"){peer.dgram_send_queue.push(new Uint8Array([255,255,255,255,"p".charCodeAt(0),"o".charCodeAt(0),"r".charCodeAt(0),"t".charCodeAt(0),(sock.sport&65280)>>8,sock.sport&255]))}return peer},getPeer:function(sock,addr,port){return sock.peers[addr+":"+port]},addPeer:function(sock,peer){sock.peers[peer.addr+":"+peer.port]=peer},removePeer:function(sock,peer){delete sock.peers[peer.addr+":"+peer.port]},handlePeerEvents:function(sock,peer){var first=true;var handleOpen=function(){Module["websocket"].emit("open",sock.stream.fd);try{var queued=peer.dgram_send_queue.shift();while(queued){peer.socket.send(queued);queued=peer.dgram_send_queue.shift()}}catch(e){peer.socket.close()}};function handleMessage(data){if(typeof data=="string"){var encoder=new TextEncoder;data=encoder.encode(data)}else{assert(data.byteLength!==undefined);if(data.byteLength==0){return}else{data=new Uint8Array(data)}}var wasfirst=first;first=false;if(wasfirst&&data.length===10&&data[0]===255&&data[1]===255&&data[2]===255&&data[3]===255&&data[4]==="p".charCodeAt(0)&&data[5]==="o".charCodeAt(0)&&data[6]==="r".charCodeAt(0)&&data[7]==="t".charCodeAt(0)){var newport=data[8]<<8|data[9];SOCKFS.websocket_sock_ops.removePeer(sock,peer);peer.port=newport;SOCKFS.websocket_sock_ops.addPeer(sock,peer);return}sock.recv_queue.push({addr:peer.addr,port:peer.port,data:data});Module["websocket"].emit("message",sock.stream.fd)}if(ENVIRONMENT_IS_NODE){peer.socket.on("open",handleOpen);peer.socket.on("message",function(data,isBinary){if(!isBinary){return}handleMessage(new Uint8Array(data).buffer)});peer.socket.on("close",function(){Module["websocket"].emit("close",sock.stream.fd)});peer.socket.on("error",function(error){sock.error=14;Module["websocket"].emit("error",[sock.stream.fd,sock.error,"ECONNREFUSED: Connection refused"])})}else{peer.socket.onopen=handleOpen;peer.socket.onclose=function(){Module["websocket"].emit("close",sock.stream.fd)};peer.socket.onmessage=function peer_socket_onmessage(event){handleMessage(event.data)};peer.socket.onerror=function(error){sock.error=14;Module["websocket"].emit("error",[sock.stream.fd,sock.error,"ECONNREFUSED: Connection refused"])}}},poll:function(sock){if(sock.type===1&&sock.server){return sock.pending.length?64|1:0}var mask=0;var dest=sock.type===1?SOCKFS.websocket_sock_ops.getPeer(sock,sock.daddr,sock.dport):null;if(sock.recv_queue.length||!dest||dest&&dest.socket.readyState===dest.socket.CLOSING||dest&&dest.socket.readyState===dest.socket.CLOSED){mask|=64|1}if(!dest||dest&&dest.socket.readyState===dest.socket.OPEN){mask|=4}if(dest&&dest.socket.readyState===dest.socket.CLOSING||dest&&dest.socket.readyState===dest.socket.CLOSED){mask|=16}return mask},ioctl:function(sock,request,arg){switch(request){case 21531:var bytes=0;if(sock.recv_queue.length){bytes=sock.recv_queue[0].data.length}HEAP32[arg>>2]=bytes;return 0;default:return 28}},close:function(sock){if(sock.server){try{sock.server.close()}catch(e){}sock.server=null}var peers=Object.keys(sock.peers);for(var i=0;i<peers.length;i++){var peer=sock.peers[peers[i]];try{peer.socket.close()}catch(e){}SOCKFS.websocket_sock_ops.removePeer(sock,peer)}return 0},bind:function(sock,addr,port){if(typeof sock.saddr!="undefined"||typeof sock.sport!="undefined"){throw new FS.ErrnoError(28)}sock.saddr=addr;sock.sport=port;if(sock.type===2){if(sock.server){sock.server.close();sock.server=null}try{sock.sock_ops.listen(sock,0)}catch(e){if(!(e instanceof FS.ErrnoError))throw e;if(e.errno!==138)throw e}}},connect:function(sock,addr,port){if(sock.server){throw new FS.ErrnoError(138)}if(typeof sock.daddr!="undefined"&&typeof sock.dport!="undefined"){var dest=SOCKFS.websocket_sock_ops.getPeer(sock,sock.daddr,sock.dport);if(dest){if(dest.socket.readyState===dest.socket.CONNECTING){throw new FS.ErrnoError(7)}else{throw new FS.ErrnoError(30)}}}var peer=SOCKFS.websocket_sock_ops.createPeer(sock,addr,port);sock.daddr=peer.addr;sock.dport=peer.port;throw new FS.ErrnoError(26)},listen:function(sock,backlog){if(!ENVIRONMENT_IS_NODE){throw new FS.ErrnoError(138)}},accept:function(listensock){if(!listensock.server||!listensock.pending.length){throw new FS.ErrnoError(28)}var newsock=listensock.pending.shift();newsock.stream.flags=listensock.stream.flags;return newsock},getname:function(sock,peer){var addr,port;if(peer){if(sock.daddr===undefined||sock.dport===undefined){throw new FS.ErrnoError(53)}addr=sock.daddr;port=sock.dport}else{addr=sock.saddr||0;port=sock.sport||0}return{addr:addr,port:port}},sendmsg:function(sock,buffer,offset,length,addr,port){if(sock.type===2){if(addr===undefined||port===undefined){addr=sock.daddr;port=sock.dport}if(addr===undefined||port===undefined){throw new FS.ErrnoError(17)}}else{addr=sock.daddr;port=sock.dport}var dest=SOCKFS.websocket_sock_ops.getPeer(sock,addr,port);if(sock.type===1){if(!dest||dest.socket.readyState===dest.socket.CLOSING||dest.socket.readyState===dest.socket.CLOSED){throw new FS.ErrnoError(53)}else if(dest.socket.readyState===dest.socket.CONNECTING){throw new FS.ErrnoError(6)}}if(ArrayBuffer.isView(buffer)){offset+=buffer.byteOffset;buffer=buffer.buffer}var data;data=buffer.slice(offset,offset+length);if(sock.type===2){if(!dest||dest.socket.readyState!==dest.socket.OPEN){if(!dest||dest.socket.readyState===dest.socket.CLOSING||dest.socket.readyState===dest.socket.CLOSED){dest=SOCKFS.websocket_sock_ops.createPeer(sock,addr,port)}dest.dgram_send_queue.push(data);return length}}try{dest.socket.send(data);return length}catch(e){throw new FS.ErrnoError(28)}},recvmsg:function(sock,length){if(sock.type===1&&sock.server){throw new FS.ErrnoError(53)}var queued=sock.recv_queue.shift();if(!queued){if(sock.type===1){var dest=SOCKFS.websocket_sock_ops.getPeer(sock,sock.daddr,sock.dport);if(!dest){throw new FS.ErrnoError(53)}else if(dest.socket.readyState===dest.socket.CLOSING||dest.socket.readyState===dest.socket.CLOSED){return null}else{throw new FS.ErrnoError(6)}}else{throw new FS.ErrnoError(6)}}var queuedLength=queued.data.byteLength||queued.data.length;var queuedOffset=queued.data.byteOffset||0;var queuedBuffer=queued.data.buffer||queued.data;var bytesRead=Math.min(length,queuedLength);var res={buffer:new Uint8Array(queuedBuffer,queuedOffset,bytesRead),addr:queued.addr,port:queued.port};if(sock.type===1&&bytesRead<queuedLength){var bytesRemaining=queuedLength-bytesRead;queued.data=new Uint8Array(queuedBuffer,queuedOffset+bytesRead,bytesRemaining);sock.recv_queue.unshift(queued)}return res}}};function getSocketFromFD(fd){var socket=SOCKFS.getSocket(fd);if(!socket)throw new FS.ErrnoError(8);return socket}function setErrNo(value){HEAP32[___errno_location()>>2]=value;return value}function inetPton4(str){var b=str.split(".");for(var i=0;i<4;i++){var tmp=Number(b[i]);if(isNaN(tmp))return null;b[i]=tmp}return(b[0]|b[1]<<8|b[2]<<16|b[3]<<24)>>>0}function jstoi_q(str){return parseInt(str)}function inetPton6(str){var words;var w,offset,z;var valid6regx=/^((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\3)::|:\b|$))|(?!\2\3)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4})$/i;var parts=[];if(!valid6regx.test(str)){return null}if(str==="::"){return[0,0,0,0,0,0,0,0]}if(str.startsWith("::")){str=str.replace("::","Z:")}else{str=str.replace("::",":Z:")}if(str.indexOf(".")>0){str=str.replace(new RegExp("[.]","g"),":");words=str.split(":");words[words.length-4]=jstoi_q(words[words.length-4])+jstoi_q(words[words.length-3])*256;words[words.length-3]=jstoi_q(words[words.length-2])+jstoi_q(words[words.length-1])*256;words=words.slice(0,words.length-2)}else{words=str.split(":")}offset=0;z=0;for(w=0;w<words.length;w++){if(typeof words[w]=="string"){if(words[w]==="Z"){for(z=0;z<8-words.length+1;z++){parts[w+z]=0}offset=z-1}else{parts[w+offset]=_htons(parseInt(words[w],16))}}else{parts[w+offset]=words[w]}}return[parts[1]<<16|parts[0],parts[3]<<16|parts[2],parts[5]<<16|parts[4],parts[7]<<16|parts[6]]}function writeSockaddr(sa,family,addr,port,addrlen){switch(family){case 2:addr=inetPton4(addr);zeroMemory(sa,16);if(addrlen){HEAP32[addrlen>>2]=16}HEAP16[sa>>1]=family;HEAP32[sa+4>>2]=addr;HEAP16[sa+2>>1]=_htons(port);break;case 10:addr=inetPton6(addr);zeroMemory(sa,28);if(addrlen){HEAP32[addrlen>>2]=28}HEAP32[sa>>2]=family;HEAP32[sa+8>>2]=addr[0];HEAP32[sa+12>>2]=addr[1];HEAP32[sa+16>>2]=addr[2];HEAP32[sa+20>>2]=addr[3];HEAP16[sa+2>>1]=_htons(port);break;default:return 5}return 0}var DNS={address_map:{id:1,addrs:{},names:{}},lookup_name:function(name){var res=inetPton4(name);if(res!==null){return name}res=inetPton6(name);if(res!==null){return name}var addr;if(DNS.address_map.addrs[name]){addr=DNS.address_map.addrs[name]}else{var id=DNS.address_map.id++;assert(id<65535,"exceeded max address mappings of 65535");addr="172.29."+(id&255)+"."+(id&65280);DNS.address_map.names[addr]=name;DNS.address_map.addrs[name]=addr}return addr},lookup_addr:function(addr){if(DNS.address_map.names[addr]){return DNS.address_map.names[addr]}return null}};function ___syscall_accept4(fd,addr,addrlen,flags){try{var sock=getSocketFromFD(fd);var newsock=sock.sock_ops.accept(sock);if(addr){var errno=writeSockaddr(addr,newsock.family,DNS.lookup_name(newsock.daddr),newsock.dport,addrlen)}return newsock.stream.fd}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function inetNtop4(addr){return(addr&255)+"."+(addr>>8&255)+"."+(addr>>16&255)+"."+(addr>>24&255)}function inetNtop6(ints){var str="";var word=0;var longest=0;var lastzero=0;var zstart=0;var len=0;var i=0;var parts=[ints[0]&65535,ints[0]>>16,ints[1]&65535,ints[1]>>16,ints[2]&65535,ints[2]>>16,ints[3]&65535,ints[3]>>16];var hasipv4=true;var v4part="";for(i=0;i<5;i++){if(parts[i]!==0){hasipv4=false;break}}if(hasipv4){v4part=inetNtop4(parts[6]|parts[7]<<16);if(parts[5]===-1){str="::ffff:";str+=v4part;return str}if(parts[5]===0){str="::";if(v4part==="0.0.0.0")v4part="";if(v4part==="0.0.0.1")v4part="1";str+=v4part;return str}}for(word=0;word<8;word++){if(parts[word]===0){if(word-lastzero>1){len=0}lastzero=word;len++}if(len>longest){longest=len;zstart=word-longest+1}}for(word=0;word<8;word++){if(longest>1){if(parts[word]===0&&word>=zstart&&word<zstart+longest){if(word===zstart){str+=":";if(zstart===0)str+=":"}continue}}str+=Number(_ntohs(parts[word]&65535)).toString(16);str+=word<7?":":""}return str}function readSockaddr(sa,salen){var family=HEAP16[sa>>1];var port=_ntohs(HEAPU16[sa+2>>1]);var addr;switch(family){case 2:if(salen!==16){return{errno:28}}addr=HEAP32[sa+4>>2];addr=inetNtop4(addr);break;case 10:if(salen!==28){return{errno:28}}addr=[HEAP32[sa+8>>2],HEAP32[sa+12>>2],HEAP32[sa+16>>2],HEAP32[sa+20>>2]];addr=inetNtop6(addr);break;default:return{errno:5}}return{family:family,addr:addr,port:port}}function getSocketAddress(addrp,addrlen,allowNull){if(allowNull&&addrp===0)return null;var info=readSockaddr(addrp,addrlen);if(info.errno)throw new FS.ErrnoError(info.errno);info.addr=DNS.lookup_addr(info.addr)||info.addr;return info}function ___syscall_bind(fd,addr,addrlen){try{var sock=getSocketFromFD(fd);var info=getSocketAddress(addr,addrlen);sock.sock_ops.bind(sock,info.addr,info.port);return 0}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_chdir(path){try{path=SYSCALLS.getStr(path);FS.chdir(path);return 0}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_chmod(path,mode){try{path=SYSCALLS.getStr(path);FS.chmod(path,mode);return 0}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_connect(fd,addr,addrlen){try{var sock=getSocketFromFD(fd);var info=getSocketAddress(addr,addrlen);sock.sock_ops.connect(sock,info.addr,info.port);return 0}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_faccessat(dirfd,path,amode,flags){try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);if(amode&~7){return-28}var lookup=FS.lookupPath(path,{follow:true});var node=lookup.node;if(!node){return-44}var perms="";if(amode&4)perms+="r";if(amode&2)perms+="w";if(amode&1)perms+="x";if(perms&&FS.nodePermissions(node,perms)){return-2}return 0}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_fcntl64(fd,cmd,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(cmd){case 0:{var arg=SYSCALLS.get();if(arg<0){return-28}var newStream;newStream=FS.createStream(stream,arg);return newStream.fd}case 1:case 2:return 0;case 3:return stream.flags;case 4:{var arg=SYSCALLS.get();stream.flags|=arg;return 0}case 5:{var arg=SYSCALLS.get();var offset=0;HEAP16[arg+offset>>1]=2;return 0}case 6:case 7:return 0;case 16:case 8:return-28;case 9:setErrNo(28);return-1;default:{return-28}}}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_getcwd(buf,size){try{if(size===0)return-28;var cwd=FS.cwd();var cwdLengthInBytes=lengthBytesUTF8(cwd)+1;if(size<cwdLengthInBytes)return-68;stringToUTF8(cwd,buf,size);return cwdLengthInBytes}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_getdents64(fd,dirp,count){try{var stream=SYSCALLS.getStreamFromFD(fd);if(!stream.getdents){stream.getdents=FS.readdir(stream.path)}var struct_size=280;var pos=0;var off=FS.llseek(stream,0,1);var idx=Math.floor(off/struct_size);while(idx<stream.getdents.length&&pos+struct_size<=count){var id;var type;var name=stream.getdents[idx];if(name==="."){id=stream.node.id;type=4}else if(name===".."){var lookup=FS.lookupPath(stream.path,{parent:true});id=lookup.node.id;type=4}else{var child=FS.lookupNode(stream.node,name);id=child.id;type=FS.isChrdev(child.mode)?2:FS.isDir(child.mode)?4:FS.isLink(child.mode)?10:8}tempI64=[id>>>0,(tempDouble=id,+Math.abs(tempDouble)>=1?tempDouble>0?(Math.min(+Math.floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[dirp+pos>>2]=tempI64[0],HEAP32[dirp+pos+4>>2]=tempI64[1];tempI64=[(idx+1)*struct_size>>>0,(tempDouble=(idx+1)*struct_size,+Math.abs(tempDouble)>=1?tempDouble>0?(Math.min(+Math.floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[dirp+pos+8>>2]=tempI64[0],HEAP32[dirp+pos+12>>2]=tempI64[1];HEAP16[dirp+pos+16>>1]=280;HEAP8[dirp+pos+18>>0]=type;stringToUTF8(name,dirp+pos+19,256);pos+=struct_size;idx+=1}FS.llseek(stream,idx*struct_size,0);return pos}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_getsockname(fd,addr,addrlen){try{err("__syscall_getsockname "+fd);var sock=getSocketFromFD(fd);var errno=writeSockaddr(addr,sock.family,DNS.lookup_name(sock.saddr||"0.0.0.0"),sock.sport,addrlen);return 0}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_getsockopt(fd,level,optname,optval,optlen){try{var sock=getSocketFromFD(fd);if(level===1){if(optname===4){HEAP32[optval>>2]=sock.error;HEAP32[optlen>>2]=4;sock.error=null;return 0}}return-50}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_ioctl(fd,op,varargs){SYSCALLS.varargs=varargs;try{var stream=SYSCALLS.getStreamFromFD(fd);switch(op){case 21509:case 21505:{if(!stream.tty)return-59;return 0}case 21510:case 21511:case 21512:case 21506:case 21507:case 21508:{if(!stream.tty)return-59;return 0}case 21519:{if(!stream.tty)return-59;var argp=SYSCALLS.get();HEAP32[argp>>2]=0;return 0}case 21520:{if(!stream.tty)return-59;return-28}case 21531:{var argp=SYSCALLS.get();return FS.ioctl(stream,op,argp)}case 21523:{if(!stream.tty)return-59;return 0}case 21524:{if(!stream.tty)return-59;return 0}default:abort("bad ioctl syscall "+op)}}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_listen(fd,backlog){try{var sock=getSocketFromFD(fd);sock.sock_ops.listen(sock,backlog);return 0}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_lstat64(path,buf){try{path=SYSCALLS.getStr(path);return SYSCALLS.doStat(FS.lstat,path,buf)}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_mkdirat(dirfd,path,mode){try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);path=PATH.normalize(path);if(path[path.length-1]==="/")path=path.substr(0,path.length-1);FS.mkdir(path,mode,0);return 0}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_newfstatat(dirfd,path,buf,flags){try{path=SYSCALLS.getStr(path);var nofollow=flags&256;var allowEmpty=flags&4096;flags=flags&~4352;path=SYSCALLS.calculateAt(dirfd,path,allowEmpty);return SYSCALLS.doStat(nofollow?FS.lstat:FS.stat,path,buf)}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_openat(dirfd,path,flags,varargs){SYSCALLS.varargs=varargs;try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);var mode=varargs?SYSCALLS.get():0;return FS.open(path,flags,mode).fd}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_poll(fds,nfds,timeout){try{var nonzero=0;for(var i=0;i<nfds;i++){var pollfd=fds+8*i;var fd=HEAP32[pollfd>>2];var events=HEAP16[pollfd+4>>1];var mask=32;var stream=FS.getStream(fd);if(stream){mask=SYSCALLS.DEFAULT_POLLMASK;if(stream.stream_ops.poll){mask=stream.stream_ops.poll(stream)}}mask&=events|8|16;if(mask)nonzero++;HEAP16[pollfd+6>>1]=mask}return nonzero}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_readlinkat(dirfd,path,buf,bufsize){try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);if(bufsize<=0)return-28;var ret=FS.readlink(path);var len=Math.min(bufsize,lengthBytesUTF8(ret));var endChar=HEAP8[buf+len];stringToUTF8(ret,buf,bufsize+1);HEAP8[buf+len]=endChar;return len}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_recvfrom(fd,buf,len,flags,addr,addrlen){try{var sock=getSocketFromFD(fd);var msg=sock.sock_ops.recvmsg(sock,len);if(!msg)return 0;if(addr){var errno=writeSockaddr(addr,sock.family,DNS.lookup_name(msg.addr),msg.port,addrlen)}HEAPU8.set(msg.buffer,buf);return msg.buffer.byteLength}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_renameat(olddirfd,oldpath,newdirfd,newpath){try{oldpath=SYSCALLS.getStr(oldpath);newpath=SYSCALLS.getStr(newpath);oldpath=SYSCALLS.calculateAt(olddirfd,oldpath);newpath=SYSCALLS.calculateAt(newdirfd,newpath);FS.rename(oldpath,newpath);return 0}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_rmdir(path){try{path=SYSCALLS.getStr(path);FS.rmdir(path);return 0}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_sendto(fd,message,length,flags,addr,addr_len){try{var sock=getSocketFromFD(fd);var dest=getSocketAddress(addr,addr_len,true);if(!dest){return FS.write(sock.stream,HEAP8,message,length)}else{return sock.sock_ops.sendmsg(sock,HEAP8,message,length,dest.addr,dest.port)}}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_socket(domain,type,protocol){try{var sock=SOCKFS.createSocket(domain,type,protocol);return sock.stream.fd}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_stat64(path,buf){try{path=SYSCALLS.getStr(path);return SYSCALLS.doStat(FS.stat,path,buf)}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_statfs64(path,size,buf){try{path=SYSCALLS.getStr(path);HEAP32[buf+4>>2]=4096;HEAP32[buf+40>>2]=4096;HEAP32[buf+8>>2]=1e6;HEAP32[buf+12>>2]=5e5;HEAP32[buf+16>>2]=5e5;HEAP32[buf+20>>2]=FS.nextInode;HEAP32[buf+24>>2]=1e6;HEAP32[buf+28>>2]=42;HEAP32[buf+44>>2]=2;HEAP32[buf+36>>2]=255;return 0}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_symlink(target,linkpath){try{target=SYSCALLS.getStr(target);linkpath=SYSCALLS.getStr(linkpath);FS.symlink(target,linkpath);return 0}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function ___syscall_unlinkat(dirfd,path,flags){try{path=SYSCALLS.getStr(path);path=SYSCALLS.calculateAt(dirfd,path);if(flags===0){FS.unlink(path)}else if(flags===512){FS.rmdir(path)}else{abort("Invalid flags passed to unlinkat")}return 0}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return-e.errno}}function __dlinit(main_dso_handle){}var dlopenMissingError="To use dlopen, you need enable dynamic linking, see https://github.com/emscripten-core/emscripten/wiki/Linking";function __dlopen_js(filename,flag){abort(dlopenMissingError)}function __dlsym_js(handle,symbol){abort(dlopenMissingError)}function __emscripten_date_now(){return Date.now()}var nowIsMonotonic=true;function __emscripten_get_now_is_monotonic(){return nowIsMonotonic}function __emscripten_throw_longjmp(){throw Infinity}function __gmtime_js(time,tmPtr){var date=new Date(HEAP32[time>>2]*1e3);HEAP32[tmPtr>>2]=date.getUTCSeconds();HEAP32[tmPtr+4>>2]=date.getUTCMinutes();HEAP32[tmPtr+8>>2]=date.getUTCHours();HEAP32[tmPtr+12>>2]=date.getUTCDate();HEAP32[tmPtr+16>>2]=date.getUTCMonth();HEAP32[tmPtr+20>>2]=date.getUTCFullYear()-1900;HEAP32[tmPtr+24>>2]=date.getUTCDay();var start=Date.UTC(date.getUTCFullYear(),0,1,0,0,0,0);var yday=(date.getTime()-start)/(1e3*60*60*24)|0;HEAP32[tmPtr+28>>2]=yday}function __localtime_js(time,tmPtr){var date=new Date(HEAP32[time>>2]*1e3);HEAP32[tmPtr>>2]=date.getSeconds();HEAP32[tmPtr+4>>2]=date.getMinutes();HEAP32[tmPtr+8>>2]=date.getHours();HEAP32[tmPtr+12>>2]=date.getDate();HEAP32[tmPtr+16>>2]=date.getMonth();HEAP32[tmPtr+20>>2]=date.getFullYear()-1900;HEAP32[tmPtr+24>>2]=date.getDay();var start=new Date(date.getFullYear(),0,1);var yday=(date.getTime()-start.getTime())/(1e3*60*60*24)|0;HEAP32[tmPtr+28>>2]=yday;HEAP32[tmPtr+36>>2]=-(date.getTimezoneOffset()*60);var summerOffset=new Date(date.getFullYear(),6,1).getTimezoneOffset();var winterOffset=start.getTimezoneOffset();var dst=(summerOffset!=winterOffset&&date.getTimezoneOffset()==Math.min(winterOffset,summerOffset))|0;HEAP32[tmPtr+32>>2]=dst}function _tzset_impl(timezone,daylight,tzname){var currentYear=(new Date).getFullYear();var winter=new Date(currentYear,0,1);var summer=new Date(currentYear,6,1);var winterOffset=winter.getTimezoneOffset();var summerOffset=summer.getTimezoneOffset();var stdTimezoneOffset=Math.max(winterOffset,summerOffset);HEAP32[timezone>>2]=stdTimezoneOffset*60;HEAP32[daylight>>2]=Number(winterOffset!=summerOffset);function extractZone(date){var match=date.toTimeString().match(/\(([A-Za-z ]+)\)$/);return match?match[1]:"GMT"}var winterName=extractZone(winter);var summerName=extractZone(summer);var winterNamePtr=allocateUTF8(winterName);var summerNamePtr=allocateUTF8(summerName);if(summerOffset<winterOffset){HEAPU32[tzname>>2]=winterNamePtr;HEAPU32[tzname+4>>2]=summerNamePtr}else{HEAPU32[tzname>>2]=summerNamePtr;HEAPU32[tzname+4>>2]=winterNamePtr}}function __tzset_js(timezone,daylight,tzname){if(__tzset_js.called)return;__tzset_js.called=true;_tzset_impl(timezone,daylight,tzname)}function _abort(){abort("")}function _emscripten_set_main_loop_timing(mode,value){Browser.mainLoop.timingMode=mode;Browser.mainLoop.timingValue=value;if(!Browser.mainLoop.func){return 1}if(!Browser.mainLoop.running){runtimeKeepalivePush();Browser.mainLoop.running=true}if(mode==0){Browser.mainLoop.scheduler=function Browser_mainLoop_scheduler_setTimeout(){var timeUntilNextTick=Math.max(0,Browser.mainLoop.tickStartTime+value-_emscripten_get_now())|0;setTimeout(Browser.mainLoop.runner,timeUntilNextTick)};Browser.mainLoop.method="timeout"}else if(mode==1){Browser.mainLoop.scheduler=function Browser_mainLoop_scheduler_rAF(){Browser.requestAnimationFrame(Browser.mainLoop.runner)};Browser.mainLoop.method="rAF"}else if(mode==2){if(typeof setImmediate=="undefined"){var setImmediates=[];var emscriptenMainLoopMessageId="setimmediate";var Browser_setImmediate_messageHandler=function(event){if(event.data===emscriptenMainLoopMessageId||event.data.target===emscriptenMainLoopMessageId){event.stopPropagation();setImmediates.shift()()}};addEventListener("message",Browser_setImmediate_messageHandler,true);setImmediate=function Browser_emulated_setImmediate(func){setImmediates.push(func);if(ENVIRONMENT_IS_WORKER){if(Module["setImmediates"]===undefined)Module["setImmediates"]=[];Module["setImmediates"].push(func);postMessage({target:emscriptenMainLoopMessageId})}else postMessage(emscriptenMainLoopMessageId,"*")}}Browser.mainLoop.scheduler=function Browser_mainLoop_scheduler_setImmediate(){setImmediate(Browser.mainLoop.runner)};Browser.mainLoop.method="immediate"}return 0}var _emscripten_get_now;_emscripten_get_now=()=>performance.now();function _emscripten_webgl_do_commit_frame(){if(!GL.currentContext||!GL.currentContext.GLctx){return-3}if(GL.currentContext.defaultFbo){GL.blitOffscreenFramebuffer(GL.currentContext);return 0}if(!GL.currentContext.attributes.explicitSwapControl){return-3}return 0}function _emscripten_webgl_commit_frame(){return _emscripten_webgl_do_commit_frame()}function runtimeKeepalivePush(){runtimeKeepaliveCounter+=1}function _exit(status){exit(status)}function maybeExit(){if(!keepRuntimeAlive()){try{_exit(EXITSTATUS)}catch(e){handleException(e)}}}function setMainLoop(browserIterationFunc,fps,simulateInfiniteLoop,arg,noSetTiming){assert(!Browser.mainLoop.func,"emscripten_set_main_loop: there can only be one main loop function at once: call emscripten_cancel_main_loop to cancel the previous one before setting a new one with different parameters.");Browser.mainLoop.func=browserIterationFunc;Browser.mainLoop.arg=arg;var thisMainLoopId=Browser.mainLoop.currentlyRunningMainloop;function checkIsRunning(){if(thisMainLoopId<Browser.mainLoop.currentlyRunningMainloop){runtimeKeepalivePop();maybeExit();return false}return true}Browser.mainLoop.running=false;Browser.mainLoop.runner=function Browser_mainLoop_runner(){if(ABORT)return;if(Browser.mainLoop.queue.length>0){var start=Date.now();var blocker=Browser.mainLoop.queue.shift();blocker.func(blocker.arg);if(Browser.mainLoop.remainingBlockers){var remaining=Browser.mainLoop.remainingBlockers;var next=remaining%1==0?remaining-1:Math.floor(remaining);if(blocker.counted){Browser.mainLoop.remainingBlockers=next}else{next=next+.5;Browser.mainLoop.remainingBlockers=(8*remaining+next)/9}}out('main loop blocker "'+blocker.name+'" took '+(Date.now()-start)+" ms");Browser.mainLoop.updateStatus();if(!checkIsRunning())return;setTimeout(Browser.mainLoop.runner,0);return}if(!checkIsRunning())return;Browser.mainLoop.currentFrameNumber=Browser.mainLoop.currentFrameNumber+1|0;if(Browser.mainLoop.timingMode==1&&Browser.mainLoop.timingValue>1&&Browser.mainLoop.currentFrameNumber%Browser.mainLoop.timingValue!=0){Browser.mainLoop.scheduler();return}else if(Browser.mainLoop.timingMode==0){Browser.mainLoop.tickStartTime=_emscripten_get_now()}Browser.mainLoop.runIter(browserIterationFunc);if(!checkIsRunning())return;if(typeof SDL=="object"&&SDL.audio&&SDL.audio.queueNewAudioData)SDL.audio.queueNewAudioData();Browser.mainLoop.scheduler()};if(!noSetTiming){if(fps&&fps>0)_emscripten_set_main_loop_timing(0,1e3/fps);else _emscripten_set_main_loop_timing(1,1);Browser.mainLoop.scheduler()}if(simulateInfiniteLoop){throw"unwind"}}function callUserCallback(func,synchronous){if(runtimeExited||ABORT){return}if(synchronous){func();return}try{func();maybeExit()}catch(e){handleException(e)}}function runtimeKeepalivePop(){runtimeKeepaliveCounter-=1}function safeSetTimeout(func,timeout){runtimeKeepalivePush();return setTimeout(function(){runtimeKeepalivePop();callUserCallback(func)},timeout)}var Browser={mainLoop:{running:false,scheduler:null,method:"",currentlyRunningMainloop:0,func:null,arg:0,timingMode:0,timingValue:0,currentFrameNumber:0,queue:[],pause:function(){Browser.mainLoop.scheduler=null;Browser.mainLoop.currentlyRunningMainloop++},resume:function(){Browser.mainLoop.currentlyRunningMainloop++;var timingMode=Browser.mainLoop.timingMode;var timingValue=Browser.mainLoop.timingValue;var func=Browser.mainLoop.func;Browser.mainLoop.func=null;setMainLoop(func,0,false,Browser.mainLoop.arg,true);_emscripten_set_main_loop_timing(timingMode,timingValue);Browser.mainLoop.scheduler()},updateStatus:function(){if(Module["setStatus"]){var message=Module["statusMessage"]||"Please wait...";var remaining=Browser.mainLoop.remainingBlockers;var expected=Browser.mainLoop.expectedBlockers;if(remaining){if(remaining<expected){Module["setStatus"](message+" ("+(expected-remaining)+"/"+expected+")")}else{Module["setStatus"](message)}}else{Module["setStatus"]("")}}},runIter:function(func){if(ABORT)return;if(Module["preMainLoop"]){var preRet=Module["preMainLoop"]();if(preRet===false){return}}callUserCallback(func);if(Module["postMainLoop"])Module["postMainLoop"]()}},isFullscreen:false,pointerLock:false,moduleContextCreatedCallbacks:[],workers:[],init:function(){if(!Module["preloadPlugins"])Module["preloadPlugins"]=[];if(Browser.initted)return;Browser.initted=true;try{new Blob;Browser.hasBlobConstructor=true}catch(e){Browser.hasBlobConstructor=false;out("warning: no blob constructor, cannot create blobs with mimetypes")}Browser.BlobBuilder=typeof MozBlobBuilder!="undefined"?MozBlobBuilder:typeof WebKitBlobBuilder!="undefined"?WebKitBlobBuilder:!Browser.hasBlobConstructor?out("warning: no BlobBuilder"):null;Browser.URLObject=typeof window!="undefined"?window.URL?window.URL:window.webkitURL:undefined;if(!Module.noImageDecoding&&typeof Browser.URLObject=="undefined"){out("warning: Browser does not support creating object URLs. Built-in browser image decoding will not be available.");Module.noImageDecoding=true}var imagePlugin={};imagePlugin["canHandle"]=function imagePlugin_canHandle(name){return!Module.noImageDecoding&&/\.(jpg|jpeg|png|bmp)$/i.test(name)};imagePlugin["handle"]=function imagePlugin_handle(byteArray,name,onload,onerror){var b=null;if(Browser.hasBlobConstructor){try{b=new Blob([byteArray],{type:Browser.getMimetype(name)});if(b.size!==byteArray.length){b=new Blob([new Uint8Array(byteArray).buffer],{type:Browser.getMimetype(name)})}}catch(e){warnOnce("Blob constructor present but fails: "+e+"; falling back to blob builder")}}if(!b){var bb=new Browser.BlobBuilder;bb.append(new Uint8Array(byteArray).buffer);b=bb.getBlob()}var url=Browser.URLObject.createObjectURL(b);var img=new Image;img.onload=()=>{assert(img.complete,"Image "+name+" could not be decoded");var canvas=document.createElement("canvas");canvas.width=img.width;canvas.height=img.height;var ctx=canvas.getContext("2d");ctx.drawImage(img,0,0);preloadedImages[name]=canvas;Browser.URLObject.revokeObjectURL(url);if(onload)onload(byteArray)};img.onerror=event=>{out("Image "+url+" could not be decoded");if(onerror)onerror()};img.src=url};Module["preloadPlugins"].push(imagePlugin);var audioPlugin={};audioPlugin["canHandle"]=function audioPlugin_canHandle(name){return!Module.noAudioDecoding&&name.substr(-4)in{".ogg":1,".wav":1,".mp3":1}};audioPlugin["handle"]=function audioPlugin_handle(byteArray,name,onload,onerror){var done=false;function finish(audio){if(done)return;done=true;preloadedAudios[name]=audio;if(onload)onload(byteArray)}function fail(){if(done)return;done=true;preloadedAudios[name]=new Audio;if(onerror)onerror()}if(Browser.hasBlobConstructor){try{var b=new Blob([byteArray],{type:Browser.getMimetype(name)})}catch(e){return fail()}var url=Browser.URLObject.createObjectURL(b);var audio=new Audio;audio.addEventListener("canplaythrough",function(){finish(audio)},false);audio.onerror=function audio_onerror(event){if(done)return;out("warning: browser could not fully decode audio "+name+", trying slower base64 approach");function encode64(data){var BASE="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";var PAD="=";var ret="";var leftchar=0;var leftbits=0;for(var i=0;i<data.length;i++){leftchar=leftchar<<8|data[i];leftbits+=8;while(leftbits>=6){var curr=leftchar>>leftbits-6&63;leftbits-=6;ret+=BASE[curr]}}if(leftbits==2){ret+=BASE[(leftchar&3)<<4];ret+=PAD+PAD}else if(leftbits==4){ret+=BASE[(leftchar&15)<<2];ret+=PAD}return ret}audio.src="data:audio/x-"+name.substr(-3)+";base64,"+encode64(byteArray);finish(audio)};audio.src=url;safeSetTimeout(function(){finish(audio)},1e4)}else{return fail()}};Module["preloadPlugins"].push(audioPlugin);function pointerLockChange(){Browser.pointerLock=document["pointerLockElement"]===Module["canvas"]||document["mozPointerLockElement"]===Module["canvas"]||document["webkitPointerLockElement"]===Module["canvas"]||document["msPointerLockElement"]===Module["canvas"]}var canvas=Module["canvas"];if(canvas){canvas.requestPointerLock=canvas["requestPointerLock"]||canvas["mozRequestPointerLock"]||canvas["webkitRequestPointerLock"]||canvas["msRequestPointerLock"]||function(){};canvas.exitPointerLock=document["exitPointerLock"]||document["mozExitPointerLock"]||document["webkitExitPointerLock"]||document["msExitPointerLock"]||function(){};canvas.exitPointerLock=canvas.exitPointerLock.bind(document);document.addEventListener("pointerlockchange",pointerLockChange,false);document.addEventListener("mozpointerlockchange",pointerLockChange,false);document.addEventListener("webkitpointerlockchange",pointerLockChange,false);document.addEventListener("mspointerlockchange",pointerLockChange,false);if(Module["elementPointerLock"]){canvas.addEventListener("click",function(ev){if(!Browser.pointerLock&&Module["canvas"].requestPointerLock){Module["canvas"].requestPointerLock();ev.preventDefault()}},false)}}},handledByPreloadPlugin:function(byteArray,fullname,finish,onerror){Browser.init();var handled=false;Module["preloadPlugins"].forEach(function(plugin){if(handled)return;if(plugin["canHandle"](fullname)){plugin["handle"](byteArray,fullname,finish,onerror);handled=true}});return handled},createContext:function(canvas,useWebGL,setInModule,webGLContextAttributes){if(useWebGL&&Module.ctx&&canvas==Module.canvas)return Module.ctx;var ctx;var contextHandle;if(useWebGL){var contextAttributes={antialias:false,alpha:false,majorVersion:typeof WebGL2RenderingContext!="undefined"?2:1};if(webGLContextAttributes){for(var attribute in webGLContextAttributes){contextAttributes[attribute]=webGLContextAttributes[attribute]}}if(typeof GL!="undefined"){contextHandle=GL.createContext(canvas,contextAttributes);if(contextHandle){ctx=GL.getContext(contextHandle).GLctx}}}else{ctx=canvas.getContext("2d")}if(!ctx)return null;if(setInModule){if(!useWebGL)assert(typeof GLctx=="undefined","cannot set in module if GLctx is used, but we are a non-GL context that would replace it");Module.ctx=ctx;if(useWebGL)GL.makeContextCurrent(contextHandle);Module.useWebGL=useWebGL;Browser.moduleContextCreatedCallbacks.forEach(function(callback){callback()});Browser.init()}return ctx},destroyContext:function(canvas,useWebGL,setInModule){},fullscreenHandlersInstalled:false,lockPointer:undefined,resizeCanvas:undefined,requestFullscreen:function(lockPointer,resizeCanvas){Browser.lockPointer=lockPointer;Browser.resizeCanvas=resizeCanvas;if(typeof Browser.lockPointer=="undefined")Browser.lockPointer=true;if(typeof Browser.resizeCanvas=="undefined")Browser.resizeCanvas=false;var canvas=Module["canvas"];function fullscreenChange(){Browser.isFullscreen=false;var canvasContainer=canvas.parentNode;if((document["fullscreenElement"]||document["mozFullScreenElement"]||document["msFullscreenElement"]||document["webkitFullscreenElement"]||document["webkitCurrentFullScreenElement"])===canvasContainer){canvas.exitFullscreen=Browser.exitFullscreen;if(Browser.lockPointer)canvas.requestPointerLock();Browser.isFullscreen=true;if(Browser.resizeCanvas){Browser.setFullscreenCanvasSize()}else{Browser.updateCanvasDimensions(canvas)}}else{canvasContainer.parentNode.insertBefore(canvas,canvasContainer);canvasContainer.parentNode.removeChild(canvasContainer);if(Browser.resizeCanvas){Browser.setWindowedCanvasSize()}else{Browser.updateCanvasDimensions(canvas)}}if(Module["onFullScreen"])Module["onFullScreen"](Browser.isFullscreen);if(Module["onFullscreen"])Module["onFullscreen"](Browser.isFullscreen)}if(!Browser.fullscreenHandlersInstalled){Browser.fullscreenHandlersInstalled=true;document.addEventListener("fullscreenchange",fullscreenChange,false);document.addEventListener("mozfullscreenchange",fullscreenChange,false);document.addEventListener("webkitfullscreenchange",fullscreenChange,false);document.addEventListener("MSFullscreenChange",fullscreenChange,false)}var canvasContainer=document.createElement("div");canvas.parentNode.insertBefore(canvasContainer,canvas);canvasContainer.appendChild(canvas);canvasContainer.requestFullscreen=canvasContainer["requestFullscreen"]||canvasContainer["mozRequestFullScreen"]||canvasContainer["msRequestFullscreen"]||(canvasContainer["webkitRequestFullscreen"]?function(){canvasContainer["webkitRequestFullscreen"](Element["ALLOW_KEYBOARD_INPUT"])}:null)||(canvasContainer["webkitRequestFullScreen"]?function(){canvasContainer["webkitRequestFullScreen"](Element["ALLOW_KEYBOARD_INPUT"])}:null);canvasContainer.requestFullscreen()},exitFullscreen:function(){if(!Browser.isFullscreen){return false}var CFS=document["exitFullscreen"]||document["cancelFullScreen"]||document["mozCancelFullScreen"]||document["msExitFullscreen"]||document["webkitCancelFullScreen"]||function(){};CFS.apply(document,[]);return true},nextRAF:0,fakeRequestAnimationFrame:function(func){var now=Date.now();if(Browser.nextRAF===0){Browser.nextRAF=now+1e3/60}else{while(now+2>=Browser.nextRAF){Browser.nextRAF+=1e3/60}}var delay=Math.max(Browser.nextRAF-now,0);setTimeout(func,delay)},requestAnimationFrame:function(func){if(typeof requestAnimationFrame=="function"){requestAnimationFrame(func);return}var RAF=Browser.fakeRequestAnimationFrame;RAF(func)},safeSetTimeout:function(func){return safeSetTimeout(func)},safeRequestAnimationFrame:function(func){runtimeKeepalivePush();return Browser.requestAnimationFrame(function(){runtimeKeepalivePop();callUserCallback(func)})},getMimetype:function(name){return{"jpg":"image/jpeg","jpeg":"image/jpeg","png":"image/png","bmp":"image/bmp","ogg":"audio/ogg","wav":"audio/wav","mp3":"audio/mpeg"}[name.substr(name.lastIndexOf(".")+1)]},getUserMedia:function(func){if(!window.getUserMedia){window.getUserMedia=navigator["getUserMedia"]||navigator["mozGetUserMedia"]}window.getUserMedia(func)},getMovementX:function(event){return event["movementX"]||event["mozMovementX"]||event["webkitMovementX"]||0},getMovementY:function(event){return event["movementY"]||event["mozMovementY"]||event["webkitMovementY"]||0},getMouseWheelDelta:function(event){var delta=0;switch(event.type){case"DOMMouseScroll":delta=event.detail/3;break;case"mousewheel":delta=event.wheelDelta/120;break;case"wheel":delta=event.deltaY;switch(event.deltaMode){case 0:delta/=100;break;case 1:delta/=3;break;case 2:delta*=80;break;default:throw"unrecognized mouse wheel delta mode: "+event.deltaMode}break;default:throw"unrecognized mouse wheel event: "+event.type}return delta},mouseX:0,mouseY:0,mouseMovementX:0,mouseMovementY:0,touches:{},lastTouches:{},calculateMouseEvent:function(event){if(Browser.pointerLock){if(event.type!="mousemove"&&"mozMovementX"in event){Browser.mouseMovementX=Browser.mouseMovementY=0}else{Browser.mouseMovementX=Browser.getMovementX(event);Browser.mouseMovementY=Browser.getMovementY(event)}if(typeof SDL!="undefined"){Browser.mouseX=SDL.mouseX+Browser.mouseMovementX;Browser.mouseY=SDL.mouseY+Browser.mouseMovementY}else{Browser.mouseX+=Browser.mouseMovementX;Browser.mouseY+=Browser.mouseMovementY}}else{var rect=Module["canvas"].getBoundingClientRect();var cw=Module["canvas"].width;var ch=Module["canvas"].height;var scrollX=typeof window.scrollX!="undefined"?window.scrollX:window.pageXOffset;var scrollY=typeof window.scrollY!="undefined"?window.scrollY:window.pageYOffset;if(event.type==="touchstart"||event.type==="touchend"||event.type==="touchmove"){var touch=event.touch;if(touch===undefined){return}var adjustedX=touch.pageX-(scrollX+rect.left);var adjustedY=touch.pageY-(scrollY+rect.top);adjustedX=adjustedX*(cw/rect.width);adjustedY=adjustedY*(ch/rect.height);var coords={x:adjustedX,y:adjustedY};if(event.type==="touchstart"){Browser.lastTouches[touch.identifier]=coords;Browser.touches[touch.identifier]=coords}else if(event.type==="touchend"||event.type==="touchmove"){var last=Browser.touches[touch.identifier];if(!last)last=coords;Browser.lastTouches[touch.identifier]=last;Browser.touches[touch.identifier]=coords}return}var x=event.pageX-(scrollX+rect.left);var y=event.pageY-(scrollY+rect.top);x=x*(cw/rect.width);y=y*(ch/rect.height);Browser.mouseMovementX=x-Browser.mouseX;Browser.mouseMovementY=y-Browser.mouseY;Browser.mouseX=x;Browser.mouseY=y}},resizeListeners:[],updateResizeListeners:function(){var canvas=Module["canvas"];Browser.resizeListeners.forEach(function(listener){listener(canvas.width,canvas.height)})},setCanvasSize:function(width,height,noUpdates){var canvas=Module["canvas"];Browser.updateCanvasDimensions(canvas,width,height);if(!noUpdates)Browser.updateResizeListeners()},windowedWidth:0,windowedHeight:0,setFullscreenCanvasSize:function(){if(typeof SDL!="undefined"){var flags=HEAPU32[SDL.screen>>2];flags=flags|8388608;HEAP32[SDL.screen>>2]=flags}Browser.updateCanvasDimensions(Module["canvas"]);Browser.updateResizeListeners()},setWindowedCanvasSize:function(){if(typeof SDL!="undefined"){var flags=HEAPU32[SDL.screen>>2];flags=flags&~8388608;HEAP32[SDL.screen>>2]=flags}Browser.updateCanvasDimensions(Module["canvas"]);Browser.updateResizeListeners()},updateCanvasDimensions:function(canvas,wNative,hNative){if(wNative&&hNative){canvas.widthNative=wNative;canvas.heightNative=hNative}else{wNative=canvas.widthNative;hNative=canvas.heightNative}var w=wNative;var h=hNative;if(Module["forcedAspectRatio"]&&Module["forcedAspectRatio"]>0){if(w/h<Module["forcedAspectRatio"]){w=Math.round(h*Module["forcedAspectRatio"])}else{h=Math.round(w/Module["forcedAspectRatio"])}}if((document["fullscreenElement"]||document["mozFullScreenElement"]||document["msFullscreenElement"]||document["webkitFullscreenElement"]||document["webkitCurrentFullScreenElement"])===canvas.parentNode&&typeof screen!="undefined"){var factor=Math.min(screen.width/w,screen.height/h);w=Math.round(w*factor);h=Math.round(h*factor)}if(Browser.resizeCanvas){if(canvas.width!=w)canvas.width=w;if(canvas.height!=h)canvas.height=h;if(typeof canvas.style!="undefined"){canvas.style.removeProperty("width");canvas.style.removeProperty("height")}}else{if(canvas.width!=wNative)canvas.width=wNative;if(canvas.height!=hNative)canvas.height=hNative;if(typeof canvas.style!="undefined"){if(w!=wNative||h!=hNative){canvas.style.setProperty("width",w+"px","important");canvas.style.setProperty("height",h+"px","important")}else{canvas.style.removeProperty("width");canvas.style.removeProperty("height")}}}}};function _emscripten_cancel_main_loop(){Browser.mainLoop.pause();Browser.mainLoop.func=null}function _emscripten_force_exit(status){noExitRuntime=false;runtimeKeepaliveCounter=0;exit(status)}function __webgl_enable_ANGLE_instanced_arrays(ctx){var ext=ctx.getExtension("ANGLE_instanced_arrays");if(ext){ctx["vertexAttribDivisor"]=function(index,divisor){ext["vertexAttribDivisorANGLE"](index,divisor)};ctx["drawArraysInstanced"]=function(mode,first,count,primcount){ext["drawArraysInstancedANGLE"](mode,first,count,primcount)};ctx["drawElementsInstanced"]=function(mode,count,type,indices,primcount){ext["drawElementsInstancedANGLE"](mode,count,type,indices,primcount)};return 1}}function __webgl_enable_OES_vertex_array_object(ctx){var ext=ctx.getExtension("OES_vertex_array_object");if(ext){ctx["createVertexArray"]=function(){return ext["createVertexArrayOES"]()};ctx["deleteVertexArray"]=function(vao){ext["deleteVertexArrayOES"](vao)};ctx["bindVertexArray"]=function(vao){ext["bindVertexArrayOES"](vao)};ctx["isVertexArray"]=function(vao){return ext["isVertexArrayOES"](vao)};return 1}}function __webgl_enable_WEBGL_draw_buffers(ctx){var ext=ctx.getExtension("WEBGL_draw_buffers");if(ext){ctx["drawBuffers"]=function(n,bufs){ext["drawBuffersWEBGL"](n,bufs)};return 1}}function __webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance(ctx){return!!(ctx.dibvbi=ctx.getExtension("WEBGL_draw_instanced_base_vertex_base_instance"))}function __webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(ctx){return!!(ctx.mdibvbi=ctx.getExtension("WEBGL_multi_draw_instanced_base_vertex_base_instance"))}function __webgl_enable_WEBGL_multi_draw(ctx){return!!(ctx.multiDrawWebgl=ctx.getExtension("WEBGL_multi_draw"))}var GL={counter:1,buffers:[],programs:[],framebuffers:[],renderbuffers:[],textures:[],shaders:[],vaos:[],contexts:[],offscreenCanvases:{},queries:[],samplers:[],transformFeedbacks:[],syncs:[],stringCache:{},stringiCache:{},unpackAlignment:4,recordError:function recordError(errorCode){if(!GL.lastError){GL.lastError=errorCode}},getNewId:function(table){var ret=GL.counter++;for(var i=table.length;i<ret;i++){table[i]=null}return ret},getSource:function(shader,count,string,length){var source="";for(var i=0;i<count;++i){var len=length?HEAP32[length+i*4>>2]:-1;source+=UTF8ToString(HEAP32[string+i*4>>2],len<0?undefined:len)}return source},createContext:function(canvas,webGLContextAttributes){if(webGLContextAttributes.renderViaOffscreenBackBuffer)webGLContextAttributes["preserveDrawingBuffer"]=true;if(!canvas.getContextSafariWebGL2Fixed){canvas.getContextSafariWebGL2Fixed=canvas.getContext;function fixedGetContext(ver,attrs){var gl=canvas.getContextSafariWebGL2Fixed(ver,attrs);return ver=="webgl"==gl instanceof WebGLRenderingContext?gl:null}canvas.getContext=fixedGetContext}var ctx=webGLContextAttributes.majorVersion>1?canvas.getContext("webgl2",webGLContextAttributes):canvas.getContext("webgl",webGLContextAttributes);if(!ctx)return 0;var handle=GL.registerContext(ctx,webGLContextAttributes);return handle},enableOffscreenFramebufferAttributes:function(webGLContextAttributes){webGLContextAttributes.renderViaOffscreenBackBuffer=true;webGLContextAttributes.preserveDrawingBuffer=true},createOffscreenFramebuffer:function(context){var gl=context.GLctx;var fbo=gl.createFramebuffer();gl.bindFramebuffer(36160,fbo);context.defaultFbo=fbo;context.defaultFboForbidBlitFramebuffer=false;if(gl.getContextAttributes().antialias){context.defaultFboForbidBlitFramebuffer=true}else{var firefoxMatch=navigator.userAgent.toLowerCase().match(/firefox\/(\d\d)/);if(firefoxMatch!=null){var firefoxVersion=firefoxMatch[1];context.defaultFboForbidBlitFramebuffer=firefoxVersion<67}}context.defaultColorTarget=gl.createTexture();context.defaultDepthTarget=gl.createRenderbuffer();GL.resizeOffscreenFramebuffer(context);gl.bindTexture(3553,context.defaultColorTarget);gl.texParameteri(3553,10241,9728);gl.texParameteri(3553,10240,9728);gl.texParameteri(3553,10242,33071);gl.texParameteri(3553,10243,33071);gl.texImage2D(3553,0,6408,gl.canvas.width,gl.canvas.height,0,6408,5121,null);gl.framebufferTexture2D(36160,36064,3553,context.defaultColorTarget,0);gl.bindTexture(3553,null);var depthTarget=gl.createRenderbuffer();gl.bindRenderbuffer(36161,context.defaultDepthTarget);gl.renderbufferStorage(36161,33189,gl.canvas.width,gl.canvas.height);gl.framebufferRenderbuffer(36160,36096,36161,context.defaultDepthTarget);gl.bindRenderbuffer(36161,null);var vertices=[-1,-1,-1,1,1,-1,1,1];var vb=gl.createBuffer();gl.bindBuffer(34962,vb);gl.bufferData(34962,new Float32Array(vertices),35044);gl.bindBuffer(34962,null);context.blitVB=vb;var vsCode="attribute vec2 pos;"+"varying lowp vec2 tex;"+"void main() { tex = pos * 0.5 + vec2(0.5,0.5); gl_Position = vec4(pos, 0.0, 1.0); }";var vs=gl.createShader(35633);gl.shaderSource(vs,vsCode);gl.compileShader(vs);var fsCode="varying lowp vec2 tex;"+"uniform sampler2D sampler;"+"void main() { gl_FragColor = texture2D(sampler, tex); }";var fs=gl.createShader(35632);gl.shaderSource(fs,fsCode);gl.compileShader(fs);var blitProgram=gl.createProgram();gl.attachShader(blitProgram,vs);gl.attachShader(blitProgram,fs);gl.linkProgram(blitProgram);context.blitProgram=blitProgram;context.blitPosLoc=gl.getAttribLocation(blitProgram,"pos");gl.useProgram(blitProgram);gl.uniform1i(gl.getUniformLocation(blitProgram,"sampler"),0);gl.useProgram(null);context.defaultVao=undefined;if(gl.createVertexArray){context.defaultVao=gl.createVertexArray();gl.bindVertexArray(context.defaultVao);gl.enableVertexAttribArray(context.blitPosLoc);gl.bindVertexArray(null)}},resizeOffscreenFramebuffer:function(context){var gl=context.GLctx;if(context.defaultColorTarget){var prevTextureBinding=gl.getParameter(32873);gl.bindTexture(3553,context.defaultColorTarget);gl.texImage2D(3553,0,6408,gl.drawingBufferWidth,gl.drawingBufferHeight,0,6408,5121,null);gl.bindTexture(3553,prevTextureBinding)}if(context.defaultDepthTarget){var prevRenderBufferBinding=gl.getParameter(36007);gl.bindRenderbuffer(36161,context.defaultDepthTarget);gl.renderbufferStorage(36161,33189,gl.drawingBufferWidth,gl.drawingBufferHeight);gl.bindRenderbuffer(36161,prevRenderBufferBinding)}},blitOffscreenFramebuffer:function(context){var gl=context.GLctx;var prevScissorTest=gl.getParameter(3089);if(prevScissorTest)gl.disable(3089);var prevFbo=gl.getParameter(36006);if(gl.blitFramebuffer&&!context.defaultFboForbidBlitFramebuffer){gl.bindFramebuffer(36008,context.defaultFbo);gl.bindFramebuffer(36009,null);gl.blitFramebuffer(0,0,gl.canvas.width,gl.canvas.height,0,0,gl.canvas.width,gl.canvas.height,16384,9728)}else{gl.bindFramebuffer(36160,null);var prevProgram=gl.getParameter(35725);gl.useProgram(context.blitProgram);var prevVB=gl.getParameter(34964);gl.bindBuffer(34962,context.blitVB);var prevActiveTexture=gl.getParameter(34016);gl.activeTexture(33984);var prevTextureBinding=gl.getParameter(32873);gl.bindTexture(3553,context.defaultColorTarget);var prevBlend=gl.getParameter(3042);if(prevBlend)gl.disable(3042);var prevCullFace=gl.getParameter(2884);if(prevCullFace)gl.disable(2884);var prevDepthTest=gl.getParameter(2929);if(prevDepthTest)gl.disable(2929);var prevStencilTest=gl.getParameter(2960);if(prevStencilTest)gl.disable(2960);function draw(){gl.vertexAttribPointer(context.blitPosLoc,2,5126,false,0,0);gl.drawArrays(5,0,4)}if(context.defaultVao){var prevVAO=gl.getParameter(34229);gl.bindVertexArray(context.defaultVao);draw();gl.bindVertexArray(prevVAO)}else{var prevVertexAttribPointer={buffer:gl.getVertexAttrib(context.blitPosLoc,34975),size:gl.getVertexAttrib(context.blitPosLoc,34339),stride:gl.getVertexAttrib(context.blitPosLoc,34340),type:gl.getVertexAttrib(context.blitPosLoc,34341),normalized:gl.getVertexAttrib(context.blitPosLoc,34922),pointer:gl.getVertexAttribOffset(context.blitPosLoc,34373)};var maxVertexAttribs=gl.getParameter(34921);var prevVertexAttribEnables=[];for(var i=0;i<maxVertexAttribs;++i){var prevEnabled=gl.getVertexAttrib(i,34338);var wantEnabled=i==context.blitPosLoc;if(prevEnabled&&!wantEnabled){gl.disableVertexAttribArray(i)}if(!prevEnabled&&wantEnabled){gl.enableVertexAttribArray(i)}prevVertexAttribEnables[i]=prevEnabled}draw();for(var i=0;i<maxVertexAttribs;++i){var prevEnabled=prevVertexAttribEnables[i];var nowEnabled=i==context.blitPosLoc;if(prevEnabled&&!nowEnabled){gl.enableVertexAttribArray(i)}if(!prevEnabled&&nowEnabled){gl.disableVertexAttribArray(i)}}gl.bindBuffer(34962,prevVertexAttribPointer.buffer);gl.vertexAttribPointer(context.blitPosLoc,prevVertexAttribPointer.size,prevVertexAttribPointer.type,prevVertexAttribPointer.normalized,prevVertexAttribPointer.stride,prevVertexAttribPointer.offset)}if(prevStencilTest)gl.enable(2960);if(prevDepthTest)gl.enable(2929);if(prevCullFace)gl.enable(2884);if(prevBlend)gl.enable(3042);gl.bindTexture(3553,prevTextureBinding);gl.activeTexture(prevActiveTexture);gl.bindBuffer(34962,prevVB);gl.useProgram(prevProgram)}gl.bindFramebuffer(36160,prevFbo);if(prevScissorTest)gl.enable(3089)},registerContext:function(ctx,webGLContextAttributes){var handle=GL.getNewId(GL.contexts);var context={handle:handle,attributes:webGLContextAttributes,version:webGLContextAttributes.majorVersion,GLctx:ctx};if(ctx.canvas)ctx.canvas.GLctxObject=context;GL.contexts[handle]=context;if(typeof webGLContextAttributes.enableExtensionsByDefault=="undefined"||webGLContextAttributes.enableExtensionsByDefault){GL.initExtensions(context)}if(webGLContextAttributes.renderViaOffscreenBackBuffer)GL.createOffscreenFramebuffer(context);return handle},makeContextCurrent:function(contextHandle){GL.currentContext=GL.contexts[contextHandle];Module.ctx=GLctx=GL.currentContext&&GL.currentContext.GLctx;return!(contextHandle&&!GLctx)},getContext:function(contextHandle){return GL.contexts[contextHandle]},deleteContext:function(contextHandle){if(GL.currentContext===GL.contexts[contextHandle])GL.currentContext=null;if(typeof JSEvents=="object")JSEvents.removeAllHandlersOnTarget(GL.contexts[contextHandle].GLctx.canvas);if(GL.contexts[contextHandle]&&GL.contexts[contextHandle].GLctx.canvas)GL.contexts[contextHandle].GLctx.canvas.GLctxObject=undefined;GL.contexts[contextHandle]=null},initExtensions:function(context){if(!context)context=GL.currentContext;if(context.initExtensionsDone)return;context.initExtensionsDone=true;var GLctx=context.GLctx;__webgl_enable_ANGLE_instanced_arrays(GLctx);__webgl_enable_OES_vertex_array_object(GLctx);__webgl_enable_WEBGL_draw_buffers(GLctx);__webgl_enable_WEBGL_draw_instanced_base_vertex_base_instance(GLctx);__webgl_enable_WEBGL_multi_draw_instanced_base_vertex_base_instance(GLctx);if(context.version>=2){GLctx.disjointTimerQueryExt=GLctx.getExtension("EXT_disjoint_timer_query_webgl2")}if(context.version<2||!GLctx.disjointTimerQueryExt){GLctx.disjointTimerQueryExt=GLctx.getExtension("EXT_disjoint_timer_query")}__webgl_enable_WEBGL_multi_draw(GLctx);var exts=GLctx.getSupportedExtensions()||[];exts.forEach(function(ext){if(!ext.includes("lose_context")&&!ext.includes("debug")){GLctx.getExtension(ext)}})}};function _emscripten_glActiveTexture(x0){GLctx["activeTexture"](x0)}function _emscripten_glAttachShader(program,shader){GLctx.attachShader(GL.programs[program],GL.shaders[shader])}function _emscripten_glBeginQuery(target,id){GLctx["beginQuery"](target,GL.queries[id])}function _emscripten_glBeginQueryEXT(target,id){GLctx.disjointTimerQueryExt["beginQueryEXT"](target,GL.queries[id])}function _emscripten_glBeginTransformFeedback(x0){GLctx["beginTransformFeedback"](x0)}function _emscripten_glBindAttribLocation(program,index,name){GLctx.bindAttribLocation(GL.programs[program],index,UTF8ToString(name))}function _emscripten_glBindBuffer(target,buffer){if(target==35051){GLctx.currentPixelPackBufferBinding=buffer}else if(target==35052){GLctx.currentPixelUnpackBufferBinding=buffer}GLctx.bindBuffer(target,GL.buffers[buffer])}function _emscripten_glBindBufferBase(target,index,buffer){GLctx["bindBufferBase"](target,index,GL.buffers[buffer])}function _emscripten_glBindBufferRange(target,index,buffer,offset,ptrsize){GLctx["bindBufferRange"](target,index,GL.buffers[buffer],offset,ptrsize)}function _emscripten_glBindFramebuffer(target,framebuffer){GLctx.bindFramebuffer(target,framebuffer?GL.framebuffers[framebuffer]:GL.currentContext.defaultFbo)}function _emscripten_glBindRenderbuffer(target,renderbuffer){GLctx.bindRenderbuffer(target,GL.renderbuffers[renderbuffer])}function _emscripten_glBindSampler(unit,sampler){GLctx["bindSampler"](unit,GL.samplers[sampler])}function _emscripten_glBindTexture(target,texture){GLctx.bindTexture(target,GL.textures[texture])}function _emscripten_glBindTransformFeedback(target,id){GLctx["bindTransformFeedback"](target,GL.transformFeedbacks[id])}function _emscripten_glBindVertexArray(vao){GLctx["bindVertexArray"](GL.vaos[vao])}function _emscripten_glBindVertexArrayOES(vao){GLctx["bindVertexArray"](GL.vaos[vao])}function _emscripten_glBlendColor(x0,x1,x2,x3){GLctx["blendColor"](x0,x1,x2,x3)}function _emscripten_glBlendEquation(x0){GLctx["blendEquation"](x0)}function _emscripten_glBlendEquationSeparate(x0,x1){GLctx["blendEquationSeparate"](x0,x1)}function _emscripten_glBlendFunc(x0,x1){GLctx["blendFunc"](x0,x1)}function _emscripten_glBlendFuncSeparate(x0,x1,x2,x3){GLctx["blendFuncSeparate"](x0,x1,x2,x3)}function _emscripten_glBlitFramebuffer(x0,x1,x2,x3,x4,x5,x6,x7,x8,x9){GLctx["blitFramebuffer"](x0,x1,x2,x3,x4,x5,x6,x7,x8,x9)}function _emscripten_glBufferData(target,size,data,usage){if(GL.currentContext.version>=2){if(data&&size){GLctx.bufferData(target,HEAPU8,usage,data,size)}else{GLctx.bufferData(target,size,usage)}}else{GLctx.bufferData(target,data?HEAPU8.subarray(data,data+size):size,usage)}}function _emscripten_glBufferSubData(target,offset,size,data){if(GL.currentContext.version>=2){size&&GLctx.bufferSubData(target,offset,HEAPU8,data,size);return}GLctx.bufferSubData(target,offset,HEAPU8.subarray(data,data+size))}function _emscripten_glCheckFramebufferStatus(x0){return GLctx["checkFramebufferStatus"](x0)}function _emscripten_glClear(x0){GLctx["clear"](x0)}function _emscripten_glClearBufferfi(x0,x1,x2,x3){GLctx["clearBufferfi"](x0,x1,x2,x3)}function _emscripten_glClearBufferfv(buffer,drawbuffer,value){GLctx["clearBufferfv"](buffer,drawbuffer,HEAPF32,value>>2)}function _emscripten_glClearBufferiv(buffer,drawbuffer,value){GLctx["clearBufferiv"](buffer,drawbuffer,HEAP32,value>>2)}function _emscripten_glClearBufferuiv(buffer,drawbuffer,value){GLctx["clearBufferuiv"](buffer,drawbuffer,HEAPU32,value>>2)}function _emscripten_glClearColor(x0,x1,x2,x3){GLctx["clearColor"](x0,x1,x2,x3)}function _emscripten_glClearDepthf(x0){GLctx["clearDepth"](x0)}function _emscripten_glClearStencil(x0){GLctx["clearStencil"](x0)}function convertI32PairToI53(lo,hi){return(lo>>>0)+hi*4294967296}function _emscripten_glClientWaitSync(sync,flags,timeoutLo,timeoutHi){return GLctx.clientWaitSync(GL.syncs[sync],flags,convertI32PairToI53(timeoutLo,timeoutHi))}function _emscripten_glColorMask(red,green,blue,alpha){GLctx.colorMask(!!red,!!green,!!blue,!!alpha)}function _emscripten_glCompileShader(shader){GLctx.compileShader(GL.shaders[shader])}function _emscripten_glCompressedTexImage2D(target,level,internalFormat,width,height,border,imageSize,data){if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding||!imageSize){GLctx["compressedTexImage2D"](target,level,internalFormat,width,height,border,imageSize,data)}else{GLctx["compressedTexImage2D"](target,level,internalFormat,width,height,border,HEAPU8,data,imageSize)}return}GLctx["compressedTexImage2D"](target,level,internalFormat,width,height,border,data?HEAPU8.subarray(data,data+imageSize):null)}function _emscripten_glCompressedTexImage3D(target,level,internalFormat,width,height,depth,border,imageSize,data){if(GLctx.currentPixelUnpackBufferBinding){GLctx["compressedTexImage3D"](target,level,internalFormat,width,height,depth,border,imageSize,data)}else{GLctx["compressedTexImage3D"](target,level,internalFormat,width,height,depth,border,HEAPU8,data,imageSize)}}function _emscripten_glCompressedTexSubImage2D(target,level,xoffset,yoffset,width,height,format,imageSize,data){if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding||!imageSize){GLctx["compressedTexSubImage2D"](target,level,xoffset,yoffset,width,height,format,imageSize,data)}else{GLctx["compressedTexSubImage2D"](target,level,xoffset,yoffset,width,height,format,HEAPU8,data,imageSize)}return}GLctx["compressedTexSubImage2D"](target,level,xoffset,yoffset,width,height,format,data?HEAPU8.subarray(data,data+imageSize):null)}function _emscripten_glCompressedTexSubImage3D(target,level,xoffset,yoffset,zoffset,width,height,depth,format,imageSize,data){if(GLctx.currentPixelUnpackBufferBinding){GLctx["compressedTexSubImage3D"](target,level,xoffset,yoffset,zoffset,width,height,depth,format,imageSize,data)}else{GLctx["compressedTexSubImage3D"](target,level,xoffset,yoffset,zoffset,width,height,depth,format,HEAPU8,data,imageSize)}}function _emscripten_glCopyBufferSubData(x0,x1,x2,x3,x4){GLctx["copyBufferSubData"](x0,x1,x2,x3,x4)}function _emscripten_glCopyTexImage2D(x0,x1,x2,x3,x4,x5,x6,x7){GLctx["copyTexImage2D"](x0,x1,x2,x3,x4,x5,x6,x7)}function _emscripten_glCopyTexSubImage2D(x0,x1,x2,x3,x4,x5,x6,x7){GLctx["copyTexSubImage2D"](x0,x1,x2,x3,x4,x5,x6,x7)}function _emscripten_glCopyTexSubImage3D(x0,x1,x2,x3,x4,x5,x6,x7,x8){GLctx["copyTexSubImage3D"](x0,x1,x2,x3,x4,x5,x6,x7,x8)}function _emscripten_glCreateProgram(){var id=GL.getNewId(GL.programs);var program=GLctx.createProgram();program.name=id;program.maxUniformLength=program.maxAttributeLength=program.maxUniformBlockNameLength=0;program.uniformIdCounter=1;GL.programs[id]=program;return id}function _emscripten_glCreateShader(shaderType){var id=GL.getNewId(GL.shaders);GL.shaders[id]=GLctx.createShader(shaderType);return id}function _emscripten_glCullFace(x0){GLctx["cullFace"](x0)}function _emscripten_glDeleteBuffers(n,buffers){for(var i=0;i<n;i++){var id=HEAP32[buffers+i*4>>2];var buffer=GL.buffers[id];if(!buffer)continue;GLctx.deleteBuffer(buffer);buffer.name=0;GL.buffers[id]=null;if(id==GLctx.currentPixelPackBufferBinding)GLctx.currentPixelPackBufferBinding=0;if(id==GLctx.currentPixelUnpackBufferBinding)GLctx.currentPixelUnpackBufferBinding=0}}function _emscripten_glDeleteFramebuffers(n,framebuffers){for(var i=0;i<n;++i){var id=HEAP32[framebuffers+i*4>>2];var framebuffer=GL.framebuffers[id];if(!framebuffer)continue;GLctx.deleteFramebuffer(framebuffer);framebuffer.name=0;GL.framebuffers[id]=null}}function _emscripten_glDeleteProgram(id){if(!id)return;var program=GL.programs[id];if(!program){GL.recordError(1281);return}GLctx.deleteProgram(program);program.name=0;GL.programs[id]=null}function _emscripten_glDeleteQueries(n,ids){for(var i=0;i<n;i++){var id=HEAP32[ids+i*4>>2];var query=GL.queries[id];if(!query)continue;GLctx["deleteQuery"](query);GL.queries[id]=null}}function _emscripten_glDeleteQueriesEXT(n,ids){for(var i=0;i<n;i++){var id=HEAP32[ids+i*4>>2];var query=GL.queries[id];if(!query)continue;GLctx.disjointTimerQueryExt["deleteQueryEXT"](query);GL.queries[id]=null}}function _emscripten_glDeleteRenderbuffers(n,renderbuffers){for(var i=0;i<n;i++){var id=HEAP32[renderbuffers+i*4>>2];var renderbuffer=GL.renderbuffers[id];if(!renderbuffer)continue;GLctx.deleteRenderbuffer(renderbuffer);renderbuffer.name=0;GL.renderbuffers[id]=null}}function _emscripten_glDeleteSamplers(n,samplers){for(var i=0;i<n;i++){var id=HEAP32[samplers+i*4>>2];var sampler=GL.samplers[id];if(!sampler)continue;GLctx["deleteSampler"](sampler);sampler.name=0;GL.samplers[id]=null}}function _emscripten_glDeleteShader(id){if(!id)return;var shader=GL.shaders[id];if(!shader){GL.recordError(1281);return}GLctx.deleteShader(shader);GL.shaders[id]=null}function _emscripten_glDeleteSync(id){if(!id)return;var sync=GL.syncs[id];if(!sync){GL.recordError(1281);return}GLctx.deleteSync(sync);sync.name=0;GL.syncs[id]=null}function _emscripten_glDeleteTextures(n,textures){for(var i=0;i<n;i++){var id=HEAP32[textures+i*4>>2];var texture=GL.textures[id];if(!texture)continue;GLctx.deleteTexture(texture);texture.name=0;GL.textures[id]=null}}function _emscripten_glDeleteTransformFeedbacks(n,ids){for(var i=0;i<n;i++){var id=HEAP32[ids+i*4>>2];var transformFeedback=GL.transformFeedbacks[id];if(!transformFeedback)continue;GLctx["deleteTransformFeedback"](transformFeedback);transformFeedback.name=0;GL.transformFeedbacks[id]=null}}function _emscripten_glDeleteVertexArrays(n,vaos){for(var i=0;i<n;i++){var id=HEAP32[vaos+i*4>>2];GLctx["deleteVertexArray"](GL.vaos[id]);GL.vaos[id]=null}}function _emscripten_glDeleteVertexArraysOES(n,vaos){for(var i=0;i<n;i++){var id=HEAP32[vaos+i*4>>2];GLctx["deleteVertexArray"](GL.vaos[id]);GL.vaos[id]=null}}function _emscripten_glDepthFunc(x0){GLctx["depthFunc"](x0)}function _emscripten_glDepthMask(flag){GLctx.depthMask(!!flag)}function _emscripten_glDepthRangef(x0,x1){GLctx["depthRange"](x0,x1)}function _emscripten_glDetachShader(program,shader){GLctx.detachShader(GL.programs[program],GL.shaders[shader])}function _emscripten_glDisable(x0){GLctx["disable"](x0)}function _emscripten_glDisableVertexAttribArray(index){GLctx.disableVertexAttribArray(index)}function _emscripten_glDrawArrays(mode,first,count){GLctx.drawArrays(mode,first,count)}function _emscripten_glDrawArraysInstanced(mode,first,count,primcount){GLctx["drawArraysInstanced"](mode,first,count,primcount)}function _emscripten_glDrawArraysInstancedANGLE(mode,first,count,primcount){GLctx["drawArraysInstanced"](mode,first,count,primcount)}function _emscripten_glDrawArraysInstancedARB(mode,first,count,primcount){GLctx["drawArraysInstanced"](mode,first,count,primcount)}function _emscripten_glDrawArraysInstancedEXT(mode,first,count,primcount){GLctx["drawArraysInstanced"](mode,first,count,primcount)}function _emscripten_glDrawArraysInstancedNV(mode,first,count,primcount){GLctx["drawArraysInstanced"](mode,first,count,primcount)}var tempFixedLengthArray=[];function _emscripten_glDrawBuffers(n,bufs){var bufArray=tempFixedLengthArray[n];for(var i=0;i<n;i++){bufArray[i]=HEAP32[bufs+i*4>>2]}GLctx["drawBuffers"](bufArray)}function _emscripten_glDrawBuffersEXT(n,bufs){var bufArray=tempFixedLengthArray[n];for(var i=0;i<n;i++){bufArray[i]=HEAP32[bufs+i*4>>2]}GLctx["drawBuffers"](bufArray)}function _emscripten_glDrawBuffersWEBGL(n,bufs){var bufArray=tempFixedLengthArray[n];for(var i=0;i<n;i++){bufArray[i]=HEAP32[bufs+i*4>>2]}GLctx["drawBuffers"](bufArray)}function _emscripten_glDrawElements(mode,count,type,indices){GLctx.drawElements(mode,count,type,indices)}function _emscripten_glDrawElementsInstanced(mode,count,type,indices,primcount){GLctx["drawElementsInstanced"](mode,count,type,indices,primcount)}function _emscripten_glDrawElementsInstancedANGLE(mode,count,type,indices,primcount){GLctx["drawElementsInstanced"](mode,count,type,indices,primcount)}function _emscripten_glDrawElementsInstancedARB(mode,count,type,indices,primcount){GLctx["drawElementsInstanced"](mode,count,type,indices,primcount)}function _emscripten_glDrawElementsInstancedEXT(mode,count,type,indices,primcount){GLctx["drawElementsInstanced"](mode,count,type,indices,primcount)}function _emscripten_glDrawElementsInstancedNV(mode,count,type,indices,primcount){GLctx["drawElementsInstanced"](mode,count,type,indices,primcount)}function _glDrawElements(mode,count,type,indices){GLctx.drawElements(mode,count,type,indices)}function _emscripten_glDrawRangeElements(mode,start,end,count,type,indices){_glDrawElements(mode,count,type,indices)}function _emscripten_glEnable(x0){GLctx["enable"](x0)}function _emscripten_glEnableVertexAttribArray(index){GLctx.enableVertexAttribArray(index)}function _emscripten_glEndQuery(x0){GLctx["endQuery"](x0)}function _emscripten_glEndQueryEXT(target){GLctx.disjointTimerQueryExt["endQueryEXT"](target)}function _emscripten_glEndTransformFeedback(){GLctx["endTransformFeedback"]()}function _emscripten_glFenceSync(condition,flags){var sync=GLctx.fenceSync(condition,flags);if(sync){var id=GL.getNewId(GL.syncs);sync.name=id;GL.syncs[id]=sync;return id}else{return 0}}function _emscripten_glFinish(){GLctx["finish"]()}function _emscripten_glFlush(){GLctx["flush"]()}function _emscripten_glFramebufferRenderbuffer(target,attachment,renderbuffertarget,renderbuffer){GLctx.framebufferRenderbuffer(target,attachment,renderbuffertarget,GL.renderbuffers[renderbuffer])}function _emscripten_glFramebufferTexture2D(target,attachment,textarget,texture,level){GLctx.framebufferTexture2D(target,attachment,textarget,GL.textures[texture],level)}function _emscripten_glFramebufferTextureLayer(target,attachment,texture,level,layer){GLctx.framebufferTextureLayer(target,attachment,GL.textures[texture],level,layer)}function _emscripten_glFrontFace(x0){GLctx["frontFace"](x0)}function __glGenObject(n,buffers,createFunction,objectTable){for(var i=0;i<n;i++){var buffer=GLctx[createFunction]();var id=buffer&&GL.getNewId(objectTable);if(buffer){buffer.name=id;objectTable[id]=buffer}else{GL.recordError(1282)}HEAP32[buffers+i*4>>2]=id}}function _emscripten_glGenBuffers(n,buffers){__glGenObject(n,buffers,"createBuffer",GL.buffers)}function _emscripten_glGenFramebuffers(n,ids){__glGenObject(n,ids,"createFramebuffer",GL.framebuffers)}function _emscripten_glGenQueries(n,ids){__glGenObject(n,ids,"createQuery",GL.queries)}function _emscripten_glGenQueriesEXT(n,ids){for(var i=0;i<n;i++){var query=GLctx.disjointTimerQueryExt["createQueryEXT"]();if(!query){GL.recordError(1282);while(i<n)HEAP32[ids+i++*4>>2]=0;return}var id=GL.getNewId(GL.queries);query.name=id;GL.queries[id]=query;HEAP32[ids+i*4>>2]=id}}function _emscripten_glGenRenderbuffers(n,renderbuffers){__glGenObject(n,renderbuffers,"createRenderbuffer",GL.renderbuffers)}function _emscripten_glGenSamplers(n,samplers){__glGenObject(n,samplers,"createSampler",GL.samplers)}function _emscripten_glGenTextures(n,textures){__glGenObject(n,textures,"createTexture",GL.textures)}function _emscripten_glGenTransformFeedbacks(n,ids){__glGenObject(n,ids,"createTransformFeedback",GL.transformFeedbacks)}function _emscripten_glGenVertexArrays(n,arrays){__glGenObject(n,arrays,"createVertexArray",GL.vaos)}function _emscripten_glGenVertexArraysOES(n,arrays){__glGenObject(n,arrays,"createVertexArray",GL.vaos)}function _emscripten_glGenerateMipmap(x0){GLctx["generateMipmap"](x0)}function __glGetActiveAttribOrUniform(funcName,program,index,bufSize,length,size,type,name){program=GL.programs[program];var info=GLctx[funcName](program,index);if(info){var numBytesWrittenExclNull=name&&stringToUTF8(info.name,name,bufSize);if(length)HEAP32[length>>2]=numBytesWrittenExclNull;if(size)HEAP32[size>>2]=info.size;if(type)HEAP32[type>>2]=info.type}}function _emscripten_glGetActiveAttrib(program,index,bufSize,length,size,type,name){__glGetActiveAttribOrUniform("getActiveAttrib",program,index,bufSize,length,size,type,name)}function _emscripten_glGetActiveUniform(program,index,bufSize,length,size,type,name){__glGetActiveAttribOrUniform("getActiveUniform",program,index,bufSize,length,size,type,name)}function _emscripten_glGetActiveUniformBlockName(program,uniformBlockIndex,bufSize,length,uniformBlockName){program=GL.programs[program];var result=GLctx["getActiveUniformBlockName"](program,uniformBlockIndex);if(!result)return;if(uniformBlockName&&bufSize>0){var numBytesWrittenExclNull=stringToUTF8(result,uniformBlockName,bufSize);if(length)HEAP32[length>>2]=numBytesWrittenExclNull}else{if(length)HEAP32[length>>2]=0}}function _emscripten_glGetActiveUniformBlockiv(program,uniformBlockIndex,pname,params){if(!params){GL.recordError(1281);return}program=GL.programs[program];if(pname==35393){var name=GLctx["getActiveUniformBlockName"](program,uniformBlockIndex);HEAP32[params>>2]=name.length+1;return}var result=GLctx["getActiveUniformBlockParameter"](program,uniformBlockIndex,pname);if(result===null)return;if(pname==35395){for(var i=0;i<result.length;i++){HEAP32[params+i*4>>2]=result[i]}}else{HEAP32[params>>2]=result}}function _emscripten_glGetActiveUniformsiv(program,uniformCount,uniformIndices,pname,params){if(!params){GL.recordError(1281);return}if(uniformCount>0&&uniformIndices==0){GL.recordError(1281);return}program=GL.programs[program];var ids=[];for(var i=0;i<uniformCount;i++){ids.push(HEAP32[uniformIndices+i*4>>2])}var result=GLctx["getActiveUniforms"](program,ids,pname);if(!result)return;var len=result.length;for(var i=0;i<len;i++){HEAP32[params+i*4>>2]=result[i]}}function _emscripten_glGetAttachedShaders(program,maxCount,count,shaders){var result=GLctx.getAttachedShaders(GL.programs[program]);var len=result.length;if(len>maxCount){len=maxCount}HEAP32[count>>2]=len;for(var i=0;i<len;++i){var id=GL.shaders.indexOf(result[i]);HEAP32[shaders+i*4>>2]=id}}function _emscripten_glGetAttribLocation(program,name){return GLctx.getAttribLocation(GL.programs[program],UTF8ToString(name))}function writeI53ToI64(ptr,num){HEAPU32[ptr>>2]=num;HEAPU32[ptr+4>>2]=(num-HEAPU32[ptr>>2])/4294967296}function emscriptenWebGLGet(name_,p,type){if(!p){GL.recordError(1281);return}var ret=undefined;switch(name_){case 36346:ret=1;break;case 36344:if(type!=0&&type!=1){GL.recordError(1280)}return;case 34814:case 36345:ret=0;break;case 34466:var formats=GLctx.getParameter(34467);ret=formats?formats.length:0;break;case 33309:if(GL.currentContext.version<2){GL.recordError(1282);return}var exts=GLctx.getSupportedExtensions()||[];ret=2*exts.length;break;case 33307:case 33308:if(GL.currentContext.version<2){GL.recordError(1280);return}ret=name_==33307?3:0;break}if(ret===undefined){var result=GLctx.getParameter(name_);switch(typeof result){case"number":ret=result;break;case"boolean":ret=result?1:0;break;case"string":GL.recordError(1280);return;case"object":if(result===null){switch(name_){case 34964:case 35725:case 34965:case 36006:case 36007:case 32873:case 34229:case 36662:case 36663:case 35053:case 35055:case 36010:case 35097:case 35869:case 32874:case 36389:case 35983:case 35368:case 34068:{ret=0;break}default:{GL.recordError(1280);return}}}else if(result instanceof Float32Array||result instanceof Uint32Array||result instanceof Int32Array||result instanceof Array){for(var i=0;i<result.length;++i){switch(type){case 0:HEAP32[p+i*4>>2]=result[i];break;case 2:HEAPF32[p+i*4>>2]=result[i];break;case 4:HEAP8[p+i>>0]=result[i]?1:0;break}}return}else{try{ret=result.name|0}catch(e){GL.recordError(1280);err("GL_INVALID_ENUM in glGet"+type+"v: Unknown object returned from WebGL getParameter("+name_+")! (error: "+e+")");return}}break;default:GL.recordError(1280);err("GL_INVALID_ENUM in glGet"+type+"v: Native code calling glGet"+type+"v("+name_+") and it returns "+result+" of type "+typeof result+"!");return}}switch(type){case 1:writeI53ToI64(p,ret);break;case 0:HEAP32[p>>2]=ret;break;case 2:HEAPF32[p>>2]=ret;break;case 4:HEAP8[p>>0]=ret?1:0;break}}function _emscripten_glGetBooleanv(name_,p){emscriptenWebGLGet(name_,p,4)}function _emscripten_glGetBufferParameteri64v(target,value,data){if(!data){GL.recordError(1281);return}writeI53ToI64(data,GLctx.getBufferParameter(target,value))}function _emscripten_glGetBufferParameteriv(target,value,data){if(!data){GL.recordError(1281);return}HEAP32[data>>2]=GLctx.getBufferParameter(target,value)}function _emscripten_glGetError(){var error=GLctx.getError()||GL.lastError;GL.lastError=0;return error}function _emscripten_glGetFloatv(name_,p){emscriptenWebGLGet(name_,p,2)}function _emscripten_glGetFragDataLocation(program,name){return GLctx["getFragDataLocation"](GL.programs[program],UTF8ToString(name))}function _emscripten_glGetFramebufferAttachmentParameteriv(target,attachment,pname,params){var result=GLctx.getFramebufferAttachmentParameter(target,attachment,pname);if(result instanceof WebGLRenderbuffer||result instanceof WebGLTexture){result=result.name|0}HEAP32[params>>2]=result}function emscriptenWebGLGetIndexed(target,index,data,type){if(!data){GL.recordError(1281);return}var result=GLctx["getIndexedParameter"](target,index);var ret;switch(typeof result){case"boolean":ret=result?1:0;break;case"number":ret=result;break;case"object":if(result===null){switch(target){case 35983:case 35368:ret=0;break;default:{GL.recordError(1280);return}}}else if(result instanceof WebGLBuffer){ret=result.name|0}else{GL.recordError(1280);return}break;default:GL.recordError(1280);return}switch(type){case 1:writeI53ToI64(data,ret);break;case 0:HEAP32[data>>2]=ret;break;case 2:HEAPF32[data>>2]=ret;break;case 4:HEAP8[data>>0]=ret?1:0;break;default:throw"internal emscriptenWebGLGetIndexed() error, bad type: "+type}}function _emscripten_glGetInteger64i_v(target,index,data){emscriptenWebGLGetIndexed(target,index,data,1)}function _emscripten_glGetInteger64v(name_,p){emscriptenWebGLGet(name_,p,1)}function _emscripten_glGetIntegeri_v(target,index,data){emscriptenWebGLGetIndexed(target,index,data,0)}function _emscripten_glGetIntegerv(name_,p){emscriptenWebGLGet(name_,p,0)}function _emscripten_glGetInternalformativ(target,internalformat,pname,bufSize,params){if(bufSize<0){GL.recordError(1281);return}if(!params){GL.recordError(1281);return}var ret=GLctx["getInternalformatParameter"](target,internalformat,pname);if(ret===null)return;for(var i=0;i<ret.length&&i<bufSize;++i){HEAP32[params+i*4>>2]=ret[i]}}function _emscripten_glGetProgramBinary(program,bufSize,length,binaryFormat,binary){GL.recordError(1282)}function _emscripten_glGetProgramInfoLog(program,maxLength,length,infoLog){var log=GLctx.getProgramInfoLog(GL.programs[program]);if(log===null)log="(unknown error)";var numBytesWrittenExclNull=maxLength>0&&infoLog?stringToUTF8(log,infoLog,maxLength):0;if(length)HEAP32[length>>2]=numBytesWrittenExclNull}function _emscripten_glGetProgramiv(program,pname,p){if(!p){GL.recordError(1281);return}if(program>=GL.counter){GL.recordError(1281);return}program=GL.programs[program];if(pname==35716){var log=GLctx.getProgramInfoLog(program);if(log===null)log="(unknown error)";HEAP32[p>>2]=log.length+1}else if(pname==35719){if(!program.maxUniformLength){for(var i=0;i<GLctx.getProgramParameter(program,35718);++i){program.maxUniformLength=Math.max(program.maxUniformLength,GLctx.getActiveUniform(program,i).name.length+1)}}HEAP32[p>>2]=program.maxUniformLength}else if(pname==35722){if(!program.maxAttributeLength){for(var i=0;i<GLctx.getProgramParameter(program,35721);++i){program.maxAttributeLength=Math.max(program.maxAttributeLength,GLctx.getActiveAttrib(program,i).name.length+1)}}HEAP32[p>>2]=program.maxAttributeLength}else if(pname==35381){if(!program.maxUniformBlockNameLength){for(var i=0;i<GLctx.getProgramParameter(program,35382);++i){program.maxUniformBlockNameLength=Math.max(program.maxUniformBlockNameLength,GLctx.getActiveUniformBlockName(program,i).length+1)}}HEAP32[p>>2]=program.maxUniformBlockNameLength}else{HEAP32[p>>2]=GLctx.getProgramParameter(program,pname)}}function _emscripten_glGetQueryObjecti64vEXT(id,pname,params){if(!params){GL.recordError(1281);return}var query=GL.queries[id];var param;if(GL.currentContext.version<2){param=GLctx.disjointTimerQueryExt["getQueryObjectEXT"](query,pname)}else{param=GLctx["getQueryParameter"](query,pname)}var ret;if(typeof param=="boolean"){ret=param?1:0}else{ret=param}writeI53ToI64(params,ret)}function _emscripten_glGetQueryObjectivEXT(id,pname,params){if(!params){GL.recordError(1281);return}var query=GL.queries[id];var param=GLctx.disjointTimerQueryExt["getQueryObjectEXT"](query,pname);var ret;if(typeof param=="boolean"){ret=param?1:0}else{ret=param}HEAP32[params>>2]=ret}function _emscripten_glGetQueryObjectui64vEXT(id,pname,params){if(!params){GL.recordError(1281);return}var query=GL.queries[id];var param;if(GL.currentContext.version<2){param=GLctx.disjointTimerQueryExt["getQueryObjectEXT"](query,pname)}else{param=GLctx["getQueryParameter"](query,pname)}var ret;if(typeof param=="boolean"){ret=param?1:0}else{ret=param}writeI53ToI64(params,ret)}function _emscripten_glGetQueryObjectuiv(id,pname,params){if(!params){GL.recordError(1281);return}var query=GL.queries[id];var param=GLctx["getQueryParameter"](query,pname);var ret;if(typeof param=="boolean"){ret=param?1:0}else{ret=param}HEAP32[params>>2]=ret}function _emscripten_glGetQueryObjectuivEXT(id,pname,params){if(!params){GL.recordError(1281);return}var query=GL.queries[id];var param=GLctx.disjointTimerQueryExt["getQueryObjectEXT"](query,pname);var ret;if(typeof param=="boolean"){ret=param?1:0}else{ret=param}HEAP32[params>>2]=ret}function _emscripten_glGetQueryiv(target,pname,params){if(!params){GL.recordError(1281);return}HEAP32[params>>2]=GLctx["getQuery"](target,pname)}function _emscripten_glGetQueryivEXT(target,pname,params){if(!params){GL.recordError(1281);return}HEAP32[params>>2]=GLctx.disjointTimerQueryExt["getQueryEXT"](target,pname)}function _emscripten_glGetRenderbufferParameteriv(target,pname,params){if(!params){GL.recordError(1281);return}HEAP32[params>>2]=GLctx.getRenderbufferParameter(target,pname)}function _emscripten_glGetSamplerParameterfv(sampler,pname,params){if(!params){GL.recordError(1281);return}HEAPF32[params>>2]=GLctx["getSamplerParameter"](GL.samplers[sampler],pname)}function _emscripten_glGetSamplerParameteriv(sampler,pname,params){if(!params){GL.recordError(1281);return}HEAP32[params>>2]=GLctx["getSamplerParameter"](GL.samplers[sampler],pname)}function _emscripten_glGetShaderInfoLog(shader,maxLength,length,infoLog){var log=GLctx.getShaderInfoLog(GL.shaders[shader]);if(log===null)log="(unknown error)";var numBytesWrittenExclNull=maxLength>0&&infoLog?stringToUTF8(log,infoLog,maxLength):0;if(length)HEAP32[length>>2]=numBytesWrittenExclNull}function _emscripten_glGetShaderPrecisionFormat(shaderType,precisionType,range,precision){var result=GLctx.getShaderPrecisionFormat(shaderType,precisionType);HEAP32[range>>2]=result.rangeMin;HEAP32[range+4>>2]=result.rangeMax;HEAP32[precision>>2]=result.precision}function _emscripten_glGetShaderSource(shader,bufSize,length,source){var result=GLctx.getShaderSource(GL.shaders[shader]);if(!result)return;var numBytesWrittenExclNull=bufSize>0&&source?stringToUTF8(result,source,bufSize):0;if(length)HEAP32[length>>2]=numBytesWrittenExclNull}function _emscripten_glGetShaderiv(shader,pname,p){if(!p){GL.recordError(1281);return}if(pname==35716){var log=GLctx.getShaderInfoLog(GL.shaders[shader]);if(log===null)log="(unknown error)";var logLength=log?log.length+1:0;HEAP32[p>>2]=logLength}else if(pname==35720){var source=GLctx.getShaderSource(GL.shaders[shader]);var sourceLength=source?source.length+1:0;HEAP32[p>>2]=sourceLength}else{HEAP32[p>>2]=GLctx.getShaderParameter(GL.shaders[shader],pname)}}function stringToNewUTF8(jsString){var length=lengthBytesUTF8(jsString)+1;var cString=_malloc(length);stringToUTF8(jsString,cString,length);return cString}function _emscripten_glGetString(name_){var ret=GL.stringCache[name_];if(!ret){switch(name_){case 7939:var exts=GLctx.getSupportedExtensions()||[];exts=exts.concat(exts.map(function(e){return"GL_"+e}));ret=stringToNewUTF8(exts.join(" "));break;case 7936:case 7937:case 37445:case 37446:var s=GLctx.getParameter(name_);if(!s){GL.recordError(1280)}ret=s&&stringToNewUTF8(s);break;case 7938:var glVersion=GLctx.getParameter(7938);if(GL.currentContext.version>=2)glVersion="OpenGL ES 3.0 ("+glVersion+")";else{glVersion="OpenGL ES 2.0 ("+glVersion+")"}ret=stringToNewUTF8(glVersion);break;case 35724:var glslVersion=GLctx.getParameter(35724);var ver_re=/^WebGL GLSL ES ([0-9]\.[0-9][0-9]?)(?:$| .*)/;var ver_num=glslVersion.match(ver_re);if(ver_num!==null){if(ver_num[1].length==3)ver_num[1]=ver_num[1]+"0";glslVersion="OpenGL ES GLSL ES "+ver_num[1]+" ("+glslVersion+")"}ret=stringToNewUTF8(glslVersion);break;default:GL.recordError(1280)}GL.stringCache[name_]=ret}return ret}function _emscripten_glGetStringi(name,index){if(GL.currentContext.version<2){GL.recordError(1282);return 0}var stringiCache=GL.stringiCache[name];if(stringiCache){if(index<0||index>=stringiCache.length){GL.recordError(1281);return 0}return stringiCache[index]}switch(name){case 7939:var exts=GLctx.getSupportedExtensions()||[];exts=exts.concat(exts.map(function(e){return"GL_"+e}));exts=exts.map(function(e){return stringToNewUTF8(e)});stringiCache=GL.stringiCache[name]=exts;if(index<0||index>=stringiCache.length){GL.recordError(1281);return 0}return stringiCache[index];default:GL.recordError(1280);return 0}}function _emscripten_glGetSynciv(sync,pname,bufSize,length,values){if(bufSize<0){GL.recordError(1281);return}if(!values){GL.recordError(1281);return}var ret=GLctx.getSyncParameter(GL.syncs[sync],pname);if(ret!==null){HEAP32[values>>2]=ret;if(length)HEAP32[length>>2]=1}}function _emscripten_glGetTexParameterfv(target,pname,params){if(!params){GL.recordError(1281);return}HEAPF32[params>>2]=GLctx.getTexParameter(target,pname)}function _emscripten_glGetTexParameteriv(target,pname,params){if(!params){GL.recordError(1281);return}HEAP32[params>>2]=GLctx.getTexParameter(target,pname)}function _emscripten_glGetTransformFeedbackVarying(program,index,bufSize,length,size,type,name){program=GL.programs[program];var info=GLctx["getTransformFeedbackVarying"](program,index);if(!info)return;if(name&&bufSize>0){var numBytesWrittenExclNull=stringToUTF8(info.name,name,bufSize);if(length)HEAP32[length>>2]=numBytesWrittenExclNull}else{if(length)HEAP32[length>>2]=0}if(size)HEAP32[size>>2]=info.size;if(type)HEAP32[type>>2]=info.type}function _emscripten_glGetUniformBlockIndex(program,uniformBlockName){return GLctx["getUniformBlockIndex"](GL.programs[program],UTF8ToString(uniformBlockName))}function _emscripten_glGetUniformIndices(program,uniformCount,uniformNames,uniformIndices){if(!uniformIndices){GL.recordError(1281);return}if(uniformCount>0&&(uniformNames==0||uniformIndices==0)){GL.recordError(1281);return}program=GL.programs[program];var names=[];for(var i=0;i<uniformCount;i++)names.push(UTF8ToString(HEAP32[uniformNames+i*4>>2]));var result=GLctx["getUniformIndices"](program,names);if(!result)return;var len=result.length;for(var i=0;i<len;i++){HEAP32[uniformIndices+i*4>>2]=result[i]}}function webglGetLeftBracePos(name){return name.slice(-1)=="]"&&name.lastIndexOf("[")}function webglPrepareUniformLocationsBeforeFirstUse(program){var uniformLocsById=program.uniformLocsById,uniformSizeAndIdsByName=program.uniformSizeAndIdsByName,i,j;if(!uniformLocsById){program.uniformLocsById=uniformLocsById={};program.uniformArrayNamesById={};for(i=0;i<GLctx.getProgramParameter(program,35718);++i){var u=GLctx.getActiveUniform(program,i);var nm=u.name;var sz=u.size;var lb=webglGetLeftBracePos(nm);var arrayName=lb>0?nm.slice(0,lb):nm;var id=program.uniformIdCounter;program.uniformIdCounter+=sz;uniformSizeAndIdsByName[arrayName]=[sz,id];for(j=0;j<sz;++j){uniformLocsById[id]=j;program.uniformArrayNamesById[id++]=arrayName}}}}function _emscripten_glGetUniformLocation(program,name){name=UTF8ToString(name);if(program=GL.programs[program]){webglPrepareUniformLocationsBeforeFirstUse(program);var uniformLocsById=program.uniformLocsById;var arrayIndex=0;var uniformBaseName=name;var leftBrace=webglGetLeftBracePos(name);if(leftBrace>0){arrayIndex=jstoi_q(name.slice(leftBrace+1))>>>0;uniformBaseName=name.slice(0,leftBrace)}var sizeAndId=program.uniformSizeAndIdsByName[uniformBaseName];if(sizeAndId&&arrayIndex<sizeAndId[0]){arrayIndex+=sizeAndId[1];if(uniformLocsById[arrayIndex]=uniformLocsById[arrayIndex]||GLctx.getUniformLocation(program,name)){return arrayIndex}}}else{GL.recordError(1281)}return-1}function webglGetUniformLocation(location){var p=GLctx.currentProgram;if(p){var webglLoc=p.uniformLocsById[location];if(typeof webglLoc=="number"){p.uniformLocsById[location]=webglLoc=GLctx.getUniformLocation(p,p.uniformArrayNamesById[location]+(webglLoc>0?"["+webglLoc+"]":""))}return webglLoc}else{GL.recordError(1282)}}function emscriptenWebGLGetUniform(program,location,params,type){if(!params){GL.recordError(1281);return}program=GL.programs[program];webglPrepareUniformLocationsBeforeFirstUse(program);var data=GLctx.getUniform(program,webglGetUniformLocation(location));if(typeof data=="number"||typeof data=="boolean"){switch(type){case 0:HEAP32[params>>2]=data;break;case 2:HEAPF32[params>>2]=data;break}}else{for(var i=0;i<data.length;i++){switch(type){case 0:HEAP32[params+i*4>>2]=data[i];break;case 2:HEAPF32[params+i*4>>2]=data[i];break}}}}function _emscripten_glGetUniformfv(program,location,params){emscriptenWebGLGetUniform(program,location,params,2)}function _emscripten_glGetUniformiv(program,location,params){emscriptenWebGLGetUniform(program,location,params,0)}function _emscripten_glGetUniformuiv(program,location,params){emscriptenWebGLGetUniform(program,location,params,0)}function emscriptenWebGLGetVertexAttrib(index,pname,params,type){if(!params){GL.recordError(1281);return}var data=GLctx.getVertexAttrib(index,pname);if(pname==34975){HEAP32[params>>2]=data&&data["name"]}else if(typeof data=="number"||typeof data=="boolean"){switch(type){case 0:HEAP32[params>>2]=data;break;case 2:HEAPF32[params>>2]=data;break;case 5:HEAP32[params>>2]=Math.fround(data);break}}else{for(var i=0;i<data.length;i++){switch(type){case 0:HEAP32[params+i*4>>2]=data[i];break;case 2:HEAPF32[params+i*4>>2]=data[i];break;case 5:HEAP32[params+i*4>>2]=Math.fround(data[i]);break}}}}function _emscripten_glGetVertexAttribIiv(index,pname,params){emscriptenWebGLGetVertexAttrib(index,pname,params,0)}function _emscripten_glGetVertexAttribIuiv(index,pname,params){emscriptenWebGLGetVertexAttrib(index,pname,params,0)}function _emscripten_glGetVertexAttribPointerv(index,pname,pointer){if(!pointer){GL.recordError(1281);return}HEAP32[pointer>>2]=GLctx.getVertexAttribOffset(index,pname)}function _emscripten_glGetVertexAttribfv(index,pname,params){emscriptenWebGLGetVertexAttrib(index,pname,params,2)}function _emscripten_glGetVertexAttribiv(index,pname,params){emscriptenWebGLGetVertexAttrib(index,pname,params,5)}function _emscripten_glHint(x0,x1){GLctx["hint"](x0,x1)}function _emscripten_glInvalidateFramebuffer(target,numAttachments,attachments){var list=tempFixedLengthArray[numAttachments];for(var i=0;i<numAttachments;i++){list[i]=HEAP32[attachments+i*4>>2]}GLctx["invalidateFramebuffer"](target,list)}function _emscripten_glInvalidateSubFramebuffer(target,numAttachments,attachments,x,y,width,height){var list=tempFixedLengthArray[numAttachments];for(var i=0;i<numAttachments;i++){list[i]=HEAP32[attachments+i*4>>2]}GLctx["invalidateSubFramebuffer"](target,list,x,y,width,height)}function _emscripten_glIsBuffer(buffer){var b=GL.buffers[buffer];if(!b)return 0;return GLctx.isBuffer(b)}function _emscripten_glIsEnabled(x0){return GLctx["isEnabled"](x0)}function _emscripten_glIsFramebuffer(framebuffer){var fb=GL.framebuffers[framebuffer];if(!fb)return 0;return GLctx.isFramebuffer(fb)}function _emscripten_glIsProgram(program){program=GL.programs[program];if(!program)return 0;return GLctx.isProgram(program)}function _emscripten_glIsQuery(id){var query=GL.queries[id];if(!query)return 0;return GLctx["isQuery"](query)}function _emscripten_glIsQueryEXT(id){var query=GL.queries[id];if(!query)return 0;return GLctx.disjointTimerQueryExt["isQueryEXT"](query)}function _emscripten_glIsRenderbuffer(renderbuffer){var rb=GL.renderbuffers[renderbuffer];if(!rb)return 0;return GLctx.isRenderbuffer(rb)}function _emscripten_glIsSampler(id){var sampler=GL.samplers[id];if(!sampler)return 0;return GLctx["isSampler"](sampler)}function _emscripten_glIsShader(shader){var s=GL.shaders[shader];if(!s)return 0;return GLctx.isShader(s)}function _emscripten_glIsSync(sync){return GLctx.isSync(GL.syncs[sync])}function _emscripten_glIsTexture(id){var texture=GL.textures[id];if(!texture)return 0;return GLctx.isTexture(texture)}function _emscripten_glIsTransformFeedback(id){return GLctx["isTransformFeedback"](GL.transformFeedbacks[id])}function _emscripten_glIsVertexArray(array){var vao=GL.vaos[array];if(!vao)return 0;return GLctx["isVertexArray"](vao)}function _emscripten_glIsVertexArrayOES(array){var vao=GL.vaos[array];if(!vao)return 0;return GLctx["isVertexArray"](vao)}function _emscripten_glLineWidth(x0){GLctx["lineWidth"](x0)}function _emscripten_glLinkProgram(program){program=GL.programs[program];GLctx.linkProgram(program);program.uniformLocsById=0;program.uniformSizeAndIdsByName={}}function _emscripten_glPauseTransformFeedback(){GLctx["pauseTransformFeedback"]()}function _emscripten_glPixelStorei(pname,param){if(pname==3317){GL.unpackAlignment=param}GLctx.pixelStorei(pname,param)}function _emscripten_glPolygonOffset(x0,x1){GLctx["polygonOffset"](x0,x1)}function _emscripten_glProgramBinary(program,binaryFormat,binary,length){GL.recordError(1280)}function _emscripten_glProgramParameteri(program,pname,value){GL.recordError(1280)}function _emscripten_glQueryCounterEXT(id,target){GLctx.disjointTimerQueryExt["queryCounterEXT"](GL.queries[id],target)}function _emscripten_glReadBuffer(x0){GLctx["readBuffer"](x0)}function computeUnpackAlignedImageSize(width,height,sizePerPixel,alignment){function roundedToNextMultipleOf(x,y){return x+y-1&-y}var plainRowSize=width*sizePerPixel;var alignedRowSize=roundedToNextMultipleOf(plainRowSize,alignment);return height*alignedRowSize}function __colorChannelsInGlTextureFormat(format){var colorChannels={5:3,6:4,8:2,29502:3,29504:4,26917:2,26918:2,29846:3,29847:4};return colorChannels[format-6402]||1}function heapObjectForWebGLType(type){type-=5120;if(type==0)return HEAP8;if(type==1)return HEAPU8;if(type==2)return HEAP16;if(type==4)return HEAP32;if(type==6)return HEAPF32;if(type==5||type==28922||type==28520||type==30779||type==30782)return HEAPU32;return HEAPU16}function heapAccessShiftForWebGLHeap(heap){return 31-Math.clz32(heap.BYTES_PER_ELEMENT)}function emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,internalFormat){var heap=heapObjectForWebGLType(type);var shift=heapAccessShiftForWebGLHeap(heap);var byteSize=1<<shift;var sizePerPixel=__colorChannelsInGlTextureFormat(format)*byteSize;var bytes=computeUnpackAlignedImageSize(width,height,sizePerPixel,GL.unpackAlignment);return heap.subarray(pixels>>shift,pixels+bytes>>shift)}function _emscripten_glReadPixels(x,y,width,height,format,type,pixels){if(GL.currentContext.version>=2){if(GLctx.currentPixelPackBufferBinding){GLctx.readPixels(x,y,width,height,format,type,pixels)}else{var heap=heapObjectForWebGLType(type);GLctx.readPixels(x,y,width,height,format,type,heap,pixels>>heapAccessShiftForWebGLHeap(heap))}return}var pixelData=emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,format);if(!pixelData){GL.recordError(1280);return}GLctx.readPixels(x,y,width,height,format,type,pixelData)}function _emscripten_glReleaseShaderCompiler(){}function _emscripten_glRenderbufferStorage(x0,x1,x2,x3){GLctx["renderbufferStorage"](x0,x1,x2,x3)}function _emscripten_glRenderbufferStorageMultisample(x0,x1,x2,x3,x4){GLctx["renderbufferStorageMultisample"](x0,x1,x2,x3,x4)}function _emscripten_glResumeTransformFeedback(){GLctx["resumeTransformFeedback"]()}function _emscripten_glSampleCoverage(value,invert){GLctx.sampleCoverage(value,!!invert)}function _emscripten_glSamplerParameterf(sampler,pname,param){GLctx["samplerParameterf"](GL.samplers[sampler],pname,param)}function _emscripten_glSamplerParameterfv(sampler,pname,params){var param=HEAPF32[params>>2];GLctx["samplerParameterf"](GL.samplers[sampler],pname,param)}function _emscripten_glSamplerParameteri(sampler,pname,param){GLctx["samplerParameteri"](GL.samplers[sampler],pname,param)}function _emscripten_glSamplerParameteriv(sampler,pname,params){var param=HEAP32[params>>2];GLctx["samplerParameteri"](GL.samplers[sampler],pname,param)}function _emscripten_glScissor(x0,x1,x2,x3){GLctx["scissor"](x0,x1,x2,x3)}function _emscripten_glShaderBinary(){GL.recordError(1280)}function _emscripten_glShaderSource(shader,count,string,length){var source=GL.getSource(shader,count,string,length);GLctx.shaderSource(GL.shaders[shader],source)}function _emscripten_glStencilFunc(x0,x1,x2){GLctx["stencilFunc"](x0,x1,x2)}function _emscripten_glStencilFuncSeparate(x0,x1,x2,x3){GLctx["stencilFuncSeparate"](x0,x1,x2,x3)}function _emscripten_glStencilMask(x0){GLctx["stencilMask"](x0)}function _emscripten_glStencilMaskSeparate(x0,x1){GLctx["stencilMaskSeparate"](x0,x1)}function _emscripten_glStencilOp(x0,x1,x2){GLctx["stencilOp"](x0,x1,x2)}function _emscripten_glStencilOpSeparate(x0,x1,x2,x3){GLctx["stencilOpSeparate"](x0,x1,x2,x3)}function _emscripten_glTexImage2D(target,level,internalFormat,width,height,border,format,type,pixels){if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding){GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,pixels)}else if(pixels){var heap=heapObjectForWebGLType(type);GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,heap,pixels>>heapAccessShiftForWebGLHeap(heap))}else{GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,null)}return}GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,pixels?emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,internalFormat):null)}function _emscripten_glTexImage3D(target,level,internalFormat,width,height,depth,border,format,type,pixels){if(GLctx.currentPixelUnpackBufferBinding){GLctx["texImage3D"](target,level,internalFormat,width,height,depth,border,format,type,pixels)}else if(pixels){var heap=heapObjectForWebGLType(type);GLctx["texImage3D"](target,level,internalFormat,width,height,depth,border,format,type,heap,pixels>>heapAccessShiftForWebGLHeap(heap))}else{GLctx["texImage3D"](target,level,internalFormat,width,height,depth,border,format,type,null)}}function _emscripten_glTexParameterf(x0,x1,x2){GLctx["texParameterf"](x0,x1,x2)}function _emscripten_glTexParameterfv(target,pname,params){var param=HEAPF32[params>>2];GLctx.texParameterf(target,pname,param)}function _emscripten_glTexParameteri(x0,x1,x2){GLctx["texParameteri"](x0,x1,x2)}function _emscripten_glTexParameteriv(target,pname,params){var param=HEAP32[params>>2];GLctx.texParameteri(target,pname,param)}function _emscripten_glTexStorage2D(x0,x1,x2,x3,x4){GLctx["texStorage2D"](x0,x1,x2,x3,x4)}function _emscripten_glTexStorage3D(x0,x1,x2,x3,x4,x5){GLctx["texStorage3D"](x0,x1,x2,x3,x4,x5)}function _emscripten_glTexSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixels){if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding){GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixels)}else if(pixels){var heap=heapObjectForWebGLType(type);GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,heap,pixels>>heapAccessShiftForWebGLHeap(heap))}else{GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,null)}return}var pixelData=null;if(pixels)pixelData=emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,0);GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixelData)}function _emscripten_glTexSubImage3D(target,level,xoffset,yoffset,zoffset,width,height,depth,format,type,pixels){if(GLctx.currentPixelUnpackBufferBinding){GLctx["texSubImage3D"](target,level,xoffset,yoffset,zoffset,width,height,depth,format,type,pixels)}else if(pixels){var heap=heapObjectForWebGLType(type);GLctx["texSubImage3D"](target,level,xoffset,yoffset,zoffset,width,height,depth,format,type,heap,pixels>>heapAccessShiftForWebGLHeap(heap))}else{GLctx["texSubImage3D"](target,level,xoffset,yoffset,zoffset,width,height,depth,format,type,null)}}function _emscripten_glTransformFeedbackVaryings(program,count,varyings,bufferMode){program=GL.programs[program];var vars=[];for(var i=0;i<count;i++)vars.push(UTF8ToString(HEAP32[varyings+i*4>>2]));GLctx["transformFeedbackVaryings"](program,vars,bufferMode)}function _emscripten_glUniform1f(location,v0){GLctx.uniform1f(webglGetUniformLocation(location),v0)}var miniTempWebGLFloatBuffers=[];function _emscripten_glUniform1fv(location,count,value){if(GL.currentContext.version>=2){count&&GLctx.uniform1fv(webglGetUniformLocation(location),HEAPF32,value>>2,count);return}if(count<=288){var view=miniTempWebGLFloatBuffers[count-1];for(var i=0;i<count;++i){view[i]=HEAPF32[value+4*i>>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*4>>2)}GLctx.uniform1fv(webglGetUniformLocation(location),view)}function _emscripten_glUniform1i(location,v0){GLctx.uniform1i(webglGetUniformLocation(location),v0)}var __miniTempWebGLIntBuffers=[];function _emscripten_glUniform1iv(location,count,value){if(GL.currentContext.version>=2){count&&GLctx.uniform1iv(webglGetUniformLocation(location),HEAP32,value>>2,count);return}if(count<=288){var view=__miniTempWebGLIntBuffers[count-1];for(var i=0;i<count;++i){view[i]=HEAP32[value+4*i>>2]}}else{var view=HEAP32.subarray(value>>2,value+count*4>>2)}GLctx.uniform1iv(webglGetUniformLocation(location),view)}function _emscripten_glUniform1ui(location,v0){GLctx.uniform1ui(webglGetUniformLocation(location),v0)}function _emscripten_glUniform1uiv(location,count,value){count&&GLctx.uniform1uiv(webglGetUniformLocation(location),HEAPU32,value>>2,count)}function _emscripten_glUniform2f(location,v0,v1){GLctx.uniform2f(webglGetUniformLocation(location),v0,v1)}function _emscripten_glUniform2fv(location,count,value){if(GL.currentContext.version>=2){count&&GLctx.uniform2fv(webglGetUniformLocation(location),HEAPF32,value>>2,count*2);return}if(count<=144){var view=miniTempWebGLFloatBuffers[2*count-1];for(var i=0;i<2*count;i+=2){view[i]=HEAPF32[value+4*i>>2];view[i+1]=HEAPF32[value+(4*i+4)>>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*8>>2)}GLctx.uniform2fv(webglGetUniformLocation(location),view)}function _emscripten_glUniform2i(location,v0,v1){GLctx.uniform2i(webglGetUniformLocation(location),v0,v1)}function _emscripten_glUniform2iv(location,count,value){if(GL.currentContext.version>=2){count&&GLctx.uniform2iv(webglGetUniformLocation(location),HEAP32,value>>2,count*2);return}if(count<=144){var view=__miniTempWebGLIntBuffers[2*count-1];for(var i=0;i<2*count;i+=2){view[i]=HEAP32[value+4*i>>2];view[i+1]=HEAP32[value+(4*i+4)>>2]}}else{var view=HEAP32.subarray(value>>2,value+count*8>>2)}GLctx.uniform2iv(webglGetUniformLocation(location),view)}function _emscripten_glUniform2ui(location,v0,v1){GLctx.uniform2ui(webglGetUniformLocation(location),v0,v1)}function _emscripten_glUniform2uiv(location,count,value){count&&GLctx.uniform2uiv(webglGetUniformLocation(location),HEAPU32,value>>2,count*2)}function _emscripten_glUniform3f(location,v0,v1,v2){GLctx.uniform3f(webglGetUniformLocation(location),v0,v1,v2)}function _emscripten_glUniform3fv(location,count,value){if(GL.currentContext.version>=2){count&&GLctx.uniform3fv(webglGetUniformLocation(location),HEAPF32,value>>2,count*3);return}if(count<=96){var view=miniTempWebGLFloatBuffers[3*count-1];for(var i=0;i<3*count;i+=3){view[i]=HEAPF32[value+4*i>>2];view[i+1]=HEAPF32[value+(4*i+4)>>2];view[i+2]=HEAPF32[value+(4*i+8)>>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*12>>2)}GLctx.uniform3fv(webglGetUniformLocation(location),view)}function _emscripten_glUniform3i(location,v0,v1,v2){GLctx.uniform3i(webglGetUniformLocation(location),v0,v1,v2)}function _emscripten_glUniform3iv(location,count,value){if(GL.currentContext.version>=2){count&&GLctx.uniform3iv(webglGetUniformLocation(location),HEAP32,value>>2,count*3);return}if(count<=96){var view=__miniTempWebGLIntBuffers[3*count-1];for(var i=0;i<3*count;i+=3){view[i]=HEAP32[value+4*i>>2];view[i+1]=HEAP32[value+(4*i+4)>>2];view[i+2]=HEAP32[value+(4*i+8)>>2]}}else{var view=HEAP32.subarray(value>>2,value+count*12>>2)}GLctx.uniform3iv(webglGetUniformLocation(location),view)}function _emscripten_glUniform3ui(location,v0,v1,v2){GLctx.uniform3ui(webglGetUniformLocation(location),v0,v1,v2)}function _emscripten_glUniform3uiv(location,count,value){count&&GLctx.uniform3uiv(webglGetUniformLocation(location),HEAPU32,value>>2,count*3)}function _emscripten_glUniform4f(location,v0,v1,v2,v3){GLctx.uniform4f(webglGetUniformLocation(location),v0,v1,v2,v3)}function _emscripten_glUniform4fv(location,count,value){if(GL.currentContext.version>=2){count&&GLctx.uniform4fv(webglGetUniformLocation(location),HEAPF32,value>>2,count*4);return}if(count<=72){var view=miniTempWebGLFloatBuffers[4*count-1];var heap=HEAPF32;value>>=2;for(var i=0;i<4*count;i+=4){var dst=value+i;view[i]=heap[dst];view[i+1]=heap[dst+1];view[i+2]=heap[dst+2];view[i+3]=heap[dst+3]}}else{var view=HEAPF32.subarray(value>>2,value+count*16>>2)}GLctx.uniform4fv(webglGetUniformLocation(location),view)}function _emscripten_glUniform4i(location,v0,v1,v2,v3){GLctx.uniform4i(webglGetUniformLocation(location),v0,v1,v2,v3)}function _emscripten_glUniform4iv(location,count,value){if(GL.currentContext.version>=2){count&&GLctx.uniform4iv(webglGetUniformLocation(location),HEAP32,value>>2,count*4);return}if(count<=72){var view=__miniTempWebGLIntBuffers[4*count-1];for(var i=0;i<4*count;i+=4){view[i]=HEAP32[value+4*i>>2];view[i+1]=HEAP32[value+(4*i+4)>>2];view[i+2]=HEAP32[value+(4*i+8)>>2];view[i+3]=HEAP32[value+(4*i+12)>>2]}}else{var view=HEAP32.subarray(value>>2,value+count*16>>2)}GLctx.uniform4iv(webglGetUniformLocation(location),view)}function _emscripten_glUniform4ui(location,v0,v1,v2,v3){GLctx.uniform4ui(webglGetUniformLocation(location),v0,v1,v2,v3)}function _emscripten_glUniform4uiv(location,count,value){count&&GLctx.uniform4uiv(webglGetUniformLocation(location),HEAPU32,value>>2,count*4)}function _emscripten_glUniformBlockBinding(program,uniformBlockIndex,uniformBlockBinding){program=GL.programs[program];GLctx["uniformBlockBinding"](program,uniformBlockIndex,uniformBlockBinding)}function _emscripten_glUniformMatrix2fv(location,count,transpose,value){if(GL.currentContext.version>=2){count&&GLctx.uniformMatrix2fv(webglGetUniformLocation(location),!!transpose,HEAPF32,value>>2,count*4);return}if(count<=72){var view=miniTempWebGLFloatBuffers[4*count-1];for(var i=0;i<4*count;i+=4){view[i]=HEAPF32[value+4*i>>2];view[i+1]=HEAPF32[value+(4*i+4)>>2];view[i+2]=HEAPF32[value+(4*i+8)>>2];view[i+3]=HEAPF32[value+(4*i+12)>>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*16>>2)}GLctx.uniformMatrix2fv(webglGetUniformLocation(location),!!transpose,view)}function _emscripten_glUniformMatrix2x3fv(location,count,transpose,value){count&&GLctx.uniformMatrix2x3fv(webglGetUniformLocation(location),!!transpose,HEAPF32,value>>2,count*6)}function _emscripten_glUniformMatrix2x4fv(location,count,transpose,value){count&&GLctx.uniformMatrix2x4fv(webglGetUniformLocation(location),!!transpose,HEAPF32,value>>2,count*8)}function _emscripten_glUniformMatrix3fv(location,count,transpose,value){if(GL.currentContext.version>=2){count&&GLctx.uniformMatrix3fv(webglGetUniformLocation(location),!!transpose,HEAPF32,value>>2,count*9);return}if(count<=32){var view=miniTempWebGLFloatBuffers[9*count-1];for(var i=0;i<9*count;i+=9){view[i]=HEAPF32[value+4*i>>2];view[i+1]=HEAPF32[value+(4*i+4)>>2];view[i+2]=HEAPF32[value+(4*i+8)>>2];view[i+3]=HEAPF32[value+(4*i+12)>>2];view[i+4]=HEAPF32[value+(4*i+16)>>2];view[i+5]=HEAPF32[value+(4*i+20)>>2];view[i+6]=HEAPF32[value+(4*i+24)>>2];view[i+7]=HEAPF32[value+(4*i+28)>>2];view[i+8]=HEAPF32[value+(4*i+32)>>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*36>>2)}GLctx.uniformMatrix3fv(webglGetUniformLocation(location),!!transpose,view)}function _emscripten_glUniformMatrix3x2fv(location,count,transpose,value){count&&GLctx.uniformMatrix3x2fv(webglGetUniformLocation(location),!!transpose,HEAPF32,value>>2,count*6)}function _emscripten_glUniformMatrix3x4fv(location,count,transpose,value){count&&GLctx.uniformMatrix3x4fv(webglGetUniformLocation(location),!!transpose,HEAPF32,value>>2,count*12)}function _emscripten_glUniformMatrix4fv(location,count,transpose,value){if(GL.currentContext.version>=2){count&&GLctx.uniformMatrix4fv(webglGetUniformLocation(location),!!transpose,HEAPF32,value>>2,count*16);return}if(count<=18){var view=miniTempWebGLFloatBuffers[16*count-1];var heap=HEAPF32;value>>=2;for(var i=0;i<16*count;i+=16){var dst=value+i;view[i]=heap[dst];view[i+1]=heap[dst+1];view[i+2]=heap[dst+2];view[i+3]=heap[dst+3];view[i+4]=heap[dst+4];view[i+5]=heap[dst+5];view[i+6]=heap[dst+6];view[i+7]=heap[dst+7];view[i+8]=heap[dst+8];view[i+9]=heap[dst+9];view[i+10]=heap[dst+10];view[i+11]=heap[dst+11];view[i+12]=heap[dst+12];view[i+13]=heap[dst+13];view[i+14]=heap[dst+14];view[i+15]=heap[dst+15]}}else{var view=HEAPF32.subarray(value>>2,value+count*64>>2)}GLctx.uniformMatrix4fv(webglGetUniformLocation(location),!!transpose,view)}function _emscripten_glUniformMatrix4x2fv(location,count,transpose,value){count&&GLctx.uniformMatrix4x2fv(webglGetUniformLocation(location),!!transpose,HEAPF32,value>>2,count*8)}function _emscripten_glUniformMatrix4x3fv(location,count,transpose,value){count&&GLctx.uniformMatrix4x3fv(webglGetUniformLocation(location),!!transpose,HEAPF32,value>>2,count*12)}function _emscripten_glUseProgram(program){program=GL.programs[program];GLctx.useProgram(program);GLctx.currentProgram=program}function _emscripten_glValidateProgram(program){GLctx.validateProgram(GL.programs[program])}function _emscripten_glVertexAttrib1f(x0,x1){GLctx["vertexAttrib1f"](x0,x1)}function _emscripten_glVertexAttrib1fv(index,v){GLctx.vertexAttrib1f(index,HEAPF32[v>>2])}function _emscripten_glVertexAttrib2f(x0,x1,x2){GLctx["vertexAttrib2f"](x0,x1,x2)}function _emscripten_glVertexAttrib2fv(index,v){GLctx.vertexAttrib2f(index,HEAPF32[v>>2],HEAPF32[v+4>>2])}function _emscripten_glVertexAttrib3f(x0,x1,x2,x3){GLctx["vertexAttrib3f"](x0,x1,x2,x3)}function _emscripten_glVertexAttrib3fv(index,v){GLctx.vertexAttrib3f(index,HEAPF32[v>>2],HEAPF32[v+4>>2],HEAPF32[v+8>>2])}function _emscripten_glVertexAttrib4f(x0,x1,x2,x3,x4){GLctx["vertexAttrib4f"](x0,x1,x2,x3,x4)}function _emscripten_glVertexAttrib4fv(index,v){GLctx.vertexAttrib4f(index,HEAPF32[v>>2],HEAPF32[v+4>>2],HEAPF32[v+8>>2],HEAPF32[v+12>>2])}function _emscripten_glVertexAttribDivisor(index,divisor){GLctx["vertexAttribDivisor"](index,divisor)}function _emscripten_glVertexAttribDivisorANGLE(index,divisor){GLctx["vertexAttribDivisor"](index,divisor)}function _emscripten_glVertexAttribDivisorARB(index,divisor){GLctx["vertexAttribDivisor"](index,divisor)}function _emscripten_glVertexAttribDivisorEXT(index,divisor){GLctx["vertexAttribDivisor"](index,divisor)}function _emscripten_glVertexAttribDivisorNV(index,divisor){GLctx["vertexAttribDivisor"](index,divisor)}function _emscripten_glVertexAttribI4i(x0,x1,x2,x3,x4){GLctx["vertexAttribI4i"](x0,x1,x2,x3,x4)}function _emscripten_glVertexAttribI4iv(index,v){GLctx.vertexAttribI4i(index,HEAP32[v>>2],HEAP32[v+4>>2],HEAP32[v+8>>2],HEAP32[v+12>>2])}function _emscripten_glVertexAttribI4ui(x0,x1,x2,x3,x4){GLctx["vertexAttribI4ui"](x0,x1,x2,x3,x4)}function _emscripten_glVertexAttribI4uiv(index,v){GLctx.vertexAttribI4ui(index,HEAPU32[v>>2],HEAPU32[v+4>>2],HEAPU32[v+8>>2],HEAPU32[v+12>>2])}function _emscripten_glVertexAttribIPointer(index,size,type,stride,ptr){GLctx["vertexAttribIPointer"](index,size,type,stride,ptr)}function _emscripten_glVertexAttribPointer(index,size,type,normalized,stride,ptr){GLctx.vertexAttribPointer(index,size,type,!!normalized,stride,ptr)}function _emscripten_glViewport(x0,x1,x2,x3){GLctx["viewport"](x0,x1,x2,x3)}function _emscripten_glWaitSync(sync,flags,timeoutLo,timeoutHi){GLctx.waitSync(GL.syncs[sync],flags,convertI32PairToI53(timeoutLo,timeoutHi))}function _emscripten_memcpy_big(dest,src,num){HEAPU8.copyWithin(dest,src,src+num)}function getHeapMax(){return 2147483648}function emscripten_realloc_buffer(size){try{wasmMemory.grow(size-buffer.byteLength+65535>>>16);updateGlobalBufferAndViews(wasmMemory.buffer);return 1}catch(e){}}function _emscripten_resize_heap(requestedSize){var oldSize=HEAPU8.length;requestedSize=requestedSize>>>0;var maxHeapSize=getHeapMax();if(requestedSize>maxHeapSize){return false}let alignUp=(x,multiple)=>x+(multiple-x%multiple)%multiple;for(var cutDown=1;cutDown<=4;cutDown*=2){var overGrownHeapSize=oldSize*(1+.2/cutDown);overGrownHeapSize=Math.min(overGrownHeapSize,requestedSize+100663296);var newSize=Math.min(maxHeapSize,alignUp(Math.max(requestedSize,overGrownHeapSize),65536));var replacement=emscripten_realloc_buffer(newSize);if(replacement){return true}}return false}function _emscripten_set_main_loop(func,fps,simulateInfiniteLoop){var browserIterationFunc=getWasmTableEntry(func);setMainLoop(browserIterationFunc,fps,simulateInfiniteLoop)}var JSEvents={inEventHandler:0,removeAllEventListeners:function(){for(var i=JSEvents.eventHandlers.length-1;i>=0;--i){JSEvents._removeHandler(i)}JSEvents.eventHandlers=[];JSEvents.deferredCalls=[]},registerRemoveEventListeners:function(){if(!JSEvents.removeEventListenersRegistered){__ATEXIT__.push(JSEvents.removeAllEventListeners);JSEvents.removeEventListenersRegistered=true}},deferredCalls:[],deferCall:function(targetFunction,precedence,argsList){function arraysHaveEqualContent(arrA,arrB){if(arrA.length!=arrB.length)return false;for(var i in arrA){if(arrA[i]!=arrB[i])return false}return true}for(var i in JSEvents.deferredCalls){var call=JSEvents.deferredCalls[i];if(call.targetFunction==targetFunction&&arraysHaveEqualContent(call.argsList,argsList)){return}}JSEvents.deferredCalls.push({targetFunction:targetFunction,precedence:precedence,argsList:argsList});JSEvents.deferredCalls.sort(function(x,y){return x.precedence<y.precedence})},removeDeferredCalls:function(targetFunction){for(var i=0;i<JSEvents.deferredCalls.length;++i){if(JSEvents.deferredCalls[i].targetFunction==targetFunction){JSEvents.deferredCalls.splice(i,1);--i}}},canPerformEventHandlerRequests:function(){return JSEvents.inEventHandler&&JSEvents.currentEventHandler.allowsDeferredCalls},runDeferredCalls:function(){if(!JSEvents.canPerformEventHandlerRequests()){return}for(var i=0;i<JSEvents.deferredCalls.length;++i){var call=JSEvents.deferredCalls[i];JSEvents.deferredCalls.splice(i,1);--i;call.targetFunction.apply(null,call.argsList)}},eventHandlers:[],removeAllHandlersOnTarget:function(target,eventTypeString){for(var i=0;i<JSEvents.eventHandlers.length;++i){if(JSEvents.eventHandlers[i].target==target&&(!eventTypeString||eventTypeString==JSEvents.eventHandlers[i].eventTypeString)){JSEvents._removeHandler(i--)}}},_removeHandler:function(i){var h=JSEvents.eventHandlers[i];h.target.removeEventListener(h.eventTypeString,h.eventListenerFunc,h.useCapture);JSEvents.eventHandlers.splice(i,1)},registerOrRemoveHandler:function(eventHandler){var jsEventHandler=function jsEventHandler(event){++JSEvents.inEventHandler;JSEvents.currentEventHandler=eventHandler;JSEvents.runDeferredCalls();eventHandler.handlerFunc(event);JSEvents.runDeferredCalls();--JSEvents.inEventHandler};if(eventHandler.callbackfunc){eventHandler.eventListenerFunc=jsEventHandler;eventHandler.target.addEventListener(eventHandler.eventTypeString,jsEventHandler,eventHandler.useCapture);JSEvents.eventHandlers.push(eventHandler);JSEvents.registerRemoveEventListeners()}else{for(var i=0;i<JSEvents.eventHandlers.length;++i){if(JSEvents.eventHandlers[i].target==eventHandler.target&&JSEvents.eventHandlers[i].eventTypeString==eventHandler.eventTypeString){JSEvents._removeHandler(i--)}}}},getNodeNameForTarget:function(target){if(!target)return"";if(target==window)return"#window";if(target==screen)return"#screen";return target&&target.nodeName?target.nodeName:""},fullscreenEnabled:function(){return document.fullscreenEnabled||document.webkitFullscreenEnabled}};var __emscripten_webgl_power_preferences=["default","low-power","high-performance"];function maybeCStringToJsString(cString){return cString>2?UTF8ToString(cString):cString}var specialHTMLTargets=[0,typeof document!="undefined"?document:0,typeof window!="undefined"?window:0];function findEventTarget(target){target=maybeCStringToJsString(target);var domElement=specialHTMLTargets[target]||(typeof document!="undefined"?document.querySelector(target):undefined);return domElement}function findCanvasEventTarget(target){return findEventTarget(target)}function _emscripten_webgl_do_create_context(target,attributes){var a=attributes>>2;var powerPreference=HEAP32[a+(24>>2)];var contextAttributes={"alpha":!!HEAP32[a+(0>>2)],"depth":!!HEAP32[a+(4>>2)],"stencil":!!HEAP32[a+(8>>2)],"antialias":!!HEAP32[a+(12>>2)],"premultipliedAlpha":!!HEAP32[a+(16>>2)],"preserveDrawingBuffer":!!HEAP32[a+(20>>2)],"powerPreference":__emscripten_webgl_power_preferences[powerPreference],"failIfMajorPerformanceCaveat":!!HEAP32[a+(28>>2)],majorVersion:HEAP32[a+(32>>2)],minorVersion:HEAP32[a+(36>>2)],enableExtensionsByDefault:HEAP32[a+(40>>2)],explicitSwapControl:HEAP32[a+(44>>2)],proxyContextToMainThread:HEAP32[a+(48>>2)],renderViaOffscreenBackBuffer:HEAP32[a+(52>>2)]};var canvas=findCanvasEventTarget(target);if(!canvas){return 0}if(contextAttributes.explicitSwapControl&&!contextAttributes.renderViaOffscreenBackBuffer){contextAttributes.renderViaOffscreenBackBuffer=true}var contextHandle=GL.createContext(canvas,contextAttributes);return contextHandle}function _emscripten_webgl_create_context(a0,a1){return _emscripten_webgl_do_create_context(a0,a1)}function _emscripten_webgl_destroy_context(contextHandle){if(GL.currentContext==contextHandle)GL.currentContext=0;GL.deleteContext(contextHandle)}function _emscripten_webgl_init_context_attributes(attributes){var a=attributes>>2;for(var i=0;i<56>>2;++i){HEAP32[a+i]=0}HEAP32[a+(0>>2)]=HEAP32[a+(4>>2)]=HEAP32[a+(12>>2)]=HEAP32[a+(16>>2)]=HEAP32[a+(32>>2)]=HEAP32[a+(40>>2)]=1}function _emscripten_webgl_make_context_current(contextHandle){var success=GL.makeContextCurrent(contextHandle);return success?0:-5}var ENV={};function getExecutableName(){return thisProgram||"./this.program"}function getEnvStrings(){if(!getEnvStrings.strings){var lang=(typeof navigator=="object"&&navigator.languages&&navigator.languages[0]||"C").replace("-","_")+".UTF-8";var env={"USER":"web_user","LOGNAME":"web_user","PATH":"/","PWD":"/","HOME":"/home/web_user","LANG":lang,"_":getExecutableName()};for(var x in ENV){if(ENV[x]===undefined)delete env[x];else env[x]=ENV[x]}var strings=[];for(var x in env){strings.push(x+"="+env[x])}getEnvStrings.strings=strings}return getEnvStrings.strings}function _environ_get(__environ,environ_buf){var bufSize=0;getEnvStrings().forEach(function(string,i){var ptr=environ_buf+bufSize;HEAPU32[__environ+i*4>>2]=ptr;writeAsciiToMemory(string,ptr);bufSize+=string.length+1});return 0}function _environ_sizes_get(penviron_count,penviron_buf_size){var strings=getEnvStrings();HEAPU32[penviron_count>>2]=strings.length;var bufSize=0;strings.forEach(function(string){bufSize+=string.length+1});HEAPU32[penviron_buf_size>>2]=bufSize;return 0}function _fd_close(fd){try{var stream=SYSCALLS.getStreamFromFD(fd);FS.close(stream);return 0}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return e.errno}}function _fd_fdstat_get(fd,pbuf){try{var stream=SYSCALLS.getStreamFromFD(fd);var type=stream.tty?2:FS.isDir(stream.mode)?3:FS.isLink(stream.mode)?7:4;HEAP8[pbuf>>0]=type;return 0}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return e.errno}}function doReadv(stream,iov,iovcnt,offset){var ret=0;for(var i=0;i<iovcnt;i++){var ptr=HEAPU32[iov>>2];var len=HEAPU32[iov+4>>2];iov+=8;var curr=FS.read(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr;if(curr<len)break}return ret}function _fd_read(fd,iov,iovcnt,pnum){try{var stream=SYSCALLS.getStreamFromFD(fd);var num=doReadv(stream,iov,iovcnt);HEAP32[pnum>>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return e.errno}}function convertI32PairToI53Checked(lo,hi){return hi+2097152>>>0<4194305-!!lo?(lo>>>0)+hi*4294967296:NaN}function _fd_seek(fd,offset_low,offset_high,whence,newOffset){try{var offset=convertI32PairToI53Checked(offset_low,offset_high);if(isNaN(offset))return 61;var stream=SYSCALLS.getStreamFromFD(fd);FS.llseek(stream,offset,whence);tempI64=[stream.position>>>0,(tempDouble=stream.position,+Math.abs(tempDouble)>=1?tempDouble>0?(Math.min(+Math.floor(tempDouble/4294967296),4294967295)|0)>>>0:~~+Math.ceil((tempDouble-+(~~tempDouble>>>0))/4294967296)>>>0:0)],HEAP32[newOffset>>2]=tempI64[0],HEAP32[newOffset+4>>2]=tempI64[1];if(stream.getdents&&offset===0&&whence===0)stream.getdents=null;return 0}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return e.errno}}function doWritev(stream,iov,iovcnt,offset){var ret=0;for(var i=0;i<iovcnt;i++){var ptr=HEAPU32[iov>>2];var len=HEAPU32[iov+4>>2];iov+=8;var curr=FS.write(stream,HEAP8,ptr,len,offset);if(curr<0)return-1;ret+=curr}return ret}function _fd_write(fd,iov,iovcnt,pnum){try{var stream=SYSCALLS.getStreamFromFD(fd);var num=doWritev(stream,iov,iovcnt);HEAPU32[pnum>>2]=num;return 0}catch(e){if(typeof FS=="undefined"||!(e instanceof FS.ErrnoError))throw e;return e.errno}}function _getTempRet0(){return getTempRet0()}function _getaddrinfo(node,service,hint,out){var addr=0;var port=0;var flags=0;var family=0;var type=0;var proto=0;var ai;function allocaddrinfo(family,type,proto,canon,addr,port){var sa,salen,ai;var errno;salen=family===10?28:16;addr=family===10?inetNtop6(addr):inetNtop4(addr);sa=_malloc(salen);errno=writeSockaddr(sa,family,addr,port);assert(!errno);ai=_malloc(32);HEAP32[ai+4>>2]=family;HEAP32[ai+8>>2]=type;HEAP32[ai+12>>2]=proto;HEAP32[ai+24>>2]=canon;HEAPU32[ai+20>>2]=sa;if(family===10){HEAP32[ai+16>>2]=28}else{HEAP32[ai+16>>2]=16}HEAP32[ai+28>>2]=0;return ai}if(hint){flags=HEAP32[hint>>2];family=HEAP32[hint+4>>2];type=HEAP32[hint+8>>2];proto=HEAP32[hint+12>>2]}if(type&&!proto){proto=type===2?17:6}if(!type&&proto){type=proto===17?2:1}if(proto===0){proto=6}if(type===0){type=1}if(!node&&!service){return-2}if(flags&~(1|2|4|1024|8|16|32)){return-1}if(hint!==0&&HEAP32[hint>>2]&2&&!node){return-1}if(flags&32){return-2}if(type!==0&&type!==1&&type!==2){return-7}if(family!==0&&family!==2&&family!==10){return-6}if(service){service=UTF8ToString(service);port=parseInt(service,10);if(isNaN(port)){if(flags&1024){return-2}return-8}}if(!node){if(family===0){family=2}if((flags&1)===0){if(family===2){addr=_htonl(2130706433)}else{addr=[0,0,0,1]}}ai=allocaddrinfo(family,type,proto,null,addr,port);HEAPU32[out>>2]=ai;return 0}node=UTF8ToString(node);addr=inetPton4(node);if(addr!==null){if(family===0||family===2){family=2}else if(family===10&&flags&8){addr=[0,0,_htonl(65535),addr];family=10}else{return-2}}else{addr=inetPton6(node);if(addr!==null){if(family===0||family===10){family=10}else{return-2}}}if(addr!=null){ai=allocaddrinfo(family,type,proto,node,addr,port);HEAPU32[out>>2]=ai;return 0}if(flags&4){return-2}node=DNS.lookup_name(node);addr=inetPton4(node);if(family===0){family=2}else if(family===10){addr=[0,0,_htonl(65535),addr]}ai=allocaddrinfo(family,type,proto,null,addr,port);HEAPU32[out>>2]=ai;return 0}function _getnameinfo(sa,salen,node,nodelen,serv,servlen,flags){var info=readSockaddr(sa,salen);if(info.errno){return-6}var port=info.port;var addr=info.addr;var overflowed=false;if(node&&nodelen){var lookup;if(flags&1||!(lookup=DNS.lookup_addr(addr))){if(flags&8){return-2}}else{addr=lookup}var numBytesWrittenExclNull=stringToUTF8(addr,node,nodelen);if(numBytesWrittenExclNull+1>=nodelen){overflowed=true}}if(serv&&servlen){port=""+port;var numBytesWrittenExclNull=stringToUTF8(port,serv,servlen);if(numBytesWrittenExclNull+1>=servlen){overflowed=true}}if(overflowed){return-12}return 0}function _glActiveTexture(x0){GLctx["activeTexture"](x0)}function _glAttachShader(program,shader){GLctx.attachShader(GL.programs[program],GL.shaders[shader])}function _glBeginTransformFeedback(x0){GLctx["beginTransformFeedback"](x0)}function _glBindAttribLocation(program,index,name){GLctx.bindAttribLocation(GL.programs[program],index,UTF8ToString(name))}function _glBindBuffer(target,buffer){if(target==35051){GLctx.currentPixelPackBufferBinding=buffer}else if(target==35052){GLctx.currentPixelUnpackBufferBinding=buffer}GLctx.bindBuffer(target,GL.buffers[buffer])}function _glBindBufferBase(target,index,buffer){GLctx["bindBufferBase"](target,index,GL.buffers[buffer])}function _glBindFramebuffer(target,framebuffer){GLctx.bindFramebuffer(target,framebuffer?GL.framebuffers[framebuffer]:GL.currentContext.defaultFbo)}function _glBindRenderbuffer(target,renderbuffer){GLctx.bindRenderbuffer(target,GL.renderbuffers[renderbuffer])}function _glBindTexture(target,texture){GLctx.bindTexture(target,GL.textures[texture])}function _glBindVertexArray(vao){GLctx["bindVertexArray"](GL.vaos[vao])}function _glBlendEquation(x0){GLctx["blendEquation"](x0)}function _glBlendFunc(x0,x1){GLctx["blendFunc"](x0,x1)}function _glBlendFuncSeparate(x0,x1,x2,x3){GLctx["blendFuncSeparate"](x0,x1,x2,x3)}function _glBlitFramebuffer(x0,x1,x2,x3,x4,x5,x6,x7,x8,x9){GLctx["blitFramebuffer"](x0,x1,x2,x3,x4,x5,x6,x7,x8,x9)}function _glBufferData(target,size,data,usage){if(GL.currentContext.version>=2){if(data&&size){GLctx.bufferData(target,HEAPU8,usage,data,size)}else{GLctx.bufferData(target,size,usage)}}else{GLctx.bufferData(target,data?HEAPU8.subarray(data,data+size):size,usage)}}function _glBufferSubData(target,offset,size,data){if(GL.currentContext.version>=2){size&&GLctx.bufferSubData(target,offset,HEAPU8,data,size);return}GLctx.bufferSubData(target,offset,HEAPU8.subarray(data,data+size))}function _glCheckFramebufferStatus(x0){return GLctx["checkFramebufferStatus"](x0)}function _glClear(x0){GLctx["clear"](x0)}function _glClearBufferfv(buffer,drawbuffer,value){GLctx["clearBufferfv"](buffer,drawbuffer,HEAPF32,value>>2)}function _glClearColor(x0,x1,x2,x3){GLctx["clearColor"](x0,x1,x2,x3)}function _glClearDepthf(x0){GLctx["clearDepth"](x0)}function _glColorMask(red,green,blue,alpha){GLctx.colorMask(!!red,!!green,!!blue,!!alpha)}function _glCompileShader(shader){GLctx.compileShader(GL.shaders[shader])}function _glCompressedTexImage2D(target,level,internalFormat,width,height,border,imageSize,data){if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding||!imageSize){GLctx["compressedTexImage2D"](target,level,internalFormat,width,height,border,imageSize,data)}else{GLctx["compressedTexImage2D"](target,level,internalFormat,width,height,border,HEAPU8,data,imageSize)}return}GLctx["compressedTexImage2D"](target,level,internalFormat,width,height,border,data?HEAPU8.subarray(data,data+imageSize):null)}function _glCompressedTexSubImage2D(target,level,xoffset,yoffset,width,height,format,imageSize,data){if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding||!imageSize){GLctx["compressedTexSubImage2D"](target,level,xoffset,yoffset,width,height,format,imageSize,data)}else{GLctx["compressedTexSubImage2D"](target,level,xoffset,yoffset,width,height,format,HEAPU8,data,imageSize)}return}GLctx["compressedTexSubImage2D"](target,level,xoffset,yoffset,width,height,format,data?HEAPU8.subarray(data,data+imageSize):null)}function _glCompressedTexSubImage3D(target,level,xoffset,yoffset,zoffset,width,height,depth,format,imageSize,data){if(GLctx.currentPixelUnpackBufferBinding){GLctx["compressedTexSubImage3D"](target,level,xoffset,yoffset,zoffset,width,height,depth,format,imageSize,data)}else{GLctx["compressedTexSubImage3D"](target,level,xoffset,yoffset,zoffset,width,height,depth,format,HEAPU8,data,imageSize)}}function _glCopyBufferSubData(x0,x1,x2,x3,x4){GLctx["copyBufferSubData"](x0,x1,x2,x3,x4)}function _glCopyTexSubImage2D(x0,x1,x2,x3,x4,x5,x6,x7){GLctx["copyTexSubImage2D"](x0,x1,x2,x3,x4,x5,x6,x7)}function _glCreateProgram(){var id=GL.getNewId(GL.programs);var program=GLctx.createProgram();program.name=id;program.maxUniformLength=program.maxAttributeLength=program.maxUniformBlockNameLength=0;program.uniformIdCounter=1;GL.programs[id]=program;return id}function _glCreateShader(shaderType){var id=GL.getNewId(GL.shaders);GL.shaders[id]=GLctx.createShader(shaderType);return id}function _glCullFace(x0){GLctx["cullFace"](x0)}function _glDeleteBuffers(n,buffers){for(var i=0;i<n;i++){var id=HEAP32[buffers+i*4>>2];var buffer=GL.buffers[id];if(!buffer)continue;GLctx.deleteBuffer(buffer);buffer.name=0;GL.buffers[id]=null;if(id==GLctx.currentPixelPackBufferBinding)GLctx.currentPixelPackBufferBinding=0;if(id==GLctx.currentPixelUnpackBufferBinding)GLctx.currentPixelUnpackBufferBinding=0}}function _glDeleteFramebuffers(n,framebuffers){for(var i=0;i<n;++i){var id=HEAP32[framebuffers+i*4>>2];var framebuffer=GL.framebuffers[id];if(!framebuffer)continue;GLctx.deleteFramebuffer(framebuffer);framebuffer.name=0;GL.framebuffers[id]=null}}function _glDeleteProgram(id){if(!id)return;var program=GL.programs[id];if(!program){GL.recordError(1281);return}GLctx.deleteProgram(program);program.name=0;GL.programs[id]=null}function _glDeleteRenderbuffers(n,renderbuffers){for(var i=0;i<n;i++){var id=HEAP32[renderbuffers+i*4>>2];var renderbuffer=GL.renderbuffers[id];if(!renderbuffer)continue;GLctx.deleteRenderbuffer(renderbuffer);renderbuffer.name=0;GL.renderbuffers[id]=null}}function _glDeleteShader(id){if(!id)return;var shader=GL.shaders[id];if(!shader){GL.recordError(1281);return}GLctx.deleteShader(shader);GL.shaders[id]=null}function _glDeleteTextures(n,textures){for(var i=0;i<n;i++){var id=HEAP32[textures+i*4>>2];var texture=GL.textures[id];if(!texture)continue;GLctx.deleteTexture(texture);texture.name=0;GL.textures[id]=null}}function _glDeleteVertexArrays(n,vaos){for(var i=0;i<n;i++){var id=HEAP32[vaos+i*4>>2];GLctx["deleteVertexArray"](GL.vaos[id]);GL.vaos[id]=null}}function _glDepthFunc(x0){GLctx["depthFunc"](x0)}function _glDepthMask(flag){GLctx.depthMask(!!flag)}function _glDisable(x0){GLctx["disable"](x0)}function _glDisableVertexAttribArray(index){GLctx.disableVertexAttribArray(index)}function _glDrawArrays(mode,first,count){GLctx.drawArrays(mode,first,count)}function _glDrawArraysInstanced(mode,first,count,primcount){GLctx["drawArraysInstanced"](mode,first,count,primcount)}function _glDrawBuffers(n,bufs){var bufArray=tempFixedLengthArray[n];for(var i=0;i<n;i++){bufArray[i]=HEAP32[bufs+i*4>>2]}GLctx["drawBuffers"](bufArray)}function _glDrawElementsInstanced(mode,count,type,indices,primcount){GLctx["drawElementsInstanced"](mode,count,type,indices,primcount)}function _glEnable(x0){GLctx["enable"](x0)}function _glEnableVertexAttribArray(index){GLctx.enableVertexAttribArray(index)}function _glEndTransformFeedback(){GLctx["endTransformFeedback"]()}function _glFinish(){GLctx["finish"]()}function _glFramebufferRenderbuffer(target,attachment,renderbuffertarget,renderbuffer){GLctx.framebufferRenderbuffer(target,attachment,renderbuffertarget,GL.renderbuffers[renderbuffer])}function _glFramebufferTexture2D(target,attachment,textarget,texture,level){GLctx.framebufferTexture2D(target,attachment,textarget,GL.textures[texture],level)}function _glFramebufferTextureLayer(target,attachment,texture,level,layer){GLctx.framebufferTextureLayer(target,attachment,GL.textures[texture],level,layer)}function _glFrontFace(x0){GLctx["frontFace"](x0)}function _glGenBuffers(n,buffers){__glGenObject(n,buffers,"createBuffer",GL.buffers)}function _glGenFramebuffers(n,ids){__glGenObject(n,ids,"createFramebuffer",GL.framebuffers)}function _glGenRenderbuffers(n,renderbuffers){__glGenObject(n,renderbuffers,"createRenderbuffer",GL.renderbuffers)}function _glGenTextures(n,textures){__glGenObject(n,textures,"createTexture",GL.textures)}function _glGenVertexArrays(n,arrays){__glGenObject(n,arrays,"createVertexArray",GL.vaos)}function _glGenerateMipmap(x0){GLctx["generateMipmap"](x0)}function _glGetError(){var error=GLctx.getError()||GL.lastError;GL.lastError=0;return error}function _glGetFloatv(name_,p){emscriptenWebGLGet(name_,p,2)}function _glGetIntegerv(name_,p){emscriptenWebGLGet(name_,p,0)}function _glGetProgramBinary(program,bufSize,length,binaryFormat,binary){GL.recordError(1282)}function _glGetProgramInfoLog(program,maxLength,length,infoLog){var log=GLctx.getProgramInfoLog(GL.programs[program]);if(log===null)log="(unknown error)";var numBytesWrittenExclNull=maxLength>0&&infoLog?stringToUTF8(log,infoLog,maxLength):0;if(length)HEAP32[length>>2]=numBytesWrittenExclNull}function _glGetProgramiv(program,pname,p){if(!p){GL.recordError(1281);return}if(program>=GL.counter){GL.recordError(1281);return}program=GL.programs[program];if(pname==35716){var log=GLctx.getProgramInfoLog(program);if(log===null)log="(unknown error)";HEAP32[p>>2]=log.length+1}else if(pname==35719){if(!program.maxUniformLength){for(var i=0;i<GLctx.getProgramParameter(program,35718);++i){program.maxUniformLength=Math.max(program.maxUniformLength,GLctx.getActiveUniform(program,i).name.length+1)}}HEAP32[p>>2]=program.maxUniformLength}else if(pname==35722){if(!program.maxAttributeLength){for(var i=0;i<GLctx.getProgramParameter(program,35721);++i){program.maxAttributeLength=Math.max(program.maxAttributeLength,GLctx.getActiveAttrib(program,i).name.length+1)}}HEAP32[p>>2]=program.maxAttributeLength}else if(pname==35381){if(!program.maxUniformBlockNameLength){for(var i=0;i<GLctx.getProgramParameter(program,35382);++i){program.maxUniformBlockNameLength=Math.max(program.maxUniformBlockNameLength,GLctx.getActiveUniformBlockName(program,i).length+1)}}HEAP32[p>>2]=program.maxUniformBlockNameLength}else{HEAP32[p>>2]=GLctx.getProgramParameter(program,pname)}}function _glGetShaderInfoLog(shader,maxLength,length,infoLog){var log=GLctx.getShaderInfoLog(GL.shaders[shader]);if(log===null)log="(unknown error)";var numBytesWrittenExclNull=maxLength>0&&infoLog?stringToUTF8(log,infoLog,maxLength):0;if(length)HEAP32[length>>2]=numBytesWrittenExclNull}function _glGetShaderSource(shader,bufSize,length,source){var result=GLctx.getShaderSource(GL.shaders[shader]);if(!result)return;var numBytesWrittenExclNull=bufSize>0&&source?stringToUTF8(result,source,bufSize):0;if(length)HEAP32[length>>2]=numBytesWrittenExclNull}function _glGetShaderiv(shader,pname,p){if(!p){GL.recordError(1281);return}if(pname==35716){var log=GLctx.getShaderInfoLog(GL.shaders[shader]);if(log===null)log="(unknown error)";var logLength=log?log.length+1:0;HEAP32[p>>2]=logLength}else if(pname==35720){var source=GLctx.getShaderSource(GL.shaders[shader]);var sourceLength=source?source.length+1:0;HEAP32[p>>2]=sourceLength}else{HEAP32[p>>2]=GLctx.getShaderParameter(GL.shaders[shader],pname)}}function _glGetString(name_){var ret=GL.stringCache[name_];if(!ret){switch(name_){case 7939:var exts=GLctx.getSupportedExtensions()||[];exts=exts.concat(exts.map(function(e){return"GL_"+e}));ret=stringToNewUTF8(exts.join(" "));break;case 7936:case 7937:case 37445:case 37446:var s=GLctx.getParameter(name_);if(!s){GL.recordError(1280)}ret=s&&stringToNewUTF8(s);break;case 7938:var glVersion=GLctx.getParameter(7938);if(GL.currentContext.version>=2)glVersion="OpenGL ES 3.0 ("+glVersion+")";else{glVersion="OpenGL ES 2.0 ("+glVersion+")"}ret=stringToNewUTF8(glVersion);break;case 35724:var glslVersion=GLctx.getParameter(35724);var ver_re=/^WebGL GLSL ES ([0-9]\.[0-9][0-9]?)(?:$| .*)/;var ver_num=glslVersion.match(ver_re);if(ver_num!==null){if(ver_num[1].length==3)ver_num[1]=ver_num[1]+"0";glslVersion="OpenGL ES GLSL ES "+ver_num[1]+" ("+glslVersion+")"}ret=stringToNewUTF8(glslVersion);break;default:GL.recordError(1280)}GL.stringCache[name_]=ret}return ret}function _glGetStringi(name,index){if(GL.currentContext.version<2){GL.recordError(1282);return 0}var stringiCache=GL.stringiCache[name];if(stringiCache){if(index<0||index>=stringiCache.length){GL.recordError(1281);return 0}return stringiCache[index]}switch(name){case 7939:var exts=GLctx.getSupportedExtensions()||[];exts=exts.concat(exts.map(function(e){return"GL_"+e}));exts=exts.map(function(e){return stringToNewUTF8(e)});stringiCache=GL.stringiCache[name]=exts;if(index<0||index>=stringiCache.length){GL.recordError(1281);return 0}return stringiCache[index];default:GL.recordError(1280);return 0}}function _glGetUniformBlockIndex(program,uniformBlockName){return GLctx["getUniformBlockIndex"](GL.programs[program],UTF8ToString(uniformBlockName))}function _glGetUniformLocation(program,name){name=UTF8ToString(name);if(program=GL.programs[program]){webglPrepareUniformLocationsBeforeFirstUse(program);var uniformLocsById=program.uniformLocsById;var arrayIndex=0;var uniformBaseName=name;var leftBrace=webglGetLeftBracePos(name);if(leftBrace>0){arrayIndex=jstoi_q(name.slice(leftBrace+1))>>>0;uniformBaseName=name.slice(0,leftBrace)}var sizeAndId=program.uniformSizeAndIdsByName[uniformBaseName];if(sizeAndId&&arrayIndex<sizeAndId[0]){arrayIndex+=sizeAndId[1];if(uniformLocsById[arrayIndex]=uniformLocsById[arrayIndex]||GLctx.getUniformLocation(program,name)){return arrayIndex}}}else{GL.recordError(1281)}return-1}function _glInvalidateFramebuffer(target,numAttachments,attachments){var list=tempFixedLengthArray[numAttachments];for(var i=0;i<numAttachments;i++){list[i]=HEAP32[attachments+i*4>>2]}GLctx["invalidateFramebuffer"](target,list)}function _glLinkProgram(program){program=GL.programs[program];GLctx.linkProgram(program);program.uniformLocsById=0;program.uniformSizeAndIdsByName={}}function _glPixelStorei(pname,param){if(pname==3317){GL.unpackAlignment=param}GLctx.pixelStorei(pname,param)}function _glProgramBinary(program,binaryFormat,binary,length){GL.recordError(1280)}function _glProgramParameteri(program,pname,value){GL.recordError(1280)}function _glReadBuffer(x0){GLctx["readBuffer"](x0)}function _glReadPixels(x,y,width,height,format,type,pixels){if(GL.currentContext.version>=2){if(GLctx.currentPixelPackBufferBinding){GLctx.readPixels(x,y,width,height,format,type,pixels)}else{var heap=heapObjectForWebGLType(type);GLctx.readPixels(x,y,width,height,format,type,heap,pixels>>heapAccessShiftForWebGLHeap(heap))}return}var pixelData=emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,format);if(!pixelData){GL.recordError(1280);return}GLctx.readPixels(x,y,width,height,format,type,pixelData)}function _glRenderbufferStorage(x0,x1,x2,x3){GLctx["renderbufferStorage"](x0,x1,x2,x3)}function _glRenderbufferStorageMultisample(x0,x1,x2,x3,x4){GLctx["renderbufferStorageMultisample"](x0,x1,x2,x3,x4)}function _glScissor(x0,x1,x2,x3){GLctx["scissor"](x0,x1,x2,x3)}function _glShaderSource(shader,count,string,length){var source=GL.getSource(shader,count,string,length);GLctx.shaderSource(GL.shaders[shader],source)}function _glTexImage2D(target,level,internalFormat,width,height,border,format,type,pixels){if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding){GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,pixels)}else if(pixels){var heap=heapObjectForWebGLType(type);GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,heap,pixels>>heapAccessShiftForWebGLHeap(heap))}else{GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,null)}return}GLctx.texImage2D(target,level,internalFormat,width,height,border,format,type,pixels?emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,internalFormat):null)}function _glTexImage3D(target,level,internalFormat,width,height,depth,border,format,type,pixels){if(GLctx.currentPixelUnpackBufferBinding){GLctx["texImage3D"](target,level,internalFormat,width,height,depth,border,format,type,pixels)}else if(pixels){var heap=heapObjectForWebGLType(type);GLctx["texImage3D"](target,level,internalFormat,width,height,depth,border,format,type,heap,pixels>>heapAccessShiftForWebGLHeap(heap))}else{GLctx["texImage3D"](target,level,internalFormat,width,height,depth,border,format,type,null)}}function _glTexParameterf(x0,x1,x2){GLctx["texParameterf"](x0,x1,x2)}function _glTexParameteri(x0,x1,x2){GLctx["texParameteri"](x0,x1,x2)}function _glTexStorage2D(x0,x1,x2,x3,x4){GLctx["texStorage2D"](x0,x1,x2,x3,x4)}function _glTexSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixels){if(GL.currentContext.version>=2){if(GLctx.currentPixelUnpackBufferBinding){GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixels)}else if(pixels){var heap=heapObjectForWebGLType(type);GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,heap,pixels>>heapAccessShiftForWebGLHeap(heap))}else{GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,null)}return}var pixelData=null;if(pixels)pixelData=emscriptenWebGLGetTexPixelData(type,format,width,height,pixels,0);GLctx.texSubImage2D(target,level,xoffset,yoffset,width,height,format,type,pixelData)}function _glTexSubImage3D(target,level,xoffset,yoffset,zoffset,width,height,depth,format,type,pixels){if(GLctx.currentPixelUnpackBufferBinding){GLctx["texSubImage3D"](target,level,xoffset,yoffset,zoffset,width,height,depth,format,type,pixels)}else if(pixels){var heap=heapObjectForWebGLType(type);GLctx["texSubImage3D"](target,level,xoffset,yoffset,zoffset,width,height,depth,format,type,heap,pixels>>heapAccessShiftForWebGLHeap(heap))}else{GLctx["texSubImage3D"](target,level,xoffset,yoffset,zoffset,width,height,depth,format,type,null)}}function _glTransformFeedbackVaryings(program,count,varyings,bufferMode){program=GL.programs[program];var vars=[];for(var i=0;i<count;i++)vars.push(UTF8ToString(HEAP32[varyings+i*4>>2]));GLctx["transformFeedbackVaryings"](program,vars,bufferMode)}function _glUniform1f(location,v0){GLctx.uniform1f(webglGetUniformLocation(location),v0)}function _glUniform1i(location,v0){GLctx.uniform1i(webglGetUniformLocation(location),v0)}function _glUniform1iv(location,count,value){if(GL.currentContext.version>=2){count&&GLctx.uniform1iv(webglGetUniformLocation(location),HEAP32,value>>2,count);return}if(count<=288){var view=__miniTempWebGLIntBuffers[count-1];for(var i=0;i<count;++i){view[i]=HEAP32[value+4*i>>2]}}else{var view=HEAP32.subarray(value>>2,value+count*4>>2)}GLctx.uniform1iv(webglGetUniformLocation(location),view)}function _glUniform1ui(location,v0){GLctx.uniform1ui(webglGetUniformLocation(location),v0)}function _glUniform2f(location,v0,v1){GLctx.uniform2f(webglGetUniformLocation(location),v0,v1)}function _glUniform2fv(location,count,value){if(GL.currentContext.version>=2){count&&GLctx.uniform2fv(webglGetUniformLocation(location),HEAPF32,value>>2,count*2);return}if(count<=144){var view=miniTempWebGLFloatBuffers[2*count-1];for(var i=0;i<2*count;i+=2){view[i]=HEAPF32[value+4*i>>2];view[i+1]=HEAPF32[value+(4*i+4)>>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*8>>2)}GLctx.uniform2fv(webglGetUniformLocation(location),view)}function _glUniform2i(location,v0,v1){GLctx.uniform2i(webglGetUniformLocation(location),v0,v1)}function _glUniform2iv(location,count,value){if(GL.currentContext.version>=2){count&&GLctx.uniform2iv(webglGetUniformLocation(location),HEAP32,value>>2,count*2);return}if(count<=144){var view=__miniTempWebGLIntBuffers[2*count-1];for(var i=0;i<2*count;i+=2){view[i]=HEAP32[value+4*i>>2];view[i+1]=HEAP32[value+(4*i+4)>>2]}}else{var view=HEAP32.subarray(value>>2,value+count*8>>2)}GLctx.uniform2iv(webglGetUniformLocation(location),view)}function _glUniform3f(location,v0,v1,v2){GLctx.uniform3f(webglGetUniformLocation(location),v0,v1,v2)}function _glUniform3fv(location,count,value){if(GL.currentContext.version>=2){count&&GLctx.uniform3fv(webglGetUniformLocation(location),HEAPF32,value>>2,count*3);return}if(count<=96){var view=miniTempWebGLFloatBuffers[3*count-1];for(var i=0;i<3*count;i+=3){view[i]=HEAPF32[value+4*i>>2];view[i+1]=HEAPF32[value+(4*i+4)>>2];view[i+2]=HEAPF32[value+(4*i+8)>>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*12>>2)}GLctx.uniform3fv(webglGetUniformLocation(location),view)}function _glUniform3i(location,v0,v1,v2){GLctx.uniform3i(webglGetUniformLocation(location),v0,v1,v2)}function _glUniform4f(location,v0,v1,v2,v3){GLctx.uniform4f(webglGetUniformLocation(location),v0,v1,v2,v3)}function _glUniform4fv(location,count,value){if(GL.currentContext.version>=2){count&&GLctx.uniform4fv(webglGetUniformLocation(location),HEAPF32,value>>2,count*4);return}if(count<=72){var view=miniTempWebGLFloatBuffers[4*count-1];var heap=HEAPF32;value>>=2;for(var i=0;i<4*count;i+=4){var dst=value+i;view[i]=heap[dst];view[i+1]=heap[dst+1];view[i+2]=heap[dst+2];view[i+3]=heap[dst+3]}}else{var view=HEAPF32.subarray(value>>2,value+count*16>>2)}GLctx.uniform4fv(webglGetUniformLocation(location),view)}function _glUniform4i(location,v0,v1,v2,v3){GLctx.uniform4i(webglGetUniformLocation(location),v0,v1,v2,v3)}function _glUniformBlockBinding(program,uniformBlockIndex,uniformBlockBinding){program=GL.programs[program];GLctx["uniformBlockBinding"](program,uniformBlockIndex,uniformBlockBinding)}function _glUniformMatrix2fv(location,count,transpose,value){if(GL.currentContext.version>=2){count&&GLctx.uniformMatrix2fv(webglGetUniformLocation(location),!!transpose,HEAPF32,value>>2,count*4);return}if(count<=72){var view=miniTempWebGLFloatBuffers[4*count-1];for(var i=0;i<4*count;i+=4){view[i]=HEAPF32[value+4*i>>2];view[i+1]=HEAPF32[value+(4*i+4)>>2];view[i+2]=HEAPF32[value+(4*i+8)>>2];view[i+3]=HEAPF32[value+(4*i+12)>>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*16>>2)}GLctx.uniformMatrix2fv(webglGetUniformLocation(location),!!transpose,view)}function _glUniformMatrix3fv(location,count,transpose,value){if(GL.currentContext.version>=2){count&&GLctx.uniformMatrix3fv(webglGetUniformLocation(location),!!transpose,HEAPF32,value>>2,count*9);return}if(count<=32){var view=miniTempWebGLFloatBuffers[9*count-1];for(var i=0;i<9*count;i+=9){view[i]=HEAPF32[value+4*i>>2];view[i+1]=HEAPF32[value+(4*i+4)>>2];view[i+2]=HEAPF32[value+(4*i+8)>>2];view[i+3]=HEAPF32[value+(4*i+12)>>2];view[i+4]=HEAPF32[value+(4*i+16)>>2];view[i+5]=HEAPF32[value+(4*i+20)>>2];view[i+6]=HEAPF32[value+(4*i+24)>>2];view[i+7]=HEAPF32[value+(4*i+28)>>2];view[i+8]=HEAPF32[value+(4*i+32)>>2]}}else{var view=HEAPF32.subarray(value>>2,value+count*36>>2)}GLctx.uniformMatrix3fv(webglGetUniformLocation(location),!!transpose,view)}function _glUniformMatrix4fv(location,count,transpose,value){if(GL.currentContext.version>=2){count&&GLctx.uniformMatrix4fv(webglGetUniformLocation(location),!!transpose,HEAPF32,value>>2,count*16);return}if(count<=18){var view=miniTempWebGLFloatBuffers[16*count-1];var heap=HEAPF32;value>>=2;for(var i=0;i<16*count;i+=16){var dst=value+i;view[i]=heap[dst];view[i+1]=heap[dst+1];view[i+2]=heap[dst+2];view[i+3]=heap[dst+3];view[i+4]=heap[dst+4];view[i+5]=heap[dst+5];view[i+6]=heap[dst+6];view[i+7]=heap[dst+7];view[i+8]=heap[dst+8];view[i+9]=heap[dst+9];view[i+10]=heap[dst+10];view[i+11]=heap[dst+11];view[i+12]=heap[dst+12];view[i+13]=heap[dst+13];view[i+14]=heap[dst+14];view[i+15]=heap[dst+15]}}else{var view=HEAPF32.subarray(value>>2,value+count*64>>2)}GLctx.uniformMatrix4fv(webglGetUniformLocation(location),!!transpose,view)}function _glUseProgram(program){program=GL.programs[program];GLctx.useProgram(program);GLctx.currentProgram=program}function _glVertexAttrib4f(x0,x1,x2,x3,x4){GLctx["vertexAttrib4f"](x0,x1,x2,x3,x4)}function _glVertexAttrib4fv(index,v){GLctx.vertexAttrib4f(index,HEAPF32[v>>2],HEAPF32[v+4>>2],HEAPF32[v+8>>2],HEAPF32[v+12>>2])}function _glVertexAttribDivisor(index,divisor){GLctx["vertexAttribDivisor"](index,divisor)}function _glVertexAttribI4ui(x0,x1,x2,x3,x4){GLctx["vertexAttribI4ui"](x0,x1,x2,x3,x4)}function _glVertexAttribIPointer(index,size,type,stride,ptr){GLctx["vertexAttribIPointer"](index,size,type,stride,ptr)}function _glVertexAttribPointer(index,size,type,normalized,stride,ptr){GLctx.vertexAttribPointer(index,size,type,!!normalized,stride,ptr)}function _glViewport(x0,x1,x2,x3){GLctx["viewport"](x0,x1,x2,x3)}var GodotRuntime={get_func:function(ptr){return wasmTable.get(ptr)},error:function(){err.apply(null,Array.from(arguments))},print:function(){out.apply(null,Array.from(arguments))},malloc:function(p_size){return _malloc(p_size)},free:function(p_ptr){_free(p_ptr)},getHeapValue:function(p_ptr,p_type){return getValue(p_ptr,p_type)},setHeapValue:function(p_ptr,p_value,p_type){setValue(p_ptr,p_value,p_type)},heapSub:function(p_heap,p_ptr,p_len){const bytes=p_heap.BYTES_PER_ELEMENT;return p_heap.subarray(p_ptr/bytes,p_ptr/bytes+p_len)},heapSlice:function(p_heap,p_ptr,p_len){const bytes=p_heap.BYTES_PER_ELEMENT;return p_heap.slice(p_ptr/bytes,p_ptr/bytes+p_len)},heapCopy:function(p_dst,p_src,p_ptr){const bytes=p_src.BYTES_PER_ELEMENT;return p_dst.set(p_src,p_ptr/bytes)},parseString:function(p_ptr){return UTF8ToString(p_ptr)},parseStringArray:function(p_ptr,p_size){const strings=[];const ptrs=GodotRuntime.heapSub(HEAP32,p_ptr,p_size);ptrs.forEach(function(ptr){strings.push(GodotRuntime.parseString(ptr))});return strings},strlen:function(p_str){return lengthBytesUTF8(p_str)},allocString:function(p_str){const length=GodotRuntime.strlen(p_str)+1;const c_str=GodotRuntime.malloc(length);stringToUTF8(p_str,c_str,length);return c_str},allocStringArray:function(p_strings){const size=p_strings.length;const c_ptr=GodotRuntime.malloc(size*4);for(let i=0;i<size;i++){HEAP32[(c_ptr>>2)+i]=GodotRuntime.allocString(p_strings[i])}return c_ptr},freeStringArray:function(p_ptr,p_len){for(let i=0;i<p_len;i++){GodotRuntime.free(HEAP32[(p_ptr>>2)+i])}GodotRuntime.free(p_ptr)},stringToHeap:function(p_str,p_ptr,p_len){return stringToUTF8Array(p_str,HEAP8,p_ptr,p_len)}};var GodotConfig={canvas:null,locale:"en",canvas_resize_policy:2,virtual_keyboard:false,persistent_drops:false,on_execute:null,on_exit:null,init_config:function(p_opts){GodotConfig.canvas_resize_policy=p_opts["canvasResizePolicy"];GodotConfig.canvas=p_opts["canvas"];GodotConfig.locale=p_opts["locale"]||GodotConfig.locale;GodotConfig.virtual_keyboard=p_opts["virtualKeyboard"];GodotConfig.persistent_drops=!!p_opts["persistentDrops"];GodotConfig.on_execute=p_opts["onExecute"];GodotConfig.on_exit=p_opts["onExit"];if(p_opts["focusCanvas"]){GodotConfig.canvas.focus()}},locate_file:function(file){return Module["locateFile"](file)},clear:function(){GodotConfig.canvas=null;GodotConfig.locale="en";GodotConfig.canvas_resize_policy=2;GodotConfig.virtual_keyboard=false;GodotConfig.persistent_drops=false;GodotConfig.on_execute=null;GodotConfig.on_exit=null}};var ERRNO_CODES={};var GodotFS={_idbfs:false,_syncing:false,_mount_points:[],is_persistent:function(){return GodotFS._idbfs?1:0},init:function(persistentPaths){GodotFS._idbfs=false;if(!Array.isArray(persistentPaths)){return Promise.reject(new Error("Persistent paths must be an array"))}if(!persistentPaths.length){return Promise.resolve()}GodotFS._mount_points=persistentPaths.slice();function createRecursive(dir){try{FS.stat(dir)}catch(e){if(e.errno!==ERRNO_CODES.ENOENT){throw e}FS.mkdirTree(dir)}}GodotFS._mount_points.forEach(function(path){createRecursive(path);FS.mount(IDBFS,{},path)});return new Promise(function(resolve,reject){FS.syncfs(true,function(err){if(err){GodotFS._mount_points=[];GodotFS._idbfs=false;GodotRuntime.print(`IndexedDB not available: ${err.message}`)}else{GodotFS._idbfs=true}resolve(err)})})},deinit:function(){GodotFS._mount_points.forEach(function(path){try{FS.unmount(path)}catch(e){GodotRuntime.print("Already unmounted",e)}if(GodotFS._idbfs&&IDBFS.dbs[path]){IDBFS.dbs[path].close();delete IDBFS.dbs[path]}});GodotFS._mount_points=[];GodotFS._idbfs=false;GodotFS._syncing=false},sync:function(){if(GodotFS._syncing){GodotRuntime.error("Already syncing!");return Promise.resolve()}GodotFS._syncing=true;return new Promise(function(resolve,reject){FS.syncfs(false,function(error){if(error){GodotRuntime.error(`Failed to save IDB file system: ${error.message}`)}GodotFS._syncing=false;resolve(error)})})},copy_to_fs:function(path,buffer){const idx=path.lastIndexOf("/");let dir="/";if(idx>0){dir=path.slice(0,idx)}try{FS.stat(dir)}catch(e){if(e.errno!==ERRNO_CODES.ENOENT){throw e}FS.mkdirTree(dir)}FS.writeFile(path,new Uint8Array(buffer))}};var GodotOS={request_quit:function(){},_async_cbs:[],_fs_sync_promise:null,atexit:function(p_promise_cb){GodotOS._async_cbs.push(p_promise_cb)},cleanup:function(exit_code){const cb=GodotConfig.on_exit;GodotFS.deinit();GodotConfig.clear();if(cb){cb(exit_code)}},finish_async:function(callback){GodotOS._fs_sync_promise.then(function(err){const promises=[];GodotOS._async_cbs.forEach(function(cb){promises.push(new Promise(cb))});return Promise.all(promises)}).then(function(){return GodotFS.sync()}).then(function(err){setTimeout(function(){callback()},0)})}};var GodotAudio={ctx:null,input:null,driver:null,interval:0,init:function(mix_rate,latency,onstatechange,onlatencyupdate){const opts={};if(mix_rate){opts["sampleRate"]=mix_rate}const ctx=new(window.AudioContext||window.webkitAudioContext)(opts);GodotAudio.ctx=ctx;ctx.onstatechange=function(){let state=0;switch(ctx.state){case"suspended":state=0;break;case"running":state=1;break;case"closed":state=2;break}onstatechange(state)};ctx.onstatechange();GodotAudio.interval=setInterval(function(){let computed_latency=0;if(ctx.baseLatency){computed_latency+=GodotAudio.ctx.baseLatency}if(ctx.outputLatency){computed_latency+=GodotAudio.ctx.outputLatency}onlatencyupdate(computed_latency)},1e3);GodotOS.atexit(GodotAudio.close_async);return ctx.destination.channelCount},create_input:function(callback){if(GodotAudio.input){return 0}function gotMediaInput(stream){try{GodotAudio.input=GodotAudio.ctx.createMediaStreamSource(stream);callback(GodotAudio.input)}catch(e){GodotRuntime.error("Failed creaating input.",e)}}if(navigator.mediaDevices&&navigator.mediaDevices.getUserMedia){navigator.mediaDevices.getUserMedia({"audio":true}).then(gotMediaInput,function(e){GodotRuntime.error("Error getting user media.",e)})}else{if(!navigator.getUserMedia){navigator.getUserMedia=navigator.webkitGetUserMedia||navigator.mozGetUserMedia}if(!navigator.getUserMedia){GodotRuntime.error("getUserMedia not available.");return 1}navigator.getUserMedia({"audio":true},gotMediaInput,function(e){GodotRuntime.print(e)})}return 0},close_async:function(resolve,reject){const ctx=GodotAudio.ctx;GodotAudio.ctx=null;if(!ctx){resolve();return}if(GodotAudio.interval){clearInterval(GodotAudio.interval);GodotAudio.interval=0}if(GodotAudio.input){GodotAudio.input.disconnect();GodotAudio.input=null}let closed=Promise.resolve();if(GodotAudio.driver){closed=GodotAudio.driver.close()}closed.then(function(){return ctx.close()}).then(function(){ctx.onstatechange=null;resolve()}).catch(function(e){ctx.onstatechange=null;GodotRuntime.error("Error closing AudioContext",e);resolve()})}};function _godot_audio_capture_start(){return GodotAudio.create_input(function(input){input.connect(GodotAudio.driver.get_node())})}function _godot_audio_capture_stop(){if(GodotAudio.input){const tracks=GodotAudio.input["mediaStream"]["getTracks"]();for(let i=0;i<tracks.length;i++){tracks[i]["stop"]()}GodotAudio.input.disconnect();GodotAudio.input=null}}function _godot_audio_has_script_processor(){return GodotAudio.ctx&&GodotAudio.ctx.createScriptProcessor?1:0}function _godot_audio_has_worklet(){return GodotAudio.ctx&&GodotAudio.ctx.audioWorklet?1:0}function _godot_audio_init(p_mix_rate,p_latency,p_state_change,p_latency_update){const statechange=GodotRuntime.get_func(p_state_change);const latencyupdate=GodotRuntime.get_func(p_latency_update);const mix_rate=GodotRuntime.getHeapValue(p_mix_rate,"i32");const channels=GodotAudio.init(mix_rate,p_latency,statechange,latencyupdate);GodotRuntime.setHeapValue(p_mix_rate,GodotAudio.ctx.sampleRate,"i32");return channels}function _godot_audio_is_available(){if(!(window.AudioContext||window.webkitAudioContext)){return 0}return 1}function _godot_audio_resume(){if(GodotAudio.ctx&&GodotAudio.ctx.state!=="running"){GodotAudio.ctx.resume()}}var GodotAudioScript={script:null,create:function(buffer_length,channel_count){GodotAudioScript.script=GodotAudio.ctx.createScriptProcessor(buffer_length,2,channel_count);GodotAudio.driver=GodotAudioScript;return GodotAudioScript.script.bufferSize},start:function(p_in_buf,p_in_size,p_out_buf,p_out_size,onprocess){GodotAudioScript.script.onaudioprocess=function(event){const inb=GodotRuntime.heapSub(HEAPF32,p_in_buf,p_in_size);const input=event.inputBuffer;if(GodotAudio.input){const inlen=input.getChannelData(0).length;for(let ch=0;ch<2;ch++){const data=input.getChannelData(ch);for(let s=0;s<inlen;s++){inb[s*2+ch]=data[s]}}}onprocess();const outb=GodotRuntime.heapSub(HEAPF32,p_out_buf,p_out_size);const output=event.outputBuffer;const channels=output.numberOfChannels;for(let ch=0;ch<channels;ch++){const data=output.getChannelData(ch);for(let sample=0;sample<data.length;sample++){data[sample]=outb[sample*channels+ch]}}};GodotAudioScript.script.connect(GodotAudio.ctx.destination)},get_node:function(){return GodotAudioScript.script},close:function(){return new Promise(function(resolve,reject){GodotAudioScript.script.disconnect();GodotAudioScript.script.onaudioprocess=null;GodotAudioScript.script=null;resolve()})}};function _godot_audio_script_create(buffer_length,channel_count){const buf_len=GodotRuntime.getHeapValue(buffer_length,"i32");try{const out_len=GodotAudioScript.create(buf_len,channel_count);GodotRuntime.setHeapValue(buffer_length,out_len,"i32")}catch(e){GodotRuntime.error("Error starting AudioDriverScriptProcessor",e);return 1}return 0}function _godot_audio_script_start(p_in_buf,p_in_size,p_out_buf,p_out_size,p_cb){const onprocess=GodotRuntime.get_func(p_cb);GodotAudioScript.start(p_in_buf,p_in_size,p_out_buf,p_out_size,onprocess)}var GodotAudioWorklet={promise:null,worklet:null,ring_buffer:null,create:function(channels){const path=GodotConfig.locate_file("godot.audio.worklet.js");GodotAudioWorklet.promise=GodotAudio.ctx.audioWorklet.addModule(path).then(function(){GodotAudioWorklet.worklet=new AudioWorkletNode(GodotAudio.ctx,"godot-processor",{"outputChannelCount":[channels]});return Promise.resolve()});GodotAudio.driver=GodotAudioWorklet},start:function(in_buf,out_buf,state){GodotAudioWorklet.promise.then(function(){const node=GodotAudioWorklet.worklet;node.connect(GodotAudio.ctx.destination);node.port.postMessage({"cmd":"start","data":[state,in_buf,out_buf]});node.port.onmessage=function(event){GodotRuntime.error(event.data)}})},start_no_threads:function(p_out_buf,p_out_size,out_callback,p_in_buf,p_in_size,in_callback){function RingBuffer(){let wpos=0;let rpos=0;let pending_samples=0;const wbuf=new Float32Array(p_out_size);function send(port){if(pending_samples===0){return}const buffer=GodotRuntime.heapSub(HEAPF32,p_out_buf,p_out_size);const size=buffer.length;const tot_sent=pending_samples;out_callback(wpos,pending_samples);if(wpos+pending_samples>=size){const high=size-wpos;wbuf.set(buffer.subarray(wpos,size));pending_samples-=high;wpos=0}if(pending_samples>0){wbuf.set(buffer.subarray(wpos,wpos+pending_samples),tot_sent-pending_samples)}port.postMessage({"cmd":"chunk","data":wbuf.subarray(0,tot_sent)});wpos+=pending_samples;pending_samples=0}this.receive=function(recv_buf){const buffer=GodotRuntime.heapSub(HEAPF32,p_in_buf,p_in_size);const from=rpos;let to_write=recv_buf.length;let high=0;if(rpos+to_write>=p_in_size){high=p_in_size-rpos;buffer.set(recv_buf.subarray(0,high),rpos);to_write-=high;rpos=0}if(to_write){buffer.set(recv_buf.subarray(high,to_write),rpos)}in_callback(from,recv_buf.length);rpos+=to_write};this.consumed=function(size,port){pending_samples+=size;send(port)}}GodotAudioWorklet.ring_buffer=new RingBuffer;GodotAudioWorklet.promise.then(function(){const node=GodotAudioWorklet.worklet;const buffer=GodotRuntime.heapSlice(HEAPF32,p_out_buf,p_out_size);node.connect(GodotAudio.ctx.destination);node.port.postMessage({"cmd":"start_nothreads","data":[buffer,p_in_size]});node.port.onmessage=function(event){if(!GodotAudioWorklet.worklet){return}if(event.data["cmd"]==="read"){const read=event.data["data"];GodotAudioWorklet.ring_buffer.consumed(read,GodotAudioWorklet.worklet.port)}else if(event.data["cmd"]==="input"){const buf=event.data["data"];if(buf.length>p_in_size){GodotRuntime.error("Input chunk is too big");return}GodotAudioWorklet.ring_buffer.receive(buf)}else{GodotRuntime.error(event.data)}}})},get_node:function(){return GodotAudioWorklet.worklet},close:function(){return new Promise(function(resolve,reject){if(GodotAudioWorklet.promise===null){return}GodotAudioWorklet.promise.then(function(){GodotAudioWorklet.worklet.port.postMessage({"cmd":"stop","data":null});GodotAudioWorklet.worklet.disconnect();GodotAudioWorklet.worklet=null;GodotAudioWorklet.promise=null;resolve()}).catch(function(err){})})}};function _godot_audio_worklet_create(channels){try{GodotAudioWorklet.create(channels)}catch(e){GodotRuntime.error("Error starting AudioDriverWorklet",e);return 1}return 0}function _godot_audio_worklet_start_no_threads(p_out_buf,p_out_size,p_out_callback,p_in_buf,p_in_size,p_in_callback){const out_callback=GodotRuntime.get_func(p_out_callback);const in_callback=GodotRuntime.get_func(p_in_callback);GodotAudioWorklet.start_no_threads(p_out_buf,p_out_size,out_callback,p_in_buf,p_in_size,in_callback)}function _godot_js_config_canvas_id_get(p_ptr,p_ptr_max){GodotRuntime.stringToHeap(`#${GodotConfig.canvas.id}`,p_ptr,p_ptr_max)}function _godot_js_config_locale_get(p_ptr,p_ptr_max){GodotRuntime.stringToHeap(GodotConfig.locale,p_ptr,p_ptr_max)}var GodotDisplayCursor={shape:"auto",visible:true,cursors:{},set_style:function(style){GodotConfig.canvas.style.cursor=style},set_shape:function(shape){GodotDisplayCursor.shape=shape;let css=shape;if(shape in GodotDisplayCursor.cursors){const c=GodotDisplayCursor.cursors[shape];css=`url("${c.url}") ${c.x} ${c.y}, auto`}if(GodotDisplayCursor.visible){GodotDisplayCursor.set_style(css)}},clear:function(){GodotDisplayCursor.set_style("");GodotDisplayCursor.shape="auto";GodotDisplayCursor.visible=true;Object.keys(GodotDisplayCursor.cursors).forEach(function(key){URL.revokeObjectURL(GodotDisplayCursor.cursors[key]);delete GodotDisplayCursor.cursors[key]})},lockPointer:function(){const canvas=GodotConfig.canvas;if(canvas.requestPointerLock){canvas.requestPointerLock()}},releasePointer:function(){if(document.exitPointerLock){document.exitPointerLock()}},isPointerLocked:function(){return document.pointerLockElement===GodotConfig.canvas}};var GodotEventListeners={handlers:[],has:function(target,event,method,capture){return GodotEventListeners.handlers.findIndex(function(e){return e.target===target&&e.event===event&&e.method===method&&e.capture===capture})!==-1},add:function(target,event,method,capture){if(GodotEventListeners.has(target,event,method,capture)){return}function Handler(p_target,p_event,p_method,p_capture){this.target=p_target;this.event=p_event;this.method=p_method;this.capture=p_capture}GodotEventListeners.handlers.push(new Handler(target,event,method,capture));target.addEventListener(event,method,capture)},clear:function(){GodotEventListeners.handlers.forEach(function(h){h.target.removeEventListener(h.event,h.method,h.capture)});GodotEventListeners.handlers.length=0}};function _emscripten_webgl_do_get_current_context(){return GL.currentContext?GL.currentContext.handle:0}function _emscripten_webgl_get_current_context(){return _emscripten_webgl_do_get_current_context()}var GodotDisplayScreen={desired_size:[0,0],hidpi:true,getPixelRatio:function(){return GodotDisplayScreen.hidpi?window.devicePixelRatio||1:1},isFullscreen:function(){const elem=document.fullscreenElement||document.mozFullscreenElement||document.webkitFullscreenElement||document.msFullscreenElement;if(elem){return elem===GodotConfig.canvas}return document.fullscreen||document.mozFullScreen||document.webkitIsFullscreen},hasFullscreen:function(){return document.fullscreenEnabled||document.mozFullScreenEnabled||document.webkitFullscreenEnabled},requestFullscreen:function(){if(!GodotDisplayScreen.hasFullscreen()){return 1}const canvas=GodotConfig.canvas;try{const promise=(canvas.requestFullscreen||canvas.msRequestFullscreen||canvas.mozRequestFullScreen||canvas.mozRequestFullscreen||canvas.webkitRequestFullscreen).call(canvas);if(promise){promise.catch(function(){})}}catch(e){return 1}return 0},exitFullscreen:function(){if(!GodotDisplayScreen.isFullscreen()){return 0}try{const promise=document.exitFullscreen();if(promise){promise.catch(function(){})}}catch(e){return 1}return 0},_updateGL:function(){const gl_context_handle=_emscripten_webgl_get_current_context();const gl=GL.getContext(gl_context_handle);if(gl){GL.resizeOffscreenFramebuffer(gl)}},updateSize:function(){const isFullscreen=GodotDisplayScreen.isFullscreen();const wantsFullWindow=GodotConfig.canvas_resize_policy===2;const noResize=GodotConfig.canvas_resize_policy===0;const wwidth=GodotDisplayScreen.desired_size[0];const wheight=GodotDisplayScreen.desired_size[1];const canvas=GodotConfig.canvas;let width=wwidth;let height=wheight;if(noResize){if(canvas.width!==width||canvas.height!==height){GodotDisplayScreen.desired_size=[canvas.width,canvas.height];GodotDisplayScreen._updateGL();return 1}return 0}const scale=GodotDisplayScreen.getPixelRatio();if(isFullscreen||wantsFullWindow){width=window.innerWidth*scale;height=window.innerHeight*scale}const csw=`${width/scale}px`;const csh=`${height/scale}px`;if(canvas.style.width!==csw||canvas.style.height!==csh||canvas.width!==width||canvas.height!==height){canvas.width=width;canvas.height=height;canvas.style.width=csw;canvas.style.height=csh;GodotDisplayScreen._updateGL();return 1}return 0}};var GodotDisplayVK={textinput:null,textarea:null,available:function(){return GodotConfig.virtual_keyboard&&"ontouchstart"in window},init:function(input_cb){function create(what){const elem=document.createElement(what);elem.style.display="none";elem.style.position="absolute";elem.style.zIndex="-1";elem.style.background="transparent";elem.style.padding="0px";elem.style.margin="0px";elem.style.overflow="hidden";elem.style.width="0px";elem.style.height="0px";elem.style.border="0px";elem.style.outline="none";elem.readonly=true;elem.disabled=true;GodotEventListeners.add(elem,"input",function(evt){const c_str=GodotRuntime.allocString(elem.value);input_cb(c_str,elem.selectionEnd);GodotRuntime.free(c_str)},false);GodotEventListeners.add(elem,"blur",function(evt){elem.style.display="none";elem.readonly=true;elem.disabled=true},false);GodotConfig.canvas.insertAdjacentElement("beforebegin",elem);return elem}GodotDisplayVK.textinput=create("input");GodotDisplayVK.textarea=create("textarea");GodotDisplayVK.updateSize()},show:function(text,multiline,start,end){if(!GodotDisplayVK.textinput||!GodotDisplayVK.textarea){return}if(GodotDisplayVK.textinput.style.display!==""||GodotDisplayVK.textarea.style.display!==""){GodotDisplayVK.hide()}GodotDisplayVK.updateSize();const elem=multiline?GodotDisplayVK.textarea:GodotDisplayVK.textinput;elem.readonly=false;elem.disabled=false;elem.value=text;elem.style.display="block";elem.focus();elem.setSelectionRange(start,end)},hide:function(){if(!GodotDisplayVK.textinput||!GodotDisplayVK.textarea){return}[GodotDisplayVK.textinput,GodotDisplayVK.textarea].forEach(function(elem){elem.blur();elem.style.display="none";elem.value=""})},updateSize:function(){if(!GodotDisplayVK.textinput||!GodotDisplayVK.textarea){return}const rect=GodotConfig.canvas.getBoundingClientRect();function update(elem){elem.style.left=`${rect.left}px`;elem.style.top=`${rect.top}px`;elem.style.width=`${rect.width}px`;elem.style.height=`${rect.height}px`}update(GodotDisplayVK.textinput);update(GodotDisplayVK.textarea)},clear:function(){if(GodotDisplayVK.textinput){GodotDisplayVK.textinput.remove();GodotDisplayVK.textinput=null}if(GodotDisplayVK.textarea){GodotDisplayVK.textarea.remove();GodotDisplayVK.textarea=null}}};var GodotDisplay={window_icon:"",findDPI:function(){function testDPI(dpi){return window.matchMedia(`(max-resolution: ${dpi}dpi)`).matches}function bisect(low,high,func){const mid=parseInt((high-low)/2+low,10);if(high-low<=1){return func(high)?high:low}if(func(mid)){return bisect(low,mid,func)}return bisect(mid,high,func)}try{const dpi=bisect(0,800,testDPI);return dpi>=96?dpi:96}catch(e){return 96}}};function _godot_js_display_alert(p_text){window.alert(GodotRuntime.parseString(p_text))}function _godot_js_display_canvas_focus(){GodotConfig.canvas.focus()}function _godot_js_display_canvas_is_focused(){return document.activeElement===GodotConfig.canvas}function _godot_js_display_clipboard_get(callback){const func=GodotRuntime.get_func(callback);try{navigator.clipboard.readText().then(function(result){const ptr=GodotRuntime.allocString(result);func(ptr);GodotRuntime.free(ptr)}).catch(function(e){})}catch(e){}}function _godot_js_display_clipboard_set(p_text){const text=GodotRuntime.parseString(p_text);if(!navigator.clipboard||!navigator.clipboard.writeText){return 1}navigator.clipboard.writeText(text).catch(function(e){GodotRuntime.error("Setting OS clipboard is only possible from an input callback for the HTML5 plafrom. Exception:",e)});return 0}function _godot_js_display_cursor_is_hidden(){return!GodotDisplayCursor.visible}function _godot_js_display_cursor_is_locked(){return GodotDisplayCursor.isPointerLocked()?1:0}function _godot_js_display_cursor_lock_set(p_lock){if(p_lock){GodotDisplayCursor.lockPointer()}else{GodotDisplayCursor.releasePointer()}}function _godot_js_display_cursor_set_custom_shape(p_shape,p_ptr,p_len,p_hotspot_x,p_hotspot_y){const shape=GodotRuntime.parseString(p_shape);const old_shape=GodotDisplayCursor.cursors[shape];if(p_len>0){const png=new Blob([GodotRuntime.heapSlice(HEAPU8,p_ptr,p_len)],{type:"image/png"});const url=URL.createObjectURL(png);GodotDisplayCursor.cursors[shape]={url:url,x:p_hotspot_x,y:p_hotspot_y}}else{delete GodotDisplayCursor.cursors[shape]}if(shape===GodotDisplayCursor.shape){GodotDisplayCursor.set_shape(GodotDisplayCursor.shape)}if(old_shape){URL.revokeObjectURL(old_shape.url)}}function _godot_js_display_cursor_set_shape(p_string){GodotDisplayCursor.set_shape(GodotRuntime.parseString(p_string))}function _godot_js_display_cursor_set_visible(p_visible){const visible=p_visible!==0;if(visible===GodotDisplayCursor.visible){return}GodotDisplayCursor.visible=visible;if(visible){GodotDisplayCursor.set_shape(GodotDisplayCursor.shape)}else{GodotDisplayCursor.set_style("none")}}function _godot_js_display_desired_size_set(width,height){GodotDisplayScreen.desired_size=[width,height];GodotDisplayScreen.updateSize()}function _godot_js_display_fullscreen_cb(callback){const canvas=GodotConfig.canvas;const func=GodotRuntime.get_func(callback);function change_cb(evt){if(evt.target===canvas){func(GodotDisplayScreen.isFullscreen())}}GodotEventListeners.add(document,"fullscreenchange",change_cb,false);GodotEventListeners.add(document,"mozfullscreenchange",change_cb,false);GodotEventListeners.add(document,"webkitfullscreenchange",change_cb,false)}function _godot_js_display_fullscreen_exit(){return GodotDisplayScreen.exitFullscreen()}function _godot_js_display_fullscreen_request(){return GodotDisplayScreen.requestFullscreen()}function _godot_js_display_glGetBufferSubData(target,offset,size,data){const gl_context_handle=_emscripten_webgl_get_current_context();const gl=GL.getContext(gl_context_handle);if(gl){gl.GLctx["getBufferSubData"](target,offset,HEAPU8,data,size)}}function _godot_js_display_has_webgl(p_version){if(p_version!==1&&p_version!==2){return false}try{return!!document.createElement("canvas").getContext(p_version===2?"webgl2":"webgl")}catch(e){}return false}function _godot_js_display_is_swap_ok_cancel(){const win=["Windows","Win64","Win32","WinCE"];const plat=navigator.platform||"";if(win.indexOf(plat)!==-1){return 1}return 0}function _godot_js_display_notification_cb(callback,p_enter,p_exit,p_in,p_out){const canvas=GodotConfig.canvas;const func=GodotRuntime.get_func(callback);const notif=[p_enter,p_exit,p_in,p_out];["mouseover","mouseleave","focus","blur"].forEach(function(evt_name,idx){GodotEventListeners.add(canvas,evt_name,function(){func(notif[idx])},true)})}function _godot_js_display_pixel_ratio_get(){return GodotDisplayScreen.getPixelRatio()}function _godot_js_display_screen_dpi_get(){return GodotDisplay.findDPI()}function _godot_js_display_screen_size_get(width,height){const scale=GodotDisplayScreen.getPixelRatio();GodotRuntime.setHeapValue(width,window.screen.width*scale,"i32");GodotRuntime.setHeapValue(height,window.screen.height*scale,"i32")}function _godot_js_display_setup_canvas(p_width,p_height,p_fullscreen,p_hidpi){const canvas=GodotConfig.canvas;GodotEventListeners.add(canvas,"contextmenu",function(ev){ev.preventDefault()},false);GodotEventListeners.add(canvas,"webglcontextlost",function(ev){alert("WebGL context lost, please reload the page");ev.preventDefault()},false);GodotDisplayScreen.hidpi=!!p_hidpi;switch(GodotConfig.canvas_resize_policy){case 0:GodotDisplayScreen.desired_size=[canvas.width,canvas.height];break;case 1:GodotDisplayScreen.desired_size=[p_width,p_height];break;default:canvas.style.position="absolute";canvas.style.top=0;canvas.style.left=0;break}GodotDisplayScreen.updateSize();if(p_fullscreen){GodotDisplayScreen.requestFullscreen()}}function _godot_js_display_size_update(){const updated=GodotDisplayScreen.updateSize();if(updated){GodotDisplayVK.updateSize()}return updated}function _godot_js_display_touchscreen_is_available(){return"ontouchstart"in window}function _godot_js_display_vk_available(){return GodotDisplayVK.available()}function _godot_js_display_vk_cb(p_input_cb){const input_cb=GodotRuntime.get_func(p_input_cb);if(GodotDisplayVK.available()){GodotDisplayVK.init(input_cb)}}function _godot_js_display_vk_hide(){GodotDisplayVK.hide()}function _godot_js_display_vk_show(p_text,p_multiline,p_start,p_end){const text=GodotRuntime.parseString(p_text);const start=p_start>0?p_start:0;const end=p_end>0?p_end:start;GodotDisplayVK.show(text,p_multiline,start,end)}function _godot_js_display_window_blur_cb(callback){const func=GodotRuntime.get_func(callback);GodotEventListeners.add(window,"blur",function(){func()},false)}function _godot_js_display_window_icon_set(p_ptr,p_len){let link=document.getElementById("-gd-engine-icon");if(link===null){link=document.createElement("link");link.rel="icon";link.id="-gd-engine-icon";document.head.appendChild(link)}const old_icon=GodotDisplay.window_icon;const png=new Blob([GodotRuntime.heapSlice(HEAPU8,p_ptr,p_len)],{type:"image/png"});GodotDisplay.window_icon=URL.createObjectURL(png);link.href=GodotDisplay.window_icon;if(old_icon){URL.revokeObjectURL(old_icon)}}function _godot_js_display_window_size_get(p_width,p_height){GodotRuntime.setHeapValue(p_width,GodotConfig.canvas.width,"i32");GodotRuntime.setHeapValue(p_height,GodotConfig.canvas.height,"i32")}function _godot_js_display_window_title_set(p_data){document.title=GodotRuntime.parseString(p_data)}function _godot_js_eval(p_js,p_use_global_ctx,p_union_ptr,p_byte_arr,p_byte_arr_write,p_callback){const js_code=GodotRuntime.parseString(p_js);let eval_ret=null;try{if(p_use_global_ctx){const global_eval=eval;eval_ret=global_eval(js_code)}else{eval_ret=eval(js_code)}}catch(e){GodotRuntime.error(e)}switch(typeof eval_ret){case"boolean":GodotRuntime.setHeapValue(p_union_ptr,eval_ret,"i32");return 1;case"number":GodotRuntime.setHeapValue(p_union_ptr,eval_ret,"double");return 3;case"string":GodotRuntime.setHeapValue(p_union_ptr,GodotRuntime.allocString(eval_ret),"*");return 4;case"object":if(eval_ret===null){break}if(ArrayBuffer.isView(eval_ret)&&!(eval_ret instanceof Uint8Array)){eval_ret=new Uint8Array(eval_ret.buffer)}else if(eval_ret instanceof ArrayBuffer){eval_ret=new Uint8Array(eval_ret)}if(eval_ret instanceof Uint8Array){const func=GodotRuntime.get_func(p_callback);const bytes_ptr=func(p_byte_arr,p_byte_arr_write,eval_ret.length);HEAPU8.set(eval_ret,bytes_ptr);return 20}break}return 0}var IDHandler={_last_id:0,_references:{},get:function(p_id){return IDHandler._references[p_id]},add:function(p_data){const id=++IDHandler._last_id;IDHandler._references[id]=p_data;return id},remove:function(p_id){delete IDHandler._references[p_id]}};var GodotFetch={onread:function(id,result){const obj=IDHandler.get(id);if(!obj){return}if(result.value){obj.chunks.push(result.value)}obj.reading=false;obj.done=result.done},onresponse:function(id,response){const obj=IDHandler.get(id);if(!obj){return}let chunked=false;response.headers.forEach(function(value,header){const v=value.toLowerCase().trim();const h=header.toLowerCase().trim();if(h==="transfer-encoding"&&v==="chunked"){chunked=true}});obj.status=response.status;obj.response=response;obj.reader=response.body.getReader();obj.chunked=chunked},onerror:function(id,err){GodotRuntime.error(err);const obj=IDHandler.get(id);if(!obj){return}obj.error=err},create:function(method,url,headers,body){const obj={request:null,response:null,reader:null,error:null,done:false,reading:false,status:0,chunks:[],bodySize:-1};const id=IDHandler.add(obj);const init={method:method,headers:headers,body:body};obj.request=fetch(url,init);obj.request.then(GodotFetch.onresponse.bind(null,id)).catch(GodotFetch.onerror.bind(null,id));return id},free:function(id){const obj=IDHandler.get(id);if(!obj){return}IDHandler.remove(id);if(!obj.request){return}obj.request.then(function(response){response.abort()}).catch(function(e){})},read:function(id){const obj=IDHandler.get(id);if(!obj){return}if(obj.reader&&!obj.reading){if(obj.done){obj.reader=null;return}obj.reading=true;obj.reader.read().then(GodotFetch.onread.bind(null,id)).catch(GodotFetch.onerror.bind(null,id))}}};function _godot_js_fetch_body_length_get(p_id){const obj=IDHandler.get(p_id);if(!obj||!obj.response){return-1}return obj.bodySize}function _godot_js_fetch_create(p_method,p_url,p_headers,p_headers_size,p_body,p_body_size){const method=GodotRuntime.parseString(p_method);const url=GodotRuntime.parseString(p_url);const headers=GodotRuntime.parseStringArray(p_headers,p_headers_size);const body=p_body_size?GodotRuntime.heapSlice(HEAP8,p_body,p_body_size):null;return GodotFetch.create(method,url,headers.map(function(hv){const idx=hv.indexOf(":");if(idx<=0){return[]}return[hv.slice(0,idx).trim(),hv.slice(idx+1).trim()]}).filter(function(v){return v.length===2}),body)}function _godot_js_fetch_free(id){GodotFetch.free(id)}function _godot_js_fetch_http_status_get(p_id){const obj=IDHandler.get(p_id);if(!obj||!obj.response){return 0}return obj.status}function _godot_js_fetch_is_chunked(p_id){const obj=IDHandler.get(p_id);if(!obj||!obj.response){return-1}return obj.chunked?1:0}function _godot_js_fetch_read_chunk(p_id,p_buf,p_buf_size){const obj=IDHandler.get(p_id);if(!obj||!obj.response){return 0}let to_read=p_buf_size;const chunks=obj.chunks;while(to_read&&chunks.length){const chunk=obj.chunks[0];if(chunk.length>to_read){GodotRuntime.heapCopy(HEAP8,chunk.slice(0,to_read),p_buf);chunks[0]=chunk.slice(to_read);to_read=0}else{GodotRuntime.heapCopy(HEAP8,chunk,p_buf);to_read-=chunk.length;chunks.pop()}}if(!chunks.length){GodotFetch.read(p_id)}return p_buf_size-to_read}function _godot_js_fetch_read_headers(p_id,p_parse_cb,p_ref){const obj=IDHandler.get(p_id);if(!obj||!obj.response){return 1}const cb=GodotRuntime.get_func(p_parse_cb);const arr=[];obj.response.headers.forEach(function(v,h){arr.push(`${h}:${v}`)});const c_ptr=GodotRuntime.allocStringArray(arr);cb(arr.length,c_ptr,p_ref);GodotRuntime.freeStringArray(c_ptr,arr.length);return 0}function _godot_js_fetch_state_get(p_id){const obj=IDHandler.get(p_id);if(!obj){return-1}if(obj.error){return-1}if(!obj.response){return 0}if(obj.reader){return 1}if(obj.done){return 2}return-1}var GodotInputGamepads={samples:[],get_pads:function(){try{const pads=navigator.getGamepads();if(pads){return pads}return[]}catch(e){return[]}},get_samples:function(){return GodotInputGamepads.samples},get_sample:function(index){const samples=GodotInputGamepads.samples;return index<samples.length?samples[index]:null},sample:function(){const pads=GodotInputGamepads.get_pads();const samples=[];for(let i=0;i<pads.length;i++){const pad=pads[i];if(!pad){samples.push(null);continue}const s={standard:pad.mapping==="standard",buttons:[],axes:[],connected:pad.connected};for(let b=0;b<pad.buttons.length;b++){s.buttons.push(pad.buttons[b].value)}for(let a=0;a<pad.axes.length;a++){s.axes.push(pad.axes[a])}samples.push(s)}GodotInputGamepads.samples=samples},init:function(onchange){GodotInputGamepads.samples=[];function add(pad){const guid=GodotInputGamepads.get_guid(pad);const c_id=GodotRuntime.allocString(pad.id);const c_guid=GodotRuntime.allocString(guid);onchange(pad.index,1,c_id,c_guid);GodotRuntime.free(c_id);GodotRuntime.free(c_guid)}const pads=GodotInputGamepads.get_pads();for(let i=0;i<pads.length;i++){if(pads[i]){add(pads[i])}}GodotEventListeners.add(window,"gamepadconnected",function(evt){if(evt.gamepad){add(evt.gamepad)}},false);GodotEventListeners.add(window,"gamepaddisconnected",function(evt){if(evt.gamepad){onchange(evt.gamepad.index,0)}},false)},get_guid:function(pad){if(pad.mapping){return pad.mapping}const ua=navigator.userAgent;let os="Unknown";if(ua.indexOf("Android")>=0){os="Android"}else if(ua.indexOf("Linux")>=0){os="Linux"}else if(ua.indexOf("iPhone")>=0){os="iOS"}else if(ua.indexOf("Macintosh")>=0){os="MacOSX"}else if(ua.indexOf("Windows")>=0){os="Windows"}const id=pad.id;const exp1=/vendor: ([0-9a-f]{4}) product: ([0-9a-f]{4})/i;const exp2=/^([0-9a-f]+)-([0-9a-f]+)-/i;let vendor="";let product="";if(exp1.test(id)){const match=exp1.exec(id);vendor=match[1].padStart(4,"0");product=match[2].padStart(4,"0")}else if(exp2.test(id)){const match=exp2.exec(id);vendor=match[1].padStart(4,"0");product=match[2].padStart(4,"0")}if(!vendor||!product){return`${os}Unknown`}return os+vendor+product}};var GodotInputDragDrop={promises:[],pending_files:[],add_entry:function(entry){if(entry.isDirectory){GodotInputDragDrop.add_dir(entry)}else if(entry.isFile){GodotInputDragDrop.add_file(entry)}else{GodotRuntime.error("Unrecognized entry...",entry)}},add_dir:function(entry){GodotInputDragDrop.promises.push(new Promise(function(resolve,reject){const reader=entry.createReader();reader.readEntries(function(entries){for(let i=0;i<entries.length;i++){GodotInputDragDrop.add_entry(entries[i])}resolve()})}))},add_file:function(entry){GodotInputDragDrop.promises.push(new Promise(function(resolve,reject){entry.file(function(file){const reader=new FileReader;reader.onload=function(){const f={"path":file.relativePath||file.webkitRelativePath,"name":file.name,"type":file.type,"size":file.size,"data":reader.result};if(!f["path"]){f["path"]=f["name"]}GodotInputDragDrop.pending_files.push(f);resolve()};reader.onerror=function(){GodotRuntime.print("Error reading file");reject()};reader.readAsArrayBuffer(file)},function(err){GodotRuntime.print("Error!");reject()})}))},process:function(resolve,reject){if(GodotInputDragDrop.promises.length===0){resolve();return}GodotInputDragDrop.promises.pop().then(function(){setTimeout(function(){GodotInputDragDrop.process(resolve,reject)},0)})},_process_event:function(ev,callback){ev.preventDefault();if(ev.dataTransfer.items){for(let i=0;i<ev.dataTransfer.items.length;i++){const item=ev.dataTransfer.items[i];let entry=null;if("getAsEntry"in item){entry=item.getAsEntry()}else if("webkitGetAsEntry"in item){entry=item.webkitGetAsEntry()}if(entry){GodotInputDragDrop.add_entry(entry)}}}else{GodotRuntime.error("File upload not supported")}new Promise(GodotInputDragDrop.process).then(function(){const DROP=`/tmp/drop-${parseInt(Math.random()*(1<<30),10)}/`;const drops=[];const files=[];FS.mkdir(DROP.slice(0,-1));GodotInputDragDrop.pending_files.forEach(elem=>{const path=elem["path"];GodotFS.copy_to_fs(DROP+path,elem["data"]);let idx=path.indexOf("/");if(idx===-1){drops.push(DROP+path)}else{const sub=path.substr(0,idx);idx=sub.indexOf("/");if(idx<0&&drops.indexOf(DROP+sub)===-1){drops.push(DROP+sub)}}files.push(DROP+path)});GodotInputDragDrop.promises=[];GodotInputDragDrop.pending_files=[];callback(drops);if(GodotConfig.persistent_drops){GodotOS.atexit(function(resolve,reject){GodotInputDragDrop.remove_drop(files,DROP);resolve()})}else{GodotInputDragDrop.remove_drop(files,DROP)}})},remove_drop:function(files,drop_path){const dirs=[drop_path.substr(0,drop_path.length-1)];files.forEach(function(file){FS.unlink(file);let dir=file.replace(drop_path,"");let idx=dir.lastIndexOf("/");while(idx>0){dir=dir.substr(0,idx);if(dirs.indexOf(drop_path+dir)===-1){dirs.push(drop_path+dir)}idx=dir.lastIndexOf("/")}});dirs.sort(function(a,b){const al=(a.match(/\//g)||[]).length;const bl=(b.match(/\//g)||[]).length;if(al>bl){return-1}else if(al<bl){return 1}return 0}).forEach(function(dir){FS.rmdir(dir)})},handler:function(callback){return function(ev){GodotInputDragDrop._process_event(ev,callback)}}};var GodotInput={getModifiers:function(evt){return evt.shiftKey+0+(evt.altKey+0<<1)+(evt.ctrlKey+0<<2)+(evt.metaKey+0<<3)},computePosition:function(evt,rect){const canvas=GodotConfig.canvas;const rw=canvas.width/rect.width;const rh=canvas.height/rect.height;const x=(evt.clientX-rect.x)*rw;const y=(evt.clientY-rect.y)*rh;return[x,y]}};function _godot_js_input_drop_files_cb(callback){const func=GodotRuntime.get_func(callback);const dropFiles=function(files){const args=files||[];if(!args.length){return}const argc=args.length;const argv=GodotRuntime.allocStringArray(args);func(argv,argc);GodotRuntime.freeStringArray(argv,argc)};const canvas=GodotConfig.canvas;GodotEventListeners.add(canvas,"dragover",function(ev){ev.preventDefault()},false);GodotEventListeners.add(canvas,"drop",GodotInputDragDrop.handler(dropFiles))}function _godot_js_input_gamepad_cb(change_cb){const onchange=GodotRuntime.get_func(change_cb);GodotInputGamepads.init(onchange)}function _godot_js_input_gamepad_sample(){GodotInputGamepads.sample();return 0}function _godot_js_input_gamepad_sample_count(){return GodotInputGamepads.get_samples().length}function _godot_js_input_gamepad_sample_get(p_index,r_btns,r_btns_num,r_axes,r_axes_num,r_standard){const sample=GodotInputGamepads.get_sample(p_index);if(!sample||!sample.connected){return 1}const btns=sample.buttons;const btns_len=btns.length<16?btns.length:16;for(let i=0;i<btns_len;i++){GodotRuntime.setHeapValue(r_btns+(i<<2),btns[i],"float")}GodotRuntime.setHeapValue(r_btns_num,btns_len,"i32");const axes=sample.axes;const axes_len=axes.length<10?axes.length:10;for(let i=0;i<axes_len;i++){GodotRuntime.setHeapValue(r_axes+(i<<2),axes[i],"float")}GodotRuntime.setHeapValue(r_axes_num,axes_len,"i32");const is_standard=sample.standard?1:0;GodotRuntime.setHeapValue(r_standard,is_standard,"i32");return 0}function _godot_js_input_key_cb(callback,code,key){const func=GodotRuntime.get_func(callback);function key_cb(pressed,evt){const modifiers=GodotInput.getModifiers(evt);GodotRuntime.stringToHeap(evt.code,code,32);GodotRuntime.stringToHeap(evt.key,key,32);func(pressed,evt.repeat,modifiers);evt.preventDefault()}GodotEventListeners.add(GodotConfig.canvas,"keydown",key_cb.bind(null,1),false);GodotEventListeners.add(GodotConfig.canvas,"keyup",key_cb.bind(null,0),false)}function _godot_js_input_mouse_button_cb(callback){const func=GodotRuntime.get_func(callback);const canvas=GodotConfig.canvas;function button_cb(p_pressed,evt){const rect=canvas.getBoundingClientRect();const pos=GodotInput.computePosition(evt,rect);const modifiers=GodotInput.getModifiers(evt);if(p_pressed){GodotConfig.canvas.focus()}if(func(p_pressed,evt.button,pos[0],pos[1],modifiers)){evt.preventDefault()}}GodotEventListeners.add(canvas,"mousedown",button_cb.bind(null,1),false);GodotEventListeners.add(window,"mouseup",button_cb.bind(null,0),false)}function _godot_js_input_mouse_move_cb(callback){const func=GodotRuntime.get_func(callback);const canvas=GodotConfig.canvas;function move_cb(evt){const rect=canvas.getBoundingClientRect();const pos=GodotInput.computePosition(evt,rect);const rw=canvas.width/rect.width;const rh=canvas.height/rect.height;const rel_pos_x=evt.movementX*rw;const rel_pos_y=evt.movementY*rh;const modifiers=GodotInput.getModifiers(evt);func(pos[0],pos[1],rel_pos_x,rel_pos_y,modifiers)}GodotEventListeners.add(window,"mousemove",move_cb,false)}function _godot_js_input_mouse_wheel_cb(callback){const func=GodotRuntime.get_func(callback);function wheel_cb(evt){if(func(evt["deltaX"]||0,evt["deltaY"]||0)){evt.preventDefault()}}GodotEventListeners.add(GodotConfig.canvas,"wheel",wheel_cb,false)}function _godot_js_input_paste_cb(callback){const func=GodotRuntime.get_func(callback);GodotEventListeners.add(window,"paste",function(evt){const text=evt.clipboardData.getData("text");const ptr=GodotRuntime.allocString(text);func(ptr);GodotRuntime.free(ptr)},false)}function _godot_js_input_touch_cb(callback,ids,coords){const func=GodotRuntime.get_func(callback);const canvas=GodotConfig.canvas;function touch_cb(type,evt){if(type===0){GodotConfig.canvas.focus()}const rect=canvas.getBoundingClientRect();const touches=evt.changedTouches;for(let i=0;i<touches.length;i++){const touch=touches[i];const pos=GodotInput.computePosition(touch,rect);GodotRuntime.setHeapValue(coords+i*2*8,pos[0],"double");GodotRuntime.setHeapValue(coords+(i*2+1)*8,pos[1],"double");GodotRuntime.setHeapValue(ids+i*4,touch.identifier,"i32")}func(type,touches.length);if(evt.cancelable){evt.preventDefault()}}GodotEventListeners.add(canvas,"touchstart",touch_cb.bind(null,0),false);GodotEventListeners.add(canvas,"touchend",touch_cb.bind(null,1),false);GodotEventListeners.add(canvas,"touchcancel",touch_cb.bind(null,1),false);GodotEventListeners.add(canvas,"touchmove",touch_cb.bind(null,2),false)}function _godot_js_input_vibrate_handheld(p_duration_ms){if(typeof navigator.vibrate!=="function"){GodotRuntime.print("This browser does not support vibration.")}else{navigator.vibrate(p_duration_ms)}}function _godot_js_os_download_buffer(p_ptr,p_size,p_name,p_mime){const buf=GodotRuntime.heapSlice(HEAP8,p_ptr,p_size);const name=GodotRuntime.parseString(p_name);const mime=GodotRuntime.parseString(p_mime);const blob=new Blob([buf],{type:mime});const url=window.URL.createObjectURL(blob);const a=document.createElement("a");a.href=url;a.download=name;a.style.display="none";document.body.appendChild(a);a.click();a.remove();window.URL.revokeObjectURL(url)}function _godot_js_os_execute(p_json){const json_args=GodotRuntime.parseString(p_json);const args=JSON.parse(json_args);if(GodotConfig.on_execute){GodotConfig.on_execute(args);return 0}return 1}function _godot_js_os_finish_async(p_callback){const func=GodotRuntime.get_func(p_callback);GodotOS.finish_async(func)}function _godot_js_os_fs_is_persistent(){return GodotFS.is_persistent()}function _godot_js_os_fs_sync(callback){const func=GodotRuntime.get_func(callback);GodotOS._fs_sync_promise=GodotFS.sync();GodotOS._fs_sync_promise.then(function(err){func()})}function _godot_js_os_hw_concurrency_get(){return navigator.hardwareConcurrency||1}function _godot_js_os_request_quit_cb(p_callback){GodotOS.request_quit=GodotRuntime.get_func(p_callback)}function _godot_js_os_shell_open(p_uri){window.open(GodotRuntime.parseString(p_uri),"_blank")}var GodotPWA={hasUpdate:false,updateState:function(cb,reg){if(!reg){return}if(!reg.active){return}if(reg.waiting){GodotPWA.hasUpdate=true;cb()}GodotEventListeners.add(reg,"updatefound",function(){const installing=reg.installing;GodotEventListeners.add(installing,"statechange",function(){if(installing.state==="installed"){GodotPWA.hasUpdate=true;cb()}})})}};function _godot_js_pwa_cb(p_update_cb){if("serviceWorker"in navigator){const cb=GodotRuntime.get_func(p_update_cb);navigator.serviceWorker.getRegistration().then(GodotPWA.updateState.bind(null,cb))}}function _godot_js_pwa_update(){if("serviceWorker"in navigator&&GodotPWA.hasUpdate){navigator.serviceWorker.getRegistration().then(function(reg){if(!reg||!reg.waiting){return}reg.waiting.postMessage("update")});return 0}return 1}var GodotRTCDataChannel={connect:function(p_id,p_on_open,p_on_message,p_on_error,p_on_close){const ref=IDHandler.get(p_id);if(!ref){return}ref.binaryType="arraybuffer";ref.onopen=function(event){p_on_open()};ref.onclose=function(event){p_on_close()};ref.onerror=function(event){p_on_error()};ref.onmessage=function(event){let buffer;let is_string=0;if(event.data instanceof ArrayBuffer){buffer=new Uint8Array(event.data)}else if(event.data instanceof Blob){GodotRuntime.error("Blob type not supported");return}else if(typeof event.data==="string"){is_string=1;const enc=new TextEncoder("utf-8");buffer=new Uint8Array(enc.encode(event.data))}else{GodotRuntime.error("Unknown message type");return}const len=buffer.length*buffer.BYTES_PER_ELEMENT;const out=GodotRuntime.malloc(len);HEAPU8.set(buffer,out);p_on_message(out,len,is_string);GodotRuntime.free(out)}},close:function(p_id){const ref=IDHandler.get(p_id);if(!ref){return}ref.onopen=null;ref.onmessage=null;ref.onerror=null;ref.onclose=null;ref.close()},get_prop:function(p_id,p_prop,p_def){const ref=IDHandler.get(p_id);return ref&&ref[p_prop]!==undefined?ref[p_prop]:p_def}};function _godot_js_rtc_datachannel_close(p_id){const ref=IDHandler.get(p_id);if(!ref){return}GodotRTCDataChannel.close(p_id)}function _godot_js_rtc_datachannel_connect(p_id,p_ref,p_on_open,p_on_message,p_on_error,p_on_close){const onopen=GodotRuntime.get_func(p_on_open).bind(null,p_ref);const onmessage=GodotRuntime.get_func(p_on_message).bind(null,p_ref);const onerror=GodotRuntime.get_func(p_on_error).bind(null,p_ref);const onclose=GodotRuntime.get_func(p_on_close).bind(null,p_ref);GodotRTCDataChannel.connect(p_id,onopen,onmessage,onerror,onclose)}function _godot_js_rtc_datachannel_destroy(p_id){GodotRTCDataChannel.close(p_id);IDHandler.remove(p_id)}function _godot_js_rtc_datachannel_get_buffered_amount(p_id){return GodotRTCDataChannel.get_prop(p_id,"bufferedAmount",0)}function _godot_js_rtc_datachannel_id_get(p_id){return GodotRTCDataChannel.get_prop(p_id,"id",65535)}function _godot_js_rtc_datachannel_is_negotiated(p_id){return GodotRTCDataChannel.get_prop(p_id,"negotiated",65535)}function _godot_js_rtc_datachannel_is_ordered(p_id){return GodotRTCDataChannel.get_prop(p_id,"ordered",true)}function _godot_js_rtc_datachannel_label_get(p_id){const ref=IDHandler.get(p_id);if(!ref||!ref.label){return 0}return GodotRuntime.allocString(ref.label)}function _godot_js_rtc_datachannel_max_packet_lifetime_get(p_id){const ref=IDHandler.get(p_id);if(!ref){return 65535}if(ref["maxPacketLifeTime"]!==undefined){return ref["maxPacketLifeTime"]}else if(ref["maxRetransmitTime"]!==undefined){return ref["maxRetransmitTime"]}return 65535}function _godot_js_rtc_datachannel_max_retransmits_get(p_id){return GodotRTCDataChannel.get_prop(p_id,"maxRetransmits",65535)}function _godot_js_rtc_datachannel_protocol_get(p_id){const ref=IDHandler.get(p_id);if(!ref||!ref.protocol){return 0}return GodotRuntime.allocString(ref.protocol)}function _godot_js_rtc_datachannel_ready_state_get(p_id){const ref=IDHandler.get(p_id);if(!ref){return 3}switch(ref.readyState){case"connecting":return 0;case"open":return 1;case"closing":return 2;case"closed":default:return 3}}function _godot_js_rtc_datachannel_send(p_id,p_buffer,p_length,p_raw){const ref=IDHandler.get(p_id);if(!ref){return 1}const bytes_array=new Uint8Array(p_length);for(let i=0;i<p_length;i++){bytes_array[i]=GodotRuntime.getHeapValue(p_buffer+i,"i8")}if(p_raw){ref.send(bytes_array.buffer)}else{const string=new TextDecoder("utf-8").decode(bytes_array);ref.send(string)}return 0}var GodotRTCPeerConnection={onstatechange:function(p_id,p_conn,callback,event){const ref=IDHandler.get(p_id);if(!ref){return}let state;switch(p_conn.iceConnectionState){case"new":state=0;break;case"checking":state=1;break;case"connected":case"completed":state=2;break;case"disconnected":state=3;break;case"failed":state=4;break;case"closed":default:state=5;break}callback(state)},onicecandidate:function(p_id,callback,event){const ref=IDHandler.get(p_id);if(!ref||!event.candidate){return}const c=event.candidate;const candidate_str=GodotRuntime.allocString(c.candidate);const mid_str=GodotRuntime.allocString(c.sdpMid);callback(mid_str,c.sdpMLineIndex,candidate_str);GodotRuntime.free(candidate_str);GodotRuntime.free(mid_str)},ondatachannel:function(p_id,callback,event){const ref=IDHandler.get(p_id);if(!ref){return}const cid=IDHandler.add(event.channel);callback(cid)},onsession:function(p_id,callback,session){const ref=IDHandler.get(p_id);if(!ref){return}const type_str=GodotRuntime.allocString(session.type);const sdp_str=GodotRuntime.allocString(session.sdp);callback(type_str,sdp_str);GodotRuntime.free(type_str);GodotRuntime.free(sdp_str)},onerror:function(p_id,callback,error){const ref=IDHandler.get(p_id);if(!ref){return}GodotRuntime.error(error);callback()}};function _godot_js_rtc_pc_close(p_id){const ref=IDHandler.get(p_id);if(!ref){return}ref.close()}function _godot_js_rtc_pc_create(p_config,p_ref,p_on_state_change,p_on_candidate,p_on_datachannel){const onstatechange=GodotRuntime.get_func(p_on_state_change).bind(null,p_ref);const oncandidate=GodotRuntime.get_func(p_on_candidate).bind(null,p_ref);const ondatachannel=GodotRuntime.get_func(p_on_datachannel).bind(null,p_ref);const config=JSON.parse(GodotRuntime.parseString(p_config));let conn=null;try{conn=new RTCPeerConnection(config)}catch(e){GodotRuntime.error(e);return 0}const base=GodotRTCPeerConnection;const id=IDHandler.add(conn);conn.oniceconnectionstatechange=base.onstatechange.bind(null,id,conn,onstatechange);conn.onicecandidate=base.onicecandidate.bind(null,id,oncandidate);conn.ondatachannel=base.ondatachannel.bind(null,id,ondatachannel);return id}function _godot_js_rtc_pc_datachannel_create(p_id,p_label,p_config){try{const ref=IDHandler.get(p_id);if(!ref){return 0}const label=GodotRuntime.parseString(p_label);const config=JSON.parse(GodotRuntime.parseString(p_config));const channel=ref.createDataChannel(label,config);return IDHandler.add(channel)}catch(e){GodotRuntime.error(e);return 0}}function _godot_js_rtc_pc_destroy(p_id){const ref=IDHandler.get(p_id);if(!ref){return}ref.oniceconnectionstatechange=null;ref.onicecandidate=null;ref.ondatachannel=null;IDHandler.remove(p_id)}function _godot_js_rtc_pc_ice_candidate_add(p_id,p_mid_name,p_mline_idx,p_sdp){const ref=IDHandler.get(p_id);if(!ref){return}const sdpMidName=GodotRuntime.parseString(p_mid_name);const sdpName=GodotRuntime.parseString(p_sdp);ref.addIceCandidate(new RTCIceCandidate({"candidate":sdpName,"sdpMid":sdpMidName,"sdpMlineIndex":p_mline_idx}))}function _godot_js_rtc_pc_local_description_set(p_id,p_type,p_sdp,p_obj,p_on_error){const ref=IDHandler.get(p_id);if(!ref){return}const type=GodotRuntime.parseString(p_type);const sdp=GodotRuntime.parseString(p_sdp);const onerror=GodotRuntime.get_func(p_on_error).bind(null,p_obj);ref.setLocalDescription({"sdp":sdp,"type":type}).catch(function(error){GodotRTCPeerConnection.onerror(p_id,onerror,error)})}function _godot_js_rtc_pc_offer_create(p_id,p_obj,p_on_session,p_on_error){const ref=IDHandler.get(p_id);if(!ref){return}const onsession=GodotRuntime.get_func(p_on_session).bind(null,p_obj);const onerror=GodotRuntime.get_func(p_on_error).bind(null,p_obj);ref.createOffer().then(function(session){GodotRTCPeerConnection.onsession(p_id,onsession,session)}).catch(function(error){GodotRTCPeerConnection.onerror(p_id,onerror,error)})}function _godot_js_rtc_pc_remote_description_set(p_id,p_type,p_sdp,p_obj,p_session_created,p_on_error){const ref=IDHandler.get(p_id);if(!ref){return}const type=GodotRuntime.parseString(p_type);const sdp=GodotRuntime.parseString(p_sdp);const onerror=GodotRuntime.get_func(p_on_error).bind(null,p_obj);const onsession=GodotRuntime.get_func(p_session_created).bind(null,p_obj);ref.setRemoteDescription({"sdp":sdp,"type":type}).then(function(){if(type!=="offer"){return Promise.resolve()}return ref.createAnswer().then(function(session){GodotRTCPeerConnection.onsession(p_id,onsession,session)})}).catch(function(error){GodotRTCPeerConnection.onerror(p_id,onerror,error)})}var GodotWebSocket={_onopen:function(p_id,callback,event){const ref=IDHandler.get(p_id);if(!ref){return}const c_str=GodotRuntime.allocString(ref.protocol);callback(c_str);GodotRuntime.free(c_str)},_onmessage:function(p_id,callback,event){const ref=IDHandler.get(p_id);if(!ref){return}let buffer;let is_string=0;if(event.data instanceof ArrayBuffer){buffer=new Uint8Array(event.data)}else if(event.data instanceof Blob){GodotRuntime.error("Blob type not supported");return}else if(typeof event.data==="string"){is_string=1;const enc=new TextEncoder("utf-8");buffer=new Uint8Array(enc.encode(event.data))}else{GodotRuntime.error("Unknown message type");return}const len=buffer.length*buffer.BYTES_PER_ELEMENT;const out=GodotRuntime.malloc(len);HEAPU8.set(buffer,out);callback(out,len,is_string);GodotRuntime.free(out)},_onerror:function(p_id,callback,event){const ref=IDHandler.get(p_id);if(!ref){return}callback()},_onclose:function(p_id,callback,event){const ref=IDHandler.get(p_id);if(!ref){return}const c_str=GodotRuntime.allocString(event.reason);callback(event.code,c_str,event.wasClean?1:0);GodotRuntime.free(c_str)},send:function(p_id,p_data){const ref=IDHandler.get(p_id);if(!ref||ref.readyState!==ref.OPEN){return 1}ref.send(p_data);return 0},bufferedAmount:function(p_id){const ref=IDHandler.get(p_id);if(!ref){return 0}return ref.bufferedAmount},create:function(socket,p_on_open,p_on_message,p_on_error,p_on_close){const id=IDHandler.add(socket);socket.onopen=GodotWebSocket._onopen.bind(null,id,p_on_open);socket.onmessage=GodotWebSocket._onmessage.bind(null,id,p_on_message);socket.onerror=GodotWebSocket._onerror.bind(null,id,p_on_error);socket.onclose=GodotWebSocket._onclose.bind(null,id,p_on_close);return id},close:function(p_id,p_code,p_reason){const ref=IDHandler.get(p_id);if(ref&&ref.readyState<ref.CLOSING){const code=p_code;const reason=GodotRuntime.parseString(p_reason);ref.close(code,reason)}},destroy:function(p_id){const ref=IDHandler.get(p_id);if(!ref){return}GodotWebSocket.close(p_id,3001,"destroyed");IDHandler.remove(p_id);ref.onopen=null;ref.onmessage=null;ref.onerror=null;ref.onclose=null}};function _godot_js_websocket_buffered_amount(p_id){return GodotWebSocket.bufferedAmount(p_id)}function _godot_js_websocket_close(p_id,p_code,p_reason){const code=p_code;const reason=GodotRuntime.parseString(p_reason);GodotWebSocket.close(p_id,code,reason)}function _godot_js_websocket_create(p_ref,p_url,p_proto,p_on_open,p_on_message,p_on_error,p_on_close){const on_open=GodotRuntime.get_func(p_on_open).bind(null,p_ref);const on_message=GodotRuntime.get_func(p_on_message).bind(null,p_ref);const on_error=GodotRuntime.get_func(p_on_error).bind(null,p_ref);const on_close=GodotRuntime.get_func(p_on_close).bind(null,p_ref);const url=GodotRuntime.parseString(p_url);const protos=GodotRuntime.parseString(p_proto);let socket=null;try{if(protos){socket=new WebSocket(url,protos.split(","))}else{socket=new WebSocket(url)}}catch(e){return 0}socket.binaryType="arraybuffer";return GodotWebSocket.create(socket,on_open,on_message,on_error,on_close)}function _godot_js_websocket_destroy(p_id){GodotWebSocket.destroy(p_id)}function _godot_js_websocket_send(p_id,p_buf,p_buf_len,p_raw){const bytes_array=new Uint8Array(p_buf_len);let i=0;for(i=0;i<p_buf_len;i++){bytes_array[i]=GodotRuntime.getHeapValue(p_buf+i,"i8")}let out=bytes_array.buffer;if(!p_raw){out=new TextDecoder("utf-8").decode(bytes_array)}return GodotWebSocket.send(p_id,out)}var GodotJSWrapper={proxies:null,MyProxy:function(val){const id=IDHandler.add(this);GodotJSWrapper.proxies.set(val,id);let refs=1;this.ref=function(){refs++};this.unref=function(){refs--;if(refs===0){IDHandler.remove(id);GodotJSWrapper.proxies.delete(val)}};this.get_val=function(){return val};this.get_id=function(){return id}},get_proxied:function(val){const id=GodotJSWrapper.proxies.get(val);if(id===undefined){const proxy=new GodotJSWrapper.MyProxy(val);return proxy.get_id()}IDHandler.get(id).ref();return id},get_proxied_value:function(id){const proxy=IDHandler.get(id);if(proxy===undefined){return undefined}return proxy.get_val()},variant2js:function(type,val){switch(type){case 0:return null;case 1:return!!GodotRuntime.getHeapValue(val,"i64");case 2:return GodotRuntime.getHeapValue(val,"i64");case 3:return GodotRuntime.getHeapValue(val,"double");case 4:return GodotRuntime.parseString(GodotRuntime.getHeapValue(val,"*"));case 17:return GodotJSWrapper.get_proxied_value(GodotRuntime.getHeapValue(val,"i64"));default:return undefined}},js2variant:function(p_val,p_exchange){if(p_val===undefined||p_val===null){return 0}const type=typeof p_val;if(type==="boolean"){GodotRuntime.setHeapValue(p_exchange,p_val,"i64");return 1}else if(type==="number"){if(Number.isInteger(p_val)){GodotRuntime.setHeapValue(p_exchange,p_val,"i64");return 2}GodotRuntime.setHeapValue(p_exchange,p_val,"double");return 3}else if(type==="string"){const c_str=GodotRuntime.allocString(p_val);GodotRuntime.setHeapValue(p_exchange,c_str,"*");return 4}const id=GodotJSWrapper.get_proxied(p_val);GodotRuntime.setHeapValue(p_exchange,id,"i64");return 17}};function _godot_js_wrapper_create_cb(p_ref,p_func){const func=GodotRuntime.get_func(p_func);let id=0;const cb=function(){if(!GodotJSWrapper.get_proxied_value(id)){return}const args=Array.from(arguments);func(p_ref,GodotJSWrapper.get_proxied(args),args.length)};id=GodotJSWrapper.get_proxied(cb);return id}function _godot_js_wrapper_create_object(p_object,p_args,p_argc,p_convert_callback,p_exchange,p_lock,p_free_lock_callback){const name=GodotRuntime.parseString(p_object);if(typeof window[name]==="undefined"){return-1}const convert=GodotRuntime.get_func(p_convert_callback);const freeLock=GodotRuntime.get_func(p_free_lock_callback);const args=new Array(p_argc);for(let i=0;i<p_argc;i++){const type=convert(p_args,i,p_exchange,p_lock);const lock=GodotRuntime.getHeapValue(p_lock,"*");args[i]=GodotJSWrapper.variant2js(type,p_exchange);if(lock){freeLock(p_lock,type)}}try{const res=new window[name](...args);return GodotJSWrapper.js2variant(res,p_exchange)}catch(e){GodotRuntime.error(`Error calling constructor ${name} with args:`,args,"error:",e);return-1}}function _godot_js_wrapper_interface_get(p_name){const name=GodotRuntime.parseString(p_name);if(typeof window[name]!=="undefined"){return GodotJSWrapper.get_proxied(window[name])}return 0}function _godot_js_wrapper_object_call(p_id,p_method,p_args,p_argc,p_convert_callback,p_exchange,p_lock,p_free_lock_callback){const obj=GodotJSWrapper.get_proxied_value(p_id);if(obj===undefined){return-1}const method=GodotRuntime.parseString(p_method);const convert=GodotRuntime.get_func(p_convert_callback);const freeLock=GodotRuntime.get_func(p_free_lock_callback);const args=new Array(p_argc);for(let i=0;i<p_argc;i++){const type=convert(p_args,i,p_exchange,p_lock);const lock=GodotRuntime.getHeapValue(p_lock,"*");args[i]=GodotJSWrapper.variant2js(type,p_exchange);if(lock){freeLock(p_lock,type)}}try{const res=obj[method](...args);return GodotJSWrapper.js2variant(res,p_exchange)}catch(e){GodotRuntime.error(`Error calling method ${method} on:`,obj,"error:",e);return-1}}function _godot_js_wrapper_object_get(p_id,p_exchange,p_prop){const obj=GodotJSWrapper.get_proxied_value(p_id);if(obj===undefined){return 0}if(p_prop){const prop=GodotRuntime.parseString(p_prop);try{return GodotJSWrapper.js2variant(obj[prop],p_exchange)}catch(e){GodotRuntime.error(`Error getting variable ${prop} on object`,obj);return 0}}return GodotJSWrapper.js2variant(obj,p_exchange)}function _godot_js_wrapper_object_getvar(p_id,p_type,p_exchange){const obj=GodotJSWrapper.get_proxied_value(p_id);if(obj===undefined){return-1}const prop=GodotJSWrapper.variant2js(p_type,p_exchange);if(prop===undefined||prop===null){return-1}try{return GodotJSWrapper.js2variant(obj[prop],p_exchange)}catch(e){GodotRuntime.error(`Error getting variable ${prop} on object`,obj,e);return-1}}function _godot_js_wrapper_object_set(p_id,p_name,p_type,p_exchange){const obj=GodotJSWrapper.get_proxied_value(p_id);if(obj===undefined){return}const name=GodotRuntime.parseString(p_name);try{obj[name]=GodotJSWrapper.variant2js(p_type,p_exchange)}catch(e){GodotRuntime.error(`Error setting variable ${name} on object`,obj)}}function _godot_js_wrapper_object_setvar(p_id,p_key_type,p_key_ex,p_val_type,p_val_ex){const obj=GodotJSWrapper.get_proxied_value(p_id);if(obj===undefined){return-1}const key=GodotJSWrapper.variant2js(p_key_type,p_key_ex);try{obj[key]=GodotJSWrapper.variant2js(p_val_type,p_val_ex);return 0}catch(e){GodotRuntime.error(`Error setting variable ${key} on object`,obj);return-1}}function _godot_js_wrapper_object_unref(p_id){const proxy=IDHandler.get(p_id);if(proxy!==undefined){proxy.unref()}}var GodotWebXR={gl:null,session:null,space:null,frame:null,pose:null,orig_requestAnimationFrame:null,requestAnimationFrame:callback=>{if(GodotWebXR.session&&GodotWebXR.space){const onFrame=function(time,frame){GodotWebXR.frame=frame;GodotWebXR.pose=frame.getViewerPose(GodotWebXR.space);callback(time);GodotWebXR.frame=null;GodotWebXR.pose=null};GodotWebXR.session.requestAnimationFrame(onFrame)}else{GodotWebXR.orig_requestAnimationFrame(callback)}},monkeyPatchRequestAnimationFrame:enable=>{if(GodotWebXR.orig_requestAnimationFrame===null){GodotWebXR.orig_requestAnimationFrame=Browser.requestAnimationFrame}Browser.requestAnimationFrame=enable?GodotWebXR.requestAnimationFrame:GodotWebXR.orig_requestAnimationFrame},pauseResumeMainLoop:()=>{Browser.mainLoop.pause();window.setTimeout(function(){Browser.mainLoop.resume()},0)},shaderProgram:null,programInfo:null,buffer:null,vsSource:"\n\t\t\tconst vec2 scale = vec2(0.5, 0.5);\n\t\t\tattribute vec4 aVertexPosition;\n\n\t\t\tvarying highp vec2 vTextureCoord;\n\n\t\t\tvoid main () {\n\t\t\t\tgl_Position = aVertexPosition;\n\t\t\t\tvTextureCoord = aVertexPosition.xy * scale + scale;\n\t\t\t}\n\t\t",fsSource:"\n\t\t\tvarying highp vec2 vTextureCoord;\n\n\t\t\tuniform sampler2D uSampler;\n\n\t\t\tvoid main() {\n\t\t\t\tgl_FragColor = texture2D(uSampler, vTextureCoord);\n\t\t\t}\n\t\t",initShaderProgram:(gl,vsSource,fsSource)=>{const vertexShader=GodotWebXR.loadShader(gl,gl.VERTEX_SHADER,vsSource);const fragmentShader=GodotWebXR.loadShader(gl,gl.FRAGMENT_SHADER,fsSource);const shaderProgram=gl.createProgram();gl.attachShader(shaderProgram,vertexShader);gl.attachShader(shaderProgram,fragmentShader);gl.linkProgram(shaderProgram);if(!gl.getProgramParameter(shaderProgram,gl.LINK_STATUS)){GodotRuntime.error(`Unable to initialize the shader program: ${gl.getProgramInfoLog(shaderProgram)}`);return null}return shaderProgram},loadShader:(gl,type,source)=>{const shader=gl.createShader(type);gl.shaderSource(shader,source);gl.compileShader(shader);if(!gl.getShaderParameter(shader,gl.COMPILE_STATUS)){GodotRuntime.error(`An error occurred compiling the shader: ${gl.getShaderInfoLog(shader)}`);gl.deleteShader(shader);return null}return shader},initBuffer:gl=>{const positionBuffer=gl.createBuffer();gl.bindBuffer(gl.ARRAY_BUFFER,positionBuffer);const positions=[-1,-1,1,-1,-1,1,1,1];gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(positions),gl.STATIC_DRAW);return positionBuffer},blitTexture:(gl,texture)=>{if(GodotWebXR.shaderProgram===null){GodotWebXR.shaderProgram=GodotWebXR.initShaderProgram(gl,GodotWebXR.vsSource,GodotWebXR.fsSource);GodotWebXR.programInfo={program:GodotWebXR.shaderProgram,attribLocations:{vertexPosition:gl.getAttribLocation(GodotWebXR.shaderProgram,"aVertexPosition")},uniformLocations:{uSampler:gl.getUniformLocation(GodotWebXR.shaderProgram,"uSampler")}};GodotWebXR.buffer=GodotWebXR.initBuffer(gl)}const orig_program=gl.getParameter(gl.CURRENT_PROGRAM);gl.useProgram(GodotWebXR.shaderProgram);gl.bindBuffer(gl.ARRAY_BUFFER,GodotWebXR.buffer);gl.vertexAttribPointer(GodotWebXR.programInfo.attribLocations.vertexPosition,2,gl.FLOAT,false,0,0);gl.enableVertexAttribArray(GodotWebXR.programInfo.attribLocations.vertexPosition);gl.activeTexture(gl.TEXTURE0);gl.bindTexture(gl.TEXTURE_2D,texture);gl.uniform1i(GodotWebXR.programInfo.uniformLocations.uSampler,0);gl.drawArrays(gl.TRIANGLE_STRIP,0,4);gl.bindTexture(gl.TEXTURE_2D,null);gl.disableVertexAttribArray(GodotWebXR.programInfo.attribLocations.vertexPosition);gl.bindBuffer(gl.ARRAY_BUFFER,null);gl.useProgram(orig_program)},controllers:[],sampleControllers:()=>{if(!GodotWebXR.session){return}let other_index=2;const controllers=[];GodotWebXR.session.inputSources.forEach(input_source=>{if(input_source.targetRayMode==="tracked-pointer"){if(input_source.handedness==="right"){controllers[1]=input_source}else if(input_source.handedness==="left"||!controllers[0]){controllers[0]=input_source}}else{controllers[other_index++]=input_source}});GodotWebXR.controllers=controllers},getControllerId:input_source=>GodotWebXR.controllers.indexOf(input_source)};function _godot_webxr_commit_for_eye(p_eye,p_texture_id){if(!GodotWebXR.session||!GodotWebXR.pose){return}const view_index=p_eye===2?1:0;const glLayer=GodotWebXR.session.renderState.baseLayer;const view=GodotWebXR.pose.views[view_index];const viewport=glLayer.getViewport(view);const gl=GodotWebXR.gl;const orig_framebuffer=gl.getParameter(gl.FRAMEBUFFER_BINDING);const orig_viewport=gl.getParameter(gl.VIEWPORT);gl.bindFramebuffer(gl.FRAMEBUFFER,glLayer.framebuffer);gl.viewport(viewport.x,viewport.y,viewport.width,viewport.height);GodotWebXR.blitTexture(gl,GL.textures[p_texture_id]);gl.bindFramebuffer(gl.FRAMEBUFFER,orig_framebuffer);gl.viewport(orig_viewport[0],orig_viewport[1],orig_viewport[2],orig_viewport[3])}function _godot_webxr_get_bounds_geometry(){if(!GodotWebXR.space||!GodotWebXR.space.boundsGeometry){return 0}const point_count=GodotWebXR.space.boundsGeometry.length;if(point_count===0){return 0}const buf=GodotRuntime.malloc((point_count*3+1)*4);GodotRuntime.setHeapValue(buf,point_count,"i32");for(let i=0;i<point_count;i++){const point=GodotWebXR.space.boundsGeometry[i];GodotRuntime.setHeapValue(buf+(i*3+1)*4,point.x,"float");GodotRuntime.setHeapValue(buf+(i*3+2)*4,point.y,"float");GodotRuntime.setHeapValue(buf+(i*3+3)*4,point.z,"float")}return buf}function _godot_webxr_get_controller_axes(p_controller,p_xr_standard_mapping){if(GodotWebXR.controllers.length===0){return 0}const controller=GodotWebXR.controllers[p_controller];if(!controller||!controller.gamepad){return 0}let axes=controller.gamepad.axes;if(controller.gamepad.mapping==="xr-standard"){if(p_xr_standard_mapping){const trigger_axis=controller.gamepad.buttons[0].value;const grip_axis=controller.gamepad.buttons[1].value;axes=[axes[2],axes[3]*-1,trigger_axis,grip_axis,grip_axis,0,axes[0],axes[1]*-1]}else{axes[1]*=-1;axes[3]*=-1}}const buf=GodotRuntime.malloc((axes.length+1)*4);GodotRuntime.setHeapValue(buf,axes.length,"i32");for(let i=0;i<axes.length;i++){GodotRuntime.setHeapValue(buf+4+i*4,axes[i],"float")}return buf}function _godot_webxr_get_controller_buttons(p_controller,p_xr_standard_mapping){if(GodotWebXR.controllers.length===0){return 0}const controller=GodotWebXR.controllers[p_controller];if(!controller||!controller.gamepad){return 0}let buttons=controller.gamepad.buttons;if(controller.gamepad.mapping==="xr-standard"&&p_xr_standard_mapping){buttons=[0,buttons[5],buttons[1],buttons[3],buttons[6],buttons[7],buttons[8],buttons[4],buttons[9],buttons[10],buttons[11],buttons[12],buttons[13],buttons[14],buttons[2],buttons[0]]}const buf=GodotRuntime.malloc((buttons.length+1)*4);GodotRuntime.setHeapValue(buf,buttons.length,"i32");for(let i=0;i<buttons.length;i++){GodotRuntime.setHeapValue(buf+4+i*4,buttons[i]?buttons[i].value:0,"float")}return buf}function _godot_webxr_get_controller_count(){if(!GodotWebXR.session||!GodotWebXR.frame){return 0}return GodotWebXR.controllers.length}function _godot_webxr_get_controller_target_ray_mode(p_controller){if(p_controller<0||p_controller>=GodotWebXR.controllers.length){return 0}const controller=GodotWebXR.controllers[p_controller];if(!controller){return 0}switch(controller.targetRayMode){case"gaze":return 1;case"tracked-pointer":return 2;case"screen":return 3;default:break}return 0}function _godot_webxr_get_controller_transform(p_controller){if(!GodotWebXR.session||!GodotWebXR.frame){return 0}const controller=GodotWebXR.controllers[p_controller];if(!controller){return 0}const frame=GodotWebXR.frame;const space=GodotWebXR.space;const pose=frame.getPose(controller.targetRaySpace,space);if(!pose){return 0}const matrix=pose.transform.matrix;const buf=GodotRuntime.malloc(16*4);for(let i=0;i<16;i++){GodotRuntime.setHeapValue(buf+i*4,matrix[i],"float")}return buf}function _godot_webxr_get_projection_for_eye(p_eye){if(!GodotWebXR.session||!GodotWebXR.pose){return 0}const view_index=p_eye===2?1:0;const matrix=GodotWebXR.pose.views[view_index].projectionMatrix;const buf=GodotRuntime.malloc(16*4);for(let i=0;i<16;i++){GodotRuntime.setHeapValue(buf+i*4,matrix[i],"float")}return buf}function _godot_webxr_get_render_targetsize(){if(!GodotWebXR.session||!GodotWebXR.pose){return 0}const glLayer=GodotWebXR.session.renderState.baseLayer;const view=GodotWebXR.pose.views[0];const viewport=glLayer.getViewport(view);const buf=GodotRuntime.malloc(2*4);GodotRuntime.setHeapValue(buf+0,viewport.width,"i32");GodotRuntime.setHeapValue(buf+4,viewport.height,"i32");return buf}function _godot_webxr_get_transform_for_eye(p_eye){if(!GodotWebXR.session||!GodotWebXR.pose){return 0}const views=GodotWebXR.pose.views;let matrix;if(p_eye===0){matrix=GodotWebXR.pose.transform.matrix}else{matrix=views[p_eye-1].transform.matrix}const buf=GodotRuntime.malloc(16*4);for(let i=0;i<16;i++){GodotRuntime.setHeapValue(buf+i*4,matrix[i],"float")}return buf}function _godot_webxr_get_view_count(){if(!GodotWebXR.session||!GodotWebXR.pose){return 0}return GodotWebXR.pose.views.length}function _godot_webxr_get_visibility_state(){if(!GodotWebXR.session||!GodotWebXR.session.visibilityState){return 0}return GodotRuntime.allocString(GodotWebXR.session.visibilityState)}function _godot_webxr_initialize(p_session_mode,p_required_features,p_optional_features,p_requested_reference_spaces,p_on_session_started,p_on_session_ended,p_on_session_failed,p_on_controller_changed,p_on_input_event,p_on_simple_event){GodotWebXR.monkeyPatchRequestAnimationFrame(true);const session_mode=GodotRuntime.parseString(p_session_mode);const required_features=GodotRuntime.parseString(p_required_features).split(",").map(s=>s.trim()).filter(s=>s!=="");const optional_features=GodotRuntime.parseString(p_optional_features).split(",").map(s=>s.trim()).filter(s=>s!=="");const requested_reference_space_types=GodotRuntime.parseString(p_requested_reference_spaces).split(",").map(s=>s.trim());const onstarted=GodotRuntime.get_func(p_on_session_started);const onended=GodotRuntime.get_func(p_on_session_ended);const onfailed=GodotRuntime.get_func(p_on_session_failed);const oncontroller=GodotRuntime.get_func(p_on_controller_changed);const oninputevent=GodotRuntime.get_func(p_on_input_event);const onsimpleevent=GodotRuntime.get_func(p_on_simple_event);const session_init={};if(required_features.length>0){session_init["requiredFeatures"]=required_features}if(optional_features.length>0){session_init["optionalFeatures"]=optional_features}navigator.xr.requestSession(session_mode,session_init).then(function(session){GodotWebXR.session=session;session.addEventListener("end",function(evt){onended()});session.addEventListener("inputsourceschange",function(evt){let controller_changed=false;[evt.added,evt.removed].forEach(lst=>{lst.forEach(input_source=>{if(input_source.targetRayMode==="tracked-pointer"){controller_changed=true}})});if(controller_changed){oncontroller()}});["selectstart","selectend","select","squeezestart","squeezeend","squeeze"].forEach((input_event,index)=>{session.addEventListener(input_event,function(evt){GodotWebXR.sampleControllers();oninputevent(index,GodotWebXR.getControllerId(evt.inputSource))})});session.addEventListener("visibilitychange",function(evt){const c_str=GodotRuntime.allocString("visibility_state_changed");onsimpleevent(c_str);GodotRuntime.free(c_str)});const gl_context_handle=_emscripten_webgl_get_current_context();const gl=GL.getContext(gl_context_handle).GLctx;GodotWebXR.gl=gl;gl.makeXRCompatible().then(function(){session.updateRenderState({baseLayer:new XRWebGLLayer(session,gl)});function onReferenceSpaceSuccess(reference_space,reference_space_type){GodotWebXR.space=reference_space;reference_space.onreset=function(evt){const c_str=GodotRuntime.allocString("reference_space_reset");onsimpleevent(c_str);GodotRuntime.free(c_str)};GodotWebXR.pauseResumeMainLoop();window.setTimeout(function(){const c_str=GodotRuntime.allocString(reference_space_type);onstarted(c_str);GodotRuntime.free(c_str)},0)}function requestReferenceSpace(){const reference_space_type=requested_reference_space_types.shift();session.requestReferenceSpace(reference_space_type).then(refSpace=>{onReferenceSpaceSuccess(refSpace,reference_space_type)}).catch(()=>{if(requested_reference_space_types.length===0){const c_str=GodotRuntime.allocString("Unable to get any of the requested reference space types");onfailed(c_str);GodotRuntime.free(c_str)}else{requestReferenceSpace()}})}requestReferenceSpace()}).catch(function(error){const c_str=GodotRuntime.allocString(`Unable to make WebGL context compatible with WebXR: ${error}`);onfailed(c_str);GodotRuntime.free(c_str)})}).catch(function(error){const c_str=GodotRuntime.allocString(`Unable to start session: ${error}`);onfailed(c_str);GodotRuntime.free(c_str)})}function _godot_webxr_is_controller_connected(p_controller){if(!GodotWebXR.session||!GodotWebXR.frame){return false}return!!GodotWebXR.controllers[p_controller]}function _godot_webxr_is_session_supported(p_session_mode,p_callback){const session_mode=GodotRuntime.parseString(p_session_mode);const cb=GodotRuntime.get_func(p_callback);if(navigator.xr){navigator.xr.isSessionSupported(session_mode).then(function(supported){const c_str=GodotRuntime.allocString(session_mode);cb(c_str,supported?1:0);GodotRuntime.free(c_str)})}else{const c_str=GodotRuntime.allocString(session_mode);cb(c_str,0);GodotRuntime.free(c_str)}}function _godot_webxr_is_supported(){return!!navigator.xr}function _godot_webxr_sample_controller_data(){GodotWebXR.sampleControllers()}function _godot_webxr_uninitialize(){if(GodotWebXR.session){GodotWebXR.session.end().catch(e=>{})}GodotWebXR.session=null;GodotWebXR.space=null;GodotWebXR.frame=null;GodotWebXR.pose=null;GodotWebXR.monkeyPatchRequestAnimationFrame(false);GodotWebXR.pauseResumeMainLoop()}function _setTempRet0(val){setTempRet0(val)}function __isLeapYear(year){return year%4===0&&(year%100!==0||year%400===0)}function __arraySum(array,index){var sum=0;for(var i=0;i<=index;sum+=array[i++]){}return sum}var __MONTH_DAYS_LEAP=[31,29,31,30,31,30,31,31,30,31,30,31];var __MONTH_DAYS_REGULAR=[31,28,31,30,31,30,31,31,30,31,30,31];function __addDays(date,days){var newDate=new Date(date.getTime());while(days>0){var leap=__isLeapYear(newDate.getFullYear());var currentMonth=newDate.getMonth();var daysInCurrentMonth=(leap?__MONTH_DAYS_LEAP:__MONTH_DAYS_REGULAR)[currentMonth];if(days>daysInCurrentMonth-newDate.getDate()){days-=daysInCurrentMonth-newDate.getDate()+1;newDate.setDate(1);if(currentMonth<11){newDate.setMonth(currentMonth+1)}else{newDate.setMonth(0);newDate.setFullYear(newDate.getFullYear()+1)}}else{newDate.setDate(newDate.getDate()+days);return newDate}}return newDate}function _strftime(s,maxsize,format,tm){var tm_zone=HEAP32[tm+40>>2];var date={tm_sec:HEAP32[tm>>2],tm_min:HEAP32[tm+4>>2],tm_hour:HEAP32[tm+8>>2],tm_mday:HEAP32[tm+12>>2],tm_mon:HEAP32[tm+16>>2],tm_year:HEAP32[tm+20>>2],tm_wday:HEAP32[tm+24>>2],tm_yday:HEAP32[tm+28>>2],tm_isdst:HEAP32[tm+32>>2],tm_gmtoff:HEAP32[tm+36>>2],tm_zone:tm_zone?UTF8ToString(tm_zone):""};var pattern=UTF8ToString(format);var EXPANSION_RULES_1={"%c":"%a %b %d %H:%M:%S %Y","%D":"%m/%d/%y","%F":"%Y-%m-%d","%h":"%b","%r":"%I:%M:%S %p","%R":"%H:%M","%T":"%H:%M:%S","%x":"%m/%d/%y","%X":"%H:%M:%S","%Ec":"%c","%EC":"%C","%Ex":"%m/%d/%y","%EX":"%H:%M:%S","%Ey":"%y","%EY":"%Y","%Od":"%d","%Oe":"%e","%OH":"%H","%OI":"%I","%Om":"%m","%OM":"%M","%OS":"%S","%Ou":"%u","%OU":"%U","%OV":"%V","%Ow":"%w","%OW":"%W","%Oy":"%y"};for(var rule in EXPANSION_RULES_1){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_1[rule])}var WEEKDAYS=["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"];var MONTHS=["January","February","March","April","May","June","July","August","September","October","November","December"];function leadingSomething(value,digits,character){var str=typeof value=="number"?value.toString():value||"";while(str.length<digits){str=character[0]+str}return str}function leadingNulls(value,digits){return leadingSomething(value,digits,"0")}function compareByDay(date1,date2){function sgn(value){return value<0?-1:value>0?1:0}var compare;if((compare=sgn(date1.getFullYear()-date2.getFullYear()))===0){if((compare=sgn(date1.getMonth()-date2.getMonth()))===0){compare=sgn(date1.getDate()-date2.getDate())}}return compare}function getFirstWeekStartDate(janFourth){switch(janFourth.getDay()){case 0:return new Date(janFourth.getFullYear()-1,11,29);case 1:return janFourth;case 2:return new Date(janFourth.getFullYear(),0,3);case 3:return new Date(janFourth.getFullYear(),0,2);case 4:return new Date(janFourth.getFullYear(),0,1);case 5:return new Date(janFourth.getFullYear()-1,11,31);case 6:return new Date(janFourth.getFullYear()-1,11,30)}}function getWeekBasedYear(date){var thisDate=__addDays(new Date(date.tm_year+1900,0,1),date.tm_yday);var janFourthThisYear=new Date(thisDate.getFullYear(),0,4);var janFourthNextYear=new Date(thisDate.getFullYear()+1,0,4);var firstWeekStartThisYear=getFirstWeekStartDate(janFourthThisYear);var firstWeekStartNextYear=getFirstWeekStartDate(janFourthNextYear);if(compareByDay(firstWeekStartThisYear,thisDate)<=0){if(compareByDay(firstWeekStartNextYear,thisDate)<=0){return thisDate.getFullYear()+1}else{return thisDate.getFullYear()}}else{return thisDate.getFullYear()-1}}var EXPANSION_RULES_2={"%a":function(date){return WEEKDAYS[date.tm_wday].substring(0,3)},"%A":function(date){return WEEKDAYS[date.tm_wday]},"%b":function(date){return MONTHS[date.tm_mon].substring(0,3)},"%B":function(date){return MONTHS[date.tm_mon]},"%C":function(date){var year=date.tm_year+1900;return leadingNulls(year/100|0,2)},"%d":function(date){return leadingNulls(date.tm_mday,2)},"%e":function(date){return leadingSomething(date.tm_mday,2," ")},"%g":function(date){return getWeekBasedYear(date).toString().substring(2)},"%G":function(date){return getWeekBasedYear(date)},"%H":function(date){return leadingNulls(date.tm_hour,2)},"%I":function(date){var twelveHour=date.tm_hour;if(twelveHour==0)twelveHour=12;else if(twelveHour>12)twelveHour-=12;return leadingNulls(twelveHour,2)},"%j":function(date){return leadingNulls(date.tm_mday+__arraySum(__isLeapYear(date.tm_year+1900)?__MONTH_DAYS_LEAP:__MONTH_DAYS_REGULAR,date.tm_mon-1),3)},"%m":function(date){return leadingNulls(date.tm_mon+1,2)},"%M":function(date){return leadingNulls(date.tm_min,2)},"%n":function(){return"\n"},"%p":function(date){if(date.tm_hour>=0&&date.tm_hour<12){return"AM"}else{return"PM"}},"%S":function(date){return leadingNulls(date.tm_sec,2)},"%t":function(){return"\t"},"%u":function(date){return date.tm_wday||7},"%U":function(date){var days=date.tm_yday+7-date.tm_wday;return leadingNulls(Math.floor(days/7),2)},"%V":function(date){var val=Math.floor((date.tm_yday+7-(date.tm_wday+6)%7)/7);if((date.tm_wday+371-date.tm_yday-2)%7<=2){val++}if(!val){val=52;var dec31=(date.tm_wday+7-date.tm_yday-1)%7;if(dec31==4||dec31==5&&__isLeapYear(date.tm_year%400-1)){val++}}else if(val==53){var jan1=(date.tm_wday+371-date.tm_yday)%7;if(jan1!=4&&(jan1!=3||!__isLeapYear(date.tm_year)))val=1}return leadingNulls(val,2)},"%w":function(date){return date.tm_wday},"%W":function(date){var days=date.tm_yday+7-(date.tm_wday+6)%7;return leadingNulls(Math.floor(days/7),2)},"%y":function(date){return(date.tm_year+1900).toString().substring(2)},"%Y":function(date){return date.tm_year+1900},"%z":function(date){var off=date.tm_gmtoff;var ahead=off>=0;off=Math.abs(off)/60;off=off/60*100+off%60;return(ahead?"+":"-")+String("0000"+off).slice(-4)},"%Z":function(date){return date.tm_zone},"%%":function(){return"%"}};pattern=pattern.replace(/%%/g,"\0\0");for(var rule in EXPANSION_RULES_2){if(pattern.includes(rule)){pattern=pattern.replace(new RegExp(rule,"g"),EXPANSION_RULES_2[rule](date))}}pattern=pattern.replace(/\0\0/g,"%");var bytes=intArrayFromString(pattern,false);if(bytes.length>maxsize){return 0}writeArrayToMemory(bytes,s);return bytes.length-1}function _strftime_l(s,maxsize,format,tm){return _strftime(s,maxsize,format,tm)}var FSNode=function(parent,name,mode,rdev){if(!parent){parent=this}this.parent=parent;this.mount=parent.mount;this.mounted=null;this.id=FS.nextInode++;this.name=name;this.mode=mode;this.node_ops={};this.stream_ops={};this.rdev=rdev};var readMode=292|73;var writeMode=146;Object.defineProperties(FSNode.prototype,{read:{get:function(){return(this.mode&readMode)===readMode},set:function(val){val?this.mode|=readMode:this.mode&=~readMode}},write:{get:function(){return(this.mode&writeMode)===writeMode},set:function(val){val?this.mode|=writeMode:this.mode&=~writeMode}},isFolder:{get:function(){return FS.isDir(this.mode)}},isDevice:{get:function(){return FS.isChrdev(this.mode)}}});FS.FSNode=FSNode;FS.staticInit();Module["requestFullscreen"]=function Module_requestFullscreen(lockPointer,resizeCanvas){Browser.requestFullscreen(lockPointer,resizeCanvas)};Module["requestAnimationFrame"]=function Module_requestAnimationFrame(func){Browser.requestAnimationFrame(func)};Module["setCanvasSize"]=function Module_setCanvasSize(width,height,noUpdates){Browser.setCanvasSize(width,height,noUpdates)};Module["pauseMainLoop"]=function Module_pauseMainLoop(){Browser.mainLoop.pause()};Module["resumeMainLoop"]=function Module_resumeMainLoop(){Browser.mainLoop.resume()};Module["getUserMedia"]=function Module_getUserMedia(){Browser.getUserMedia()};Module["createContext"]=function Module_createContext(canvas,useWebGL,setInModule,webGLContextAttributes){return Browser.createContext(canvas,useWebGL,setInModule,webGLContextAttributes)};var preloadedImages={};var preloadedAudios={};var GLctx;for(var i=0;i<32;++i)tempFixedLengthArray.push(new Array(i));var miniTempWebGLFloatBuffersStorage=new Float32Array(288);for(var i=0;i<288;++i){miniTempWebGLFloatBuffers[i]=miniTempWebGLFloatBuffersStorage.subarray(0,i+1)}var __miniTempWebGLIntBuffersStorage=new Int32Array(288);for(var i=0;i<288;++i){__miniTempWebGLIntBuffers[i]=__miniTempWebGLIntBuffersStorage.subarray(0,i+1)}Module["request_quit"]=function(){GodotOS.request_quit()};Module["onExit"]=GodotOS.cleanup;GodotOS._fs_sync_promise=Promise.resolve();Module["initConfig"]=GodotConfig.init_config;Module["initFS"]=GodotFS.init;Module["copyToFS"]=GodotFS.copy_to_fs;ERRNO_CODES={"EPERM":63,"ENOENT":44,"ESRCH":71,"EINTR":27,"EIO":29,"ENXIO":60,"E2BIG":1,"ENOEXEC":45,"EBADF":8,"ECHILD":12,"EAGAIN":6,"EWOULDBLOCK":6,"ENOMEM":48,"EACCES":2,"EFAULT":21,"ENOTBLK":105,"EBUSY":10,"EEXIST":20,"EXDEV":75,"ENODEV":43,"ENOTDIR":54,"EISDIR":31,"EINVAL":28,"ENFILE":41,"EMFILE":33,"ENOTTY":59,"ETXTBSY":74,"EFBIG":22,"ENOSPC":51,"ESPIPE":70,"EROFS":69,"EMLINK":34,"EPIPE":64,"EDOM":18,"ERANGE":68,"ENOMSG":49,"EIDRM":24,"ECHRNG":106,"EL2NSYNC":156,"EL3HLT":107,"EL3RST":108,"ELNRNG":109,"EUNATCH":110,"ENOCSI":111,"EL2HLT":112,"EDEADLK":16,"ENOLCK":46,"EBADE":113,"EBADR":114,"EXFULL":115,"ENOANO":104,"EBADRQC":103,"EBADSLT":102,"EDEADLOCK":16,"EBFONT":101,"ENOSTR":100,"ENODATA":116,"ETIME":117,"ENOSR":118,"ENONET":119,"ENOPKG":120,"EREMOTE":121,"ENOLINK":47,"EADV":122,"ESRMNT":123,"ECOMM":124,"EPROTO":65,"EMULTIHOP":36,"EDOTDOT":125,"EBADMSG":9,"ENOTUNIQ":126,"EBADFD":127,"EREMCHG":128,"ELIBACC":129,"ELIBBAD":130,"ELIBSCN":131,"ELIBMAX":132,"ELIBEXEC":133,"ENOSYS":52,"ENOTEMPTY":55,"ENAMETOOLONG":37,"ELOOP":32,"EOPNOTSUPP":138,"EPFNOSUPPORT":139,"ECONNRESET":15,"ENOBUFS":42,"EAFNOSUPPORT":5,"EPROTOTYPE":67,"ENOTSOCK":57,"ENOPROTOOPT":50,"ESHUTDOWN":140,"ECONNREFUSED":14,"EADDRINUSE":3,"ECONNABORTED":13,"ENETUNREACH":40,"ENETDOWN":38,"ETIMEDOUT":73,"EHOSTDOWN":142,"EHOSTUNREACH":23,"EINPROGRESS":26,"EALREADY":7,"EDESTADDRREQ":17,"EMSGSIZE":35,"EPROTONOSUPPORT":66,"ESOCKTNOSUPPORT":137,"EADDRNOTAVAIL":4,"ENETRESET":39,"EISCONN":30,"ENOTCONN":53,"ETOOMANYREFS":141,"EUSERS":136,"EDQUOT":19,"ESTALE":72,"ENOTSUP":138,"ENOMEDIUM":148,"EILSEQ":25,"EOVERFLOW":61,"ECANCELED":11,"ENOTRECOVERABLE":56,"EOWNERDEAD":62,"ESTRPIPE":135};GodotOS.atexit(function(resolve,reject){GodotDisplayCursor.clear();resolve()});GodotOS.atexit(function(resolve,reject){GodotEventListeners.clear();resolve()});GodotOS.atexit(function(resolve,reject){GodotDisplayVK.clear();resolve()});GodotJSWrapper.proxies=new Map;function intArrayFromString(stringy,dontAddNull,length){var len=length>0?length:lengthBytesUTF8(stringy)+1;var u8array=new Array(len);var numBytesWritten=stringToUTF8Array(stringy,u8array,0,u8array.length);if(dontAddNull)u8array.length=numBytesWritten;return u8array}var asmLibraryArg={"Xc":___call_sighandler,"Rc":___syscall__newselect,"Mc":___syscall_accept4,"Lc":___syscall_bind,"rd":___syscall_chdir,"qd":___syscall_chmod,"Kc":___syscall_connect,"sd":___syscall_faccessat,"Fa":___syscall_fcntl64,"fd":___syscall_getcwd,"Wc":___syscall_getdents64,"Jc":___syscall_getsockname,"Ic":___syscall_getsockopt,"mb":___syscall_ioctl,"Hc":___syscall_listen,"ad":___syscall_lstat64,"_c":___syscall_mkdirat,"$c":___syscall_newfstatat,"nb":___syscall_openat,"Zc":___syscall_poll,"Vc":___syscall_readlinkat,"Gc":___syscall_recvfrom,"Sc":___syscall_renameat,"Tc":___syscall_rmdir,"Fc":___syscall_sendto,"jb":___syscall_socket,"bd":___syscall_stat64,"Qc":___syscall_statfs64,"Pc":___syscall_symlink,"Uc":___syscall_unlinkat,"nd":__dlinit,"pd":__dlopen_js,"od":__dlsym_js,"Va":__emscripten_date_now,"id":__emscripten_get_now_is_monotonic,"Ec":__emscripten_throw_longjmp,"jd":__gmtime_js,"kd":__localtime_js,"md":__tzset_js,"ja":_abort,"qb":_emscripten_cancel_main_loop,"Jh":_emscripten_force_exit,"Ua":_emscripten_get_now,"yi":_emscripten_glActiveTexture,"xi":_emscripten_glAttachShader,"mf":_emscripten_glBeginQuery,"Qi":_emscripten_glBeginQueryEXT,"Ue":_emscripten_glBeginTransformFeedback,"wi":_emscripten_glBindAttribLocation,"vi":_emscripten_glBindBuffer,"Qe":_emscripten_glBindBufferBase,"Re":_emscripten_glBindBufferRange,"ui":_emscripten_glBindFramebuffer,"ti":_emscripten_glBindRenderbuffer,"Td":_emscripten_glBindSampler,"si":_emscripten_glBindTexture,"Kd":_emscripten_glBindTransformFeedback,"Ze":_emscripten_glBindVertexArray,"Hi":_emscripten_glBindVertexArrayOES,"ri":_emscripten_glBlendColor,"qi":_emscripten_glBlendEquation,"pi":_emscripten_glBlendEquationSeparate,"ni":_emscripten_glBlendFunc,"mi":_emscripten_glBlendFuncSeparate,"af":_emscripten_glBlitFramebuffer,"li":_emscripten_glBufferData,"ki":_emscripten_glBufferSubData,"ji":_emscripten_glCheckFramebufferStatus,"ii":_emscripten_glClear,"re":_emscripten_glClearBufferfi,"se":_emscripten_glClearBufferfv,"ue":_emscripten_glClearBufferiv,"te":_emscripten_glClearBufferuiv,"hi":_emscripten_glClearColor,"gi":_emscripten_glClearDepthf,"fi":_emscripten_glClearStencil,"ce":_emscripten_glClientWaitSync,"ei":_emscripten_glColorMask,"bi":_emscripten_glCompileShader,"ai":_emscripten_glCompressedTexImage2D,"rf":_emscripten_glCompressedTexImage3D,"$h":_emscripten_glCompressedTexSubImage2D,"qf":_emscripten_glCompressedTexSubImage3D,"pe":_emscripten_glCopyBufferSubData,"_h":_emscripten_glCopyTexImage2D,"Zh":_emscripten_glCopyTexSubImage2D,"sf":_emscripten_glCopyTexSubImage3D,"Yh":_emscripten_glCreateProgram,"Xh":_emscripten_glCreateShader,"Wh":_emscripten_glCullFace,"Vh":_emscripten_glDeleteBuffers,"Uh":_emscripten_glDeleteFramebuffers,"Th":_emscripten_glDeleteProgram,"of":_emscripten_glDeleteQueries,"Si":_emscripten_glDeleteQueriesEXT,"Sh":_emscripten_glDeleteRenderbuffers,"Vd":_emscripten_glDeleteSamplers,"Rh":_emscripten_glDeleteShader,"de":_emscripten_glDeleteSync,"Qh":_emscripten_glDeleteTextures,"Jd":_emscripten_glDeleteTransformFeedbacks,"Ye":_emscripten_glDeleteVertexArrays,"Gi":_emscripten_glDeleteVertexArraysOES,"Ph":_emscripten_glDepthFunc,"Oh":_emscripten_glDepthMask,"Nh":_emscripten_glDepthRangef,"Mh":_emscripten_glDetachShader,"Lh":_emscripten_glDisable,"Kh":_emscripten_glDisableVertexAttribArray,"Ih":_emscripten_glDrawArrays,"he":_emscripten_glDrawArraysInstanced,"Ci":_emscripten_glDrawArraysInstancedANGLE,"Bf":_emscripten_glDrawArraysInstancedARB,"Cf":_emscripten_glDrawArraysInstancedEXT,"td":_emscripten_glDrawArraysInstancedNV,"hf":_emscripten_glDrawBuffers,"xf":_emscripten_glDrawBuffersEXT,"Di":_emscripten_glDrawBuffersWEBGL,"Hh":_emscripten_glDrawElements,"ge":_emscripten_glDrawElementsInstanced,"Bi":_emscripten_glDrawElementsInstancedANGLE,"yf":_emscripten_glDrawElementsInstancedARB,"zf":_emscripten_glDrawElementsInstancedEXT,"Af":_emscripten_glDrawElementsInstancedNV,"vf":_emscripten_glDrawRangeElements,"Gh":_emscripten_glEnable,"Fh":_emscripten_glEnableVertexAttribArray,"lf":_emscripten_glEndQuery,"Pi":_emscripten_glEndQueryEXT,"Se":_emscripten_glEndTransformFeedback,"fe":_emscripten_glFenceSync,"Eh":_emscripten_glFinish,"Dh":_emscripten_glFlush,"Ch":_emscripten_glFramebufferRenderbuffer,"Bh":_emscripten_glFramebufferTexture2D,"_e":_emscripten_glFramebufferTextureLayer,"Ah":_emscripten_glFrontFace,"zh":_emscripten_glGenBuffers,"xh":_emscripten_glGenFramebuffers,"pf":_emscripten_glGenQueries,"Ti":_emscripten_glGenQueriesEXT,"wh":_emscripten_glGenRenderbuffers,"Wd":_emscripten_glGenSamplers,"vh":_emscripten_glGenTextures,"Id":_emscripten_glGenTransformFeedbacks,"Xe":_emscripten_glGenVertexArrays,"Fi":_emscripten_glGenVertexArraysOES,"yh":_emscripten_glGenerateMipmap,"uh":_emscripten_glGetActiveAttrib,"th":_emscripten_glGetActiveUniform,"je":_emscripten_glGetActiveUniformBlockName,"ke":_emscripten_glGetActiveUniformBlockiv,"ne":_emscripten_glGetActiveUniformsiv,"sh":_emscripten_glGetAttachedShaders,"rh":_emscripten_glGetAttribLocation,"qh":_emscripten_glGetBooleanv,"Xd":_emscripten_glGetBufferParameteri64v,"ph":_emscripten_glGetBufferParameteriv,"nh":_emscripten_glGetError,"mh":_emscripten_glGetFloatv,"Ee":_emscripten_glGetFragDataLocation,"lh":_emscripten_glGetFramebufferAttachmentParameteriv,"Yd":_emscripten_glGetInteger64i_v,"_d":_emscripten_glGetInteger64v,"Ve":_emscripten_glGetIntegeri_v,"kh":_emscripten_glGetIntegerv,"wd":_emscripten_glGetInternalformativ,"Dd":_emscripten_glGetProgramBinary,"ih":_emscripten_glGetProgramInfoLog,"jh":_emscripten_glGetProgramiv,"Ji":_emscripten_glGetQueryObjecti64vEXT,"Mi":_emscripten_glGetQueryObjectivEXT,"Ii":_emscripten_glGetQueryObjectui64vEXT,"jf":_emscripten_glGetQueryObjectuiv,"Li":_emscripten_glGetQueryObjectuivEXT,"kf":_emscripten_glGetQueryiv,"Ni":_emscripten_glGetQueryivEXT,"hh":_emscripten_glGetRenderbufferParameteriv,"Md":_emscripten_glGetSamplerParameterfv,"Nd":_emscripten_glGetSamplerParameteriv,"fh":_emscripten_glGetShaderInfoLog,"eh":_emscripten_glGetShaderPrecisionFormat,"ch":_emscripten_glGetShaderSource,"gh":_emscripten_glGetShaderiv,"bh":_emscripten_glGetString,"qe":_emscripten_glGetStringi,"Zd":_emscripten_glGetSynciv,"ah":_emscripten_glGetTexParameterfv,"$g":_emscripten_glGetTexParameteriv,"Oe":_emscripten_glGetTransformFeedbackVarying,"le":_emscripten_glGetUniformBlockIndex,"oe":_emscripten_glGetUniformIndices,"Yg":_emscripten_glGetUniformLocation,"_g":_emscripten_glGetUniformfv,"Zg":_emscripten_glGetUniformiv,"Fe":_emscripten_glGetUniformuiv,"Me":_emscripten_glGetVertexAttribIiv,"Le":_emscripten_glGetVertexAttribIuiv,"Vg":_emscripten_glGetVertexAttribPointerv,"Xg":_emscripten_glGetVertexAttribfv,"Wg":_emscripten_glGetVertexAttribiv,"Tg":_emscripten_glHint,"Ad":_emscripten_glInvalidateFramebuffer,"zd":_emscripten_glInvalidateSubFramebuffer,"Sg":_emscripten_glIsBuffer,"Rg":_emscripten_glIsEnabled,"Qg":_emscripten_glIsFramebuffer,"Pg":_emscripten_glIsProgram,"nf":_emscripten_glIsQuery,"Ri":_emscripten_glIsQueryEXT,"Og":_emscripten_glIsRenderbuffer,"Ud":_emscripten_glIsSampler,"Ng":_emscripten_glIsShader,"ee":_emscripten_glIsSync,"Mg":_emscripten_glIsTexture,"Hd":_emscripten_glIsTransformFeedback,"We":_emscripten_glIsVertexArray,"Ei":_emscripten_glIsVertexArrayOES,"Lg":_emscripten_glLineWidth,"Kg":_emscripten_glLinkProgram,"Fd":_emscripten_glPauseTransformFeedback,"Ig":_emscripten_glPixelStorei,"Hg":_emscripten_glPolygonOffset,"Cd":_emscripten_glProgramBinary,"Bd":_emscripten_glProgramParameteri,"Oi":_emscripten_glQueryCounterEXT,"wf":_emscripten_glReadBuffer,"Gg":_emscripten_glReadPixels,"Fg":_emscripten_glReleaseShaderCompiler,"Eg":_emscripten_glRenderbufferStorage,"$e":_emscripten_glRenderbufferStorageMultisample,"Ed":_emscripten_glResumeTransformFeedback,"Dg":_emscripten_glSampleCoverage,"Pd":_emscripten_glSamplerParameterf,"Od":_emscripten_glSamplerParameterfv,"Sd":_emscripten_glSamplerParameteri,"Qd":_emscripten_glSamplerParameteriv,"Cg":_emscripten_glScissor,"Bg":_emscripten_glShaderBinary,"Ag":_emscripten_glShaderSource,"zg":_emscripten_glStencilFunc,"xg":_emscripten_glStencilFuncSeparate,"wg":_emscripten_glStencilMask,"vg":_emscripten_glStencilMaskSeparate,"ug":_emscripten_glStencilOp,"tg":_emscripten_glStencilOpSeparate,"sg":_emscripten_glTexImage2D,"uf":_emscripten_glTexImage3D,"rg":_emscripten_glTexParameterf,"qg":_emscripten_glTexParameterfv,"pg":_emscripten_glTexParameteri,"og":_emscripten_glTexParameteriv,"yd":_emscripten_glTexStorage2D,"xd":_emscripten_glTexStorage3D,"mg":_emscripten_glTexSubImage2D,"tf":_emscripten_glTexSubImage3D,"Pe":_emscripten_glTransformFeedbackVaryings,"lg":_emscripten_glUniform1f,"kg":_emscripten_glUniform1fv,"jg":_emscripten_glUniform1i,"ig":_emscripten_glUniform1iv,"De":_emscripten_glUniform1ui,"ze":_emscripten_glUniform1uiv,"hg":_emscripten_glUniform2f,"gg":_emscripten_glUniform2fv,"fg":_emscripten_glUniform2i,"eg":_emscripten_glUniform2iv,"Ce":_emscripten_glUniform2ui,"ye":_emscripten_glUniform2uiv,"dg":_emscripten_glUniform3f,"ag":_emscripten_glUniform3fv,"$f":_emscripten_glUniform3i,"_f":_emscripten_glUniform3iv,"Be":_emscripten_glUniform3ui,"we":_emscripten_glUniform3uiv,"Zf":_emscripten_glUniform4f,"Yf":_emscripten_glUniform4fv,"Xf":_emscripten_glUniform4i,"Wf":_emscripten_glUniform4iv,"Ae":_emscripten_glUniform4ui,"ve":_emscripten_glUniform4uiv,"ie":_emscripten_glUniformBlockBinding,"Vf":_emscripten_glUniformMatrix2fv,"gf":_emscripten_glUniformMatrix2x3fv,"ef":_emscripten_glUniformMatrix2x4fv,"Uf":_emscripten_glUniformMatrix3fv,"ff":_emscripten_glUniformMatrix3x2fv,"cf":_emscripten_glUniformMatrix3x4fv,"Tf":_emscripten_glUniformMatrix4fv,"df":_emscripten_glUniformMatrix4x2fv,"bf":_emscripten_glUniformMatrix4x3fv,"Rf":_emscripten_glUseProgram,"Qf":_emscripten_glValidateProgram,"Pf":_emscripten_glVertexAttrib1f,"Of":_emscripten_glVertexAttrib1fv,"Nf":_emscripten_glVertexAttrib2f,"Mf":_emscripten_glVertexAttrib2fv,"Lf":_emscripten_glVertexAttrib3f,"Kf":_emscripten_glVertexAttrib3fv,"Jf":_emscripten_glVertexAttrib4f,"If":_emscripten_glVertexAttrib4fv,"Ld":_emscripten_glVertexAttribDivisor,"Ai":_emscripten_glVertexAttribDivisorANGLE,"Df":_emscripten_glVertexAttribDivisorARB,"Ef":_emscripten_glVertexAttribDivisorEXT,"ud":_emscripten_glVertexAttribDivisorNV,"Ke":_emscripten_glVertexAttribI4i,"He":_emscripten_glVertexAttribI4iv,"Je":_emscripten_glVertexAttribI4ui,"Ge":_emscripten_glVertexAttribI4uiv,"Ne":_emscripten_glVertexAttribIPointer,"Gf":_emscripten_glVertexAttribPointer,"Ff":_emscripten_glViewport,"$d":_emscripten_glWaitSync,"hd":_emscripten_memcpy_big,"Ta":_emscripten_resize_heap,"pb":_emscripten_set_main_loop,"fb":_emscripten_webgl_commit_frame,"Cc":_emscripten_webgl_create_context,"bc":_emscripten_webgl_destroy_context,"Oc":_emscripten_webgl_init_context_attributes,"xc":_emscripten_webgl_make_context_current,"dd":_environ_get,"ed":_environ_sizes_get,"ua":_fd_close,"cd":_fd_fdstat_get,"lb":_fd_read,"Ac":_fd_seek,"kb":_fd_write,"k":_getTempRet0,"Sa":_getaddrinfo,"Pb":_getnameinfo,"c":_glActiveTexture,"Na":_glAttachShader,"bb":_glBeginTransformFeedback,"vb":_glBindAttribLocation,"b":_glBindBuffer,"P":_glBindBufferBase,"e":_glBindFramebuffer,"_":_glBindRenderbuffer,"a":_glBindTexture,"m":_glBindVertexArray,"D":_glBlendEquation,"X":_glBlendFunc,"w":_glBlendFuncSeparate,"ha":_glBlitFramebuffer,"q":_glBufferData,"K":_glBufferSubData,"M":_glCheckFramebufferStatus,"J":_glClear,"qa":_glClearBufferfv,"O":_glClearColor,"aa":_glClearDepthf,"N":_glColorMask,"ka":_glCompileShader,"Ab":_glCompressedTexImage2D,"gj":_glCompressedTexSubImage2D,"zb":_glCompressedTexSubImage3D,"ej":_glCopyBufferSubData,"_a":_glCopyTexSubImage2D,"$a":_glCreateProgram,"Da":_glCreateShader,"ra":_glCullFace,"L":_glDeleteBuffers,"F":_glDeleteFramebuffers,"Q":_glDeleteProgram,"U":_glDeleteRenderbuffers,"I":_glDeleteShader,"A":_glDeleteTextures,"ea":_glDeleteVertexArrays,"Y":_glDepthFunc,"H":_glDepthMask,"i":_glDisable,"p":_glDisableVertexAttribArray,"B":_glDrawArrays,"ya":_glDrawArraysInstanced,"Ja":_glDrawBuffers,"ba":_glDrawElements,"Ka":_glDrawElementsInstanced,"s":_glEnable,"j":_glEnableVertexAttribArray,"ab":_glEndTransformFeedback,"Db":_glFinish,"Z":_glFramebufferRenderbuffer,"x":_glFramebufferTexture2D,"fj":_glFramebufferTextureLayer,"Bb":_glFrontFace,"C":_glGenBuffers,"E":_glGenFramebuffers,"ga":_glGenRenderbuffers,"v":_glGenTextures,"W":_glGenVertexArrays,"R":_glGenerateMipmap,"Cb":_glGetError,"wb":_glGetFloatv,"$":_glGetIntegerv,"Zi":_glGetProgramBinary,"tb":_glGetProgramInfoLog,"Ea":_glGetProgramiv,"Oa":_glGetShaderInfoLog,"Vi":_glGetShaderSource,"da":_glGetShaderiv,"wa":_glGetString,"dj":_glGetStringi,"Xi":_glGetUniformBlockIndex,"va":_glGetUniformLocation,"lj":_glInvalidateFramebuffer,"ub":_glLinkProgram,"la":_glPixelStorei,"bj":_glProgramBinary,"_i":_glProgramParameteri,"ia":_glReadBuffer,"cb":_glReadPixels,"fa":_glRenderbufferStorage,"Ga":_glRenderbufferStorageMultisample,"T":_glScissor,"Pa":_glShaderSource,"r":_glTexImage2D,"Ia":_glTexImage3D,"g":_glTexParameterf,"d":_glTexParameteri,"ij":_glTexStorage2D,"Ha":_glTexSubImage2D,"Qa":_glTexSubImage3D,"$i":_glTransformFeedbackVaryings,"f":_glUniform1f,"u":_glUniform1i,"db":_glUniform1iv,"xb":_glUniform1ui,"Za":_glUniform2f,"n":_glUniform2fv,"Ca":_glUniform2i,"ma":_glUniform2iv,"Ya":_glUniform3f,"V":_glUniform3fv,"Ba":_glUniform3i,"xa":_glUniform4f,"y":_glUniform4fv,"Aa":_glUniform4i,"Wi":_glUniformBlockBinding,"sb":_glUniformMatrix2fv,"rb":_glUniformMatrix3fv,"o":_glUniformMatrix4fv,"pa":_glUseProgram,"z":_glVertexAttrib4f,"S":_glVertexAttrib4fv,"G":_glVertexAttribDivisor,"pj":_glVertexAttribI4ui,"La":_glVertexAttribIPointer,"h":_glVertexAttribPointer,"t":_glViewport,"di":_godot_audio_capture_start,"cg":_godot_audio_capture_stop,"be":_godot_audio_has_script_processor,"dc":_godot_audio_has_worklet,"bk":_godot_audio_init,"ck":_godot_audio_is_available,"kj":_godot_audio_resume,"yc":_godot_audio_script_create,"nc":_godot_audio_script_start,"Ub":_godot_audio_worklet_create,"ak":_godot_audio_worklet_start_no_threads,"Sb":_godot_js_config_canvas_id_get,"dh":_godot_js_config_locale_get,"_b":_godot_js_display_alert,"me":_godot_js_display_canvas_focus,"xe":_godot_js_display_canvas_is_focused,"ld":_godot_js_display_clipboard_get,"vd":_godot_js_display_clipboard_set,"Te":_godot_js_display_cursor_is_hidden,"Ie":_godot_js_display_cursor_is_locked,"Wa":_godot_js_display_cursor_lock_set,"ob":_godot_js_display_cursor_set_custom_shape,"Hf":_godot_js_display_cursor_set_shape,"Xa":_godot_js_display_cursor_set_visible,"yg":_godot_js_display_desired_size_set,"oc":_godot_js_display_fullscreen_cb,"Sf":_godot_js_display_fullscreen_exit,"bg":_godot_js_display_fullscreen_request,"Rj":_godot_js_display_glGetBufferSubData,"ib":_godot_js_display_has_webgl,"Yc":_godot_js_display_is_swap_ok_cancel,"lc":_godot_js_display_notification_cb,"cc":_godot_js_display_pixel_ratio_get,"ec":_godot_js_display_screen_dpi_get,"Jg":_godot_js_display_screen_size_get,"gd":_godot_js_display_setup_canvas,"Ug":_godot_js_display_size_update,"ae":_godot_js_display_touchscreen_is_available,"jc":_godot_js_display_vk_available,"kc":_godot_js_display_vk_cb,"hc":_godot_js_display_vk_hide,"ic":_godot_js_display_vk_show,"mc":_godot_js_display_window_blur_cb,"Yb":_godot_js_display_window_icon_set,"ng":_godot_js_display_window_size_get,"Zb":_godot_js_display_window_title_set,"zi":_godot_js_eval,"qj":_godot_js_fetch_body_length_get,"Aj":_godot_js_fetch_create,"Jb":_godot_js_fetch_free,"nj":_godot_js_fetch_http_status_get,"rj":_godot_js_fetch_is_chunked,"oj":_godot_js_fetch_read_chunk,"mj":_godot_js_fetch_read_headers,"eb":_godot_js_fetch_state_get,"pc":_godot_js_input_drop_files_cb,"rc":_godot_js_input_gamepad_cb,"fc":_godot_js_input_gamepad_sample,"Rd":_godot_js_input_gamepad_sample_count,"Gd":_godot_js_input_gamepad_sample_get,"sc":_godot_js_input_key_cb,"wc":_godot_js_input_mouse_button_cb,"vc":_godot_js_input_mouse_move_cb,"uc":_godot_js_input_mouse_wheel_cb,"qc":_godot_js_input_paste_cb,"tc":_godot_js_input_touch_cb,"Wb":_godot_js_input_vibrate_handheld,"oi":_godot_js_os_download_buffer,"ac":_godot_js_os_execute,"oh":_godot_js_os_finish_async,"Rb":_godot_js_os_fs_is_persistent,"gc":_godot_js_os_fs_sync,"$b":_godot_js_os_hw_concurrency_get,"Tb":_godot_js_os_request_quit_cb,"Xb":_godot_js_os_shell_open,"Qb":_godot_js_pwa_cb,"Vb":_godot_js_pwa_update,"Ob":_godot_js_rtc_datachannel_close,"Vj":_godot_js_rtc_datachannel_connect,"Sj":_godot_js_rtc_datachannel_destroy,"Wj":_godot_js_rtc_datachannel_get_buffered_amount,"_j":_godot_js_rtc_datachannel_id_get,"Xj":_godot_js_rtc_datachannel_is_negotiated,"$j":_godot_js_rtc_datachannel_is_ordered,"Uj":_godot_js_rtc_datachannel_label_get,"Zj":_godot_js_rtc_datachannel_max_packet_lifetime_get,"Yj":_godot_js_rtc_datachannel_max_retransmits_get,"Tj":_godot_js_rtc_datachannel_protocol_get,"Nb":_godot_js_rtc_datachannel_ready_state_get,"Mb":_godot_js_rtc_datachannel_send,"Qj":_godot_js_rtc_pc_close,"Lj":_godot_js_rtc_pc_create,"Kj":_godot_js_rtc_pc_datachannel_create,"Lb":_godot_js_rtc_pc_destroy,"Mj":_godot_js_rtc_pc_ice_candidate_add,"Oj":_godot_js_rtc_pc_local_description_set,"Pj":_godot_js_rtc_pc_offer_create,"Nj":_godot_js_rtc_pc_remote_description_set,"Kb":_godot_js_websocket_buffered_amount,"Ij":_godot_js_websocket_close,"Hj":_godot_js_websocket_create,"Ib":_godot_js_websocket_destroy,"Jj":_godot_js_websocket_send,"Yi":_godot_js_wrapper_create_cb,"Ki":_godot_js_wrapper_create_object,"Ui":_godot_js_wrapper_interface_get,"aj":_godot_js_wrapper_object_call,"hj":_godot_js_wrapper_object_get,"yb":_godot_js_wrapper_object_getvar,"jj":_godot_js_wrapper_object_set,"cj":_godot_js_wrapper_object_setvar,"ci":_godot_js_wrapper_object_unref,"vj":_godot_webxr_commit_for_eye,"Ej":_godot_webxr_get_bounds_geometry,"Fb":_godot_webxr_get_controller_axes,"sj":_godot_webxr_get_controller_buttons,"uj":_godot_webxr_get_controller_count,"Ra":_godot_webxr_get_controller_target_ray_mode,"tj":_godot_webxr_get_controller_transform,"wj":_godot_webxr_get_projection_for_eye,"yj":_godot_webxr_get_render_targetsize,"xj":_godot_webxr_get_transform_for_eye,"Dj":_godot_webxr_get_view_count,"Fj":_godot_webxr_get_visibility_state,"Bj":_godot_webxr_initialize,"Gb":_godot_webxr_is_controller_connected,"Gj":_godot_webxr_is_session_supported,"Cj":_godot_webxr_is_supported,"Hb":_godot_webxr_sample_controller_data,"zj":_godot_webxr_uninitialize,"za":invoke_ii,"na":invoke_iii,"gb":invoke_iiii,"hb":invoke_iiiii,"Dc":invoke_iiiiii,"Bc":invoke_iiiiiii,"zc":invoke_iij,"ca":invoke_vi,"oa":invoke_vii,"ta":invoke_viii,"sa":invoke_viiii,"Ma":invoke_viiiiiii,"l":_setTempRet0,"Eb":_strftime,"Nc":_strftime_l};var asm=createWasm();var ___wasm_call_ctors=Module["___wasm_call_ctors"]=function(){return(___wasm_call_ctors=Module["___wasm_call_ctors"]=Module["asm"]["ek"]).apply(null,arguments)};var _free=Module["_free"]=function(){return(_free=Module["_free"]=Module["asm"]["fk"]).apply(null,arguments)};var __Z13godot_js_mainiPPc=Module["__Z13godot_js_mainiPPc"]=function(){return(__Z13godot_js_mainiPPc=Module["__Z13godot_js_mainiPPc"]=Module["asm"]["gk"]).apply(null,arguments)};var _main=Module["_main"]=function(){return(_main=Module["_main"]=Module["asm"]["hk"]).apply(null,arguments)};var _malloc=Module["_malloc"]=function(){return(_malloc=Module["_malloc"]=Module["asm"]["ik"]).apply(null,arguments)};var _htonl=Module["_htonl"]=function(){return(_htonl=Module["_htonl"]=Module["asm"]["jk"]).apply(null,arguments)};var _htons=Module["_htons"]=function(){return(_htons=Module["_htons"]=Module["asm"]["kk"]).apply(null,arguments)};var _ntohs=Module["_ntohs"]=function(){return(_ntohs=Module["_ntohs"]=Module["asm"]["lk"]).apply(null,arguments)};var _fflush=Module["_fflush"]=function(){return(_fflush=Module["_fflush"]=Module["asm"]["mk"]).apply(null,arguments)};var ___errno_location=Module["___errno_location"]=function(){return(___errno_location=Module["___errno_location"]=Module["asm"]["nk"]).apply(null,arguments)};var __emwebxr_on_input_event=Module["__emwebxr_on_input_event"]=function(){return(__emwebxr_on_input_event=Module["__emwebxr_on_input_event"]=Module["asm"]["ok"]).apply(null,arguments)};var __emwebxr_on_simple_event=Module["__emwebxr_on_simple_event"]=function(){return(__emwebxr_on_simple_event=Module["__emwebxr_on_simple_event"]=Module["asm"]["pk"]).apply(null,arguments)};var ___funcs_on_exit=Module["___funcs_on_exit"]=function(){return(___funcs_on_exit=Module["___funcs_on_exit"]=Module["asm"]["qk"]).apply(null,arguments)};var _setThrew=Module["_setThrew"]=function(){return(_setThrew=Module["_setThrew"]=Module["asm"]["sk"]).apply(null,arguments)};var stackSave=Module["stackSave"]=function(){return(stackSave=Module["stackSave"]=Module["asm"]["tk"]).apply(null,arguments)};var stackRestore=Module["stackRestore"]=function(){return(stackRestore=Module["stackRestore"]=Module["asm"]["uk"]).apply(null,arguments)};var stackAlloc=Module["stackAlloc"]=function(){return(stackAlloc=Module["stackAlloc"]=Module["asm"]["vk"]).apply(null,arguments)};var dynCall_iij=Module["dynCall_iij"]=function(){return(dynCall_iij=Module["dynCall_iij"]=Module["asm"]["wk"]).apply(null,arguments)};function invoke_vii(index,a1,a2){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_vi(index,a1){var sp=stackSave();try{getWasmTableEntry(index)(a1)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viii(index,a1,a2,a3){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_ii(index,a1){var sp=stackSave();try{return getWasmTableEntry(index)(a1)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iii(index,a1,a2){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiiii(index,a1,a2,a3,a4){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiiiii(index,a1,a2,a3,a4,a5){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4,a5)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiii(index,a1,a2,a3,a4){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiii(index,a1,a2,a3){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_viiiiiii(index,a1,a2,a3,a4,a5,a6,a7){var sp=stackSave();try{getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6,a7)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iiiiiii(index,a1,a2,a3,a4,a5,a6){var sp=stackSave();try{return getWasmTableEntry(index)(a1,a2,a3,a4,a5,a6)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}function invoke_iij(index,a1,a2,a3){var sp=stackSave();try{return dynCall_iij(index,a1,a2,a3)}catch(e){stackRestore(sp);if(e!==e+0)throw e;_setThrew(1,0)}}Module["cwrap"]=cwrap;Module["callMain"]=callMain;var calledRun;function ExitStatus(status){this.name="ExitStatus";this.message="Program terminated with exit("+status+")";this.status=status}var calledMain=false;dependenciesFulfilled=function runCaller(){if(!calledRun)run();if(!calledRun)dependenciesFulfilled=runCaller};function callMain(args){var entryFunction=Module["_main"];args=args||[];args.unshift(thisProgram);var argc=args.length;var argv=stackAlloc((argc+1)*4);var argv_ptr=argv>>2;args.forEach(arg=>{HEAP32[argv_ptr++]=allocateUTF8OnStack(arg)});HEAP32[argv_ptr]=0;try{var ret=entryFunction(argc,argv);exit(ret,true);return ret}catch(e){return handleException(e)}finally{calledMain=true}}function run(args){args=args||arguments_;if(runDependencies>0){return}preRun();if(runDependencies>0){return}function doRun(){if(calledRun)return;calledRun=true;Module["calledRun"]=true;if(ABORT)return;initRuntime();preMain();readyPromiseResolve(Module);if(Module["onRuntimeInitialized"])Module["onRuntimeInitialized"]();if(shouldRunNow)callMain(args);postRun()}if(Module["setStatus"]){Module["setStatus"]("Running...");setTimeout(function(){setTimeout(function(){Module["setStatus"]("")},1);doRun()},1)}else{doRun()}}Module["run"]=run;function exit(status,implicit){EXITSTATUS=status;if(!keepRuntimeAlive()){exitRuntime()}procExit(status)}function procExit(code){EXITSTATUS=code;if(!keepRuntimeAlive()){if(Module["onExit"])Module["onExit"](code);ABORT=true}quit_(code,new ExitStatus(code))}if(Module["preInit"]){if(typeof Module["preInit"]=="function")Module["preInit"]=[Module["preInit"]];while(Module["preInit"].length>0){Module["preInit"].pop()()}}var shouldRunNow=false;if(Module["noInitialRun"])shouldRunNow=false;run();
10
11
12 return Godot.ready
13}
14);
15})();
16if (typeof exports === 'object' && typeof module === 'object')
17 module.exports = Godot;
18else if (typeof define === 'function' && define['amd'])
19 define([], function() { return Godot; });
20else if (typeof exports === 'object')
21 exports["Godot"] = Godot;
22
23const Preloader = /** @constructor */ function () { // eslint-disable-line no-unused-vars
24 function getTrackedResponse(response, load_status) {
25 function onloadprogress(reader, controller) {
26 return reader.read().then(function (result) {
27 if (load_status.done) {
28 return Promise.resolve();
29 }
30 if (result.value) {
31 controller.enqueue(result.value);
32 load_status.loaded += result.value.length;
33 }
34 if (!result.done) {
35 return onloadprogress(reader, controller);
36 }
37 load_status.done = true;
38 return Promise.resolve();
39 });
40 }
41 const reader = response.body.getReader();
42 return new Response(new ReadableStream({
43 start: function (controller) {
44 onloadprogress(reader, controller).then(function () {
45 controller.close();
46 });
47 },
48 }), { headers: response.headers });
49 }
50
51 function loadFetch(file, tracker, fileSize, raw) {
52 tracker[file] = {
53 total: fileSize || 0,
54 loaded: 0,
55 done: false,
56 };
57 return fetch(file).then(function (response) {
58 if (!response.ok) {
59 return Promise.reject(new Error(`Failed loading file '${file}'`));
60 }
61 const tr = getTrackedResponse(response, tracker[file]);
62 if (raw) {
63 return Promise.resolve(tr);
64 }
65 return tr.arrayBuffer();
66 });
67 }
68
69 function retry(func, attempts = 1) {
70 function onerror(err) {
71 if (attempts <= 1) {
72 return Promise.reject(err);
73 }
74 return new Promise(function (resolve, reject) {
75 setTimeout(function () {
76 retry(func, attempts - 1).then(resolve).catch(reject);
77 }, 1000);
78 });
79 }
80 return func().catch(onerror);
81 }
82
83 const DOWNLOAD_ATTEMPTS_MAX = 4;
84 const loadingFiles = {};
85 const lastProgress = { loaded: 0, total: 0 };
86 let progressFunc = null;
87
88 const animateProgress = function () {
89 let loaded = 0;
90 let total = 0;
91 let totalIsValid = true;
92 let progressIsFinal = true;
93
94 Object.keys(loadingFiles).forEach(function (file) {
95 const stat = loadingFiles[file];
96 if (!stat.done) {
97 progressIsFinal = false;
98 }
99 if (!totalIsValid || stat.total === 0) {
100 totalIsValid = false;
101 total = 0;
102 } else {
103 total += stat.total;
104 }
105 loaded += stat.loaded;
106 });
107 if (loaded !== lastProgress.loaded || total !== lastProgress.total) {
108 lastProgress.loaded = loaded;
109 lastProgress.total = total;
110 if (typeof progressFunc === 'function') {
111 progressFunc(loaded, total);
112 }
113 }
114 if (!progressIsFinal) {
115 requestAnimationFrame(animateProgress);
116 }
117 };
118
119 this.animateProgress = animateProgress;
120
121 this.setProgressFunc = function (callback) {
122 progressFunc = callback;
123 };
124
125 this.loadPromise = function (file, fileSize, raw = false) {
126 return retry(loadFetch.bind(null, file, loadingFiles, fileSize, raw), DOWNLOAD_ATTEMPTS_MAX);
127 };
128
129 this.preloadedFiles = [];
130 this.preload = function (pathOrBuffer, destPath, fileSize) {
131 let buffer = null;
132 if (typeof pathOrBuffer === 'string') {
133 const me = this;
134 return this.loadPromise(pathOrBuffer, fileSize).then(function (buf) {
135 me.preloadedFiles.push({
136 path: destPath || pathOrBuffer,
137 buffer: buf,
138 });
139 return Promise.resolve();
140 });
141 } else if (pathOrBuffer instanceof ArrayBuffer) {
142 buffer = new Uint8Array(pathOrBuffer);
143 } else if (ArrayBuffer.isView(pathOrBuffer)) {
144 buffer = new Uint8Array(pathOrBuffer.buffer);
145 }
146 if (buffer) {
147 this.preloadedFiles.push({
148 path: destPath,
149 buffer: pathOrBuffer,
150 });
151 return Promise.resolve();
152 }
153 return Promise.reject(new Error('Invalid object for preloading'));
154 };
155};
156
157/**
158 * An object used to configure the Engine instance based on godot export options, and to override those in custom HTML
159 * templates if needed.
160 *
161 * @header Engine configuration
162 * @summary The Engine configuration object. This is just a typedef, create it like a regular object, e.g.:
163 *
164 * ``const MyConfig = { executable: 'godot', unloadAfterInit: false }``
165 *
166 * @typedef {Object} EngineConfig
167 */
168const EngineConfig = {}; // eslint-disable-line no-unused-vars
169
170/**
171 * @struct
172 * @constructor
173 * @ignore
174 */
175const InternalConfig = function (initConfig) { // eslint-disable-line no-unused-vars
176 const cfg = /** @lends {InternalConfig.prototype} */ {
177 /**
178 * Whether the unload the engine automatically after the instance is initialized.
179 *
180 * @memberof EngineConfig
181 * @default
182 * @type {boolean}
183 */
184 unloadAfterInit: true,
185 /**
186 * The HTML DOM Canvas object to use.
187 *
188 * By default, the first canvas element in the document will be used is none is specified.
189 *
190 * @memberof EngineConfig
191 * @default
192 * @type {?HTMLCanvasElement}
193 */
194 canvas: null,
195 /**
196 * The name of the WASM file without the extension. (Set by Godot Editor export process).
197 *
198 * @memberof EngineConfig
199 * @default
200 * @type {string}
201 */
202 executable: '',
203 /**
204 * An alternative name for the game pck to load. The executable name is used otherwise.
205 *
206 * @memberof EngineConfig
207 * @default
208 * @type {?string}
209 */
210 mainPack: null,
211 /**
212 * Specify a language code to select the proper localization for the game.
213 *
214 * The browser locale will be used if none is specified. See complete list of
215 * :ref:`supported locales <doc_locales>`.
216 *
217 * @memberof EngineConfig
218 * @type {?string}
219 * @default
220 */
221 locale: null,
222 /**
223 * The canvas resize policy determines how the canvas should be resized by Godot.
224 *
225 * ``0`` means Godot won't do any resizing. This is useful if you want to control the canvas size from
226 * javascript code in your template.
227 *
228 * ``1`` means Godot will resize the canvas on start, and when changing window size via engine functions.
229 *
230 * ``2`` means Godot will adapt the canvas size to match the whole browser window.
231 *
232 * @memberof EngineConfig
233 * @type {number}
234 * @default
235 */
236 canvasResizePolicy: 2,
237 /**
238 * The arguments to be passed as command line arguments on startup.
239 *
240 * See :ref:`command line tutorial <doc_command_line_tutorial>`.
241 *
242 * **Note**: :js:meth:`startGame <Engine.prototype.startGame>` will always add the ``--main-pack`` argument.
243 *
244 * @memberof EngineConfig
245 * @type {Array<string>}
246 * @default
247 */
248 args: [],
249 /**
250 * When enabled, the game canvas will automatically grab the focus when the engine starts.
251 *
252 * @memberof EngineConfig
253 * @type {boolean}
254 * @default
255 */
256 focusCanvas: true,
257 /**
258 * When enabled, this will turn on experimental virtual keyboard support on mobile.
259 *
260 * @memberof EngineConfig
261 * @type {boolean}
262 * @default
263 */
264 experimentalVK: false,
265 /**
266 * The progressive web app service worker to install.
267 * @memberof EngineConfig
268 * @default
269 * @type {string}
270 */
271 serviceWorker: '',
272 /**
273 * @ignore
274 * @type {Array.<string>}
275 */
276 persistentPaths: ['/userfs'],
277 /**
278 * @ignore
279 * @type {boolean}
280 */
281 persistentDrops: false,
282 /**
283 * @ignore
284 * @type {Array.<string>}
285 */
286 gdnativeLibs: [],
287 /**
288 * @ignore
289 * @type {Array.<string>}
290 */
291 fileSizes: [],
292 /**
293 * A callback function for handling Godot's ``OS.execute`` calls.
294 *
295 * This is for example used in the Web Editor template to switch between project manager and editor, and for running the game.
296 *
297 * @callback EngineConfig.onExecute
298 * @param {string} path The path that Godot's wants executed.
299 * @param {Array.<string>} args The arguments of the "command" to execute.
300 */
301 /**
302 * @ignore
303 * @type {?function(string, Array.<string>)}
304 */
305 onExecute: null,
306 /**
307 * A callback function for being notified when the Godot instance quits.
308 *
309 * **Note**: This function will not be called if the engine crashes or become unresponsive.
310 *
311 * @callback EngineConfig.onExit
312 * @param {number} status_code The status code returned by Godot on exit.
313 */
314 /**
315 * @ignore
316 * @type {?function(number)}
317 */
318 onExit: null,
319 /**
320 * A callback function for displaying download progress.
321 *
322 * The function is called once per frame while downloading files, so the usage of ``requestAnimationFrame()``
323 * is not necessary.
324 *
325 * If the callback function receives a total amount of bytes as 0, this means that it is impossible to calculate.
326 * Possible reasons include:
327 *
328 * - Files are delivered with server-side chunked compression
329 * - Files are delivered with server-side compression on Chromium
330 * - Not all file downloads have started yet (usually on servers without multi-threading)
331 *
332 * @callback EngineConfig.onProgress
333 * @param {number} current The current amount of downloaded bytes so far.
334 * @param {number} total The total amount of bytes to be downloaded.
335 */
336 /**
337 * @ignore
338 * @type {?function(number, number)}
339 */
340 onProgress: null,
341 /**
342 * A callback function for handling the standard output stream. This method should usually only be used in debug pages.
343 *
344 * By default, ``console.log()`` is used.
345 *
346 * @callback EngineConfig.onPrint
347 * @param {...*} [var_args] A variadic number of arguments to be printed.
348 */
349 /**
350 * @ignore
351 * @type {?function(...*)}
352 */
353 onPrint: function () {
354 console.log.apply(console, Array.from(arguments)); // eslint-disable-line no-console
355 },
356 /**
357 * A callback function for handling the standard error stream. This method should usually only be used in debug pages.
358 *
359 * By default, ``console.error()`` is used.
360 *
361 * @callback EngineConfig.onPrintError
362 * @param {...*} [var_args] A variadic number of arguments to be printed as errors.
363 */
364 /**
365 * @ignore
366 * @type {?function(...*)}
367 */
368 onPrintError: function (var_args) {
369 console.error.apply(console, Array.from(arguments)); // eslint-disable-line no-console
370 },
371 };
372
373 /**
374 * @ignore
375 * @struct
376 * @constructor
377 * @param {EngineConfig} opts
378 */
379 function Config(opts) {
380 this.update(opts);
381 }
382
383 Config.prototype = cfg;
384
385 /**
386 * @ignore
387 * @param {EngineConfig} opts
388 */
389 Config.prototype.update = function (opts) {
390 const config = opts || {};
391 // NOTE: We must explicitly pass the default, accessing it via
392 // the key will fail due to closure compiler renames.
393 function parse(key, def) {
394 if (typeof (config[key]) === 'undefined') {
395 return def;
396 }
397 return config[key];
398 }
399 // Module config
400 this.unloadAfterInit = parse('unloadAfterInit', this.unloadAfterInit);
401 this.onPrintError = parse('onPrintError', this.onPrintError);
402 this.onPrint = parse('onPrint', this.onPrint);
403 this.onProgress = parse('onProgress', this.onProgress);
404
405 // Godot config
406 this.canvas = parse('canvas', this.canvas);
407 this.executable = parse('executable', this.executable);
408 this.mainPack = parse('mainPack', this.mainPack);
409 this.locale = parse('locale', this.locale);
410 this.canvasResizePolicy = parse('canvasResizePolicy', this.canvasResizePolicy);
411 this.persistentPaths = parse('persistentPaths', this.persistentPaths);
412 this.persistentDrops = parse('persistentDrops', this.persistentDrops);
413 this.experimentalVK = parse('experimentalVK', this.experimentalVK);
414 this.focusCanvas = parse('focusCanvas', this.focusCanvas);
415 this.serviceWorker = parse('serviceWorker', this.serviceWorker);
416 this.gdnativeLibs = parse('gdnativeLibs', this.gdnativeLibs);
417 this.fileSizes = parse('fileSizes', this.fileSizes);
418 this.args = parse('args', this.args);
419 this.onExecute = parse('onExecute', this.onExecute);
420 this.onExit = parse('onExit', this.onExit);
421 };
422
423 /**
424 * @ignore
425 * @param {string} loadPath
426 * @param {Response} response
427 */
428 Config.prototype.getModuleConfig = function (loadPath, response) {
429 let r = response;
430 return {
431 'print': this.onPrint,
432 'printErr': this.onPrintError,
433 'thisProgram': this.executable,
434 'noExitRuntime': true,
435 'dynamicLibraries': [`${loadPath}.side.wasm`],
436 'instantiateWasm': function (imports, onSuccess) {
437 function done(result) {
438 onSuccess(result['instance'], result['module']);
439 }
440 if (typeof (WebAssembly.instantiateStreaming) !== 'undefined') {
441 WebAssembly.instantiateStreaming(Promise.resolve(r), imports).then(done);
442 } else {
443 r.arrayBuffer().then(function (buffer) {
444 WebAssembly.instantiate(buffer, imports).then(done);
445 });
446 }
447 r = null;
448 return {};
449 },
450 'locateFile': function (path) {
451 if (path.endsWith('.worker.js')) {
452 return `${loadPath}.worker.js`;
453 } else if (path.endsWith('.audio.worklet.js')) {
454 return `${loadPath}.audio.worklet.js`;
455 } else if (path.endsWith('.js')) {
456 return `${loadPath}.js`;
457 } else if (path.endsWith('.side.wasm')) {
458 return `${loadPath}.side.wasm`;
459 } else if (path.endsWith('.wasm')) {
460 return `${loadPath}.wasm`;
461 }
462 return path;
463 },
464 };
465 };
466
467 /**
468 * @ignore
469 * @param {function()} cleanup
470 */
471 Config.prototype.getGodotConfig = function (cleanup) {
472 // Try to find a canvas
473 if (!(this.canvas instanceof HTMLCanvasElement)) {
474 const nodes = document.getElementsByTagName('canvas');
475 if (nodes.length && nodes[0] instanceof HTMLCanvasElement) {
476 this.canvas = nodes[0];
477 }
478 if (!this.canvas) {
479 throw new Error('No canvas found in page');
480 }
481 }
482 // Canvas can grab focus on click, or key events won't work.
483 if (this.canvas.tabIndex < 0) {
484 this.canvas.tabIndex = 0;
485 }
486
487 // Browser locale, or custom one if defined.
488 let locale = this.locale;
489 if (!locale) {
490 locale = navigator.languages ? navigator.languages[0] : navigator.language;
491 locale = locale.split('.')[0];
492 }
493 locale = locale.replace('-', '_');
494 const onExit = this.onExit;
495
496 // Godot configuration.
497 return {
498 'canvas': this.canvas,
499 'canvasResizePolicy': this.canvasResizePolicy,
500 'locale': locale,
501 'persistentDrops': this.persistentDrops,
502 'virtualKeyboard': this.experimentalVK,
503 'focusCanvas': this.focusCanvas,
504 'onExecute': this.onExecute,
505 'onExit': function (p_code) {
506 cleanup(); // We always need to call the cleanup callback to free memory.
507 if (typeof (onExit) === 'function') {
508 onExit(p_code);
509 }
510 },
511 };
512 };
513 return new Config(initConfig);
514};
515
516/**
517 * Projects exported for the Web expose the :js:class:`Engine` class to the JavaScript environment, that allows
518 * fine control over the engine's start-up process.
519 *
520 * This API is built in an asynchronous manner and requires basic understanding
521 * of `Promises <https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Using_promises>`__.
522 *
523 * @module Engine
524 * @header HTML5 shell class reference
525 */
526const Engine = (function () {
527 const preloader = new Preloader();
528
529 let loadPromise = null;
530 let loadPath = '';
531 let initPromise = null;
532
533 /**
534 * @classdesc The ``Engine`` class provides methods for loading and starting exported projects on the Web. For default export
535 * settings, this is already part of the exported HTML page. To understand practical use of the ``Engine`` class,
536 * see :ref:`Custom HTML page for Web export <doc_customizing_html5_shell>`.
537 *
538 * @description Create a new Engine instance with the given configuration.
539 *
540 * @global
541 * @constructor
542 * @param {EngineConfig} initConfig The initial config for this instance.
543 */
544 function Engine(initConfig) { // eslint-disable-line no-shadow
545 this.config = new InternalConfig(initConfig);
546 this.rtenv = null;
547 }
548
549 /**
550 * Load the engine from the specified base path.
551 *
552 * @param {string} basePath Base path of the engine to load.
553 * @param {number=} [size=0] The file size if known.
554 * @returns {Promise} A Promise that resolves once the engine is loaded.
555 *
556 * @function Engine.load
557 */
558 Engine.load = function (basePath, size) {
559 if (loadPromise == null) {
560 loadPath = basePath;
561 loadPromise = preloader.loadPromise(`${loadPath}.wasm`, size, true);
562 requestAnimationFrame(preloader.animateProgress);
563 }
564 return loadPromise;
565 };
566
567 /**
568 * Unload the engine to free memory.
569 *
570 * This method will be called automatically depending on the configuration. See :js:attr:`unloadAfterInit`.
571 *
572 * @function Engine.unload
573 */
574 Engine.unload = function () {
575 loadPromise = null;
576 };
577
578 /**
579 * Check whether WebGL is available. Optionally, specify a particular version of WebGL to check for.
580 *
581 * @param {number=} [majorVersion=1] The major WebGL version to check for.
582 * @returns {boolean} If the given major version of WebGL is available.
583 * @function Engine.isWebGLAvailable
584 */
585 Engine.isWebGLAvailable = function (majorVersion = 1) {
586 try {
587 return !!document.createElement('canvas').getContext(['webgl', 'webgl2'][majorVersion - 1]);
588 } catch (e) { /* Not available */ }
589 return false;
590 };
591
592 /**
593 * Safe Engine constructor, creates a new prototype for every new instance to avoid prototype pollution.
594 * @ignore
595 * @constructor
596 */
597 function SafeEngine(initConfig) {
598 const proto = /** @lends Engine.prototype */ {
599 /**
600 * Initialize the engine instance. Optionally, pass the base path to the engine to load it,
601 * if it hasn't been loaded yet. See :js:meth:`Engine.load`.
602 *
603 * @param {string=} basePath Base path of the engine to load.
604 * @return {Promise} A ``Promise`` that resolves once the engine is loaded and initialized.
605 */
606 init: function (basePath) {
607 if (initPromise) {
608 return initPromise;
609 }
610 if (loadPromise == null) {
611 if (!basePath) {
612 initPromise = Promise.reject(new Error('A base path must be provided when calling `init` and the engine is not loaded.'));
613 return initPromise;
614 }
615 Engine.load(basePath, this.config.fileSizes[`${basePath}.wasm`]);
616 }
617 const me = this;
618 function doInit(promise) {
619 // Care! Promise chaining is bogus with old emscripten versions.
620 // This caused a regression with the Mono build (which uses an older emscripten version).
621 // Make sure to test that when refactoring.
622 return new Promise(function (resolve, reject) {
623 promise.then(function (response) {
624 const cloned = new Response(response.clone().body, { 'headers': [['content-type', 'application/wasm']] });
625 Godot(me.config.getModuleConfig(loadPath, cloned)).then(function (module) {
626 const paths = me.config.persistentPaths;
627 module['initFS'](paths).then(function (err) {
628 me.rtenv = module;
629 if (me.config.unloadAfterInit) {
630 Engine.unload();
631 }
632 resolve();
633 });
634 });
635 });
636 });
637 }
638 preloader.setProgressFunc(this.config.onProgress);
639 initPromise = doInit(loadPromise);
640 return initPromise;
641 },
642
643 /**
644 * Load a file so it is available in the instance's file system once it runs. Must be called **before** starting the
645 * instance.
646 *
647 * If not provided, the ``path`` is derived from the URL of the loaded file.
648 *
649 * @param {string|ArrayBuffer} file The file to preload.
650 *
651 * If a ``string`` the file will be loaded from that path.
652 *
653 * If an ``ArrayBuffer`` or a view on one, the buffer will used as the content of the file.
654 *
655 * @param {string=} path Path by which the file will be accessible. Required, if ``file`` is not a string.
656 *
657 * @returns {Promise} A Promise that resolves once the file is loaded.
658 */
659 preloadFile: function (file, path) {
660 return preloader.preload(file, path, this.config.fileSizes[file]);
661 },
662
663 /**
664 * Start the engine instance using the given override configuration (if any).
665 * :js:meth:`startGame <Engine.prototype.startGame>` can be used in typical cases instead.
666 *
667 * This will initialize the instance if it is not initialized. For manual initialization, see :js:meth:`init <Engine.prototype.init>`.
668 * The engine must be loaded beforehand.
669 *
670 * Fails if a canvas cannot be found on the page, or not specified in the configuration.
671 *
672 * @param {EngineConfig} override An optional configuration override.
673 * @return {Promise} Promise that resolves once the engine started.
674 */
675 start: function (override) {
676 this.config.update(override);
677 const me = this;
678 return me.init().then(function () {
679 if (!me.rtenv) {
680 return Promise.reject(new Error('The engine must be initialized before it can be started'));
681 }
682
683 let config = {};
684 try {
685 config = me.config.getGodotConfig(function () {
686 me.rtenv = null;
687 });
688 } catch (e) {
689 return Promise.reject(e);
690 }
691 // Godot configuration.
692 me.rtenv['initConfig'](config);
693
694 // Preload GDNative libraries.
695 const libs = [];
696 me.config.gdnativeLibs.forEach(function (lib) {
697 libs.push(me.rtenv['loadDynamicLibrary'](lib, { 'loadAsync': true }));
698 });
699 return Promise.all(libs).then(function () {
700 return new Promise(function (resolve, reject) {
701 preloader.preloadedFiles.forEach(function (file) {
702 me.rtenv['copyToFS'](file.path, file.buffer);
703 });
704 preloader.preloadedFiles.length = 0; // Clear memory
705 me.rtenv['callMain'](me.config.args);
706 initPromise = null;
707 if (me.config.serviceWorker && 'serviceWorker' in navigator) {
708 navigator.serviceWorker.register(me.config.serviceWorker);
709 }
710 resolve();
711 });
712 });
713 });
714 },
715
716 /**
717 * Start the game instance using the given configuration override (if any).
718 *
719 * This will initialize the instance if it is not initialized. For manual initialization, see :js:meth:`init <Engine.prototype.init>`.
720 *
721 * This will load the engine if it is not loaded, and preload the main pck.
722 *
723 * This method expects the initial config (or the override) to have both the :js:attr:`executable` and :js:attr:`mainPack`
724 * properties set (normally done by the editor during export).
725 *
726 * @param {EngineConfig} override An optional configuration override.
727 * @return {Promise} Promise that resolves once the game started.
728 */
729 startGame: function (override) {
730 this.config.update(override);
731 // Add main-pack argument.
732 const exe = this.config.executable;
733 const pack = this.config.mainPack || `${exe}.pck`;
734 this.config.args = ['--main-pack', pack].concat(this.config.args);
735 // Start and init with execName as loadPath if not inited.
736 const me = this;
737 return Promise.all([
738 this.init(exe),
739 this.preloadFile(pack, pack),
740 ]).then(function () {
741 return me.start.apply(me);
742 });
743 },
744
745 /**
746 * Create a file at the specified ``path`` with the passed as ``buffer`` in the instance's file system.
747 *
748 * @param {string} path The location where the file will be created.
749 * @param {ArrayBuffer} buffer The content of the file.
750 */
751 copyToFS: function (path, buffer) {
752 if (this.rtenv == null) {
753 throw new Error('Engine must be inited before copying files');
754 }
755 this.rtenv['copyToFS'](path, buffer);
756 },
757
758 /**
759 * Request that the current instance quit.
760 *
761 * This is akin the user pressing the close button in the window manager, and will
762 * have no effect if the engine has crashed, or is stuck in a loop.
763 *
764 */
765 requestQuit: function () {
766 if (this.rtenv) {
767 this.rtenv['request_quit']();
768 }
769 },
770 };
771
772 Engine.prototype = proto;
773 // Closure compiler exported instance methods.
774 Engine.prototype['init'] = Engine.prototype.init;
775 Engine.prototype['preloadFile'] = Engine.prototype.preloadFile;
776 Engine.prototype['start'] = Engine.prototype.start;
777 Engine.prototype['startGame'] = Engine.prototype.startGame;
778 Engine.prototype['copyToFS'] = Engine.prototype.copyToFS;
779 Engine.prototype['requestQuit'] = Engine.prototype.requestQuit;
780 // Also expose static methods as instance methods
781 Engine.prototype['load'] = Engine.load;
782 Engine.prototype['unload'] = Engine.unload;
783 Engine.prototype['isWebGLAvailable'] = Engine.isWebGLAvailable;
784 return new Engine(initConfig);
785 }
786
787 // Closure compiler exported static methods.
788 SafeEngine['load'] = Engine.load;
789 SafeEngine['unload'] = Engine.unload;
790 SafeEngine['isWebGLAvailable'] = Engine.isWebGLAvailable;
791
792 return SafeEngine;
793}());
794if (typeof window !== 'undefined') {
795 window['Engine'] = Engine;
796}
diff --git a/static/posts/godot-dynamic-tile-loading/example1/index.pck b/static/posts/godot-dynamic-tile-loading/example1/index.pck
deleted file mode 100644
index 07ac55c..0000000
--- a/static/posts/godot-dynamic-tile-loading/example1/index.pck
+++ /dev/null
Binary files differ
diff --git a/static/posts/godot-dynamic-tile-loading/example1/index.png b/static/posts/godot-dynamic-tile-loading/example1/index.png
deleted file mode 100644
index 766b0b6..0000000
--- a/static/posts/godot-dynamic-tile-loading/example1/index.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/godot-dynamic-tile-loading/example1/index.wasm b/static/posts/godot-dynamic-tile-loading/example1/index.wasm
deleted file mode 100644
index 5151d56..0000000
--- a/static/posts/godot-dynamic-tile-loading/example1/index.wasm
+++ /dev/null
Binary files differ
diff --git a/static/posts/godot-dynamic-tile-loading/village-creator.png b/static/posts/godot-dynamic-tile-loading/village-creator.png
deleted file mode 100644
index bb5b468..0000000
--- a/static/posts/godot-dynamic-tile-loading/village-creator.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/helix-editor/editor.png b/static/posts/helix-editor/editor.png
deleted file mode 100755
index 2648364..0000000
--- a/static/posts/helix-editor/editor.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/iot-application/iot-app-output.png b/static/posts/iot-application/iot-app-output.png
deleted file mode 100755
index 1c80589..0000000
--- a/static/posts/iot-application/iot-app-output.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/iot-application/iot-rest-example.png b/static/posts/iot-application/iot-rest-example.png
deleted file mode 100755
index 3ed86aa..0000000
--- a/static/posts/iot-application/iot-rest-example.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/iot-application/iot-sqlite-db.png b/static/posts/iot-application/iot-sqlite-db.png
deleted file mode 100755
index 82e1e29..0000000
--- a/static/posts/iot-application/iot-sqlite-db.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/iot-application/kcachegrind.png b/static/posts/iot-application/kcachegrind.png
deleted file mode 100755
index 0dc48ab..0000000
--- a/static/posts/iot-application/kcachegrind.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/iot-application/profiling-viewer.png b/static/posts/iot-application/profiling-viewer.png
deleted file mode 100755
index a450513..0000000
--- a/static/posts/iot-application/profiling-viewer.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/iot-application/simple-iot-application-overview.svg b/static/posts/iot-application/simple-iot-application-overview.svg
deleted file mode 100755
index 817666d..0000000
--- a/static/posts/iot-application/simple-iot-application-overview.svg
+++ /dev/null
@@ -1,2 +0,0 @@
1<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
2<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="623px" height="482px" version="1.1" content="&lt;mxfile userAgent=&quot;Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36&quot; version=&quot;7.1.3&quot; editor=&quot;www.draw.io&quot; type=&quot;google&quot;&gt;&lt;diagram id=&quot;d1a10cf0-d877-4170-d86f-ec45460d7050&quot; name=&quot;Page-1&quot;&gt;7Vnbbts4EP0aPzYQdbP9mKTNFtjtokgWSPpIi7RNrCRqKfq2X79DiZREUU5sV267RREgoI6o4XDmkHNIT4L7bP+bwMX6Eyc0nfge2U+C9xPfn8Yz+K+AQw1Ecw2sBCM1hFrgif1LNehpdMMILa2OkvNUssIGE57nNJEWhoXgO7vbkqf2qAVeUQd4SnDqos+MyHWNziKvxT9StlqbkZGn32TYdNZAucaE7zpQ8GES3AvOZd3K9vc0VbEzcam/ezjytnFM0Fye8oFff7DF6UbP7T2WeIFLqv2TBzNpcLVQzeSQspxQMQnudmsm6VOBE4XvINWArWWWwhOC5oJvoCP5Y2GAUgr+dxMymOzdkufySY+hnd9SIen+6HxQEyVgF+UZleIAXfQHwVzPSDMrjHWgd22e4qiG1p0UzXQ3rJmxaiy3wYOGjt9wLAMnlhM/TqUKBDRWqmEANW0ruvE/G25evCsrwt9CBxQV+/alsfJMF8rVokhZgiXjuTELHtaW7dEAdjwgbNuHjnpp1p/xI3RdamyIgcFP9QmwAbdO8XRw2Dft9wguarrCg/c2t10qj8Fesy0ces8d9vpmL+nSt9lgvoa/4QB/eyGiOblV+yc85TynVRywkAZLUlyWLLEjBXMXhxcV1RsUzgzwpQLm8VQBeyZfdNhVu34XVV3JA1MOV+/cmFemPlPBYLJqR6q61V5T4uzhvTTAzPhGJNTaCWE6Kyo7C9pNVicZ0UAuDCZoCotzazsxlB89wmfOquXWcCGyuBD1t6jaef1Vd4vvG5r2DAU9Q/WUHUOQVHzodCtUh/IVhyObvJFnlR5o1BZbLjYxPYme0Vn0bKloMVSzdpies2japSe68VCXnsihZ2X6F0H/JwQN5+iqBI1RMItmOF7OEY0hPO9cxj4LKCoDhY2A6Cpqb08qVVBi5FA9uucpFy3Nl0DNHoRTtsrV+gCqVRpOFSyQEemtfpExQtQwgwVwhBrn9xVa6Na4cIC1/ggVzsnQ1MnQI8XktQSVP3+GIhT9OBmaORm6FWTDcj6QpE+/P4IQ8s6We+gSubdSBUZv6GOfYvzYLqVo4BSD/IEUxNdIwdzdxqoDyEIdpIGhIwc24Zmq21cJbPhDBdZcZ4ytuI/IkJeOrDYSp6u+b/yoq3Ac+X2ZbAlc2TK8yL+Xjukvtst1DOoZupbQ7p0SzeXF1XQMMkvvq6T3qFSd9ql6PXLOf5HzDHJG35yc/iWbKMHluilRr/LRlm0TP7ir/s6g3PfiTjwbTsXZ3EHxG4aOcOeC9CK8REmYYN+fYoo9OnCG6t1OLnFi305+pOmWKsHs3lI+8o3UN6vKyWM3lKNLeVHn9jwlb8uortzsK6QHnLFU5eYvllFYm96fdAf/H3mG82uIqGBq0SGYuyJqeqXzgcOP+Hr8wAX7dhRJ6fLnYUgQeG8yZD4OQ+Cx/bWs3nDanxyDD/8B&lt;/diagram&gt;&lt;/mxfile&gt;"><defs/><g transform="translate(0.5,0.5)"><path d="M 283 367 C 283 345.67 348 345.67 348 367 L 348 415 C 348 436.33 283 436.33 283 415 Z" fill="#ffffff" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 283 367 C 283 383 348 383 348 367" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(287.5,395.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="54" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 54px; white-space: nowrap; word-wrap: normal; font-weight: bold; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Database</div></div></foreignObject><text x="27" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica" font-weight="bold">Database</text></switch></g><rect x="211" y="211" width="200" height="100" fill="#ffffff" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(252.5,234.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="115" height="51" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 115px; white-space: nowrap; word-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;"><b><font style="font-size: 15px">Web application</font></b><div><b><font size="4"><br /></font></b></div><div><b><br /></b></div></div></div></foreignObject><text x="58" y="32" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">[Not supported by viewer]</text></switch></g><path d="M 274.76 391 L 251 391 Q 241 391 241 381 L 241 308" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 280.76 391 L 272.76 395 L 274.76 391 L 272.76 387 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 348 391 L 372 391 Q 382 391 382 381 L 382 321.24" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 382 315.24 L 386 323.24 L 382 321.24 L 378 323.24 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(177.5,327.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="50" height="26" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 50px; white-space: nowrap; word-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Write<div>datapoint</div></div></div></foreignObject><text x="25" y="19" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">[Not supported by viewer]</text></switch></g><g transform="translate(397.5,327.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="56" height="26" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 56px; white-space: nowrap; word-wrap: normal; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Read<div>datapoints</div></div></div></foreignObject><text x="28" y="19" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica">[Not supported by viewer]</text></switch></g><rect x="151" y="51" width="120" height="60" rx="9" ry="9" fill="#ffffff" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(182.5,67.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="55" height="26" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 55px; white-space: nowrap; word-wrap: normal; font-weight: bold; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Arduino<div>MKR1000</div></div></div></foreignObject><text x="28" y="19" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica" font-weight="bold">[Not supported by viewer]</text></switch></g><rect x="351" y="51" width="120" height="60" rx="9" ry="9" fill="#ffffff" stroke="#000000" stroke-width="2" pointer-events="none"/><g transform="translate(372.5,74.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="75" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 77px; white-space: nowrap; word-wrap: normal; font-weight: bold; text-align: center;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;">Web browser</div></div></foreignObject><text x="38" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Helvetica" font-weight="bold">Web browser</text></switch></g><path d="M 254.57 205.86 L 218.81 177.25 Q 211 171 211 161 L 211 111" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 259.25 209.6 L 250.51 207.73 L 254.57 205.86 L 255.51 201.48 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 367.43 205.86 L 403.19 177.25 Q 411 171 411 161 L 411 119.24" fill="none" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 362.75 209.6 L 366.49 201.48 L 367.43 205.86 L 371.49 207.73 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 411 113.24 L 415 121.24 L 411 119.24 L 407 121.24 Z" fill="#000000" stroke="#000000" stroke-width="2" stroke-miterlimit="10" pointer-events="none"/><path d="M 571 171 L 51 171" fill="none" stroke="#b3b3b3" stroke-width="2" stroke-miterlimit="10" stroke-dasharray="6 6" pointer-events="none"/><g transform="translate(350.5,284.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="45" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: &quot;Times New Roman&quot;; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 46px; white-space: nowrap; word-wrap: normal; font-weight: bold; text-align: right;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;"><font face="Helvetica">Route: /</font></div></div></foreignObject><text x="23" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Times New Roman" font-weight="bold">[Not supported by viewer]</text></switch></g><g transform="translate(222.5,284.5)"><switch><foreignObject style="overflow:visible;" pointer-events="all" width="62" height="12" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"><div xmlns="http://www.w3.org/1999/xhtml" style="display: inline-block; font-size: 12px; font-family: &quot;Times New Roman&quot;; color: rgb(0, 0, 0); line-height: 1.2; vertical-align: top; width: 63px; white-space: nowrap; word-wrap: normal; font-weight: bold;"><div xmlns="http://www.w3.org/1999/xhtml" style="display:inline-block;text-align:inherit;text-decoration:inherit;"><font face="Helvetica">Route: /api</font></div></div></foreignObject><text x="31" y="12" fill="#000000" text-anchor="middle" font-size="12px" font-family="Times New Roman" font-weight="bold">[Not supported by viewer]</text></switch></g></g></svg> \ No newline at end of file
diff --git a/static/posts/iot-application/simple-iot-application.zip b/static/posts/iot-application/simple-iot-application.zip
deleted file mode 100755
index 46d3205..0000000
--- a/static/posts/iot-application/simple-iot-application.zip
+++ /dev/null
Binary files differ
diff --git a/static/posts/iot-application/snakeviz.png b/static/posts/iot-application/snakeviz.png
deleted file mode 100755
index 5bab395..0000000
--- a/static/posts/iot-application/snakeviz.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/microsoundtrack/cow.m4v b/static/posts/microsoundtrack/cow.m4v
deleted file mode 100644
index 1b2461b..0000000
--- a/static/posts/microsoundtrack/cow.m4v
+++ /dev/null
Binary files differ
diff --git a/static/posts/pid1/boxes.mp4 b/static/posts/pid1/boxes.mp4
deleted file mode 100755
index eb647ff..0000000
--- a/static/posts/pid1/boxes.mp4
+++ /dev/null
Binary files differ
diff --git a/static/posts/pid1/qemu.log b/static/posts/pid1/qemu.log
deleted file mode 100755
index 11be312..0000000
--- a/static/posts/pid1/qemu.log
+++ /dev/null
@@ -1,320 +0,0 @@
1[ 0.000000] Linux version 5.15.7 (m@khan) (gcc (GCC) 11.2.1 20211203 (Red Hat 11.2.1-7), GNU ld version 2.37-10.fc35) #7 SMP Mon Dec 13 10:23:25 CET 2021
2[ 0.000000] Command line: console=ttyS0
3[ 0.000000] x86/fpu: x87 FPU will use FXSAVE
4[ 0.000000] signal: max sigframe size: 1440
5[ 0.000000] BIOS-provided physical RAM map:
6[ 0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable
7[ 0.000000] BIOS-e820: [mem 0x000000000009fc00-0x000000000009ffff] reserved
8[ 0.000000] BIOS-e820: [mem 0x00000000000f0000-0x00000000000fffff] reserved
9[ 0.000000] BIOS-e820: [mem 0x0000000000100000-0x0000000007fdffff] usable
10[ 0.000000] BIOS-e820: [mem 0x0000000007fe0000-0x0000000007ffffff] reserved
11[ 0.000000] BIOS-e820: [mem 0x00000000fffc0000-0x00000000ffffffff] reserved
12[ 0.000000] NX (Execute Disable) protection: active
13[ 0.000000] SMBIOS 2.8 present.
14[ 0.000000] DMI: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.14.0-6.fc35 04/01/2014
15[ 0.000000] tsc: Fast TSC calibration failed
16[ 0.000000] last_pfn = 0x7fe0 max_arch_pfn = 0x400000000
17[ 0.000000] x86/PAT: Configuration [0-7]: WB WC UC- UC WB WP UC- WT
18[ 0.000000] found SMP MP-table at [mem 0x000f5c40-0x000f5c4f]
19[ 0.000000] RAMDISK: [mem 0x07e06000-0x07fdffff]
20[ 0.000000] ACPI: Early table checksum verification disabled
21[ 0.000000] ACPI: RSDP 0x00000000000F5A80 000014 (v00 BOCHS )
22[ 0.000000] ACPI: RSDT 0x0000000007FE1905 000034 (v01 BOCHS BXPC 00000001 BXPC 00000001)
23[ 0.000000] ACPI: FACP 0x0000000007FE17B9 000074 (v01 BOCHS BXPC 00000001 BXPC 00000001)
24[ 0.000000] ACPI: DSDT 0x0000000007FE0040 001779 (v01 BOCHS BXPC 00000001 BXPC 00000001)
25[ 0.000000] ACPI: FACS 0x0000000007FE0000 000040
26[ 0.000000] ACPI: APIC 0x0000000007FE182D 000078 (v01 BOCHS BXPC 00000001 BXPC 00000001)
27[ 0.000000] ACPI: HPET 0x0000000007FE18A5 000038 (v01 BOCHS BXPC 00000001 BXPC 00000001)
28[ 0.000000] ACPI: WAET 0x0000000007FE18DD 000028 (v01 BOCHS BXPC 00000001 BXPC 00000001)
29[ 0.000000] ACPI: Reserving FACP table memory at [mem 0x7fe17b9-0x7fe182c]
30[ 0.000000] ACPI: Reserving DSDT table memory at [mem 0x7fe0040-0x7fe17b8]
31[ 0.000000] ACPI: Reserving FACS table memory at [mem 0x7fe0000-0x7fe003f]
32[ 0.000000] ACPI: Reserving APIC table memory at [mem 0x7fe182d-0x7fe18a4]
33[ 0.000000] ACPI: Reserving HPET table memory at [mem 0x7fe18a5-0x7fe18dc]
34[ 0.000000] ACPI: Reserving WAET table memory at [mem 0x7fe18dd-0x7fe1904]
35[ 0.000000] No NUMA configuration found
36[ 0.000000] Faking a node at [mem 0x0000000000000000-0x0000000007fdffff]
37[ 0.000000] NODE_DATA(0) allocated [mem 0x07e02000-0x07e05fff]
38[ 0.000000] Zone ranges:
39[ 0.000000] DMA [mem 0x0000000000001000-0x0000000000ffffff]
40[ 0.000000] DMA32 [mem 0x0000000001000000-0x0000000007fdffff]
41[ 0.000000] Normal empty
42[ 0.000000] Movable zone start for each node
43[ 0.000000] Early memory node ranges
44[ 0.000000] node 0: [mem 0x0000000000001000-0x000000000009efff]
45[ 0.000000] node 0: [mem 0x0000000000100000-0x0000000007fdffff]
46[ 0.000000] Initmem setup node 0 [mem 0x0000000000001000-0x0000000007fdffff]
47[ 0.000000] On node 0, zone DMA: 1 pages in unavailable ranges
48[ 0.000000] On node 0, zone DMA: 97 pages in unavailable ranges
49[ 0.000000] On node 0, zone DMA32: 32 pages in unavailable ranges
50[ 0.000000] ACPI: PM-Timer IO Port: 0x608
51[ 0.000000] ACPI: LAPIC_NMI (acpi_id[0xff] dfl dfl lint[0x1])
52[ 0.000000] IOAPIC[0]: apic_id 0, version 32, address 0xfec00000, GSI 0-23
53[ 0.000000] ACPI: INT_SRC_OVR (bus 0 bus_irq 0 global_irq 2 dfl dfl)
54[ 0.000000] ACPI: INT_SRC_OVR (bus 0 bus_irq 5 global_irq 5 high level)
55[ 0.000000] ACPI: INT_SRC_OVR (bus 0 bus_irq 9 global_irq 9 high level)
56[ 0.000000] ACPI: INT_SRC_OVR (bus 0 bus_irq 10 global_irq 10 high level)
57[ 0.000000] ACPI: INT_SRC_OVR (bus 0 bus_irq 11 global_irq 11 high level)
58[ 0.000000] ACPI: Using ACPI (MADT) for SMP configuration information
59[ 0.000000] ACPI: HPET id: 0x8086a201 base: 0xfed00000
60[ 0.000000] smpboot: Allowing 1 CPUs, 0 hotplug CPUs
61[ 0.000000] PM: hibernation: Registered nosave memory: [mem 0x00000000-0x00000fff]
62[ 0.000000] PM: hibernation: Registered nosave memory: [mem 0x0009f000-0x0009ffff]
63[ 0.000000] PM: hibernation: Registered nosave memory: [mem 0x000a0000-0x000effff]
64[ 0.000000] PM: hibernation: Registered nosave memory: [mem 0x000f0000-0x000fffff]
65[ 0.000000] [mem 0x08000000-0xfffbffff] available for PCI devices
66[ 0.000000] clocksource: refined-jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 1910969940391419 ns
67[ 0.000000] setup_percpu: NR_CPUS:64 nr_cpumask_bits:64 nr_cpu_ids:1 nr_node_ids:1
68[ 0.000000] percpu: Embedded 52 pages/cpu s174360 r8192 d30440 u2097152
69[ 0.000000] Built 1 zonelists, mobility grouping on. Total pages: 31968
70[ 0.000000] Policy zone: DMA32
71[ 0.000000] Kernel command line: console=ttyS0
72[ 0.000000] Dentry cache hash table entries: 16384 (order: 5, 131072 bytes, linear)
73[ 0.000000] Inode-cache hash table entries: 8192 (order: 4, 65536 bytes, linear)
74[ 0.000000] mem auto-init: stack:off, heap alloc:off, heap free:off
75[ 0.000000] Memory: 94464K/130552K available (14350K kernel code, 2582K rwdata, 3596K rodata, 1368K init, 1488K bss, 35828K reserved, 0K cma-reserved)
76[ 0.000000] SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=1, Nodes=1
77[ 0.000000] rcu: Hierarchical RCU implementation.
78[ 0.000000] rcu: RCU event tracing is enabled.
79[ 0.000000] rcu: RCU restricting CPUs from NR_CPUS=64 to nr_cpu_ids=1.
80[ 0.000000] rcu: RCU calculated value of scheduler-enlistment delay is 100 jiffies.
81[ 0.000000] rcu: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=1
82[ 0.000000] NR_IRQS: 4352, nr_irqs: 256, preallocated irqs: 16
83[ 0.000000] random: get_random_bytes called from start_kernel+0x492/0x65f with crng_init=0
84[ 0.000000] Console: colour VGA+ 80x25
85[ 0.000000] printk: console [ttyS0] enabled
86[ 0.000000] ACPI: Core revision 20210730
87[ 0.000000] clocksource: hpet: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604467 ns
88[ 0.002000] APIC: Switch to symmetric I/O mode setup
89[ 0.005000] ..TIMER: vector=0x30 apic1=0 pin1=2 apic2=-1 pin2=-1
90[ 0.013000] tsc: Unable to calibrate against PIT
91[ 0.014000] tsc: using HPET reference calibration
92[ 0.014000] tsc: Detected 3189.099 MHz processor
93[ 0.001005] clocksource: tsc-early: mask: 0xffffffffffffffff max_cycles: 0x2df8103a89b, max_idle_ns: 440795220785 ns
94[ 0.002672] Calibrating delay loop (skipped), value calculated using timer frequency.. 6378.19 BogoMIPS (lpj=3189099)
95[ 0.002960] pid_max: default: 32768 minimum: 301
96[ 0.003627] LSM: Security Framework initializing
97[ 0.004329] SELinux: Initializing.
98[ 0.005051] Mount-cache hash table entries: 512 (order: 0, 4096 bytes, linear)
99[ 0.005202] Mountpoint-cache hash table entries: 512 (order: 0, 4096 bytes, linear)
100[ 0.020479] process: using AMD E400 aware idle routine
101[ 0.020699] Last level iTLB entries: 4KB 512, 2MB 255, 4MB 127
102[ 0.020832] Last level dTLB entries: 4KB 512, 2MB 255, 4MB 127, 1GB 0
103[ 0.021165] Spectre V1 : Mitigation: usercopy/swapgs barriers and __user pointer sanitization
104[ 0.021438] Spectre V2 : Mitigation: Full AMD retpoline
105[ 0.021586] Spectre V2 : Spectre v2 / SpectreRSB mitigation: Filling RSB on context switch
106[ 0.238228] Freeing SMP alternatives memory: 44K
107[ 0.242641] random: fast init done
108[ 0.350203] smpboot: CPU0: AMD QEMU Virtual CPU version 2.5+ (family: 0xf, model: 0x6b, stepping: 0x1)
109[ 0.355136] Performance Events: PMU not available due to virtualization, using software events only.
110[ 0.356607] rcu: Hierarchical SRCU implementation.
111[ 0.360890] smp: Bringing up secondary CPUs ...
112[ 0.361082] smp: Brought up 1 node, 1 CPU
113[ 0.361253] smpboot: Max logical packages: 1
114[ 0.361394] smpboot: Total of 1 processors activated (6378.19 BogoMIPS)
115[ 0.371481] devtmpfs: initialized
116[ 0.378162] clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 1911260446275000 ns
117[ 0.378478] futex hash table entries: 256 (order: 2, 16384 bytes, linear)
118[ 0.381522] PM: RTC time: 00:19:47, date: 2021-12-27
119[ 0.384915] NET: Registered PF_NETLINK/PF_ROUTE protocol family
120[ 0.387403] audit: initializing netlink subsys (disabled)
121[ 0.391765] audit: type=2000 audit(1640564386.402:1): state=initialized audit_enabled=0 res=1
122[ 0.392916] thermal_sys: Registered thermal governor 'step_wise'
123[ 0.392950] thermal_sys: Registered thermal governor 'user_space'
124[ 0.393202] cpuidle: using governor menu
125[ 0.394085] ACPI: bus type PCI registered
126[ 0.396583] PCI: Using configuration type 1 for base access
127[ 0.415012] Kprobes globally optimized
128[ 0.416844] HugeTLB registered 2.00 MiB page size, pre-allocated 0 pages
129[ 0.420649] cryptomgr_test (20) used greatest stack depth: 15680 bytes left
130[ 0.426071] ACPI: Added _OSI(Module Device)
131[ 0.426182] ACPI: Added _OSI(Processor Device)
132[ 0.426279] ACPI: Added _OSI(3.0 _SCP Extensions)
133[ 0.426376] ACPI: Added _OSI(Processor Aggregator Device)
134[ 0.426606] ACPI: Added _OSI(Linux-Dell-Video)
135[ 0.426709] ACPI: Added _OSI(Linux-Lenovo-NV-HDMI-Audio)
136[ 0.426821] ACPI: Added _OSI(Linux-HPI-Hybrid-Graphics)
137[ 0.439511] ACPI: 1 ACPI AML tables successfully acquired and loaded
138[ 0.452709] ACPI: Interpreter enabled
139[ 0.453468] ACPI: PM: (supports S0 S3 S4 S5)
140[ 0.453603] ACPI: Using IOAPIC for interrupt routing
141[ 0.454022] PCI: Using host bridge windows from ACPI; if necessary, use "pci=nocrs" and report a bug
142[ 0.455266] ACPI: Enabled 2 GPEs in block 00 to 0F
143[ 0.480013] ACPI: PCI Root Bridge [PCI0] (domain 0000 [bus 00-ff])
144[ 0.480702] acpi PNP0A03:00: _OSC: OS supports [ASPM ClockPM Segments MSI HPX-Type3]
145[ 0.481425] acpi PNP0A03:00: fail to add MMCONFIG information, can't access extended PCI configuration space under this bridge.
146[ 0.483666] PCI host bridge to bus 0000:00
147[ 0.483848] pci_bus 0000:00: root bus resource [io 0x0000-0x0cf7 window]
148[ 0.484096] pci_bus 0000:00: root bus resource [io 0x0d00-0xffff window]
149[ 0.484237] pci_bus 0000:00: root bus resource [mem 0x000a0000-0x000bffff window]
150[ 0.484480] pci_bus 0000:00: root bus resource [mem 0x08000000-0xfebfffff window]
151[ 0.484578] pci_bus 0000:00: root bus resource [mem 0x100000000-0x17fffffff window]
152[ 0.484870] pci_bus 0000:00: root bus resource [bus 00-ff]
153[ 0.486588] pci 0000:00:00.0: [8086:1237] type 00 class 0x060000
154[ 0.492625] pci 0000:00:01.0: [8086:7000] type 00 class 0x060100
155[ 0.493621] pci 0000:00:01.1: [8086:7010] type 00 class 0x010180
156[ 0.495015] pci 0000:00:01.1: reg 0x20: [io 0xc040-0xc04f]
157[ 0.495760] pci 0000:00:01.1: legacy IDE quirk: reg 0x10: [io 0x01f0-0x01f7]
158[ 0.495936] pci 0000:00:01.1: legacy IDE quirk: reg 0x14: [io 0x03f6]
159[ 0.496095] pci 0000:00:01.1: legacy IDE quirk: reg 0x18: [io 0x0170-0x0177]
160[ 0.496598] pci 0000:00:01.1: legacy IDE quirk: reg 0x1c: [io 0x0376]
161[ 0.497793] pci 0000:00:01.3: [8086:7113] type 00 class 0x068000
162[ 0.498219] pci 0000:00:01.3: quirk: [io 0x0600-0x063f] claimed by PIIX4 ACPI
163[ 0.498384] pci 0000:00:01.3: quirk: [io 0x0700-0x070f] claimed by PIIX4 SMB
164[ 0.499487] pci 0000:00:02.0: [1234:1111] type 00 class 0x030000
165[ 0.500186] pci 0000:00:02.0: reg 0x10: [mem 0xfd000000-0xfdffffff pref]
166[ 0.500569] pci 0000:00:02.0: reg 0x18: [mem 0xfebf0000-0xfebf0fff]
167[ 0.502569] pci 0000:00:02.0: reg 0x30: [mem 0xfebe0000-0xfebeffff pref]
168[ 0.508052] pci 0000:00:03.0: [8086:100e] type 00 class 0x020000
169[ 0.508590] pci 0000:00:03.0: reg 0x10: [mem 0xfebc0000-0xfebdffff]
170[ 0.509075] pci 0000:00:03.0: reg 0x14: [io 0xc000-0xc03f]
171[ 0.511015] pci 0000:00:03.0: reg 0x30: [mem 0xfeb80000-0xfebbffff pref]
172[ 0.517286] ACPI: PCI: Interrupt link LNKA configured for IRQ 10
173[ 0.518032] ACPI: PCI: Interrupt link LNKB configured for IRQ 10
174[ 0.518504] ACPI: PCI: Interrupt link LNKC configured for IRQ 11
175[ 0.518920] ACPI: PCI: Interrupt link LNKD configured for IRQ 11
176[ 0.519208] ACPI: PCI: Interrupt link LNKS configured for IRQ 9
177[ 0.521412] iommu: Default domain type: Translated
178[ 0.521589] iommu: DMA domain TLB invalidation policy: lazy mode
179[ 0.524448] pci 0000:00:02.0: vgaarb: setting as boot VGA device
180[ 0.524569] pci 0000:00:02.0: vgaarb: VGA device added: decodes=io+mem,owns=io+mem,locks=none
181[ 0.524633] pci 0000:00:02.0: vgaarb: bridge control possible
182[ 0.524846] vgaarb: loaded
183[ 0.526151] SCSI subsystem initialized
184[ 0.528124] ACPI: bus type USB registered
185[ 0.528600] usbcore: registered new interface driver usbfs
186[ 0.528917] usbcore: registered new interface driver hub
187[ 0.529156] usbcore: registered new device driver usb
188[ 0.529593] pps_core: LinuxPPS API ver. 1 registered
189[ 0.529693] pps_core: Software ver. 5.3.6 - Copyright 2005-2007 Rodolfo Giometti <giometti@linux.it>
190[ 0.529916] PTP clock support registered
191[ 0.531428] Advanced Linux Sound Architecture Driver Initialized.
192[ 0.538313] NetLabel: Initializing
193[ 0.538413] NetLabel: domain hash size = 128
194[ 0.538513] NetLabel: protocols = UNLABELED CIPSOv4 CALIPSO
195[ 0.539300] NetLabel: unlabeled traffic allowed by default
196[ 0.540192] PCI: Using ACPI for IRQ routing
197[ 0.541336] hpet: 3 channels of 0 reserved for per-cpu timers
198[ 0.541742] hpet0: at MMIO 0xfed00000, IRQs 2, 8, 0
199[ 0.541934] hpet0: 3 comparators, 64-bit 100.000000 MHz counter
200[ 0.547124] clocksource: Switched to clocksource tsc-early
201[ 0.589778] VFS: Disk quotas dquot_6.6.0
202[ 0.590116] VFS: Dquot-cache hash table entries: 512 (order 0, 4096 bytes)
203[ 0.591999] pnp: PnP ACPI init
204[ 1.348853] pnp: PnP ACPI: found 6 devices
205[ 1.363393] clocksource: acpi_pm: mask: 0xffffff max_cycles: 0xffffff, max_idle_ns: 2085701024 ns
206[ 1.364026] NET: Registered PF_INET protocol family
207[ 1.364871] IP idents hash table entries: 2048 (order: 2, 16384 bytes, linear)
208[ 1.369722] tcp_listen_portaddr_hash hash table entries: 256 (order: 0, 4096 bytes, linear)
209[ 1.369973] TCP established hash table entries: 1024 (order: 1, 8192 bytes, linear)
210[ 1.370241] TCP bind hash table entries: 1024 (order: 2, 16384 bytes, linear)
211[ 1.370483] TCP: Hash tables configured (established 1024 bind 1024)
212[ 1.371348] UDP hash table entries: 256 (order: 1, 8192 bytes, linear)
213[ 1.371835] UDP-Lite hash table entries: 256 (order: 1, 8192 bytes, linear)
214[ 1.373053] NET: Registered PF_UNIX/PF_LOCAL protocol family
215[ 1.374701] RPC: Registered named UNIX socket transport module.
216[ 1.375153] RPC: Registered udp transport module.
217[ 1.375280] RPC: Registered tcp transport module.
218[ 1.375386] RPC: Registered tcp NFSv4.1 backchannel transport module.
219[ 1.377429] pci_bus 0000:00: resource 4 [io 0x0000-0x0cf7 window]
220[ 1.377567] pci_bus 0000:00: resource 5 [io 0x0d00-0xffff window]
221[ 1.377738] pci_bus 0000:00: resource 6 [mem 0x000a0000-0x000bffff window]
222[ 1.377893] pci_bus 0000:00: resource 7 [mem 0x08000000-0xfebfffff window]
223[ 1.378032] pci_bus 0000:00: resource 8 [mem 0x100000000-0x17fffffff window]
224[ 1.378574] pci 0000:00:01.0: PIIX3: Enabling Passive Release
225[ 1.378817] pci 0000:00:00.0: Limiting direct PCI/PCI transfers
226[ 1.378993] pci 0000:00:01.0: Activating ISA DMA hang workarounds
227[ 1.379296] pci 0000:00:02.0: Video device with shadowed ROM at [mem 0x000c0000-0x000dffff]
228[ 1.379537] PCI: CLS 0 bytes, default 64
229[ 1.385473] Unpacking initramfs...
230[ 1.394653] Initialise system trusted keyrings
231[ 1.395898] workingset: timestamp_bits=56 max_order=15 bucket_order=0
232[ 1.400517] Freeing initrd memory: 1896K
233[ 1.409899] NFS: Registering the id_resolver key type
234[ 1.410240] Key type id_resolver registered
235[ 1.410358] Key type id_legacy registered
236[ 1.436299] Key type asymmetric registered
237[ 1.436505] Asymmetric key parser 'x509' registered
238[ 1.436899] Block layer SCSI generic (bsg) driver version 0.4 loaded (major 251)
239[ 1.437334] io scheduler mq-deadline registered
240[ 1.437848] io scheduler kyber registered
241[ 1.440723] input: Power Button as /devices/LNXSYSTM:00/LNXPWRBN:00/input/input0
242[ 1.443386] ACPI: button: Power Button [PWRF]
243[ 1.445654] Serial: 8250/16550 driver, 4 ports, IRQ sharing enabled
244[ 1.447264] 00:04: ttyS0 at I/O 0x3f8 (irq = 4, base_baud = 115200) is a 16550A
245[ 1.450740] Non-volatile memory driver v1.3
246[ 1.451106] Linux agpgart interface v0.103
247[ 1.467087] loop: module loaded
248[ 1.474468] scsi host0: ata_piix
249[ 1.476252] scsi host1: ata_piix
250[ 1.476701] ata1: PATA max MWDMA2 cmd 0x1f0 ctl 0x3f6 bmdma 0xc040 irq 14
251[ 1.476882] ata2: PATA max MWDMA2 cmd 0x170 ctl 0x376 bmdma 0xc048 irq 15
252[ 1.481539] libphy: Fixed MDIO Bus: probed
253[ 1.482188] e100: Intel(R) PRO/100 Network Driver
254[ 1.482313] e100: Copyright(c) 1999-2006 Intel Corporation
255[ 1.482507] e1000: Intel(R) PRO/1000 Network Driver
256[ 1.482702] e1000: Copyright (c) 1999-2006 Intel Corporation.
257[ 1.616439] ACPI: \_SB_.LNKC: Enabled at IRQ 11
258[ 1.649465] ata2.00: ATAPI: QEMU DVD-ROM, 2.5+, max UDMA/100
259[ 1.664135] scsi 1:0:0:0: CD-ROM QEMU QEMU DVD-ROM 2.5+ PQ: 0 ANSI: 5
260[ 1.693021] sr 1:0:0:0: [sr0] scsi3-mmc drive: 4x/4x cd/rw xa/form2 tray
261[ 1.693338] cdrom: Uniform CD-ROM driver Revision: 3.20
262[ 1.723925] sr 1:0:0:0: Attached scsi generic sg0 type 5
263[ 1.946674] e1000 0000:00:03.0 eth0: (PCI:33MHz:32-bit) 52:54:00:12:34:56
264[ 1.947107] e1000 0000:00:03.0 eth0: Intel(R) PRO/1000 Network Connection
265[ 1.947650] e1000e: Intel(R) PRO/1000 Network Driver
266[ 1.947749] e1000e: Copyright(c) 1999 - 2015 Intel Corporation.
267[ 1.947947] sky2: driver version 1.30
268[ 1.948805] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI) Driver
269[ 1.948993] ehci-pci: EHCI PCI platform driver
270[ 1.949218] ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
271[ 1.949394] ohci-pci: OHCI PCI platform driver
272[ 1.949636] uhci_hcd: USB Universal Host Controller Interface driver
273[ 1.950082] usbcore: registered new interface driver usblp
274[ 1.950302] usbcore: registered new interface driver usb-storage
275[ 1.951012] i8042: PNP: PS/2 Controller [PNP0303:KBD,PNP0f13:MOU] at 0x60,0x64 irq 1,12
276[ 1.954333] serio: i8042 KBD port at 0x60,0x64 irq 1
277[ 1.954634] serio: i8042 AUX port at 0x60,0x64 irq 12
278[ 1.957984] input: AT Translated Set 2 keyboard as /devices/platform/i8042/serio0/input/input1
279[ 1.960071] rtc_cmos 00:05: RTC can wake from S4
280[ 1.964738] rtc_cmos 00:05: registered as rtc0
281[ 1.965357] rtc_cmos 00:05: alarms up to one day, y3k, 242 bytes nvram, hpet irqs
282[ 1.966676] device-mapper: ioctl: 4.45.0-ioctl (2021-03-22) initialised: dm-devel@redhat.com
283[ 1.967364] hid: raw HID events driver (C) Jiri Kosina
284[ 1.968571] usbcore: registered new interface driver usbhid
285[ 1.968750] usbhid: USB HID core driver
286[ 1.974818] Initializing XFRM netlink socket
287[ 1.975673] NET: Registered PF_INET6 protocol family
288[ 1.981212] Segment Routing with IPv6
289[ 1.981421] In-situ OAM (IOAM) with IPv6
290[ 1.982292] sit: IPv6, IPv4 and MPLS over IPv4 tunneling driver
291[ 1.984278] NET: Registered PF_PACKET protocol family
292[ 1.984857] Key type dns_resolver registered
293[ 1.985989] IPI shorthand broadcast: enabled
294[ 1.986261] sched_clock: Marking stable (1999028700, -13430834)->(1985937339, -339473)
295[ 1.987965] registered taskstats version 1
296[ 1.988095] Loading compiled-in X.509 certificates
297[ 1.991283] PM: Magic number: 1:335:305
298[ 1.991523] tty tty34: hash matches
299[ 1.991951] printk: console [netcon0] enabled
300[ 1.992067] netconsole: network logging started
301[ 1.994549] cfg80211: Loading compiled-in X.509 certificates for regulatory database
302[ 2.004972] kworker/u2:2 (64) used greatest stack depth: 14856 bytes left
303[ 2.012521] cfg80211: Loaded X.509 cert 'sforshee: 00b28ddf47aef9cea7'
304[ 2.013924] platform regulatory.0: Direct firmware load for regulatory.db failed with error -2
305[ 2.014318] cfg80211: failed to load regulatory.db
306[ 2.016106] ALSA device list:
307[ 2.016329] No soundcards found.
308[ 2.053176] Freeing unused kernel image (initmem) memory: 1368K
309[ 2.056095] Write protecting the kernel read-only data: 20480k
310[ 2.058248] Freeing unused kernel image (text/rodata gap) memory: 2032K
311[ 2.058811] Freeing unused kernel image (rodata/data gap) memory: 500K
312[ 2.059164] Run /init as init process
313Hello from Golang
314[ 2.386879] tsc: Refined TSC clocksource calibration: 3192.032 MHz
315[ 2.387114] clocksource: tsc: mask: 0xffffffffffffffff max_cycles: 0x2e02e31fa14, max_idle_ns: 440795264947 ns
316[ 2.387380] clocksource: Switched to clocksource tsc
317[ 2.587895] input: ImExPS/2 Generic Explorer Mouse as /devices/platform/i8042/serio1/input/input3
318Hello from Golang
319Hello from Golang
320Hello from Golang
diff --git a/static/posts/pid1/unikernels.png b/static/posts/pid1/unikernels.png
deleted file mode 100644
index 4396d02..0000000
--- a/static/posts/pid1/unikernels.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/pid1/unikernels.svg b/static/posts/pid1/unikernels.svg
deleted file mode 100755
index 47ad8f0..0000000
--- a/static/posts/pid1/unikernels.svg
+++ /dev/null
@@ -1,587 +0,0 @@
1<?xml version="1.0" encoding="UTF-8" standalone="no"?>
2<!-- Created with Inkscape (http://www.inkscape.org/) -->
3
4<svg
5 width="200.21642mm"
6 height="75mm"
7 viewBox="0 0 200.21642 75"
8 version="1.1"
9 id="svg5"
10 inkscape:version="1.3 (0e150ed6c4, 2023-07-21)"
11 sodipodi:docname="unikernels.svg"
12 inkscape:export-filename="unikernels.webp"
13 inkscape:export-xdpi="202.98035"
14 inkscape:export-ydpi="202.98035"
15 xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
16 xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
17 xmlns="http://www.w3.org/2000/svg"
18 xmlns:svg="http://www.w3.org/2000/svg">
19 <sodipodi:namedview
20 id="namedview7"
21 pagecolor="#ffffff"
22 bordercolor="#666666"
23 borderopacity="1.0"
24 inkscape:pageshadow="2"
25 inkscape:pageopacity="0.0"
26 inkscape:pagecheckerboard="0"
27 inkscape:document-units="mm"
28 showgrid="false"
29 inkscape:zoom="1.0570195"
30 inkscape:cx="460.72944"
31 inkscape:cy="274.35634"
32 inkscape:window-width="2803"
33 inkscape:window-height="1917"
34 inkscape:window-x="661"
35 inkscape:window-y="163"
36 inkscape:window-maximized="0"
37 inkscape:current-layer="g2"
38 showguides="true"
39 inkscape:guide-bbox="true"
40 inkscape:showpageshadow="2"
41 inkscape:deskcolor="#d1d1d1" />
42 <defs
43 id="defs2" />
44 <g
45 inkscape:label="Layer 1"
46 inkscape:groupmode="layer"
47 id="layer1"
48 transform="translate(0.10821027)">
49 <g
50 id="g2">
51 <rect
52 style="fill:#ececec;stroke:none;stroke-width:0.317673;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
53 id="rect18248"
54 width="65.511665"
55 height="74.960197"
56 x="-0.10821027"
57 y="0.039806042"
58 inkscape:export-filename="/home/m/Vault/projects/mitjafelicijan.com/pid1/unikernels.png"
59 inkscape:export-xdpi="127.98862"
60 inkscape:export-ydpi="127.98862" />
61 <text
62 xml:space="preserve"
63 style="font-style:normal;font-variant:normal;font-weight:900;font-stretch:normal;font-size:2.82222px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Heavy';fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
64 x="33.413715"
65 y="69.135246"
66 id="text18439"
67 inkscape:export-filename="/home/m/Vault/projects/mitjafelicijan.com/pid1/unikernels.png"
68 inkscape:export-xdpi="127.98862"
69 inkscape:export-ydpi="127.98862"><tspan
70 sodipodi:role="line"
71 id="tspan18437"
72 style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:2.82222px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Ultra-Bold';text-align:center;text-anchor:middle;fill:#000000;stroke-width:0.264583"
73 x="33.413715"
74 y="69.135246">VIRTUAL MACHINE</tspan></text>
75 <g
76 id="g50691"
77 transform="translate(-5.8033597,-177.06712)"
78 inkscape:export-filename="/home/m/Vault/projects/mitjafelicijan.com/pid1/unikernels.png"
79 inkscape:export-xdpi="127.98862"
80 inkscape:export-ydpi="127.98862">
81 <rect
82 style="fill:#f9f9f9;stroke:none;stroke-width:0.429153;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
83 id="rect38097-3"
84 width="50.57568"
85 height="8.4333"
86 x="13.294504"
87 y="213.63496"
88 ry="1.5" />
89 <text
90 xml:space="preserve"
91 style="font-style:normal;font-variant:normal;font-weight:900;font-stretch:normal;font-size:2.46944px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Heavy';text-align:center;text-anchor:middle;fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:0.264583"
92 x="38.437649"
93 y="218.54976"
94 id="text32261"><tspan
95 sodipodi:role="line"
96 id="tspan32259"
97 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.46944px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;text-anchor:middle;fill:#4d4d4d;stroke-width:0.264583"
98 x="38.437649"
99 y="218.54976">HOST OS / HYPERVISOR</tspan></text>
100 </g>
101 <rect
102 style="fill:#f9f9f9;stroke:none;stroke-width:0.499999;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
103 id="rect38097"
104 width="22.000685"
105 height="26.315866"
106 x="7.4911447"
107 y="6.5477819"
108 ry="1.5" />
109 <text
110 xml:space="preserve"
111 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:0.264583"
112 x="18.532665"
113 y="26.623709"
114 id="text38435"
115 dx="0 0 0 0 0 0 0 0"><tspan
116 sodipodi:role="line"
117 id="tspan38433"
118 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;text-anchor:middle;fill:#4d4d4d;stroke-width:0.264583"
119 x="18.532665"
120 y="26.623709">VIRTUAL</tspan><tspan
121 sodipodi:role="line"
122 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;text-anchor:middle;fill:#4d4d4d;stroke-width:0.264583"
123 x="18.532665"
124 y="28.740379"
125 id="tspan38945">MACHINE</tspan></text>
126 <text
127 xml:space="preserve"
128 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:0.264583"
129 x="18.532665"
130 y="20.60285"
131 id="text41165"><tspan
132 sodipodi:role="line"
133 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;text-anchor:middle;fill:#4d4d4d;stroke-width:0.264583"
134 x="18.532665"
135 y="20.60285"
136 id="tspan41163">GUEST OS</tspan></text>
137 <text
138 xml:space="preserve"
139 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:0.264583"
140 x="18.532665"
141 y="11.807091"
142 id="text42587"><tspan
143 sodipodi:role="line"
144 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;text-anchor:middle;fill:#4d4d4d;stroke-width:0.264583"
145 x="18.532665"
146 y="11.807091"
147 id="tspan42611"><tspan
148 dx="0.088498212"
149 id="tspan1"
150 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;text-anchor:middle;fill:#4d4d4d;stroke-width:0.264583">TARGET</tspan></tspan><tspan
151 sodipodi:role="line"
152 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;text-anchor:middle;fill:#4d4d4d;stroke-width:0.264583"
153 x="18.532665"
154 y="13.92376"
155 id="tspan2">SOFTWARE</tspan></text>
156 <g
157 id="g50696"
158 transform="translate(-5.8033597,-174.95045)"
159 inkscape:export-filename="/home/m/Vault/projects/mitjafelicijan.com/pid1/unikernels.png"
160 inkscape:export-xdpi="127.98862"
161 inkscape:export-ydpi="127.98862">
162 <rect
163 style="fill:#f9f9f9;stroke:none;stroke-width:0.429153;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
164 id="rect48544"
165 width="50.57568"
166 height="8.4333"
167 x="13.294504"
168 y="223.15991"
169 ry="1.5" />
170 <text
171 xml:space="preserve"
172 style="font-style:normal;font-variant:normal;font-weight:900;font-stretch:normal;font-size:2.46944px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Heavy';text-align:center;text-anchor:middle;fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:0.264583"
173 x="38.437649"
174 y="228.24654"
175 id="text47169"><tspan
176 sodipodi:role="line"
177 id="tspan47167"
178 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.46944px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;text-anchor:middle;fill:#4d4d4d;stroke-width:0.264583"
179 x="38.437649"
180 y="228.24654">HARDWARE</tspan></text>
181 </g>
182 <g
183 id="g48202"
184 transform="translate(22.771639,-177.59628)"
185 inkscape:export-filename="/home/m/Vault/projects/mitjafelicijan.com/pid1/unikernels.png"
186 inkscape:export-xdpi="127.98862"
187 inkscape:export-ydpi="127.98862">
188 <rect
189 style="fill:#f9f9f9;stroke:none;stroke-width:0.499999;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
190 id="rect48184"
191 width="22.000685"
192 height="26.315866"
193 x="13.294504"
194 y="184.14406"
195 ry="1.5" />
196 <text
197 xml:space="preserve"
198 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:0.264583"
199 x="24.336025"
200 y="204.21999"
201 id="text48190"><tspan
202 sodipodi:role="line"
203 id="tspan48186"
204 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;text-anchor:middle;fill:#4d4d4d;stroke-width:0.264583"
205 x="24.336025"
206 y="204.21999">VIRTUAL</tspan><tspan
207 sodipodi:role="line"
208 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;text-anchor:middle;fill:#4d4d4d;stroke-width:0.264583"
209 x="24.336025"
210 y="206.33665"
211 id="tspan48188">MACHINE</tspan></text>
212 <text
213 xml:space="preserve"
214 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:0.264583"
215 x="24.336025"
216 y="198.19913"
217 id="text48194"><tspan
218 sodipodi:role="line"
219 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;text-anchor:middle;fill:#4d4d4d;stroke-width:0.264583"
220 x="24.336025"
221 y="198.19913"
222 id="tspan48192">GUEST OS</tspan></text>
223 <text
224 xml:space="preserve"
225 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:0.264583"
226 x="24.336025"
227 y="189.40337"
228 id="text48200"><tspan
229 sodipodi:role="line"
230 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;text-anchor:middle;fill:#4d4d4d;stroke-width:0.264583"
231 x="24.336025"
232 y="189.40337"
233 id="tspan48196">TARGET</tspan><tspan
234 sodipodi:role="line"
235 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;text-anchor:middle;fill:#4d4d4d;stroke-width:0.264583"
236 x="24.336025"
237 y="191.52003"
238 id="tspan48198">SOFTWARE</tspan></text>
239 </g>
240 </g>
241 <g
242 id="g19"
243 transform="translate(-1.6776424,0.01990127)">
244 <g
245 id="g17"
246 transform="translate(69.03002,-0.03980604)">
247 <rect
248 style="fill:#ececec;stroke:none;stroke-width:0.317673;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
249 id="rect2"
250 width="65.511665"
251 height="74.960197"
252 x="-0.10821027"
253 y="0.039806042"
254 inkscape:export-filename="/home/m/Vault/projects/mitjafelicijan.com/pid1/unikernels.png"
255 inkscape:export-xdpi="127.98862"
256 inkscape:export-ydpi="127.98862" />
257 <text
258 xml:space="preserve"
259 style="font-style:normal;font-variant:normal;font-weight:900;font-stretch:normal;font-size:2.82222px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Heavy';text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
260 x="30.965847"
261 y="69.175049"
262 id="text3"
263 inkscape:export-filename="/home/m/Vault/projects/mitjafelicijan.com/pid1/unikernels.png"
264 inkscape:export-xdpi="127.98862"
265 inkscape:export-ydpi="127.98862"><tspan
266 sodipodi:role="line"
267 id="tspan3"
268 style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:2.82222px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Ultra-Bold';text-align:center;text-anchor:middle;fill:#000000;stroke-width:0.264583"
269 x="30.965847"
270 y="69.175049">CONTAINERS</tspan></text>
271 <g
272 id="g4"
273 transform="translate(-5.8033597,-177.06712)"
274 inkscape:export-filename="/home/m/Vault/projects/mitjafelicijan.com/pid1/unikernels.png"
275 inkscape:export-xdpi="127.98862"
276 inkscape:export-ydpi="127.98862">
277 <rect
278 style="fill:#f9f9f9;stroke:none;stroke-width:0.429153;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
279 id="rect3"
280 width="50.57568"
281 height="8.4333"
282 x="13.294504"
283 y="213.63496"
284 ry="1.5" />
285 <text
286 xml:space="preserve"
287 style="font-style:normal;font-variant:normal;font-weight:900;font-stretch:normal;font-size:2.46944px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Heavy';text-align:center;text-anchor:middle;fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:0.264583"
288 x="38.437649"
289 y="218.72159"
290 id="text4"><tspan
291 sodipodi:role="line"
292 id="tspan4"
293 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.46944px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;text-anchor:middle;fill:#4d4d4d;stroke-width:0.264583"
294 x="38.437649"
295 y="218.72159">HOST OS</tspan></text>
296 </g>
297 <rect
298 style="fill:#f9f9f9;stroke:none;stroke-width:0.499999;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
299 id="rect4"
300 width="22.000685"
301 height="26.315866"
302 x="7.4911447"
303 y="6.5477819"
304 ry="1.5" />
305 <text
306 xml:space="preserve"
307 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:0.264583"
308 x="18.532665"
309 y="26.623709"
310 id="text6"><tspan
311 sodipodi:role="line"
312 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;text-anchor:middle;fill:#4d4d4d;stroke-width:0.264583"
313 x="18.532665"
314 y="26.623709"
315 id="tspan6">CONTAINER</tspan></text>
316 <text
317 xml:space="preserve"
318 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:0.264583"
319 x="18.532665"
320 y="19.015348"
321 id="text7"><tspan
322 sodipodi:role="line"
323 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;text-anchor:middle;fill:#4d4d4d;stroke-width:0.264583"
324 x="18.532665"
325 y="19.015348"
326 id="tspan7">PROGRAMS &amp;</tspan><tspan
327 sodipodi:role="line"
328 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;text-anchor:middle;fill:#4d4d4d;stroke-width:0.264583"
329 x="18.532665"
330 y="21.132019"
331 id="tspan17">LIBRARIES</tspan></text>
332 <text
333 xml:space="preserve"
334 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:0.264583"
335 x="18.532665"
336 y="11.807091"
337 id="text10"><tspan
338 sodipodi:role="line"
339 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;text-anchor:middle;fill:#4d4d4d;stroke-width:0.264583"
340 x="18.532665"
341 y="11.807091"
342 id="tspan9"><tspan
343 dx="0.088498212"
344 id="tspan8"
345 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;text-anchor:middle;fill:#4d4d4d;stroke-width:0.264583">TARGET</tspan></tspan><tspan
346 sodipodi:role="line"
347 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;text-anchor:middle;fill:#4d4d4d;stroke-width:0.264583"
348 x="18.532665"
349 y="13.92376"
350 id="tspan10">SOFTWARE</tspan></text>
351 <g
352 id="g11"
353 transform="translate(-5.8033597,-174.95045)"
354 inkscape:export-filename="/home/m/Vault/projects/mitjafelicijan.com/pid1/unikernels.png"
355 inkscape:export-xdpi="127.98862"
356 inkscape:export-ydpi="127.98862">
357 <rect
358 style="fill:#f9f9f9;stroke:none;stroke-width:0.429153;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
359 id="rect10"
360 width="50.57568"
361 height="8.4333"
362 x="13.294504"
363 y="223.15991"
364 ry="1.5" />
365 <text
366 xml:space="preserve"
367 style="font-style:normal;font-variant:normal;font-weight:900;font-stretch:normal;font-size:2.46944px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Heavy';text-align:center;text-anchor:middle;fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:0.264583"
368 x="38.437649"
369 y="228.24654"
370 id="text11"><tspan
371 sodipodi:role="line"
372 id="tspan11"
373 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.46944px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;text-anchor:middle;fill:#4d4d4d;stroke-width:0.264583"
374 x="38.437649"
375 y="228.24654">HARDWARE</tspan></text>
376 </g>
377 <g
378 id="g16"
379 transform="translate(22.771639,-177.59628)"
380 inkscape:export-filename="/home/m/Vault/projects/mitjafelicijan.com/pid1/unikernels.png"
381 inkscape:export-xdpi="127.98862"
382 inkscape:export-ydpi="127.98862">
383 <rect
384 style="fill:#f9f9f9;stroke:none;stroke-width:0.499999;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
385 id="rect11"
386 width="22.000685"
387 height="26.315866"
388 x="13.294504"
389 y="184.14406"
390 ry="1.5" />
391 <text
392 xml:space="preserve"
393 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:0.264583"
394 x="24.336025"
395 y="204.21999"
396 id="text13"><tspan
397 sodipodi:role="line"
398 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;text-anchor:middle;fill:#4d4d4d;stroke-width:0.264583"
399 x="24.336025"
400 y="204.21999"
401 id="tspan13">CONTAINER</tspan></text>
402 <text
403 xml:space="preserve"
404 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:0.264583"
405 x="24.336025"
406 y="196.61165"
407 id="text14"><tspan
408 sodipodi:role="line"
409 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;text-anchor:middle;fill:#4d4d4d;stroke-width:0.264583"
410 x="24.336025"
411 y="196.61165"
412 id="tspan14">PROGRAMS &amp;</tspan><tspan
413 sodipodi:role="line"
414 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;text-anchor:middle;fill:#4d4d4d;stroke-width:0.264583"
415 x="24.336025"
416 y="198.72832"
417 id="tspan18">LIBRARIES</tspan></text>
418 <text
419 xml:space="preserve"
420 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:0.264583"
421 x="24.336025"
422 y="189.40337"
423 id="text16"><tspan
424 sodipodi:role="line"
425 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;text-anchor:middle;fill:#4d4d4d;stroke-width:0.264583"
426 x="24.336025"
427 y="189.40337"
428 id="tspan15">TARGET</tspan><tspan
429 sodipodi:role="line"
430 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;text-anchor:middle;fill:#4d4d4d;stroke-width:0.264583"
431 x="24.336025"
432 y="191.52003"
433 id="tspan16">SOFTWARE</tspan></text>
434 </g>
435 </g>
436 </g>
437 <g
438 id="g48182"
439 transform="translate(0,-102.12917)"
440 inkscape:export-filename="/home/m/Vault/projects/mitjafelicijan.com/pid1/unikernels.png"
441 inkscape:export-xdpi="127.98862"
442 inkscape:export-ydpi="127.98862" />
443 <g
444 id="g34"
445 transform="translate(65.674737)">
446 <g
447 id="g33"
448 transform="translate(69.03002,-0.03980604)">
449 <rect
450 style="fill:#ececec;stroke:none;stroke-width:0.317673;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
451 id="rect19"
452 width="65.511665"
453 height="74.960197"
454 x="-0.10821027"
455 y="0.039806042"
456 inkscape:export-filename="/home/m/Vault/projects/mitjafelicijan.com/pid1/unikernels.png"
457 inkscape:export-xdpi="127.98862"
458 inkscape:export-ydpi="127.98862" />
459 <text
460 xml:space="preserve"
461 style="font-style:normal;font-variant:normal;font-weight:900;font-stretch:normal;font-size:2.82222px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Heavy';text-align:center;text-anchor:middle;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.264583"
462 x="30.965847"
463 y="69.175049"
464 id="text19"
465 inkscape:export-filename="/home/m/Vault/projects/mitjafelicijan.com/pid1/unikernels.png"
466 inkscape:export-xdpi="127.98862"
467 inkscape:export-ydpi="127.98862"><tspan
468 sodipodi:role="line"
469 id="tspan19"
470 style="font-style:normal;font-variant:normal;font-weight:800;font-stretch:normal;font-size:2.82222px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Ultra-Bold';text-align:center;text-anchor:middle;fill:#000000;stroke-width:0.264583"
471 x="30.965847"
472 y="69.175049">UNIKERNELS</tspan></text>
473 <g
474 id="g20"
475 transform="translate(-5.8033597,-177.06712)"
476 inkscape:export-filename="/home/m/Vault/projects/mitjafelicijan.com/pid1/unikernels.png"
477 inkscape:export-xdpi="127.98862"
478 inkscape:export-ydpi="127.98862">
479 <rect
480 style="fill:#f9f9f9;stroke:none;stroke-width:0.429153;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
481 id="rect20"
482 width="50.57568"
483 height="8.4333"
484 x="13.294504"
485 y="213.63496"
486 ry="1.5" />
487 <text
488 xml:space="preserve"
489 style="font-style:normal;font-variant:normal;font-weight:900;font-stretch:normal;font-size:2.46944px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Heavy';text-align:center;text-anchor:middle;fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:0.264583"
490 x="38.5317"
491 y="218.72159"
492 id="text20"><tspan
493 sodipodi:role="line"
494 id="tspan20"
495 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.46944px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;text-anchor:middle;fill:#4d4d4d;stroke-width:0.264583"
496 x="38.5317"
497 y="218.72159">HYPERVISOR</tspan></text>
498 </g>
499 <rect
500 style="fill:#f9f9f9;stroke:none;stroke-width:0.364235;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
501 id="rect21"
502 width="22.000685"
503 height="13.965061"
504 x="7.4911447"
505 y="18.898588"
506 ry="0.79600614" />
507 <text
508 xml:space="preserve"
509 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:0.264583"
510 x="18.532665"
511 y="25.565374"
512 id="text21"><tspan
513 sodipodi:role="line"
514 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;text-anchor:middle;fill:#4d4d4d;stroke-width:0.264583"
515 x="18.532665"
516 y="25.565374"
517 id="tspan21">UNIKERNEL &amp;</tspan><tspan
518 sodipodi:role="line"
519 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;text-anchor:middle;fill:#4d4d4d;stroke-width:0.264583"
520 x="18.532665"
521 y="27.682045"
522 id="tspan34">APPLICATION</tspan></text>
523 <g
524 id="g27"
525 transform="translate(-5.8033597,-174.95045)"
526 inkscape:export-filename="/home/m/Vault/projects/mitjafelicijan.com/pid1/unikernels.png"
527 inkscape:export-xdpi="127.98862"
528 inkscape:export-ydpi="127.98862">
529 <rect
530 style="fill:#f9f9f9;stroke:none;stroke-width:0.429153;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
531 id="rect26"
532 width="50.57568"
533 height="8.4333"
534 x="13.294504"
535 y="223.15991"
536 ry="1.5" />
537 <text
538 xml:space="preserve"
539 style="font-style:normal;font-variant:normal;font-weight:900;font-stretch:normal;font-size:2.46944px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Heavy';text-align:center;text-anchor:middle;fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:0.264583"
540 x="38.437649"
541 y="228.24654"
542 id="text27"><tspan
543 sodipodi:role="line"
544 id="tspan27"
545 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.46944px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;text-anchor:middle;fill:#4d4d4d;stroke-width:0.264583"
546 x="38.437649"
547 y="228.24654">HARDWARE</tspan></text>
548 </g>
549 <rect
550 style="fill:#f9f9f9;stroke:none;stroke-width:0.364235;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
551 id="rect27"
552 width="22.000685"
553 height="13.965027"
554 x="36.066143"
555 y="18.898619"
556 ry="0.79600418" />
557 <text
558 xml:space="preserve"
559 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;letter-spacing:0px;word-spacing:0px;text-anchor:middle;fill:#4d4d4d;fill-opacity:1;stroke:none;stroke-width:0.264583"
560 x="47.107666"
561 y="25.565388"
562 id="text28"><tspan
563 sodipodi:role="line"
564 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;text-anchor:middle;fill:#4d4d4d;stroke-width:0.264583"
565 x="47.107666"
566 y="25.565388"
567 id="tspan28">UNIKERNEL &amp;</tspan><tspan
568 sodipodi:role="line"
569 style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:2.11667px;line-height:1;font-family:'SF Pro Display';-inkscape-font-specification:'SF Pro Display Bold';text-align:center;text-anchor:middle;fill:#4d4d4d;stroke-width:0.264583"
570 x="47.107666"
571 y="27.682058"
572 id="tspan35">APPLICATION</tspan></text>
573 <text
574 xml:space="preserve"
575 style="font-size:3.175px;line-height:1;text-align:center;text-anchor:middle;fill:#000000;stroke-width:0.264583"
576 x="23.345249"
577 y="25.881119"
578 id="text36"><tspan
579 sodipodi:role="line"
580 id="tspan36"
581 style="stroke-width:0.264583"
582 x="23.757999"
583 y="25.881119"> </tspan></text>
584 </g>
585 </g>
586 </g>
587</svg>
diff --git a/static/posts/pid1/unikernels.webp b/static/posts/pid1/unikernels.webp
deleted file mode 100644
index c823d00..0000000
--- a/static/posts/pid1/unikernels.webp
+++ /dev/null
Binary files differ
diff --git a/static/posts/profile-bind-error/error.jpg b/static/posts/profile-bind-error/error.jpg
deleted file mode 100755
index c2e4e8f..0000000
--- a/static/posts/profile-bind-error/error.jpg
+++ /dev/null
Binary files differ
diff --git a/static/posts/python-profiling/kcachegrind.png b/static/posts/python-profiling/kcachegrind.png
deleted file mode 100755
index 0dc48ab..0000000
--- a/static/posts/python-profiling/kcachegrind.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/python-profiling/profiling-viewer.png b/static/posts/python-profiling/profiling-viewer.png
deleted file mode 100755
index a450513..0000000
--- a/static/posts/python-profiling/profiling-viewer.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/python-profiling/snakeviz.png b/static/posts/python-profiling/snakeviz.png
deleted file mode 100755
index 5bab395..0000000
--- a/static/posts/python-profiling/snakeviz.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/sentiment-analysis/.ipynb_checkpoints/TF Test-checkpoint.ipynb b/static/posts/sentiment-analysis/.ipynb_checkpoints/TF Test-checkpoint.ipynb
deleted file mode 100755
index e2a85c4..0000000
--- a/static/posts/sentiment-analysis/.ipynb_checkpoints/TF Test-checkpoint.ipynb
+++ /dev/null
@@ -1,588 +0,0 @@
1{
2 "cells": [
3 {
4 "cell_type": "code",
5 "execution_count": 1,
6 "metadata": {},
7 "outputs": [
8 {
9 "name": "stderr",
10 "output_type": "stream",
11 "text": [
12 "/home/m/.local/lib/python3.7/site-packages/tensorflow/python/framework/dtypes.py:516: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
13 " _np_qint8 = np.dtype([(\"qint8\", np.int8, 1)])\n",
14 "/home/m/.local/lib/python3.7/site-packages/tensorflow/python/framework/dtypes.py:517: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
15 " _np_quint8 = np.dtype([(\"quint8\", np.uint8, 1)])\n",
16 "/home/m/.local/lib/python3.7/site-packages/tensorflow/python/framework/dtypes.py:518: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
17 " _np_qint16 = np.dtype([(\"qint16\", np.int16, 1)])\n",
18 "/home/m/.local/lib/python3.7/site-packages/tensorflow/python/framework/dtypes.py:519: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
19 " _np_quint16 = np.dtype([(\"quint16\", np.uint16, 1)])\n",
20 "/home/m/.local/lib/python3.7/site-packages/tensorflow/python/framework/dtypes.py:520: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
21 " _np_qint32 = np.dtype([(\"qint32\", np.int32, 1)])\n",
22 "/home/m/.local/lib/python3.7/site-packages/tensorflow/python/framework/dtypes.py:525: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
23 " np_resource = np.dtype([(\"resource\", np.ubyte, 1)])\n"
24 ]
25 },
26 {
27 "name": "stdout",
28 "output_type": "stream",
29 "text": [
30 "2.0.0-beta1\n"
31 ]
32 },
33 {
34 "name": "stderr",
35 "output_type": "stream",
36 "text": [
37 "/home/m/.local/lib/python3.7/site-packages/tensorboard/compat/tensorflow_stub/dtypes.py:541: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
38 " _np_qint8 = np.dtype([(\"qint8\", np.int8, 1)])\n",
39 "/home/m/.local/lib/python3.7/site-packages/tensorboard/compat/tensorflow_stub/dtypes.py:542: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
40 " _np_quint8 = np.dtype([(\"quint8\", np.uint8, 1)])\n",
41 "/home/m/.local/lib/python3.7/site-packages/tensorboard/compat/tensorflow_stub/dtypes.py:543: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
42 " _np_qint16 = np.dtype([(\"qint16\", np.int16, 1)])\n",
43 "/home/m/.local/lib/python3.7/site-packages/tensorboard/compat/tensorflow_stub/dtypes.py:544: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
44 " _np_quint16 = np.dtype([(\"quint16\", np.uint16, 1)])\n",
45 "/home/m/.local/lib/python3.7/site-packages/tensorboard/compat/tensorflow_stub/dtypes.py:545: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
46 " _np_qint32 = np.dtype([(\"qint32\", np.int32, 1)])\n",
47 "/home/m/.local/lib/python3.7/site-packages/tensorboard/compat/tensorflow_stub/dtypes.py:550: FutureWarning: Passing (type, 1) or '1type' as a synonym of type is deprecated; in a future version of numpy, it will be understood as (type, (1,)) / '(1,)type'.\n",
48 " np_resource = np.dtype([(\"resource\", np.ubyte, 1)])\n"
49 ]
50 }
51 ],
52 "source": [
53 "import tensorflow as tf\n",
54 "from tensorflow import keras\n",
55 "\n",
56 "# Helper libraries\n",
57 "import numpy as np\n",
58 "import matplotlib.pyplot as plt\n",
59 "\n",
60 "print(tf.__version__)"
61 ]
62 },
63 {
64 "cell_type": "code",
65 "execution_count": 2,
66 "metadata": {},
67 "outputs": [],
68 "source": [
69 "from numpy import genfromtxt\n",
70 "data = genfromtxt('data.csv', delimiter=',')"
71 ]
72 },
73 {
74 "cell_type": "code",
75 "execution_count": 3,
76 "metadata": {},
77 "outputs": [],
78 "source": [
79 "data_input = data[:,0:3]\n",
80 "data_labels = data[:,3]\n",
81 "\n",
82 "#data_input = np.transpose(data_input)\n",
83 "#data_labels = np.transpose(data_labels)"
84 ]
85 },
86 {
87 "cell_type": "code",
88 "execution_count": 4,
89 "metadata": {},
90 "outputs": [
91 {
92 "name": "stdout",
93 "output_type": "stream",
94 "text": [
95 "(600, 3)\n",
96 "[1.e-01 1.e+00 3.e+02]\n"
97 ]
98 }
99 ],
100 "source": [
101 "print(np.shape(data_input))\n",
102 "print(data_input[2])"
103 ]
104 },
105 {
106 "cell_type": "markdown",
107 "metadata": {},
108 "source": [
109 "print(len(data_input))\n",
110 "print(len(data_labels))"
111 ]
112 },
113 {
114 "cell_type": "code",
115 "execution_count": 5,
116 "metadata": {},
117 "outputs": [
118 {
119 "name": "stdout",
120 "output_type": "stream",
121 "text": [
122 "(500, 3)\n",
123 "(100, 3)\n",
124 "(500,)\n",
125 "(100,)\n"
126 ]
127 }
128 ],
129 "source": [
130 "data_input_train = data_input[0:500,:]\n",
131 "data_input_test = data_input[500:,:]\n",
132 "\n",
133 "data_labels_train = data_labels[0:500]\n",
134 "data_labels_test = data_labels[500:]\n",
135 "\n",
136 "print(np.shape(data_input_train))\n",
137 "print(np.shape(data_input_test))\n",
138 "\n",
139 "print(np.shape(data_labels_train))\n",
140 "print(np.shape(data_labels_test))"
141 ]
142 },
143 {
144 "cell_type": "code",
145 "execution_count": 6,
146 "metadata": {},
147 "outputs": [],
148 "source": [
149 "model = keras.Sequential([\n",
150 " keras.layers.Dense(128, activation='relu', input_shape=[3]),\n",
151 " keras.layers.Dense(512, activation='relu'),\n",
152 " keras.layers.Dense(512, activation='relu'),\n",
153 " keras.layers.Dense(512, activation='relu'),\n",
154 " keras.layers.Dense(128, activation='relu'),\n",
155 " keras.layers.Dense(1)\n",
156 "])"
157 ]
158 },
159 {
160 "cell_type": "code",
161 "execution_count": 7,
162 "metadata": {},
163 "outputs": [],
164 "source": [
165 "optimizer = tf.keras.optimizers.RMSprop(0.001)\n",
166 "model.compile(loss='mse',\n",
167 " optimizer=optimizer,\n",
168 " metrics=['accuracy'])"
169 ]
170 },
171 {
172 "cell_type": "code",
173 "execution_count": 8,
174 "metadata": {},
175 "outputs": [
176 {
177 "name": "stdout",
178 "output_type": "stream",
179 "text": [
180 "Train on 500 samples\n",
181 "Epoch 1/100\n",
182 "500/500 [==============================] - 0s 399us/sample - loss: 247.2794 - accuracy: 0.0040\n",
183 "Epoch 2/100\n",
184 "500/500 [==============================] - 0s 121us/sample - loss: 4.2495 - accuracy: 0.0060\n",
185 "Epoch 3/100\n",
186 "500/500 [==============================] - 0s 131us/sample - loss: 1.8787 - accuracy: 0.0040\n",
187 "Epoch 4/100\n",
188 "500/500 [==============================] - 0s 121us/sample - loss: 0.4284 - accuracy: 0.0060\n",
189 "Epoch 5/100\n",
190 "500/500 [==============================] - 0s 107us/sample - loss: 4.7904 - accuracy: 0.0080\n",
191 "Epoch 6/100\n",
192 "500/500 [==============================] - 0s 113us/sample - loss: 0.0819 - accuracy: 0.0040\n",
193 "Epoch 7/100\n",
194 "500/500 [==============================] - 0s 108us/sample - loss: 1.6904 - accuracy: 0.0040\n",
195 "Epoch 8/100\n",
196 "500/500 [==============================] - 0s 116us/sample - loss: 0.1761 - accuracy: 0.0040\n",
197 "Epoch 9/100\n",
198 "500/500 [==============================] - 0s 142us/sample - loss: 0.1135 - accuracy: 0.0040\n",
199 "Epoch 10/100\n",
200 "500/500 [==============================] - 0s 124us/sample - loss: 0.4387 - accuracy: 0.0040\n",
201 "Epoch 11/100\n",
202 "500/500 [==============================] - 0s 112us/sample - loss: 0.0815 - accuracy: 0.0040\n",
203 "Epoch 12/100\n",
204 "500/500 [==============================] - 0s 117us/sample - loss: 0.1725 - accuracy: 0.0040\n",
205 "Epoch 13/100\n",
206 "500/500 [==============================] - 0s 119us/sample - loss: 0.1487 - accuracy: 0.0040\n",
207 "Epoch 14/100\n",
208 "500/500 [==============================] - 0s 111us/sample - loss: 0.0720 - accuracy: 0.0040\n",
209 "Epoch 15/100\n",
210 "500/500 [==============================] - 0s 111us/sample - loss: 0.3110 - accuracy: 0.0040\n",
211 "Epoch 16/100\n",
212 "500/500 [==============================] - 0s 128us/sample - loss: 0.0947 - accuracy: 0.0040\n",
213 "Epoch 17/100\n",
214 "500/500 [==============================] - 0s 133us/sample - loss: 0.0739 - accuracy: 0.0040\n",
215 "Epoch 18/100\n",
216 "500/500 [==============================] - 0s 131us/sample - loss: 0.1353 - accuracy: 0.0060\n",
217 "Epoch 19/100\n",
218 "500/500 [==============================] - 0s 135us/sample - loss: 0.0837 - accuracy: 0.0040\n",
219 "Epoch 20/100\n",
220 "500/500 [==============================] - 0s 130us/sample - loss: 0.0754 - accuracy: 0.0040\n",
221 "Epoch 21/100\n",
222 "500/500 [==============================] - 0s 118us/sample - loss: 0.0840 - accuracy: 0.0040\n",
223 "Epoch 22/100\n",
224 "500/500 [==============================] - 0s 115us/sample - loss: 0.1105 - accuracy: 0.0040\n",
225 "Epoch 23/100\n",
226 "500/500 [==============================] - 0s 116us/sample - loss: 0.0651 - accuracy: 0.0040\n",
227 "Epoch 24/100\n",
228 "500/500 [==============================] - 0s 109us/sample - loss: 0.0615 - accuracy: 0.0040\n",
229 "Epoch 25/100\n",
230 "500/500 [==============================] - 0s 118us/sample - loss: 0.0656 - accuracy: 0.0040\n",
231 "Epoch 26/100\n",
232 "500/500 [==============================] - 0s 113us/sample - loss: 0.0695 - accuracy: 0.0040\n",
233 "Epoch 27/100\n",
234 "500/500 [==============================] - 0s 116us/sample - loss: 0.0585 - accuracy: 0.0040\n",
235 "Epoch 28/100\n",
236 "500/500 [==============================] - 0s 118us/sample - loss: 0.1300 - accuracy: 0.0040\n",
237 "Epoch 29/100\n",
238 "500/500 [==============================] - 0s 112us/sample - loss: 0.0567 - accuracy: 0.0040\n",
239 "Epoch 30/100\n",
240 "500/500 [==============================] - 0s 137us/sample - loss: 0.0647 - accuracy: 0.0040\n",
241 "Epoch 31/100\n",
242 "500/500 [==============================] - 0s 130us/sample - loss: 0.0559 - accuracy: 0.0040\n",
243 "Epoch 32/100\n",
244 "500/500 [==============================] - 0s 130us/sample - loss: 0.0576 - accuracy: 0.0040\n",
245 "Epoch 33/100\n",
246 "500/500 [==============================] - 0s 128us/sample - loss: 0.0578 - accuracy: 0.0040\n",
247 "Epoch 34/100\n",
248 "500/500 [==============================] - 0s 130us/sample - loss: 0.0512 - accuracy: 0.0040\n",
249 "Epoch 35/100\n",
250 "500/500 [==============================] - 0s 114us/sample - loss: 0.0601 - accuracy: 0.0040\n",
251 "Epoch 36/100\n",
252 "500/500 [==============================] - 0s 111us/sample - loss: 0.0531 - accuracy: 0.0040\n",
253 "Epoch 37/100\n",
254 "500/500 [==============================] - 0s 130us/sample - loss: 0.0532 - accuracy: 0.0040\n",
255 "Epoch 38/100\n",
256 "500/500 [==============================] - 0s 131us/sample - loss: 0.0480 - accuracy: 0.0040\n",
257 "Epoch 39/100\n",
258 "500/500 [==============================] - 0s 136us/sample - loss: 0.0503 - accuracy: 0.0040\n",
259 "Epoch 40/100\n",
260 "500/500 [==============================] - 0s 134us/sample - loss: 0.0468 - accuracy: 0.0040\n",
261 "Epoch 41/100\n",
262 "500/500 [==============================] - 0s 115us/sample - loss: 0.0509 - accuracy: 0.0040\n",
263 "Epoch 42/100\n",
264 "500/500 [==============================] - 0s 109us/sample - loss: 0.0453 - accuracy: 0.0040\n",
265 "Epoch 43/100\n",
266 "500/500 [==============================] - 0s 111us/sample - loss: 0.0484 - accuracy: 0.0040\n",
267 "Epoch 44/100\n",
268 "500/500 [==============================] - 0s 104us/sample - loss: 0.0458 - accuracy: 0.0040\n",
269 "Epoch 45/100\n",
270 "500/500 [==============================] - 0s 110us/sample - loss: 0.0481 - accuracy: 0.0040\n",
271 "Epoch 46/100\n",
272 "500/500 [==============================] - 0s 114us/sample - loss: 0.0468 - accuracy: 0.0060\n",
273 "Epoch 47/100\n",
274 "500/500 [==============================] - 0s 124us/sample - loss: 0.0473 - accuracy: 0.0060\n",
275 "Epoch 48/100\n",
276 "500/500 [==============================] - 0s 137us/sample - loss: 0.0455 - accuracy: 0.0040\n",
277 "Epoch 49/100\n",
278 "500/500 [==============================] - 0s 125us/sample - loss: 0.0431 - accuracy: 0.0060\n",
279 "Epoch 50/100\n",
280 "500/500 [==============================] - 0s 132us/sample - loss: 0.0432 - accuracy: 0.0060\n",
281 "Epoch 51/100\n",
282 "500/500 [==============================] - 0s 116us/sample - loss: 0.0484 - accuracy: 0.0060\n",
283 "Epoch 52/100\n",
284 "500/500 [==============================] - 0s 112us/sample - loss: 0.0482 - accuracy: 0.0040\n",
285 "Epoch 53/100\n",
286 "500/500 [==============================] - 0s 117us/sample - loss: 0.0444 - accuracy: 0.0060\n",
287 "Epoch 54/100\n",
288 "500/500 [==============================] - 0s 109us/sample - loss: 0.0469 - accuracy: 0.0060\n",
289 "Epoch 55/100\n",
290 "500/500 [==============================] - 0s 106us/sample - loss: 0.0427 - accuracy: 0.0040\n",
291 "Epoch 56/100\n",
292 "500/500 [==============================] - 0s 110us/sample - loss: 0.0433 - accuracy: 0.0040\n",
293 "Epoch 57/100\n",
294 "500/500 [==============================] - 0s 102us/sample - loss: 0.0437 - accuracy: 0.0060\n",
295 "Epoch 58/100\n",
296 "500/500 [==============================] - 0s 117us/sample - loss: 0.0425 - accuracy: 0.0040\n",
297 "Epoch 59/100\n",
298 "500/500 [==============================] - 0s 105us/sample - loss: 0.0418 - accuracy: 0.0040\n",
299 "Epoch 60/100\n",
300 "500/500 [==============================] - 0s 109us/sample - loss: 0.0397 - accuracy: 0.0040\n",
301 "Epoch 61/100\n",
302 "500/500 [==============================] - 0s 119us/sample - loss: 0.0507 - accuracy: 0.0040\n",
303 "Epoch 62/100\n",
304 "500/500 [==============================] - 0s 112us/sample - loss: 0.0402 - accuracy: 0.0060\n",
305 "Epoch 63/100\n",
306 "500/500 [==============================] - 0s 133us/sample - loss: 0.0397 - accuracy: 0.0040\n",
307 "Epoch 64/100\n",
308 "500/500 [==============================] - 0s 132us/sample - loss: 0.0427 - accuracy: 0.0060\n",
309 "Epoch 65/100\n",
310 "500/500 [==============================] - 0s 138us/sample - loss: 0.0398 - accuracy: 0.0040\n",
311 "Epoch 66/100\n",
312 "500/500 [==============================] - 0s 145us/sample - loss: 0.0375 - accuracy: 0.0060\n",
313 "Epoch 67/100\n",
314 "500/500 [==============================] - 0s 138us/sample - loss: 0.0402 - accuracy: 0.0060\n",
315 "Epoch 68/100\n",
316 "500/500 [==============================] - 0s 132us/sample - loss: 0.0388 - accuracy: 0.0080\n",
317 "Epoch 69/100\n",
318 "500/500 [==============================] - 0s 115us/sample - loss: 0.0375 - accuracy: 0.0080\n",
319 "Epoch 70/100\n",
320 "500/500 [==============================] - 0s 113us/sample - loss: 0.0384 - accuracy: 0.0040\n",
321 "Epoch 71/100\n",
322 "500/500 [==============================] - 0s 109us/sample - loss: 0.0360 - accuracy: 0.0080\n",
323 "Epoch 72/100\n",
324 "500/500 [==============================] - 0s 111us/sample - loss: 0.0350 - accuracy: 0.0080\n",
325 "Epoch 73/100\n",
326 "500/500 [==============================] - 0s 118us/sample - loss: 0.0370 - accuracy: 0.0060\n",
327 "Epoch 74/100\n",
328 "500/500 [==============================] - 0s 95us/sample - loss: 0.0354 - accuracy: 0.0080\n",
329 "Epoch 75/100\n",
330 "500/500 [==============================] - 0s 102us/sample - loss: 0.0376 - accuracy: 0.0060\n",
331 "Epoch 76/100\n",
332 "500/500 [==============================] - 0s 106us/sample - loss: 0.0371 - accuracy: 0.0080\n",
333 "Epoch 77/100\n",
334 "500/500 [==============================] - 0s 100us/sample - loss: 0.0369 - accuracy: 0.0060\n",
335 "Epoch 78/100\n"
336 ]
337 },
338 {
339 "name": "stdout",
340 "output_type": "stream",
341 "text": [
342 "500/500 [==============================] - 0s 98us/sample - loss: 0.0315 - accuracy: 0.0060\n",
343 "Epoch 79/100\n",
344 "500/500 [==============================] - 0s 97us/sample - loss: 0.0355 - accuracy: 0.0060\n",
345 "Epoch 80/100\n",
346 "500/500 [==============================] - 0s 100us/sample - loss: 0.0278 - accuracy: 0.0080\n",
347 "Epoch 81/100\n",
348 "500/500 [==============================] - 0s 99us/sample - loss: 0.0320 - accuracy: 0.0080\n",
349 "Epoch 82/100\n",
350 "500/500 [==============================] - 0s 99us/sample - loss: 0.0321 - accuracy: 0.0080\n",
351 "Epoch 83/100\n",
352 "500/500 [==============================] - 0s 94us/sample - loss: 0.0332 - accuracy: 0.0060\n",
353 "Epoch 84/100\n",
354 "500/500 [==============================] - 0s 106us/sample - loss: 0.0317 - accuracy: 0.0060\n",
355 "Epoch 85/100\n",
356 "500/500 [==============================] - 0s 103us/sample - loss: 0.0293 - accuracy: 0.0080\n",
357 "Epoch 86/100\n",
358 "500/500 [==============================] - 0s 107us/sample - loss: 0.0304 - accuracy: 0.0060\n",
359 "Epoch 87/100\n",
360 "500/500 [==============================] - 0s 101us/sample - loss: 0.0327 - accuracy: 0.0040\n",
361 "Epoch 88/100\n",
362 "500/500 [==============================] - 0s 100us/sample - loss: 0.0290 - accuracy: 0.0080\n",
363 "Epoch 89/100\n",
364 "500/500 [==============================] - 0s 123us/sample - loss: 0.0293 - accuracy: 0.0060\n",
365 "Epoch 90/100\n",
366 "500/500 [==============================] - 0s 104us/sample - loss: 0.0246 - accuracy: 0.0060\n",
367 "Epoch 91/100\n",
368 "500/500 [==============================] - 0s 124us/sample - loss: 0.0303 - accuracy: 0.0060\n",
369 "Epoch 92/100\n",
370 "500/500 [==============================] - 0s 129us/sample - loss: 0.0376 - accuracy: 0.0080\n",
371 "Epoch 93/100\n",
372 "500/500 [==============================] - 0s 122us/sample - loss: 0.0264 - accuracy: 0.0080\n",
373 "Epoch 94/100\n",
374 "500/500 [==============================] - 0s 102us/sample - loss: 0.0265 - accuracy: 0.0080\n",
375 "Epoch 95/100\n",
376 "500/500 [==============================] - 0s 108us/sample - loss: 0.0291 - accuracy: 0.0080\n",
377 "Epoch 96/100\n",
378 "500/500 [==============================] - 0s 101us/sample - loss: 0.0314 - accuracy: 0.0080\n",
379 "Epoch 97/100\n",
380 "500/500 [==============================] - 0s 95us/sample - loss: 0.0257 - accuracy: 0.0060\n",
381 "Epoch 98/100\n",
382 "500/500 [==============================] - 0s 100us/sample - loss: 0.0248 - accuracy: 0.0080\n",
383 "Epoch 99/100\n",
384 "500/500 [==============================] - 0s 94us/sample - loss: 0.0250 - accuracy: 0.0040\n",
385 "Epoch 100/100\n",
386 "500/500 [==============================] - 0s 106us/sample - loss: 0.0312 - accuracy: 0.0060\n"
387 ]
388 },
389 {
390 "data": {
391 "text/plain": [
392 "<tensorflow.python.keras.callbacks.History at 0x7f55a3853f60>"
393 ]
394 },
395 "execution_count": 8,
396 "metadata": {},
397 "output_type": "execute_result"
398 }
399 ],
400 "source": [
401 "#model.fit(data_input_train, data_labels_train, validation_data=(data_input_test, data_labels_test), epochs=100)\n",
402 "model.fit(data_input_train, data_labels_train, epochs=100)"
403 ]
404 },
405 {
406 "cell_type": "code",
407 "execution_count": 9,
408 "metadata": {},
409 "outputs": [
410 {
411 "name": "stdout",
412 "output_type": "stream",
413 "text": [
414 "100/100 - 0s - loss: 0.0470 - accuracy: 0.0100\n",
415 "\n",
416 "Test accuracy: 0.01\n"
417 ]
418 }
419 ],
420 "source": [
421 "test_loss, test_acc = model.evaluate(data_input_test, data_labels_test, verbose=2)\n",
422 "\n",
423 "print('\\nTest accuracy:', test_acc)"
424 ]
425 },
426 {
427 "cell_type": "code",
428 "execution_count": 10,
429 "metadata": {},
430 "outputs": [
431 {
432 "name": "stdout",
433 "output_type": "stream",
434 "text": [
435 "[[0.3141548]]\n"
436 ]
437 }
438 ],
439 "source": [
440 "input = np.array([0.46,2,136])\n",
441 "input.shape = (1,3)\n",
442 "\n",
443 "prediction = model.predict(input)\n",
444 "print(prediction)"
445 ]
446 },
447 {
448 "cell_type": "code",
449 "execution_count": 11,
450 "metadata": {},
451 "outputs": [],
452 "source": [
453 "predictions = model.predict(data_input_test)"
454 ]
455 },
456 {
457 "cell_type": "code",
458 "execution_count": 12,
459 "metadata": {},
460 "outputs": [],
461 "source": [
462 "%matplotlib qt \n",
463 "plt.plot(predictions)\n",
464 "plt.plot(data_labels_test, 'r')\n",
465 "plt.show()"
466 ]
467 },
468 {
469 "cell_type": "code",
470 "execution_count": 204,
471 "metadata": {},
472 "outputs": [],
473 "source": [
474 "%matplotlib qt\n",
475 "a = data_labels_test - predictions\n",
476 "plt.plot(a[0])\n",
477 "plt.show()"
478 ]
479 },
480 {
481 "cell_type": "code",
482 "execution_count": 207,
483 "metadata": {},
484 "outputs": [],
485 "source": [
486 "%matplotlib qt\n",
487 "a = data_labels_test - predictions\n",
488 "plt.plot(predictions)\n",
489 "plt.plot(data_labels_test, 'r')\n",
490 "plt.plot(a[0], 'g')\n",
491 "plt.show()"
492 ]
493 },
494 {
495 "cell_type": "code",
496 "execution_count": 180,
497 "metadata": {},
498 "outputs": [
499 {
500 "data": {
501 "text/plain": [
502 "-0.08489150602276586"
503 ]
504 },
505 "execution_count": 180,
506 "metadata": {},
507 "output_type": "execute_result"
508 }
509 ],
510 "source": [
511 "np.average(a[0])"
512 ]
513 },
514 {
515 "cell_type": "code",
516 "execution_count": 182,
517 "metadata": {},
518 "outputs": [
519 {
520 "name": "stdout",
521 "output_type": "stream",
522 "text": [
523 "Model: \"sequential_13\"\n",
524 "_________________________________________________________________\n",
525 "Layer (type) Output Shape Param # \n",
526 "=================================================================\n",
527 "dense_38 (Dense) (None, 128) 512 \n",
528 "_________________________________________________________________\n",
529 "dense_39 (Dense) (None, 512) 66048 \n",
530 "_________________________________________________________________\n",
531 "dense_40 (Dense) (None, 512) 262656 \n",
532 "_________________________________________________________________\n",
533 "dense_41 (Dense) (None, 512) 262656 \n",
534 "_________________________________________________________________\n",
535 "dense_42 (Dense) (None, 128) 65664 \n",
536 "_________________________________________________________________\n",
537 "dense_43 (Dense) (None, 1) 129 \n",
538 "=================================================================\n",
539 "Total params: 657,665\n",
540 "Trainable params: 657,665\n",
541 "Non-trainable params: 0\n",
542 "_________________________________________________________________\n"
543 ]
544 }
545 ],
546 "source": [
547 "model.summary()"
548 ]
549 },
550 {
551 "cell_type": "code",
552 "execution_count": 183,
553 "metadata": {},
554 "outputs": [],
555 "source": [
556 "model.save('my_model.h5')"
557 ]
558 },
559 {
560 "cell_type": "code",
561 "execution_count": null,
562 "metadata": {},
563 "outputs": [],
564 "source": []
565 }
566 ],
567 "metadata": {
568 "kernelspec": {
569 "display_name": "Python 3",
570 "language": "python",
571 "name": "python3"
572 },
573 "language_info": {
574 "codemirror_mode": {
575 "name": "ipython",
576 "version": 3
577 },
578 "file_extension": ".py",
579 "mimetype": "text/x-python",
580 "name": "python",
581 "nbconvert_exporter": "python",
582 "pygments_lexer": "ipython3",
583 "version": "3.7.3"
584 }
585 },
586 "nbformat": 4,
587 "nbformat_minor": 2
588}
diff --git a/static/posts/sentiment-analysis/.ipynb_checkpoints/sentiment-analysis-checkpoint.ipynb b/static/posts/sentiment-analysis/.ipynb_checkpoints/sentiment-analysis-checkpoint.ipynb
deleted file mode 100755
index 2c0934c..0000000
--- a/static/posts/sentiment-analysis/.ipynb_checkpoints/sentiment-analysis-checkpoint.ipynb
+++ /dev/null
@@ -1,170 +0,0 @@
1{
2 "cells": [
3 {
4 "cell_type": "markdown",
5 "metadata": {},
6 "source": [
7 "# Sentiment analysis of Guardian World News articles"
8 ]
9 },
10 {
11 "cell_type": "markdown",
12 "metadata": {},
13 "source": [
14 "## Get articles from a website"
15 ]
16 },
17 {
18 "cell_type": "markdown",
19 "metadata": {},
20 "source": [
21 "### Install rss parser dependency"
22 ]
23 },
24 {
25 "cell_type": "code",
26 "execution_count": null,
27 "metadata": {},
28 "outputs": [],
29 "source": [
30 "!pip3 install feedparser"
31 ]
32 },
33 {
34 "cell_type": "markdown",
35 "metadata": {},
36 "source": [
37 "### Parsing RSS feed for world news"
38 ]
39 },
40 {
41 "cell_type": "code",
42 "execution_count": null,
43 "metadata": {},
44 "outputs": [],
45 "source": [
46 "import feedparser\n",
47 "feed_url = \"https://www.theguardian.com/world/rss\"\n",
48 "feed = feedparser.parse(feed_url)"
49 ]
50 },
51 {
52 "cell_type": "code",
53 "execution_count": null,
54 "metadata": {},
55 "outputs": [],
56 "source": [
57 "import re\n",
58 "for item in feed.entries:\n",
59 " # sanitize html\n",
60 " item.description = re.sub('<[^<]+?>', '', item.description)"
61 ]
62 },
63 {
64 "cell_type": "markdown",
65 "metadata": {},
66 "source": [
67 "### Install Vader Sentiment library and perform sentiment analysis"
68 ]
69 },
70 {
71 "cell_type": "code",
72 "execution_count": null,
73 "metadata": {},
74 "outputs": [],
75 "source": [
76 "!pip3 install vaderSentiment"
77 ]
78 },
79 {
80 "cell_type": "code",
81 "execution_count": null,
82 "metadata": {},
83 "outputs": [],
84 "source": [
85 "from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer\n",
86 "analyser = SentimentIntensityAnalyzer()"
87 ]
88 },
89 {
90 "cell_type": "code",
91 "execution_count": null,
92 "metadata": {},
93 "outputs": [],
94 "source": [
95 "sentiment_results = []\n",
96 "for item in feed.entries:\n",
97 " sentiment_title = analyser.polarity_scores(item.title)\n",
98 " sentiment_description = analyser.polarity_scores(item.description)\n",
99 " sentiment_results.append([sentiment_title['compound'], sentiment_description['compound']])"
100 ]
101 },
102 {
103 "cell_type": "markdown",
104 "metadata": {},
105 "source": [
106 "### Install Matplotlib and visualize compound score"
107 ]
108 },
109 {
110 "cell_type": "code",
111 "execution_count": null,
112 "metadata": {},
113 "outputs": [],
114 "source": [
115 "!pip3 install matplotlib"
116 ]
117 },
118 {
119 "cell_type": "code",
120 "execution_count": null,
121 "metadata": {},
122 "outputs": [],
123 "source": [
124 "import matplotlib.pyplot as plt"
125 ]
126 },
127 {
128 "cell_type": "code",
129 "execution_count": null,
130 "metadata": {},
131 "outputs": [],
132 "source": [
133 "%matplotlib inline\n",
134 "plt.rcParams['figure.figsize'] = (15, 3)\n",
135 "plt.plot(sentiment_results, drawstyle='steps')\n",
136 "plt.title('Sentiment analysis relationship between title and description (Guardian World News)')\n",
137 "plt.legend(['title', 'description'])\n",
138 "plt.show()"
139 ]
140 },
141 {
142 "cell_type": "code",
143 "execution_count": null,
144 "metadata": {},
145 "outputs": [],
146 "source": []
147 }
148 ],
149 "metadata": {
150 "kernelspec": {
151 "display_name": "Python 3",
152 "language": "python",
153 "name": "python3"
154 },
155 "language_info": {
156 "codemirror_mode": {
157 "name": "ipython",
158 "version": 3
159 },
160 "file_extension": ".py",
161 "mimetype": "text/x-python",
162 "name": "python",
163 "nbconvert_exporter": "python",
164 "pygments_lexer": "ipython3",
165 "version": "3.7.3"
166 }
167 },
168 "nbformat": 4,
169 "nbformat_minor": 4
170}
diff --git a/static/posts/sentiment-analysis/guardian-sa-title-desc-relationship.png b/static/posts/sentiment-analysis/guardian-sa-title-desc-relationship.png
deleted file mode 100755
index 7195bbf..0000000
--- a/static/posts/sentiment-analysis/guardian-sa-title-desc-relationship.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/sentiment-analysis/sentiment-analysis.ipynb b/static/posts/sentiment-analysis/sentiment-analysis.ipynb
deleted file mode 100755
index 2c0934c..0000000
--- a/static/posts/sentiment-analysis/sentiment-analysis.ipynb
+++ /dev/null
@@ -1,170 +0,0 @@
1{
2 "cells": [
3 {
4 "cell_type": "markdown",
5 "metadata": {},
6 "source": [
7 "# Sentiment analysis of Guardian World News articles"
8 ]
9 },
10 {
11 "cell_type": "markdown",
12 "metadata": {},
13 "source": [
14 "## Get articles from a website"
15 ]
16 },
17 {
18 "cell_type": "markdown",
19 "metadata": {},
20 "source": [
21 "### Install rss parser dependency"
22 ]
23 },
24 {
25 "cell_type": "code",
26 "execution_count": null,
27 "metadata": {},
28 "outputs": [],
29 "source": [
30 "!pip3 install feedparser"
31 ]
32 },
33 {
34 "cell_type": "markdown",
35 "metadata": {},
36 "source": [
37 "### Parsing RSS feed for world news"
38 ]
39 },
40 {
41 "cell_type": "code",
42 "execution_count": null,
43 "metadata": {},
44 "outputs": [],
45 "source": [
46 "import feedparser\n",
47 "feed_url = \"https://www.theguardian.com/world/rss\"\n",
48 "feed = feedparser.parse(feed_url)"
49 ]
50 },
51 {
52 "cell_type": "code",
53 "execution_count": null,
54 "metadata": {},
55 "outputs": [],
56 "source": [
57 "import re\n",
58 "for item in feed.entries:\n",
59 " # sanitize html\n",
60 " item.description = re.sub('<[^<]+?>', '', item.description)"
61 ]
62 },
63 {
64 "cell_type": "markdown",
65 "metadata": {},
66 "source": [
67 "### Install Vader Sentiment library and perform sentiment analysis"
68 ]
69 },
70 {
71 "cell_type": "code",
72 "execution_count": null,
73 "metadata": {},
74 "outputs": [],
75 "source": [
76 "!pip3 install vaderSentiment"
77 ]
78 },
79 {
80 "cell_type": "code",
81 "execution_count": null,
82 "metadata": {},
83 "outputs": [],
84 "source": [
85 "from vaderSentiment.vaderSentiment import SentimentIntensityAnalyzer\n",
86 "analyser = SentimentIntensityAnalyzer()"
87 ]
88 },
89 {
90 "cell_type": "code",
91 "execution_count": null,
92 "metadata": {},
93 "outputs": [],
94 "source": [
95 "sentiment_results = []\n",
96 "for item in feed.entries:\n",
97 " sentiment_title = analyser.polarity_scores(item.title)\n",
98 " sentiment_description = analyser.polarity_scores(item.description)\n",
99 " sentiment_results.append([sentiment_title['compound'], sentiment_description['compound']])"
100 ]
101 },
102 {
103 "cell_type": "markdown",
104 "metadata": {},
105 "source": [
106 "### Install Matplotlib and visualize compound score"
107 ]
108 },
109 {
110 "cell_type": "code",
111 "execution_count": null,
112 "metadata": {},
113 "outputs": [],
114 "source": [
115 "!pip3 install matplotlib"
116 ]
117 },
118 {
119 "cell_type": "code",
120 "execution_count": null,
121 "metadata": {},
122 "outputs": [],
123 "source": [
124 "import matplotlib.pyplot as plt"
125 ]
126 },
127 {
128 "cell_type": "code",
129 "execution_count": null,
130 "metadata": {},
131 "outputs": [],
132 "source": [
133 "%matplotlib inline\n",
134 "plt.rcParams['figure.figsize'] = (15, 3)\n",
135 "plt.plot(sentiment_results, drawstyle='steps')\n",
136 "plt.title('Sentiment analysis relationship between title and description (Guardian World News)')\n",
137 "plt.legend(['title', 'description'])\n",
138 "plt.show()"
139 ]
140 },
141 {
142 "cell_type": "code",
143 "execution_count": null,
144 "metadata": {},
145 "outputs": [],
146 "source": []
147 }
148 ],
149 "metadata": {
150 "kernelspec": {
151 "display_name": "Python 3",
152 "language": "python",
153 "name": "python3"
154 },
155 "language_info": {
156 "codemirror_mode": {
157 "name": "ipython",
158 "version": 3
159 },
160 "file_extension": ".py",
161 "mimetype": "text/x-python",
162 "name": "python",
163 "nbconvert_exporter": "python",
164 "pygments_lexer": "ipython3",
165 "version": "3.7.3"
166 }
167 },
168 "nbformat": 4,
169 "nbformat_minor": 4
170}
diff --git a/static/posts/simple-pubsub-server/caniuse.png b/static/posts/simple-pubsub-server/caniuse.png
deleted file mode 100755
index 90f7883..0000000
--- a/static/posts/simple-pubsub-server/caniuse.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/simple-pubsub-server/chrome-debugging.png b/static/posts/simple-pubsub-server/chrome-debugging.png
deleted file mode 100755
index 1bdc448..0000000
--- a/static/posts/simple-pubsub-server/chrome-debugging.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/simple-pubsub-server/clients.m4v b/static/posts/simple-pubsub-server/clients.m4v
deleted file mode 100755
index 1342bc6..0000000
--- a/static/posts/simple-pubsub-server/clients.m4v
+++ /dev/null
Binary files differ
diff --git a/static/posts/simple-pubsub-server/pubsub-overview.png b/static/posts/simple-pubsub-server/pubsub-overview.png
deleted file mode 100755
index 0279ec3..0000000
--- a/static/posts/simple-pubsub-server/pubsub-overview.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/simple-pubsub-server/sse-pubsub-server.zip b/static/posts/simple-pubsub-server/sse-pubsub-server.zip
deleted file mode 100755
index 898b290..0000000
--- a/static/posts/simple-pubsub-server/sse-pubsub-server.zip
+++ /dev/null
Binary files differ
diff --git a/static/posts/state-of-web/2008-vs-2020.png b/static/posts/state-of-web/2008-vs-2020.png
deleted file mode 100755
index 6cf94e5..0000000
--- a/static/posts/state-of-web/2008-vs-2020.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/state-of-web/compiling-vs-transpiling.png b/static/posts/state-of-web/compiling-vs-transpiling.png
deleted file mode 100755
index afd5000..0000000
--- a/static/posts/state-of-web/compiling-vs-transpiling.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/wap/emulator.mp4 b/static/posts/wap/emulator.mp4
deleted file mode 100755
index e4f59aa..0000000
--- a/static/posts/wap/emulator.mp4
+++ /dev/null
Binary files differ
diff --git a/static/posts/wap/phones.gif b/static/posts/wap/phones.gif
deleted file mode 100755
index 15f99e2..0000000
--- a/static/posts/wap/phones.gif
+++ /dev/null
Binary files differ
diff --git a/static/posts/world-clock/enclosure.stl b/static/posts/world-clock/enclosure.stl
deleted file mode 100755
index 99f3d1a..0000000
--- a/static/posts/world-clock/enclosure.stl
+++ /dev/null
Binary files differ
diff --git a/static/posts/world-clock/hardware.jpg b/static/posts/world-clock/hardware.jpg
deleted file mode 100755
index 315a04d..0000000
--- a/static/posts/world-clock/hardware.jpg
+++ /dev/null
Binary files differ
diff --git a/static/posts/world-clock/world-clock.jpg b/static/posts/world-clock/world-clock.jpg
deleted file mode 100755
index afdb6e2..0000000
--- a/static/posts/world-clock/world-clock.jpg
+++ /dev/null
Binary files differ
diff --git a/static/posts/yapyap/hello.png b/static/posts/yapyap/hello.png
deleted file mode 100755
index d141cd3..0000000
--- a/static/posts/yapyap/hello.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/yapyap/pid1.jpg b/static/posts/yapyap/pid1.jpg
deleted file mode 100755
index 99bc1d8..0000000
--- a/static/posts/yapyap/pid1.jpg
+++ /dev/null
Binary files differ
diff --git a/static/posts/zed/zed-1.png b/static/posts/zed/zed-1.png
deleted file mode 100755
index c4da2f6..0000000
--- a/static/posts/zed/zed-1.png
+++ /dev/null
Binary files differ
diff --git a/static/posts/zed/zed-2.png b/static/posts/zed/zed-2.png
deleted file mode 100755
index 38ce72d..0000000
--- a/static/posts/zed/zed-2.png
+++ /dev/null
Binary files differ
diff --git a/templates/includes/.gitkeep b/templates/includes/.gitkeep
deleted file mode 100644
index e69de29..0000000
--- a/templates/includes/.gitkeep
+++ /dev/null
diff --git a/templates/index.html b/templates/index.html
deleted file mode 100644
index 67ddd0c..0000000
--- a/templates/index.html
+++ /dev/null
@@ -1,40 +0,0 @@
1{{ template "base.html" . }}
2
3{{ define "content" }}
4<div>
5 <p>{{ .Config.Description }}</p>
6
7 <h2><a name="posts"></a>More long form, ramblings etc</h2>
8 <ul itemscope itemtype="https://schema.org/SiteNavigationElement" role="list" aria-label="Articles" class="list">
9 <meta itemprop="name" content="Article list">
10 {{ range .Pages }}
11 {{ if eq .Type "post" }}
12 <li role="listitem"><a href="/{{ .RelPermalink }}">{{ .Title }}</a></li>
13 {{ end }}
14 {{ end }}
15 </ul>
16
17 <h2><a name="notes"></a>Notes?! Maybe useful</h2>
18 <h2></h2>
19 <ul itemscope itemtype="https://schema.org/SiteNavigationElement" role="list" aria-label="Notes" class="list">
20 <meta itemprop="name" content="Note list">
21 {{ range .Pages }}
22 {{ if eq .Type "note" }}
23 <li role="listitem"><a href="/{{ .RelPermalink }}">{{ .Title }}</a></li>
24 {{ end }}
25 {{ end }}
26 </ul>
27
28 <h2><a name="sideprojects"></a>Side projects I work/worked on</h2>
29 <ul itemscope itemtype="https://schema.org/SiteNavigationElement" role="list" aria-label="Side projects" class="list">
30 <meta itemprop="name" content="Side projects">
31 <li role="listitem"><a href="https://git.mitjafelicijan.com/cord.h.git/" target="_blank">cord.h</a> — Small C library for handling strings</li>
32 <li role="listitem"><a href="https://git.mitjafelicijan.com/mprogress.git/" target="_blank">mprogress</a> — Tiny utility that displays progress bar in terminal</li>
33 <li role="listitem"><a href="https://git.mitjafelicijan.com/journalctl-proxy.git/" target="_blank">journalctl-proxy</a> — Exposes your systemd logs to web via web interface</li>
34 <li role="listitem"><a href="https://git.mitjafelicijan.com/redis-marshal.git/" target="_blank">redis-marshal</a> — Lightweight Redis data exploration tool</li>
35 <li role="listitem"><a href="https://git.mitjafelicijan.com/vertex.git/" target="_blank">vertex</a> — Create mock API's and add basic logic to simplify prototyping</li>
36 <li role="listitem"><a href="https://git.mitjafelicijan.com/dna-encoding.git/" target="_blank">dna-encoding</a> — Tools for encoding files to DNA sequence</li>
37 <li role="listitem"><a href="https://git.mitjafelicijan.com/scarecrow.git/" target="_blank">scarecrow</a> — Minimal configuration reverse proxy</li>
38 </ul>
39</div>
40{{ end }}
diff --git a/templates/index.xml b/templates/index.xml
deleted file mode 100644
index 11c4886..0000000
--- a/templates/index.xml
+++ /dev/null
@@ -1,21 +0,0 @@
1<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
2 <channel>
3 <title>{{ .Config.Title }}'s posts</title>
4 <link>{{ .Config.BaseURL }}</link>
5 <description>{{ .Config.Description }}</description>
6 <language>{{ .Config.Language }}</language>
7
8 {{ range $idx, $page := .Pages }}
9 {{ if eq $page.Type "post" }}
10 <item>
11 <title>{{ $page.Title }}</title>
12 <link>{{ $.Config.BaseURL }}/{{ $page.RelPermalink }}</link>
13 <pubDate>{{ $page.Created.Format "Mon, 02 Jan 2006 15:04:05 -0700" }}</pubDate>
14 <guid>{{ $.Config.BaseURL }}/{{ $page.RelPermalink }}</guid>
15 <description>{{ $page.Summary }}</description>
16 <content:encoded>{{ $page.Raw }}</content:encoded>
17 </item>
18 {{ end }}
19 {{ end }}
20 </channel>
21</rss>
diff --git a/templates/note.html b/templates/note.html
deleted file mode 100644
index 28c7907..0000000
--- a/templates/note.html
+++ /dev/null
@@ -1,14 +0,0 @@
1{{ template "base.html" . }}
2
3{{ define "title" }}{{ .Page.Title }}{{ end }}
4{{ define "description" }}{{ .Page.Summary }}{{ end }}
5
6{{ define "content" }}
7<article itemtype="http://schema.org/Article">
8 <h1 itemtype="headline">{{ .Page.Title }}</h1>
9 <p><cap>{{ .Page.Type }}</cap>, {{ .Page.Created.Format "Jan 2, 2006" }} on <a href="{{ .Config.BaseURL }}">{{ .Config.Title }}'s blog</a></p>
10 <div>
11 {{ .Page.HTML }}
12 </div>
13</article>
14{{ end }}
diff --git a/templates/notes.xml b/templates/notes.xml
deleted file mode 100644
index b7217fb..0000000
--- a/templates/notes.xml
+++ /dev/null
@@ -1,21 +0,0 @@
1<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
2 <channel>
3 <title>{{ .Config.Title }}'s notes</title>
4 <link>{{ .Config.BaseURL }}</link>
5 <description>{{ .Config.Description }}</description>
6 <language>en-us</language>
7
8 {{ range $idx, $page := .Pages }}
9 {{ if eq $page.Type "note" }}
10 <item>
11 <title>{{ $page.Title }}</title>
12 <link>{{ $.Config.BaseURL }}/{{ $page.RelPermalink }}</link>
13 <pubDate>{{ $page.Created.Format "Mon, 02 Jan 2006 15:04:05 -0700" }}</pubDate>
14 <guid>{{ $.Config.BaseURL }}/{{ $page.RelPermalink }}</guid>
15 <description>{{ $page.Summary }}</description>
16 <content:encoded>{{ $page.Raw }}</content:encoded>
17 </item>
18 {{ end }}
19 {{ end }}
20 </channel>
21</rss>
diff --git a/templates/openring.html b/templates/openring.html
deleted file mode 100644
index 5eb52e9..0000000
--- a/templates/openring.html
+++ /dev/null
@@ -1,12 +0,0 @@
1<h2>Posts from blogs I follow around the net</h2>
2
3<ul>
4 {{ range .Articles }}
5 <li>
6 <a href="{{ .Link }}" target="_blank" rel="noopener">{{ .Title }}</a> — <a href="{{ .SourceLink }}">{{ .SourceTitle }}</a>
7 <div>{{ .Summary }}
8 </li>
9 {{ end }}
10</ul>
11
12<p>Generated with <a href="https://git.sr.ht/~sircmpwn/openring" target="_blank" rel="noopener">openring</a>.</p>
diff --git a/templates/page.html b/templates/page.html
deleted file mode 100644
index 7ee5219..0000000
--- a/templates/page.html
+++ /dev/null
@@ -1,13 +0,0 @@
1{{ template "base.html" . }}
2
3{{ define "title" }}{{ .Page.Title }}{{ end }}
4{{ define "description" }}{{ .Page.Summary }}{{ end }}
5
6{{ define "content" }}
7<div>
8 <h1>{{ .Page.Title }}</h1>
9 <div>
10 {{ .Page.HTML }}
11 </div>
12</div>
13{{ end }}
diff --git a/templates/post.html b/templates/post.html
deleted file mode 100644
index 28c7907..0000000
--- a/templates/post.html
+++ /dev/null
@@ -1,14 +0,0 @@
1{{ template "base.html" . }}
2
3{{ define "title" }}{{ .Page.Title }}{{ end }}
4{{ define "description" }}{{ .Page.Summary }}{{ end }}
5
6{{ define "content" }}
7<article itemtype="http://schema.org/Article">
8 <h1 itemtype="headline">{{ .Page.Title }}</h1>
9 <p><cap>{{ .Page.Type }}</cap>, {{ .Page.Created.Format "Jan 2, 2006" }} on <a href="{{ .Config.BaseURL }}">{{ .Config.Title }}'s blog</a></p>
10 <div>
11 {{ .Page.HTML }}
12 </div>
13</article>
14{{ end }}
diff --git a/templates/radio.pls b/templates/radio.pls
deleted file mode 100644
index 77e6307..0000000
--- a/templates/radio.pls
+++ /dev/null
@@ -1,38 +0,0 @@
1# Find stations: https://streamurl.link/
2
3[playlist]
4
5Title1=Metal
6File1=http://kathy.torontocast.com:2820/
7
8Title2=Technolovers Minimal
9File2=https://stream.technolovers.fm/minimal
10
11Title3=Indie Rock
12File3=http://s5.radio.co/s36d03408d/listen
13
14Title4=Montreal's Classic Rock
15File4=http://streams.justclassicrock.com:8000
16
17Title5=Raute Metal
18File5=https://metal-high.rautemusik.fm/?ref
19
20Title6=NCC 1701a Engine Noise
21File6=https://files.mitjafelicijan.com/haphazard/ncc-1701-a-engine-noise.ogg
22
23Title7=Funk & Soul
24File7=http://streams.80s80s.de/soul/mp3-192/
25
26Title8=80's Pop
27File8=http://streams.fluxfm.de/80er/mp3-320
28
29Title9=Roots Legacy Radio Dub
30File9=http://l.rootslegacy.fr/
31
32Title10=Ambiental
33File10=http://radio.stereoscenic.com/ama-h
34
35#Title6=
36#File6=
37
38Length1=-1
diff --git a/templates/robots.txt b/templates/robots.txt
deleted file mode 100644
index c2a49f4..0000000
--- a/templates/robots.txt
+++ /dev/null
@@ -1,2 +0,0 @@
1User-agent: *
2Allow: /
diff --git a/templates/sitemap.xml b/templates/sitemap.xml
deleted file mode 100644
index b7a0926..0000000
--- a/templates/sitemap.xml
+++ /dev/null
@@ -1,8 +0,0 @@
1<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9" xmlns:xhtml="http://www.w3.org/1999/xhtml">
2 {{ range $idx, $page := .Pages }}
3 <url>
4 <loc>{{ $.Config.BaseURL }}/{{ $page.RelPermalink }}</loc>
5 <lastmod>{{ $page.Created.Format "2006-01-02T15:04:05" }}+00:00</lastmod>
6 </url>
7 {{ end }}
8</urlset>
diff --git a/templates/vault.md b/templates/vault.md
deleted file mode 100644
index 666a247..0000000
--- a/templates/vault.md
+++ /dev/null
@@ -1,20 +0,0 @@
1---
2title: Personal vault
3date: 2022-08-27T12:00:00+02:00
4url: vault.html
5type: page
6draft: false
7---
8
9**Hi traveler!**
10
11This is a repository of interesting things I have gathered over time and it also
12stores binaries etc of my personal projects.
13
14Be kind, this server is bandwidth limited.
15
16*Good luck!*
17
18---
19
20{CONTENT}
diff --git a/vault.py b/vault.py
deleted file mode 100644
index 5610c87..0000000
--- a/vault.py
+++ /dev/null
@@ -1,54 +0,0 @@
1import xml.etree.ElementTree as ET
2import requests
3
4url = "https://mitjafelicijan.fra1.digitaloceanspaces.com/"
5
6def truncate_filename(filename, max_length):
7 if len(filename) <= max_length:
8 return filename
9 file_extension = filename.split('.')[-1]
10 return f"{filename[:max_length - len(file_extension) - 5]}….{file_extension}"
11
12response = requests.get(url)
13if response.status_code == 200:
14 xml_data = response.text
15 root = ET.fromstring(xml_data)
16
17 # Handle namespace
18 ns = {'s3': 'http://s3.amazonaws.com/doc/2006-03-01/'}
19
20 # Create an empty dictionary to hold the tree structure
21 tree = {}
22
23 for content in root.findall(".//s3:Contents", ns):
24 key = content.find("s3:Key", ns).text
25 parts = key.split("/")
26 node = tree
27 for part in parts:
28 if part:
29 node = node.setdefault(part, {})
30
31 # Function to convert the tree structure to markdown list
32 def tree_to_md(tree, indent=0, path=""):
33 md = ""
34 for k, v in tree.items():
35 if v: # If the node has children, it's a directory
36 md += " " * indent + f"- {k}\n"
37 md += tree_to_md(v, indent + 1, path=f"{path}{k}/")
38 else: # If the node is empty, it's a file
39 file_url = f"{url}{path}{k}"
40 file_name = truncate_filename(k, 300)
41 md += " " * indent + f"- [{file_name}](<{file_url}>)\n"
42 return md
43
44 md = tree_to_md(tree)
45
46 with open("templates/vault.md", "r") as fp:
47 content = fp.read()
48
49 new_content = content.replace("{CONTENT}", md)
50
51 with open("content/pages/vault.md", "w") as fp:
52 fp.write(new_content)
53else:
54 print(f"Failed to fetch XML data. Status code: {response.status_code}")