diff options
| -rw-r--r-- | .editorconfig | 20 | ||||
| -rw-r--r-- | .gitignore | 7 | ||||
| -rw-r--r-- | 404.html | 24 | ||||
| -rw-r--r-- | Gemfile | 33 | ||||
| -rw-r--r-- | Gemfile.lock | 84 | ||||
| -rw-r--r-- | Makefile | 30 | ||||
| -rw-r--r-- | _config.yml | 15 | ||||
| -rw-r--r-- | _includes/webring.html | 57 | ||||
| -rw-r--r-- | _layouts/base.html (renamed from templates/base.html) | 100 | ||||
| -rw-r--r-- | _layouts/index.html | 10 | ||||
| -rw-r--r-- | _layouts/page.html | 10 | ||||
| -rw-r--r-- | _layouts/post.html | 14 | ||||
| -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.md | 20 | ||||
| -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) | bin | 249 -> 249 bytes | |||
| -rw-r--r-- | assets/general/9logo.png (renamed from public/general/9logo.png) | bin | 39825 -> 39825 bytes | |||
| -rwxr-xr-x | assets/general/alert-dark.svg (renamed from public/general/alert-dark.svg) | 0 | ||||
| -rwxr-xr-x | assets/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) | bin | 70575 -> 70575 bytes | |||
| -rw-r--r-- | assets/general/og-big.xcf (renamed from public/general/og-big.xcf) | bin | 10025863 -> 10025863 bytes | |||
| -rw-r--r-- | assets/general/og.jpg (renamed from public/general/og.jpg) | bin | 44366 -> 44366 bytes | |||
| -rw-r--r-- | assets/general/og.xcf (renamed from public/general/og.xcf) | bin | 898329 -> 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) | bin | 21762 -> 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) | bin | 16587109 -> 16587109 bytes | |||
| -rw-r--r-- | assets/notes/60s-ibm-computers-commercial.jpg (renamed from public/notes/60s-ibm-computers-commercial.jpg) | bin | 32372 -> 32372 bytes | |||
| -rw-r--r-- | assets/notes/60s-ibm-computers-commercial.mp4 (renamed from public/notes/60s-ibm-computers-commercial.mp4) | bin | 35273598 -> 35273598 bytes | |||
| -rw-r--r-- | assets/notes/9front-desktop.png (renamed from public/notes/9front-desktop.png) | bin | 38054 -> 38054 bytes | |||
| -rw-r--r-- | assets/notes/dcss-quickstart.pdf (renamed from public/notes/dcss-quickstart.pdf) | bin | 80328 -> 80328 bytes | |||
| -rw-r--r-- | assets/notes/dcss.jpg (renamed from public/notes/dcss.jpg) | bin | 855457 -> 855457 bytes | |||
| -rw-r--r-- | assets/notes/dcss_manual.pdf (renamed from public/notes/dcss_manual.pdf) | bin | 203302 -> 203302 bytes | |||
| -rwxr-xr-x | assets/notes/floods/IMG_1461.mp4 (renamed from public/notes/floods/IMG_1461.mp4) | bin | 14410656 -> 14410656 bytes | |||
| -rwxr-xr-x | assets/notes/floods/IMG_1466.mp4 (renamed from public/notes/floods/IMG_1466.mp4) | bin | 8902148 -> 8902148 bytes | |||
| -rwxr-xr-x | assets/notes/floods/IMG_1469.webp (renamed from public/notes/floods/IMG_1469.webp) | bin | 816680 -> 816680 bytes | |||
| -rwxr-xr-x | assets/notes/floods/IMG_1470.webp (renamed from public/notes/floods/IMG_1470.webp) | bin | 933574 -> 933574 bytes | |||
| -rwxr-xr-x | assets/notes/floods/IMG_1471.mp4 (renamed from public/notes/floods/IMG_1471.mp4) | bin | 10163115 -> 10163115 bytes | |||
| -rwxr-xr-x | assets/notes/floods/IMG_1474.mp4 (renamed from public/notes/floods/IMG_1474.mp4) | bin | 14032243 -> 14032243 bytes | |||
| -rw-r--r-- | assets/notes/grep-less.png (renamed from public/notes/grep-less.png) | bin | 178000 -> 178000 bytes | |||
| -rw-r--r-- | assets/notes/plan9-pixels.png (renamed from public/notes/plan9-pixels.png) | bin | 12134 -> 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) | bin | 24272 -> 24272 bytes | |||
| -rw-r--r-- | assets/notes/xterm-palette.png (renamed from public/notes/xterm-palette.png) | bin | 9524 -> 9524 bytes | |||
| -rwxr-xr-x | assets/posts/algae-sava/dji-algae-0.jpg (renamed from public/posts/algae-sava/dji-algae-0.jpg) | bin | 145615 -> 145615 bytes | |||
| -rwxr-xr-x | assets/posts/algae-sava/dji-algae-1.jpg (renamed from public/posts/algae-sava/dji-algae-1.jpg) | bin | 154416 -> 154416 bytes | |||
| -rwxr-xr-x | assets/posts/algae-sava/dji-algae-2.jpg (renamed from public/posts/algae-sava/dji-algae-2.jpg) | bin | 114347 -> 114347 bytes | |||
| -rwxr-xr-x | assets/posts/algae-sava/dji-algae-3.jpg (renamed from public/posts/algae-sava/dji-algae-3.jpg) | bin | 128019 -> 128019 bytes | |||
| -rwxr-xr-x | assets/posts/algae-sava/dji-algae-4.jpg (renamed from public/posts/algae-sava/dji-algae-4.jpg) | bin | 217747 -> 217747 bytes | |||
| -rwxr-xr-x | assets/posts/algae-sava/dji-algae-5.jpg (renamed from public/posts/algae-sava/dji-algae-5.jpg) | bin | 264884 -> 264884 bytes | |||
| -rwxr-xr-x | assets/posts/cv/avatar.gif (renamed from public/posts/cv/avatar.gif) | bin | 2174 -> 2174 bytes | |||
| -rwxr-xr-x | assets/posts/dfd-rice/desktop.png (renamed from public/posts/dfd-rice/desktop.png) | bin | 329498 -> 329498 bytes | |||
| -rwxr-xr-x | assets/posts/dfd-rice/install-00.png (renamed from public/posts/dfd-rice/install-00.png) | bin | 35695 -> 35695 bytes | |||
| -rwxr-xr-x | assets/posts/dfd-rice/install-01.png (renamed from public/posts/dfd-rice/install-01.png) | bin | 28042 -> 28042 bytes | |||
| -rwxr-xr-x | assets/posts/dfd-rice/install-02.png (renamed from public/posts/dfd-rice/install-02.png) | bin | 21638 -> 21638 bytes | |||
| -rwxr-xr-x | assets/posts/dfd-rice/install-03.png (renamed from public/posts/dfd-rice/install-03.png) | bin | 34698 -> 34698 bytes | |||
| -rwxr-xr-x | assets/posts/dfd-rice/install-04.png (renamed from public/posts/dfd-rice/install-04.png) | bin | 28346 -> 28346 bytes | |||
| -rwxr-xr-x | assets/posts/dfd-rice/install-05.png (renamed from public/posts/dfd-rice/install-05.png) | bin | 13755 -> 13755 bytes | |||
| -rwxr-xr-x | assets/posts/dfd-rice/installation.svg (renamed from public/posts/dfd-rice/installation.svg) | 0 | ||||
| -rwxr-xr-x | assets/posts/dfd-rice/layout.png (renamed from public/posts/dfd-rice/layout.png) | bin | 9072 -> 9072 bytes | |||
| -rwxr-xr-x | assets/posts/dfd-rice/layout.svg (renamed from public/posts/dfd-rice/layout.svg) | 0 | ||||
| -rwxr-xr-x | assets/posts/dfd-rice/script.png (renamed from public/posts/dfd-rice/script.png) | bin | 65747 -> 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-x | assets/posts/dna-sequence/dna-basics.jpg (renamed from public/posts/dna-sequence/dna-basics.jpg) | bin | 165883 -> 165883 bytes | |||
| -rwxr-xr-x | assets/posts/dna-sequence/quote.png (renamed from public/posts/dna-sequence/quote.png) | bin | 1068 -> 1068 bytes | |||
| -rwxr-xr-x | assets/posts/dna-sequence/sample-binary-file.png (renamed from public/posts/dna-sequence/sample-binary-file.png) | bin | 66417 -> 66417 bytes | |||
| -rwxr-xr-x | assets/posts/dna-sequence/sample.png (renamed from public/posts/dna-sequence/sample.png) | bin | 65930 -> 65930 bytes | |||
| -rwxr-xr-x | assets/posts/dna-synthesized/bison/in.txt (renamed from public/posts/dna-synthesized/bison/in.txt) | 0 | ||||
| -rwxr-xr-x | assets/posts/dna-synthesized/bison/out.mp3 (renamed from public/posts/dna-synthesized/bison/out.mp3) | bin | 960469 -> 960469 bytes | |||
| -rwxr-xr-x | assets/posts/dna-synthesized/bison/spectogram.png (renamed from public/posts/dna-synthesized/bison/spectogram.png) | bin | 52808 -> 52808 bytes | |||
| -rwxr-xr-x | assets/posts/dna-synthesized/elektron/IMG_0619.jpg (renamed from public/posts/dna-synthesized/elektron/IMG_0619.jpg) | bin | 226025 -> 226025 bytes | |||
| -rwxr-xr-x | assets/posts/dna-synthesized/elektron/IMG_0620.jpg (renamed from public/posts/dna-synthesized/elektron/IMG_0620.jpg) | bin | 242937 -> 242937 bytes | |||
| -rwxr-xr-x | assets/posts/dna-synthesized/elektron/IMG_0622.jpg (renamed from public/posts/dna-synthesized/elektron/IMG_0622.jpg) | bin | 279234 -> 279234 bytes | |||
| -rwxr-xr-x | assets/posts/dna-synthesized/elektron/elektron.mp4 (renamed from public/posts/dna-synthesized/elektron/elektron.mp4) | bin | 22478213 -> 22478213 bytes | |||
| -rwxr-xr-x | assets/posts/dna-synthesized/elektron/midi-studio.jpg (renamed from public/posts/dna-synthesized/elektron/midi-studio.jpg) | bin | 63633 -> 63633 bytes | |||
| -rwxr-xr-x | assets/posts/dna-synthesized/mouse/in.txt (renamed from public/posts/dna-synthesized/mouse/in.txt) | 0 | ||||
| -rwxr-xr-x | assets/posts/dna-synthesized/mouse/out.mp3 (renamed from public/posts/dna-synthesized/mouse/out.mp3) | bin | 864547 -> 864547 bytes | |||
| -rwxr-xr-x | assets/posts/dna-synthesized/mouse/spectogram.png (renamed from public/posts/dna-synthesized/mouse/spectogram.png) | bin | 114261 -> 114261 bytes | |||
| -rwxr-xr-x | assets/posts/dna-synthesized/quote/in.txt (renamed from public/posts/dna-synthesized/quote/in.txt) | 0 | ||||
| -rwxr-xr-x | assets/posts/dna-synthesized/quote/out.mp3 (renamed from public/posts/dna-synthesized/quote/out.mp3) | bin | 678973 -> 678973 bytes | |||
| -rwxr-xr-x | assets/posts/dna-synthesized/quote/spectogram.png (renamed from public/posts/dna-synthesized/quote/spectogram.png) | bin | 108863 -> 108863 bytes | |||
| -rwxr-xr-x | assets/posts/dna-synthesized/symphony-no6-1st-movement.mp3 (renamed from public/posts/dna-synthesized/symphony-no6-1st-movement.mp3) | bin | 11650187 -> 11650187 bytes | |||
| -rwxr-xr-x | assets/posts/dna-synthesized/symphony-no6-1st-movement.png (renamed from public/posts/dna-synthesized/symphony-no6-1st-movement.png) | bin | 245694 -> 245694 bytes | |||
| -rwxr-xr-x | assets/posts/dna-synthesized/taurus/in.txt (renamed from public/posts/dna-synthesized/taurus/in.txt) | 0 | ||||
| -rwxr-xr-x | assets/posts/dna-synthesized/taurus/out.mp3 (renamed from public/posts/dna-synthesized/taurus/out.mp3) | bin | 1056599 -> 1056599 bytes | |||
| -rwxr-xr-x | assets/posts/dna-synthesized/taurus/spectogram.png (renamed from public/posts/dna-synthesized/taurus/spectogram.png) | bin | 109064 -> 109064 bytes | |||
| -rwxr-xr-x | assets/posts/do-fuse/copy-benchmarks.tsv (renamed from public/posts/do-fuse/copy-benchmarks.tsv) | 0 | ||||
| -rwxr-xr-x | assets/posts/do-fuse/fuse-droplets.png (renamed from public/posts/do-fuse/fuse-droplets.png) | bin | 42891 -> 42891 bytes | |||
| -rwxr-xr-x | assets/posts/do-fuse/fuse-spaces.png (renamed from public/posts/do-fuse/fuse-spaces.png) | bin | 32450 -> 32450 bytes | |||
| -rwxr-xr-x | assets/posts/do-fuse/sqlite-benchmarks.tsv (renamed from public/posts/do-fuse/sqlite-benchmarks.tsv) | 0 | ||||
| -rwxr-xr-x | assets/posts/dropbox-sync/dropbox-spaces.png (renamed from public/posts/dropbox-sync/dropbox-spaces.png) | bin | 47661 -> 47661 bytes | |||
| -rwxr-xr-x | assets/posts/esp8366-micropython/boards.jpg (renamed from public/posts/esp8366-micropython/boards.jpg) | bin | 98162 -> 98162 bytes | |||
| -rwxr-xr-x | assets/posts/go-profiling/golang-profiling-cpu.pdf (renamed from public/posts/go-profiling/golang-profiling-cpu.pdf) | bin | 16518 -> 16518 bytes | |||
| -rwxr-xr-x | assets/posts/go-profiling/golang-profiling-mem.pdf (renamed from public/posts/go-profiling/golang-profiling-mem.pdf) | bin | 19221 -> 19221 bytes | |||
| -rwxr-xr-x | assets/posts/goaccess/goaccess-dash-html.png (renamed from public/posts/goaccess/goaccess-dash-html.png) | bin | 16129 -> 16129 bytes | |||
| -rwxr-xr-x | assets/posts/goaccess/goaccess-dash-term.png (renamed from public/posts/goaccess/goaccess-dash-term.png) | bin | 9188 -> 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) | bin | 975421 -> 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) | bin | 373408 -> 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) | bin | 18955 -> 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) | bin | 3305 -> 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) | bin | 7056 -> 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) | bin | 21443 -> 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) | bin | 13789463 -> 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) | bin | 97628 -> 97628 bytes | |||
| -rwxr-xr-x | assets/posts/helix-editor/editor.png (renamed from public/posts/helix-editor/editor.png) | bin | 159442 -> 159442 bytes | |||
| -rwxr-xr-x | assets/posts/iot-application/iot-app-output.png (renamed from public/posts/iot-application/iot-app-output.png) | bin | 23767 -> 23767 bytes | |||
| -rwxr-xr-x | assets/posts/iot-application/iot-rest-example.png (renamed from public/posts/iot-application/iot-rest-example.png) | bin | 33912 -> 33912 bytes | |||
| -rwxr-xr-x | assets/posts/iot-application/iot-sqlite-db.png (renamed from public/posts/iot-application/iot-sqlite-db.png) | bin | 199821 -> 199821 bytes | |||
| -rwxr-xr-x | assets/posts/iot-application/kcachegrind.png (renamed from public/posts/iot-application/kcachegrind.png) | bin | 88486 -> 88486 bytes | |||
| -rwxr-xr-x | assets/posts/iot-application/profiling-viewer.png (renamed from public/posts/iot-application/profiling-viewer.png) | bin | 173672 -> 173672 bytes | |||
| -rwxr-xr-x | assets/posts/iot-application/simple-iot-application-overview.svg (renamed from public/posts/iot-application/simple-iot-application-overview.svg) | 0 | ||||
| -rwxr-xr-x | assets/posts/iot-application/simple-iot-application.zip (renamed from public/posts/iot-application/simple-iot-application.zip) | bin | 6406 -> 6406 bytes | |||
| -rwxr-xr-x | assets/posts/iot-application/snakeviz.png (renamed from public/posts/iot-application/snakeviz.png) | bin | 59601 -> 59601 bytes | |||
| -rw-r--r-- | assets/posts/microsoundtrack/cow.m4v (renamed from public/posts/microsoundtrack/cow.m4v) | bin | 1113250 -> 1113250 bytes | |||
| -rwxr-xr-x | assets/posts/pid1/boxes.mp4 (renamed from public/posts/pid1/boxes.mp4) | bin | 443830 -> 443830 bytes | |||
| -rwxr-xr-x | assets/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) | bin | 33009 -> 33009 bytes | |||
| -rwxr-xr-x | assets/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) | bin | 23304 -> 23304 bytes | |||
| -rwxr-xr-x | assets/posts/profile-bind-error/error.jpg (renamed from public/posts/profile-bind-error/error.jpg) | bin | 57047 -> 57047 bytes | |||
| -rwxr-xr-x | assets/posts/python-profiling/kcachegrind.png (renamed from public/posts/python-profiling/kcachegrind.png) | bin | 88486 -> 88486 bytes | |||
| -rwxr-xr-x | assets/posts/python-profiling/profiling-viewer.png (renamed from public/posts/python-profiling/profiling-viewer.png) | bin | 173672 -> 173672 bytes | |||
| -rwxr-xr-x | assets/posts/python-profiling/snakeviz.png (renamed from public/posts/python-profiling/snakeviz.png) | bin | 59601 -> 59601 bytes | |||
| -rwxr-xr-x | assets/posts/sentiment-analysis/.ipynb_checkpoints/TF Test-checkpoint.ipynb (renamed from public/posts/sentiment-analysis/.ipynb_checkpoints/TF Test-checkpoint.ipynb) | 0 | ||||
| -rwxr-xr-x | assets/posts/sentiment-analysis/.ipynb_checkpoints/sentiment-analysis-checkpoint.ipynb (renamed from public/posts/sentiment-analysis/.ipynb_checkpoints/sentiment-analysis-checkpoint.ipynb) | 0 | ||||
| -rwxr-xr-x | assets/posts/sentiment-analysis/guardian-sa-title-desc-relationship.png (renamed from public/posts/sentiment-analysis/guardian-sa-title-desc-relationship.png) | bin | 15404 -> 15404 bytes | |||
| -rwxr-xr-x | assets/posts/sentiment-analysis/sentiment-analysis.ipynb (renamed from public/posts/sentiment-analysis/sentiment-analysis.ipynb) | 0 | ||||
| -rwxr-xr-x | assets/posts/simple-pubsub-server/caniuse.png (renamed from public/posts/simple-pubsub-server/caniuse.png) | bin | 56379 -> 56379 bytes | |||
| -rwxr-xr-x | assets/posts/simple-pubsub-server/chrome-debugging.png (renamed from public/posts/simple-pubsub-server/chrome-debugging.png) | bin | 151160 -> 151160 bytes | |||
| -rwxr-xr-x | assets/posts/simple-pubsub-server/clients.m4v (renamed from public/posts/simple-pubsub-server/clients.m4v) | bin | 369179 -> 369179 bytes | |||
| -rwxr-xr-x | assets/posts/simple-pubsub-server/pubsub-overview.png (renamed from public/posts/simple-pubsub-server/pubsub-overview.png) | bin | 18471 -> 18471 bytes | |||
| -rwxr-xr-x | assets/posts/simple-pubsub-server/sse-pubsub-server.zip (renamed from public/posts/simple-pubsub-server/sse-pubsub-server.zip) | bin | 4158 -> 4158 bytes | |||
| -rwxr-xr-x | assets/posts/state-of-web/2008-vs-2020.png (renamed from public/posts/state-of-web/2008-vs-2020.png) | bin | 126650 -> 126650 bytes | |||
| -rwxr-xr-x | assets/posts/state-of-web/compiling-vs-transpiling.png (renamed from public/posts/state-of-web/compiling-vs-transpiling.png) | bin | 41481 -> 41481 bytes | |||
| -rwxr-xr-x | assets/posts/wap/emulator.mp4 (renamed from public/posts/wap/emulator.mp4) | bin | 892887 -> 892887 bytes | |||
| -rwxr-xr-x | assets/posts/wap/phones.gif (renamed from public/posts/wap/phones.gif) | bin | 348891 -> 348891 bytes | |||
| -rwxr-xr-x | assets/posts/world-clock/enclosure.stl (renamed from public/posts/world-clock/enclosure.stl) | bin | 1884 -> 1884 bytes | |||
| -rwxr-xr-x | assets/posts/world-clock/hardware.jpg (renamed from public/posts/world-clock/hardware.jpg) | bin | 82279 -> 82279 bytes | |||
| -rwxr-xr-x | assets/posts/world-clock/world-clock.jpg (renamed from public/posts/world-clock/world-clock.jpg) | bin | 148673 -> 148673 bytes | |||
| -rwxr-xr-x | assets/posts/yapyap/hello.png (renamed from public/posts/yapyap/hello.png) | bin | 25962 -> 25962 bytes | |||
| -rwxr-xr-x | assets/posts/yapyap/pid1.jpg (renamed from public/posts/yapyap/pid1.jpg) | bin | 394011 -> 394011 bytes | |||
| -rwxr-xr-x | assets/posts/zed/zed-1.png (renamed from public/posts/zed/zed-1.png) | bin | 450802 -> 450802 bytes | |||
| -rwxr-xr-x | assets/posts/zed/zed-2.png (renamed from public/posts/zed/zed-2.png) | bin | 812483 -> 812483 bytes | |||
| -rw-r--r-- | bin/webring.rb | 82 | ||||
| -rw-r--r-- | config.yaml | 24 | ||||
| -rw-r--r-- | content/notes/2023-08-05-floods-in-slovenia.md | 19 | ||||
| -rw-r--r-- | content/pages/vault.md | 405 | ||||
| -rw-r--r-- | curriculum-vitae.md (renamed from content/pages/curriculum-vitae.md) | 21 | ||||
| -rw-r--r-- | index.html | 30 | ||||
| -rwxr-xr-x | public/10gui-10-finger-multitouch-user-interface.html | 48 | ||||
| -rwxr-xr-x | public/60s-ibm-computers-commercial.html | 46 | ||||
| -rwxr-xr-x | public/aerial-photography-of-algae-spotted-on-river-sava.html | 49 | ||||
| -rwxr-xr-x | public/alacritty-open-links-with-modifier.html | 58 | ||||
| -rwxr-xr-x | public/aws-eb-pyyaml-fix.html | 56 | ||||
| -rwxr-xr-x | public/bind-warning-on-login-in-ubuntu.html | 69 | ||||
| -rwxr-xr-x | public/bringing-all-of-my-projects-together-under-one-umbrella.html | 197 | ||||
| -rwxr-xr-x | public/bulk-make-thumbnails.html | 52 | ||||
| -rwxr-xr-x | public/cachebusting-in-hugo.html | 48 | ||||
| -rwxr-xr-x | public/catv-weechat-config.html | 51 | ||||
| -rwxr-xr-x | public/compile-drawterm-on-fedora-38.html | 48 | ||||
| -rwxr-xr-x | public/convert-mkv.html | 49 | ||||
| -rwxr-xr-x | public/crafting-stories-in-zed-editor.html | 57 | ||||
| -rwxr-xr-x | public/create-placeholder-images-with-sharp.html | 111 | ||||
| -rwxr-xr-x | public/cronjobs-github-with-actions.html | 60 | ||||
| -rwxr-xr-x | public/curriculum-vitae.html | 54 | ||||
| -rwxr-xr-x | public/dcss-new-player-guide.html | 76 | ||||
| -rwxr-xr-x | public/dcss-on-4k-display.html | 55 | ||||
| -rwxr-xr-x | public/debian-based-riced-up-distribution-for-developers-and-devops-folks.html | 158 | ||||
| -rwxr-xr-x | public/development-environments-with-nix.html | 74 | ||||
| -rwxr-xr-x | public/digitalocean-spaces-to-sync-between-computers.html | 98 | ||||
| -rwxr-xr-x | public/disable-mouse-wake-from-suspend-with-systemd-service.html | 84 | ||||
| -rwxr-xr-x | public/download-youtube-videos.html | 50 | ||||
| -rwxr-xr-x | public/drawing-pixels-in-plan9.html | 96 | ||||
| -rwxr-xr-x | public/easy-time-took-in-bash.html | 56 | ||||
| -rwxr-xr-x | public/encoding-binary-data-into-dna-sequence.html | 219 | ||||
| -rwxr-xr-x | public/esp8266-and-micropython-guide.html | 128 | ||||
| -rwxr-xr-x | public/ewd-manuscripts-ebook.html | 46 | ||||
| -rwxr-xr-x | public/extend-lua-with-custom-c.html | 72 | ||||
| -rwxr-xr-x | public/extending-dte-editor.html | 79 | ||||
| -rwxr-xr-x | public/fix-plan9-bootloader.html | 50 | ||||
| -rwxr-xr-x | public/fix-screen-tearing-on-debian-12-xorg-and-i3.html | 52 | ||||
| -rwxr-xr-x | public/floods-in-slovenia.html | 44 | ||||
| -rwxr-xr-x | public/fresh-9front-desktop.html | 45 | ||||
| -rwxr-xr-x | public/from-internet-consumer-to-full-hominum-again.html | 112 | ||||
| -rwxr-xr-x | public/git-push-multiple-origins.html | 47 | ||||
| -rwxr-xr-x | public/golang-profiling-simplified.html | 124 | ||||
| -rwxr-xr-x | public/grep-to-less-maintain-colors.html | 49 | ||||
| -rwxr-xr-x | public/i-was-wrong-about-git-workflows.html | 84 | ||||
| -rwxr-xr-x | public/index.html | 44 | ||||
| -rwxr-xr-x | public/index.xml | 6103 | ||||
| -rwxr-xr-x | public/install-plan9port-linux.html | 51 | ||||
| -rwxr-xr-x | public/led-technology-not-so-eco.html | 56 | ||||
| -rwxr-xr-x | public/linux-cheatsheet.html | 144 | ||||
| -rwxr-xr-x | public/make-b-w-svg-charts-with-matplotlib.html | 86 | ||||
| -rwxr-xr-x | public/making-cgit-look-nicer.html | 228 | ||||
| -rwxr-xr-x | public/mass-set-permission.html | 46 | ||||
| -rwxr-xr-x | public/most-likely-to-succeed-in-year-of-2011.html | 60 | ||||
| -rwxr-xr-x | public/mount-plan9-over-network.html | 51 | ||||
| -rwxr-xr-x | public/my-love-and-hate-relationship-with-nodejs.html | 110 | ||||
| -rwxr-xr-x | public/non-blocking-shell-exec-csharp.html | 69 | ||||
| -rwxr-xr-x | public/notes.xml | 1569 | ||||
| -rwxr-xr-x | public/online-radio-streaming-with-mpv-from-terminal.html | 47 | ||||
| -rwxr-xr-x | public/parse-rss-with-lua.html | 68 | ||||
| -rwxr-xr-x | public/plan9-screenshot.html | 52 | ||||
| -rwxr-xr-x | public/presentations-with-markdown.html | 102 | ||||
| -rwxr-xr-x | public/preview-troff-man-pages.html | 50 | ||||
| -rwxr-xr-x | public/profiling-python-web-applications-with-visual-tools.html | 176 | ||||
| -rwxr-xr-x | public/radio.pls | 38 | ||||
| -rwxr-xr-x | public/re-inventing-task-runner-that-i-actually-used-daily.html | 145 | ||||
| -rwxr-xr-x | public/rekindling-my-love-for-programming.html | 85 | ||||
| -rwxr-xr-x | public/remote-work.html | 78 | ||||
| -rwxr-xr-x | public/replacing-dropbox-in-favor-of-digitalocean-spaces.html | 106 | ||||
| -rwxr-xr-x | public/robots.txt | 2 | ||||
| -rwxr-xr-x | public/run-9front-in-qemu.html | 56 | ||||
| -rwxr-xr-x | public/running-golang-application-as-pid1.html | 222 | ||||
| -rwxr-xr-x | public/set-color-temperature-of-displays-on-i3.html | 46 | ||||
| -rwxr-xr-x | public/simple-iot-application.html | 472 | ||||
| -rwxr-xr-x | public/simple-server-sent-events-based-pubsub-server.html | 343 | ||||
| -rwxr-xr-x | public/simple-world-clock-with-eiink-display-and-raspberry-pi-zero.html | 104 | ||||
| -rwxr-xr-x | public/simplifying-and-reducing-clutter.html | 80 | ||||
| -rwxr-xr-x | public/sitemap.xml | 418 | ||||
| -rwxr-xr-x | public/software-development-pitfalls.html | 152 | ||||
| -rwxr-xr-x | public/state-of-web-technologies-and-web-development-in-year-2022.html | 220 | ||||
| -rwxr-xr-x | public/that-sound-that-machine-makes-when-struggling.html | 64 | ||||
| -rwxr-xr-x | public/the-strange-case-of-elasticsearch-allocation-failure.html | 97 | ||||
| -rwxr-xr-x | public/tmux-sane-defaults.html | 69 | ||||
| -rwxr-xr-x | public/trying-to-build-a-new-kind-of-terminal-emulator.html | 224 | ||||
| -rwxr-xr-x | public/tying-out-helix-code-editor.html | 67 | ||||
| -rwxr-xr-x | public/using-digitalocean-spaces-object-storage-with-fuse.html | 280 | ||||
| -rwxr-xr-x | public/using-goaccess-with-nginx-to-replace-google-analytics.html | 129 | ||||
| -rwxr-xr-x | public/using-sentiment-analysis-for-clickbait-detection-in-rss-feeds.html | 88 | ||||
| -rwxr-xr-x | public/vault.html | 45 | ||||
| -rwxr-xr-x | public/wap-mobile-web-before-the-web.html | 153 | ||||
| -rwxr-xr-x | public/what-i-ve-learned-developing-ad-server.html | 159 | ||||
| -rwxr-xr-x | public/what-would-dna-sound-if-synthesized.html | 237 | ||||
| -rwxr-xr-x | public/who-knows-what-the-world-will-look-like-tomorrow.html | 109 | ||||
| -rwxr-xr-x | public/wireless-sensor-networks.html | 71 | ||||
| -rwxr-xr-x | public/write-iso-usb.html | 45 | ||||
| -rwxr-xr-x | public/xterm-color-palette.html | 112 | ||||
| -rw-r--r-- | shell.nix | 6 | ||||
| -rw-r--r-- | static/general/9front-cursor.png | bin | 249 -> 0 bytes | |||
| -rw-r--r-- | static/general/9logo.png | bin | 39825 -> 0 bytes | |||
| -rwxr-xr-x | static/general/alert-dark.svg | 99 | ||||
| -rwxr-xr-x | static/general/alert-light.svg | 99 | ||||
| -rw-r--r-- | static/general/index.css | 1 | ||||
| -rw-r--r-- | static/general/og-big.jpg | bin | 70575 -> 0 bytes | |||
| -rw-r--r-- | static/general/og-big.xcf | bin | 10025863 -> 0 bytes | |||
| -rw-r--r-- | static/general/og.jpg | bin | 44366 -> 0 bytes | |||
| -rw-r--r-- | static/general/og.xcf | bin | 898329 -> 0 bytes | |||
| -rw-r--r-- | static/mitjafelicijan.pgp.pub.txt | 41 | ||||
| -rw-r--r-- | static/notes/10gui-10-finger-multitouch-user-interface.jpg | bin | 21762 -> 0 bytes | |||
| -rw-r--r-- | static/notes/10gui-10-finger-multitouch-user-interface.mp4 | bin | 16587109 -> 0 bytes | |||
| -rw-r--r-- | static/notes/60s-ibm-computers-commercial.jpg | bin | 32372 -> 0 bytes | |||
| -rw-r--r-- | static/notes/60s-ibm-computers-commercial.mp4 | bin | 35273598 -> 0 bytes | |||
| -rw-r--r-- | static/notes/9front-desktop.png | bin | 38054 -> 0 bytes | |||
| -rw-r--r-- | static/notes/dcss-quickstart.pdf | bin | 80328 -> 0 bytes | |||
| -rw-r--r-- | static/notes/dcss.jpg | bin | 855457 -> 0 bytes | |||
| -rw-r--r-- | static/notes/dcss_manual.pdf | bin | 203302 -> 0 bytes | |||
| -rwxr-xr-x | static/notes/floods/IMG_1461.mp4 | bin | 14410656 -> 0 bytes | |||
| -rwxr-xr-x | static/notes/floods/IMG_1466.mp4 | bin | 8902148 -> 0 bytes | |||
| -rwxr-xr-x | static/notes/floods/IMG_1469.webp | bin | 816680 -> 0 bytes | |||
| -rwxr-xr-x | static/notes/floods/IMG_1470.webp | bin | 933574 -> 0 bytes | |||
| -rwxr-xr-x | static/notes/floods/IMG_1471.mp4 | bin | 10163115 -> 0 bytes | |||
| -rwxr-xr-x | static/notes/floods/IMG_1474.mp4 | bin | 14032243 -> 0 bytes | |||
| -rw-r--r-- | static/notes/grep-less.png | bin | 178000 -> 0 bytes | |||
| -rw-r--r-- | static/notes/plan9-pixels.png | bin | 12134 -> 0 bytes | |||
| -rw-r--r-- | static/notes/plot.svg | 1546 | ||||
| -rw-r--r-- | static/notes/ps1-prompt.png | bin | 24272 -> 0 bytes | |||
| -rw-r--r-- | static/notes/xterm-palette.png | bin | 9524 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/algae-sava/dji-algae-0.jpg | bin | 145615 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/algae-sava/dji-algae-1.jpg | bin | 154416 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/algae-sava/dji-algae-2.jpg | bin | 114347 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/algae-sava/dji-algae-3.jpg | bin | 128019 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/algae-sava/dji-algae-4.jpg | bin | 217747 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/algae-sava/dji-algae-5.jpg | bin | 264884 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/cv/avatar.gif | bin | 2174 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/dfd-rice/desktop.png | bin | 329498 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/dfd-rice/install-00.png | bin | 35695 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/dfd-rice/install-01.png | bin | 28042 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/dfd-rice/install-02.png | bin | 21638 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/dfd-rice/install-03.png | bin | 34698 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/dfd-rice/install-04.png | bin | 28346 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/dfd-rice/install-05.png | bin | 13755 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/dfd-rice/installation.svg | 1388 | ||||
| -rwxr-xr-x | static/posts/dfd-rice/layout.png | bin | 9072 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/dfd-rice/layout.svg | 28 | ||||
| -rwxr-xr-x | static/posts/dfd-rice/script.png | bin | 65747 -> 0 bytes | |||
| -rw-r--r-- | static/posts/dna-sequence/benchmarks.csv | 7 | ||||
| -rw-r--r-- | static/posts/dna-sequence/chart-size.py | 28 | ||||
| -rw-r--r-- | static/posts/dna-sequence/chart-size.svg | 1553 | ||||
| -rw-r--r-- | static/posts/dna-sequence/chart-speed.py | 23 | ||||
| -rw-r--r-- | static/posts/dna-sequence/chart-speed.svg | 1416 | ||||
| -rwxr-xr-x | static/posts/dna-sequence/dna-basics.jpg | bin | 165883 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/dna-sequence/quote.png | bin | 1068 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/dna-sequence/sample-binary-file.png | bin | 66417 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/dna-sequence/sample.png | bin | 65930 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/dna-synthesized/bison/in.txt | 11 | ||||
| -rwxr-xr-x | static/posts/dna-synthesized/bison/out.mp3 | bin | 960469 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/dna-synthesized/bison/spectogram.png | bin | 52808 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/dna-synthesized/elektron/IMG_0619.jpg | bin | 226025 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/dna-synthesized/elektron/IMG_0620.jpg | bin | 242937 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/dna-synthesized/elektron/IMG_0622.jpg | bin | 279234 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/dna-synthesized/elektron/elektron.mp4 | bin | 22478213 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/dna-synthesized/elektron/midi-studio.jpg | bin | 63633 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/dna-synthesized/mouse/in.txt | 9 | ||||
| -rwxr-xr-x | static/posts/dna-synthesized/mouse/out.mp3 | bin | 864547 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/dna-synthesized/mouse/spectogram.png | bin | 114261 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/dna-synthesized/quote/in.txt | 8 | ||||
| -rwxr-xr-x | static/posts/dna-synthesized/quote/out.mp3 | bin | 678973 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/dna-synthesized/quote/spectogram.png | bin | 108863 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/dna-synthesized/symphony-no6-1st-movement.mp3 | bin | 11650187 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/dna-synthesized/symphony-no6-1st-movement.png | bin | 245694 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/dna-synthesized/taurus/in.txt | 11 | ||||
| -rwxr-xr-x | static/posts/dna-synthesized/taurus/out.mp3 | bin | 1056599 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/dna-synthesized/taurus/spectogram.png | bin | 109064 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/do-fuse/copy-benchmarks.tsv | 101 | ||||
| -rwxr-xr-x | static/posts/do-fuse/fuse-droplets.png | bin | 42891 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/do-fuse/fuse-spaces.png | bin | 32450 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/do-fuse/sqlite-benchmarks.tsv | 1001 | ||||
| -rwxr-xr-x | static/posts/dropbox-sync/dropbox-spaces.png | bin | 47661 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/esp8366-micropython/boards.jpg | bin | 98162 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/go-profiling/golang-profiling-cpu.pdf | bin | 16518 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/go-profiling/golang-profiling-mem.pdf | bin | 19221 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/goaccess/goaccess-dash-html.png | bin | 16129 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/goaccess/goaccess-dash-term.png | bin | 9188 -> 0 bytes | |||
| -rw-r--r-- | static/posts/godot-dynamic-tile-loading/2d-player-movement.webm | bin | 975421 -> 0 bytes | |||
| -rw-r--r-- | static/posts/godot-dynamic-tile-loading/cellular-automata.png | bin | 373408 -> 0 bytes | |||
| -rw-r--r-- | static/posts/godot-dynamic-tile-loading/example1/index.apple-touch-icon.png | bin | 18955 -> 0 bytes | |||
| -rw-r--r-- | static/posts/godot-dynamic-tile-loading/example1/index.audio.worklet.js | 211 | ||||
| -rw-r--r-- | static/posts/godot-dynamic-tile-loading/example1/index.html | 248 | ||||
| -rw-r--r-- | static/posts/godot-dynamic-tile-loading/example1/index.icon.png | bin | 3305 -> 0 bytes | |||
| -rw-r--r-- | static/posts/godot-dynamic-tile-loading/example1/index.js | 796 | ||||
| -rw-r--r-- | static/posts/godot-dynamic-tile-loading/example1/index.pck | bin | 7056 -> 0 bytes | |||
| -rw-r--r-- | static/posts/godot-dynamic-tile-loading/example1/index.png | bin | 21443 -> 0 bytes | |||
| -rw-r--r-- | static/posts/godot-dynamic-tile-loading/example1/index.wasm | bin | 13789463 -> 0 bytes | |||
| -rw-r--r-- | static/posts/godot-dynamic-tile-loading/village-creator.png | bin | 97628 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/helix-editor/editor.png | bin | 159442 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/iot-application/iot-app-output.png | bin | 23767 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/iot-application/iot-rest-example.png | bin | 33912 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/iot-application/iot-sqlite-db.png | bin | 199821 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/iot-application/kcachegrind.png | bin | 88486 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/iot-application/profiling-viewer.png | bin | 173672 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/iot-application/simple-iot-application-overview.svg | 2 | ||||
| -rwxr-xr-x | static/posts/iot-application/simple-iot-application.zip | bin | 6406 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/iot-application/snakeviz.png | bin | 59601 -> 0 bytes | |||
| -rw-r--r-- | static/posts/microsoundtrack/cow.m4v | bin | 1113250 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/pid1/boxes.mp4 | bin | 443830 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/pid1/qemu.log | 320 | ||||
| -rw-r--r-- | static/posts/pid1/unikernels.png | bin | 33009 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/pid1/unikernels.svg | 587 | ||||
| -rw-r--r-- | static/posts/pid1/unikernels.webp | bin | 23304 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/profile-bind-error/error.jpg | bin | 57047 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/python-profiling/kcachegrind.png | bin | 88486 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/python-profiling/profiling-viewer.png | bin | 173672 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/python-profiling/snakeviz.png | bin | 59601 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/sentiment-analysis/.ipynb_checkpoints/TF Test-checkpoint.ipynb | 588 | ||||
| -rwxr-xr-x | static/posts/sentiment-analysis/.ipynb_checkpoints/sentiment-analysis-checkpoint.ipynb | 170 | ||||
| -rwxr-xr-x | static/posts/sentiment-analysis/guardian-sa-title-desc-relationship.png | bin | 15404 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/sentiment-analysis/sentiment-analysis.ipynb | 170 | ||||
| -rwxr-xr-x | static/posts/simple-pubsub-server/caniuse.png | bin | 56379 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/simple-pubsub-server/chrome-debugging.png | bin | 151160 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/simple-pubsub-server/clients.m4v | bin | 369179 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/simple-pubsub-server/pubsub-overview.png | bin | 18471 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/simple-pubsub-server/sse-pubsub-server.zip | bin | 4158 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/state-of-web/2008-vs-2020.png | bin | 126650 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/state-of-web/compiling-vs-transpiling.png | bin | 41481 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/wap/emulator.mp4 | bin | 892887 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/wap/phones.gif | bin | 348891 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/world-clock/enclosure.stl | bin | 1884 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/world-clock/hardware.jpg | bin | 82279 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/world-clock/world-clock.jpg | bin | 148673 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/yapyap/hello.png | bin | 25962 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/yapyap/pid1.jpg | bin | 394011 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/zed/zed-1.png | bin | 450802 -> 0 bytes | |||
| -rwxr-xr-x | static/posts/zed/zed-2.png | bin | 812483 -> 0 bytes | |||
| -rw-r--r-- | templates/includes/.gitkeep | 0 | ||||
| -rw-r--r-- | templates/index.html | 40 | ||||
| -rw-r--r-- | templates/index.xml | 21 | ||||
| -rw-r--r-- | templates/note.html | 14 | ||||
| -rw-r--r-- | templates/notes.xml | 21 | ||||
| -rw-r--r-- | templates/openring.html | 12 | ||||
| -rw-r--r-- | templates/page.html | 13 | ||||
| -rw-r--r-- | templates/post.html | 14 | ||||
| -rw-r--r-- | templates/radio.pls | 38 | ||||
| -rw-r--r-- | templates/robots.txt | 2 | ||||
| -rw-r--r-- | templates/sitemap.xml | 8 | ||||
| -rw-r--r-- | templates/vault.md | 20 | ||||
| -rw-r--r-- | vault.py | 54 |
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 | |||
| 5 | trim_trailing_whitespace = true | 5 | trim_trailing_whitespace = true |
| 6 | insert_final_newline = true | 6 | insert_final_newline = true |
| 7 | end_of_line = lf | 7 | end_of_line = lf |
| 8 | |||
| 9 | [Makefile] | ||
| 10 | indent_style = tab | ||
| 11 | indent_size = 4 | ||
| 12 | |||
| 13 | [*.c] | ||
| 8 | indent_style = space | 14 | indent_style = space |
| 9 | indent_size = 2 | 15 | indent_size = 2 |
| 10 | 16 | ||
| 11 | [Makefile] | 17 | [*.sh] |
| 18 | indent_style = space | ||
| 19 | indent_size = 4 | ||
| 20 | |||
| 21 | [*.go] | ||
| 12 | indent_style = tab | 22 | indent_style = tab |
| 13 | indent_size = 4 | 23 | indent_size = 4 |
| 24 | |||
| 25 | [*.sql] | ||
| 26 | indent_style = space | ||
| 27 | indent_size = 2 | ||
| 28 | |||
| 29 | [*.{css,html,js,django}] | ||
| 30 | indent_style = space | ||
| 31 | indent_size = 2 | ||
| @@ -1,2 +1,5 @@ | |||
| 1 | templates/includes/openring.html | 1 | _site |
| 2 | .DS_Store \ No newline at end of file | 2 | .sass-cache |
| 3 | .jekyll-cache | ||
| 4 | .jekyll-metadata | ||
| 5 | vendor | ||
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 | --- | ||
| 2 | permalink: /404.html | ||
| 3 | layout: 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> | ||
| @@ -0,0 +1,33 @@ | |||
| 1 | source "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! | ||
| 10 | gem "jekyll", "~> 4.3.2" | ||
| 11 | # This is the default theme for new Jekyll sites. You may change this to anything you like. | ||
| 12 | gem "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! | ||
| 17 | group :jekyll_plugins do | ||
| 18 | gem "jekyll-feed", "~> 0.12" | ||
| 19 | end | ||
| 20 | |||
| 21 | # Windows and JRuby does not include zoneinfo files, so bundle the tzinfo-data gem | ||
| 22 | # and associated library. | ||
| 23 | platforms :mingw, :x64_mingw, :mswin, :jruby do | ||
| 24 | gem "tzinfo", ">= 1", "< 3" | ||
| 25 | gem "tzinfo-data" | ||
| 26 | end | ||
| 27 | |||
| 28 | # Performance-booster for watching directories on Windows | ||
| 29 | gem "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. | ||
| 33 | gem "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 @@ | |||
| 1 | GEM | ||
| 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 | |||
| 71 | PLATFORMS | ||
| 72 | x86_64-linux | ||
| 73 | |||
| 74 | DEPENDENCIES | ||
| 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 | |||
| 83 | BUNDLED 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 @@ | |||
| 1 | MAKEFLAGS=-j4 | ||
| 2 | |||
| 3 | # Using: https://github.com/mitjafelicijan/jbmafp | ||
| 4 | |||
| 5 | build: 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 | |||
| 10 | dev: | ||
| 11 | jbmafp --build --server | ||
| 12 | |||
| 13 | openring: | ||
| 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 | |||
| 28 | deploy: 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 @@ | |||
| 1 | title: Mitja Felicijan | ||
| 2 | author: Mitja Felicijan | ||
| 3 | email: mitja.felicijan@gmail.com | ||
| 4 | url: https://mitjafelicijan.com | ||
| 5 | lang: en | ||
| 6 | |||
| 7 | description: >- | ||
| 8 | You do not learn by relaxing. You learn by violently assaulting your problem | ||
| 9 | until it surrenders its mysteries to you. | ||
| 10 | |||
| 11 | markdown: kramdown | ||
| 12 | highlighter: rouge | ||
| 13 | |||
| 14 | plugins: | ||
| 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 "real name" 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 “real name”. Such projects have a so-called “real name” 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’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 "url" parameter is valid but upstream response is invalid</a> | ||
| 23 | — | ||
| 24 | <a href="https://mirzapandzo.com/" target="_blank" rel="noopener">Mirza Pandzo'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'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 <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 | --- | ||
| 2 | layout: 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 | --- | ||
| 2 | layout: 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 | --- | ||
| 2 | layout: 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 | --- |
| 2 | title: Most likely to succeed in the year of 2011 | 2 | title: Most likely to succeed in the year of 2011 |
| 3 | url: most-likely-to-succeed-in-year-of-2011.html | 3 | permalink: /most-likely-to-succeed-in-year-of-2011.html |
| 4 | date: 2011-01-13T12:00:00+02:00 | 4 | date: 2011-01-13T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: 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 | --- |
| 2 | title: LED technology might not be as eco-friendly as you think | 2 | title: LED technology might not be as eco-friendly as you think |
| 3 | url: led-technology-not-so-eco.html | 3 | permalink: /led-technology-not-so-eco.html |
| 4 | date: 2012-03-09T12:00:00+02:00 | 4 | date: 2012-03-09T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: 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 | --- |
| 2 | title: Wireless sensor networks | 2 | title: Wireless sensor networks |
| 3 | url: wireless-sensor-networks.html | 3 | permalink: /wireless-sensor-networks.html |
| 4 | date: 2013-10-24T12:00:00+02:00 | 4 | date: 2013-10-24T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: 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 | --- |
| 2 | title: Software development and my favorite pitfalls | 2 | title: Software development and my favorite pitfalls |
| 3 | url: software-development-pitfalls.html | 3 | permalink: /software-development-pitfalls.html |
| 4 | date: 2015-11-10T12:00:00+02:00 | 4 | date: 2015-11-10T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: 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 | --- |
| 2 | title: Golang profiling simplified | 2 | title: Golang profiling simplified |
| 3 | url: golang-profiling-simplified.html | 3 | permalink: /golang-profiling-simplified.html |
| 4 | date: 2017-03-07T12:00:00+02:00 | 4 | date: 2017-03-07T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: false |
| 7 | --- | 8 | --- |
| @@ -121,6 +122,6 @@ go tool pprof -pdf ./cpu cpu.pprof > cpu.pdf | |||
| 121 | 122 | ||
| 122 | This will generate PDF document with visualized profile. | 123 | This 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 | --- |
| 2 | title: What I've learned developing ad server | 2 | title: What I've learned developing ad server |
| 3 | url: what-i-ve-learned-developing-ad-server.html | 3 | permalink: /what-i-ve-learned-developing-ad-server.html |
| 4 | date: 2017-04-17T12:00:00+02:00 | 4 | date: 2017-04-17T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: 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 | --- |
| 2 | title: Profiling Python web applications with visual tools | 2 | title: Profiling Python web applications with visual tools |
| 3 | url: profiling-python-web-applications-with-visual-tools.html | 3 | permalink: /profiling-python-web-applications-with-visual-tools.html |
| 4 | date: 2017-04-21T12:00:00+02:00 | 4 | date: 2017-04-21T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: false |
| 7 | --- | 8 | --- |
| @@ -21,7 +22,7 @@ If you are using MacOS you should check out [Profiling | |||
| 21 | Viewer](http://www.profilingviewer.com/) or | 22 | Viewer](http://www.profilingviewer.com/) or |
| 22 | [MacCallGrind](http://www.maccallgrind.com/). | 23 | [MacCallGrind](http://www.maccallgrind.com/). |
| 23 | 24 | ||
| 24 |  | 25 |  |
| 25 | 26 | ||
| 26 | We will be dividing this post into two main categories: | 27 | We 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 | |||
| 146 | you can see from this example there is hierarchy of execution order of your | 147 | you can see from this example there is hierarchy of execution order of your |
| 147 | code. | 148 | code. |
| 148 | 149 | ||
| 149 |  | 150 |  |
| 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 |
| 152 | refresh and take a look at your possible optimizations because cProfile updates | 153 | refresh 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 |  | 181 |  |
| 181 | 182 | ||
| 182 | Reddit user [ccharles](https://www.reddit.com/user/ccharles) suggested a better | 183 | Reddit user [ccharles](https://www.reddit.com/user/ccharles) suggested a better |
| 183 | way for installing pip software by targeting user level instead of using sudo. | 184 | way 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 | --- |
| 2 | title: Simple IOT application supported by real-time monitoring and data history | 2 | title: Simple IOT application supported by real-time monitoring and data history |
| 3 | url: simple-iot-application.html | 3 | permalink: /simple-iot-application.html |
| 4 | date: 2017-08-11T12:00:00+02:00 | 4 | date: 2017-08-11T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: false |
| 7 | --- | 8 | --- |
| @@ -50,7 +51,7 @@ to API and another to serving HTML with chart. | |||
| 50 | Schema below represents what we will try to achieve and how different parts | 51 | Schema below represents what we will try to achieve and how different parts |
| 51 | correlates to each other. | 52 | correlates to each other. |
| 52 | 53 | ||
| 53 |  | 54 |  |
| 54 | 55 | ||
| 55 | ## Simple Python API | 56 | ## Simple Python API |
| 56 | 57 | ||
| @@ -218,12 +219,12 @@ available via POST method on /api route. | |||
| 218 | After testing the service with Restlet Client you should be able to view your | 219 | After testing the service with Restlet Client you should be able to view your |
| 219 | data in a database file ```data.db```. | 220 | data in a database file ```data.db```. |
| 220 | 221 | ||
| 221 |  | 222 |  |
| 222 | 223 | ||
| 223 | You can also check the contents of new database file by using desktop client | 224 | You can also check the contents of new database file by using desktop client |
| 224 | for SQLite → [DB Browser for SQLite](http://sqlitebrowser.org/). | 225 | for SQLite → [DB Browser for SQLite](http://sqlitebrowser.org/). |
| 225 | 226 | ||
| 226 |  | 227 |  |
| 227 | 228 | ||
| 228 | Table structure is as simple as it can be. We have ts (timestamp) and value | 229 | Table 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. | |||
| 585 | If you navigate to ```http://0.0.0.0:5000``` you should see rendered chart as | 586 | If you navigate to ```http://0.0.0.0:5000``` you should see rendered chart as |
| 586 | shown on picture below. | 587 | shown on picture below. |
| 587 | 588 | ||
| 588 |  | 589 |  |
| 589 | 590 | ||
| 590 | Complete application with all the code is available for | 591 | Complete 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 | --- |
| 2 | title: Using DigitalOcean Spaces Object Storage with FUSE | 2 | title: Using DigitalOcean Spaces Object Storage with FUSE |
| 3 | url: using-digitalocean-spaces-object-storage-with-fuse.html | 3 | permalink: /using-digitalocean-spaces-object-storage-with-fuse.html |
| 4 | date: 2018-01-16T12:00:00+02:00 | 4 | date: 2018-01-16T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: false |
| 7 | --- | 8 | --- |
| @@ -55,7 +56,7 @@ Instuctions on how to use SSH keys and how to setup them are available in | |||
| 55 | article [How To Use SSH Keys with DigitalOcean | 56 | article [How To Use SSH Keys with DigitalOcean |
| 56 | Droplets](https://www.digitalocean.com/community/tutorials/how-to-use-ssh-keys-with-digitalocean-droplets). | 57 | Droplets](https://www.digitalocean.com/community/tutorials/how-to-use-ssh-keys-with-digitalocean-droplets). |
| 57 | 58 | ||
| 58 |  | 59 |  |
| 59 | 60 | ||
| 60 | After we created Droplet it's time to create new Space. This is done by clicking | 61 | After we created Droplet it's time to create new Space. This is done by clicking |
| 61 | on a button [Create](https://cloud.digitalocean.com/spaces/new) (right top | 62 | on 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 | |||
| 68 | to the page when you can generate this key. After you create new one, please | 69 | to the page when you can generate this key. After you create new one, please |
| 69 | save provided Key and Secret because Secret will not be shown again. | 70 | save provided Key and Secret because Secret will not be shown again. |
| 70 | 71 | ||
| 71 |  | 72 |  |
| 72 | 73 | ||
| 73 | Now that we have new Space and Access key we should SSH into our machine. | 74 | Now 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 | ||
| 150 | You can download [raw result here](/posts/do-fuse/copy-benchmarks.tsv). | 151 | You can download [raw result here](/assets/posts/do-fuse/copy-benchmarks.tsv). |
| 151 | Measurements are in seconds. | 152 | Measurements 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 | |||
| 271 | print("CLOSE: %g seconds" % (result_time)) | 272 | print("CLOSE: %g seconds" % (result_time)) |
| 272 | ``` | 273 | ``` |
| 273 | 274 | ||
| 274 | You can download [raw result here](/posts/do-fuse/sqlite-benchmarks.tsv). And | 275 | You can download [raw result here](/assets/posts/do-fuse/sqlite-benchmarks.tsv). And |
| 275 | again, these results are done on a local block storage and do not represent | 276 | again, these results are done on a local block storage and do not represent |
| 276 | capabilities of object storage. With my current approach and state of the test | 277 | capabilities of object storage. With my current approach and state of the test |
| 277 | code these can not be done. I would need to make Python code much more robust | 278 | code 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 | --- |
| 2 | title: Encoding binary data into DNA sequence | 2 | title: Encoding binary data into DNA sequence |
| 3 | url: encoding-binary-data-into-dna-sequence.html | 3 | permalink: /encoding-binary-data-into-dna-sequence.html |
| 4 | date: 2019-01-03T12:00:00+02:00 | 4 | date: 2019-01-03T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: false |
| 7 | --- | 8 | --- |
| @@ -109,7 +110,7 @@ The nucleotide in DNA consists of a sugar (deoxyribose), one of four bases | |||
| 109 | Cytosine and thymine are pyrimidine bases, while adenine and guanine are purine | 110 | Cytosine and thymine are pyrimidine bases, while adenine and guanine are purine |
| 110 | bases. The sugar and the base together are called a nucleoside. | 111 | bases. The sugar and the base together are called a nucleoside. |
| 111 | 112 | ||
| 112 |  | 113 |  |
| 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 |
| 114 | cytosine pairs with guanine. (credit a: modification of work by Jerome Walker, | 115 | cytosine pairs with guanine. (credit a: modification of work by Jerome Walker, |
| 115 | Dennis Myts)* | 116 | Dennis Myts)* |
| @@ -299,12 +300,12 @@ Then we encode FASTA file from previous operation to encode this data into PNG. | |||
| 299 | 300 | ||
| 300 | After encoding into PNG format this file looks like this. | 301 | After encoding into PNG format this file looks like this. |
| 301 | 302 | ||
| 302 |  | 303 |  |
| 303 | The larger the input stream is the larger the PNG file would be. | 304 | The larger the input stream is the larger the PNG file would be. |
| 304 | 305 | ||
| 305 | Compiled basic Hello World C program with | 306 | Compiled 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 |
| 307 | like](/posts/dna-sequence/sample.png). | 308 | like](/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 |  | 372 |  |
| 372 | Our freshly generated 1KB file looks something like this (its full of | 373 | Our freshly generated 1KB file looks something like this (its full of |
| 373 | garbage data as intended). | 374 | garbage data as intended). |
| 374 | 375 | ||
| @@ -394,13 +395,13 @@ Then we GZIP all the FASTA files to see how much the can be compressed. | |||
| 394 | gzip -9 < 10MB.fa > 10MB.fa.gz | 395 | gzip -9 < 10MB.fa > 10MB.fa.gz |
| 395 | ``` | 396 | ``` |
| 396 | 397 | ||
| 397 |  | 398 |  |
| 398 | The speed increase that occurs when encoding to FASTA format. | 399 | The speed increase that occurs when encoding to FASTA format. |
| 399 | 400 | ||
| 400 |  | 401 |  |
| 401 | Size of the out file after encoding. | 402 | Size 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 | --- |
| 2 | title: Simplifying and reducing clutter in my life and work | 2 | title: Simplifying and reducing clutter in my life and work |
| 3 | url: simplifying-and-reducing-clutter.html | 3 | permalink: /simplifying-and-reducing-clutter.html |
| 4 | date: 2019-10-14T12:00:00+02:00 | 4 | date: 2019-10-14T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: 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 | --- |
| 2 | title: Using sentiment analysis for clickbait detection in RSS feeds | 2 | title: Using sentiment analysis for clickbait detection in RSS feeds |
| 3 | url: using-sentiment-analysis-for-clickbait-detection-in-rss-feeds.html | 3 | permalink: /using-sentiment-analysis-for-clickbait-detection-in-rss-feeds.html |
| 4 | date: 2019-10-19T12:00:00+02:00 | 4 | date: 2019-10-19T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: 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 |  | 96 |  |
| 96 | 97 | ||
| 97 | Figure above displays difference between title and description sentiment for | 98 | Figure above displays difference between title and description sentiment for |
| 98 | specific RSS feed item. 1 means positive and -1 means negative sentiment. | 99 | specific 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 | --- |
| 2 | title: Simple Server-Sent Events based PubSub Server | 2 | title: Simple Server-Sent Events based PubSub Server |
| 3 | url: simple-server-sent-events-based-pubsub-server.html | 3 | permalink: /simple-server-sent-events-based-pubsub-server.html |
| 4 | date: 2020-03-22T12:00:00+02:00 | 4 | date: 2020-03-22T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: false |
| 7 | --- | 8 | --- |
| @@ -38,7 +39,7 @@ simple. We have subscribers that receive messages, and we have publishers that | |||
| 38 | create and post messages. Similar model is also well know pattern that works on | 39 | create and post messages. Similar model is also well know pattern that works on |
| 39 | a premise of consumers and producers, and they take similar roles. | 40 | a premise of consumers and producers, and they take similar roles. |
| 40 | 41 | ||
| 41 |  | 42 |  |
| 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 |  | 78 |  |
| 78 | 79 | ||
| 79 | Check | 80 | Check |
| 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 |  | 146 |  |
| 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 | ||
| 286 | You can download [the code](../simple-pubsub-server/sse-pubsub-server.zip) and | 287 | You can download [the code](../simple-pubsub-server/sse-pubsub-server.zip) and |
| 287 | follow along. | 288 | follow 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 | --- |
| 2 | title: Create placeholder images with sharp Node.js image processing library | 2 | title: Create placeholder images with sharp Node.js image processing library |
| 3 | url: create-placeholder-images-with-sharp.html | 3 | permalink: /create-placeholder-images-with-sharp.html |
| 4 | date: 2020-03-27T12:00:00+02:00 | 4 | date: 2020-03-27T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: 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 | --- |
| 2 | title: The strange case of Elasticsearch allocation failure | 2 | title: The strange case of Elasticsearch allocation failure |
| 3 | url: the-strange-case-of-elasticsearch-allocation-failure.html | 3 | permalink: /the-strange-case-of-elasticsearch-allocation-failure.html |
| 4 | date: 2020-03-29T12:00:00+02:00 | 4 | date: 2020-03-29T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: 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 | --- |
| 2 | title: My love and hate relationship with Node.js | 2 | title: My love and hate relationship with Node.js |
| 3 | url: my-love-and-hate-relationship-with-nodejs.html | 3 | permalink: /my-love-and-hate-relationship-with-nodejs.html |
| 4 | date: 2020-03-30T12:00:00+02:00 | 4 | date: 2020-03-30T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: 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 | --- |
| 2 | title: Remote work and how it affects the daily lives of people | 2 | title: Remote work and how it affects the daily lives of people |
| 3 | url: remote-work.html | 3 | permalink: /remote-work.html |
| 4 | date: 2020-05-05T12:00:00+02:00 | 4 | date: 2020-05-05T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: 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 | --- |
| 2 | title: Disable mouse wake from suspend with systemd service | 2 | title: Disable mouse wake from suspend with systemd service |
| 3 | url: disable-mouse-wake-from-suspend-with-systemd-service.html | 3 | permalink: /disable-mouse-wake-from-suspend-with-systemd-service.html |
| 4 | date: 2020-08-15T12:00:00+02:00 | 4 | date: 2020-08-15T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: 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 | --- |
| 2 | title: Getting started with MicroPython and ESP8266 | 2 | title: Getting started with MicroPython and ESP8266 |
| 3 | url: esp8266-and-micropython-guide.html | 3 | permalink: /esp8266-and-micropython-guide.html |
| 4 | date: 2020-09-06T12:00:00+02:00 | 4 | date: 2020-09-06T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: false |
| 7 | --- | 8 | --- |
| @@ -19,7 +20,7 @@ but I could easily choose | |||
| 19 | contains which tools I use and how I prepared my workspace to code for | 20 | contains 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 |  | 23 |  |
| 23 | 24 | ||
| 24 | This guide covers: | 25 | This 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 | --- |
| 2 | title: Fix bind warning in .profile on login in Ubuntu | 2 | title: Fix bind warning in .profile on login in Ubuntu |
| 3 | url: bind-warning-on-login-in-ubuntu.html | 3 | permalink: /bind-warning-on-login-in-ubuntu.html |
| 4 | date: 2020-09-08T12:00:00+02:00 | 4 | date: 2020-09-08T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: false |
| 7 | --- | 8 | --- |
| @@ -30,7 +31,7 @@ bind '"\e[Z":menu-complete-backward' | |||
| 30 | I haven't noticed anything wrong with this and all was working fine until I | 31 | I haven't noticed anything wrong with this and all was working fine until I |
| 31 | restarted my machine and then I got this error. | 32 | restarted my machine and then I got this error. |
| 32 | 33 | ||
| 33 |  | 34 |  |
| 34 | 35 | ||
| 35 | When I pressed OK, I got into the [Gnome | 36 | When I pressed OK, I got into the [Gnome |
| 36 | shell](https://wiki.gnome.org/Projects/GnomeShell) and all was working fine, but | 37 | shell](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 | --- |
| 2 | title: Using Digitalocean Spaces to sync between computers | 2 | title: Using Digitalocean Spaces to sync between computers |
| 3 | url: digitalocean-spaces-to-sync-between-computers.html | 3 | permalink: /digitalocean-spaces-to-sync-between-computers.html |
| 4 | date: 2020-09-09T12:00:00+02:00 | 4 | date: 2020-09-09T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: 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 | --- |
| 2 | title: Replacing Dropbox in favor of DigitalOcean spaces | 2 | title: Replacing Dropbox in favor of DigitalOcean spaces |
| 3 | url: replacing-dropbox-in-favor-of-digitalocean-spaces.html | 3 | permalink: /replacing-dropbox-in-favor-of-digitalocean-spaces.html |
| 4 | date: 2021-01-24T12:00:00+02:00 | 4 | date: 2021-01-24T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: false |
| 7 | --- | 8 | --- |
| @@ -105,7 +106,7 @@ You can use this script in a combination with [Cron](https://en.wikipedia.org/wi | |||
| 105 | When you start syncing your local stuff with a remote server you can review your | 106 | When you start syncing your local stuff with a remote server you can review your |
| 106 | items on DigitalOcean. | 107 | items on DigitalOcean. |
| 107 | 108 | ||
| 108 |  | 109 |  |
| 109 | 110 | ||
| 110 | I have been using this script now for quite some time, and it's working | 111 | I have been using this script now for quite some time, and it's working |
| 111 | flawlessly. I also uninstalled Dropbox and stopped using it completely. | 112 | flawlessly. 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 | --- |
| 2 | title: Using GoAccess with Nginx to replace Google Analytics | 2 | title: Using GoAccess with Nginx to replace Google Analytics |
| 3 | url: using-goaccess-with-nginx-to-replace-google-analytics.html | 3 | permalink: /using-goaccess-with-nginx-to-replace-google-analytics.html |
| 4 | date: 2021-01-25T12:00:00+02:00 | 4 | date: 2021-01-25T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: false |
| 7 | --- | 8 | --- |
| @@ -41,11 +42,11 @@ all the functionalities I need, and it's a single binary. Written in Go. | |||
| 41 | 42 | ||
| 42 | GoAccess can be used in two different modes. | 43 | GoAccess can be used in two different modes. |
| 43 | 44 | ||
| 44 |  | 45 |  |
| 45 | 46 | ||
| 46 | *Running in a terminal* | 47 | *Running in a terminal* |
| 47 | 48 | ||
| 48 |  | 49 |  |
| 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 | --- |
| 2 | title: Simple world clock with eInk display and Raspberry Pi Zero | 2 | title: Simple world clock with eInk display and Raspberry Pi Zero |
| 3 | url: simple-world-clock-with-eiink-display-and-raspberry-pi-zero.html | 3 | permalink: /simple-world-clock-with-eiink-display-and-raspberry-pi-zero.html |
| 4 | date: 2021-06-26T12:00:00+02:00 | 4 | date: 2021-06-26T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: false |
| 7 | --- | 8 | --- |
| @@ -23,7 +24,7 @@ have a bunch of [Raspberry Pi's | |||
| 23 | Zero](https://www.raspberrypi.org/products/raspberry-pi-zero/) lying around that | 24 | Zero](https://www.raspberrypi.org/products/raspberry-pi-zero/) lying around that |
| 24 | I really need to use. | 25 | I really need to use. |
| 25 | 26 | ||
| 26 |  | 27 |  |
| 27 | 28 | ||
| 28 | Since the Inky [Inky | 29 | Since the Inky [Inky |
| 29 | pHAT](https://shop.pimoroni.com/products/inky-phat?variant=12549254217811) is | 30 | pHAT](https://shop.pimoroni.com/products/inky-phat?variant=12549254217811) is |
| @@ -94,7 +95,7 @@ Then we add a cronjob with `crontab -e`. | |||
| 94 | 95 | ||
| 95 | So, we end up with a result like this. | 96 | So, we end up with a result like this. |
| 96 | 97 | ||
| 97 |  | 98 |  |
| 98 | 99 | ||
| 99 | And for the enclosure that can be 3D printed, but I haven't yet something like | 100 | And for the enclosure that can be 3D printed, but I haven't yet something like |
| 100 | this can be used. | 101 | this 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 | ||
| 104 | You can download my [STL file for the enclosure | 105 | You can download my [STL file for the enclosure |
| 105 | here](/posts/world-clock/enclosure.stl), but make sure that dimensions make | 106 | here](/assets/posts/world-clock/enclosure.stl), but make sure that dimensions make |
| 106 | sense and also opening for USB port should be added or just use a drill and some | 107 | sense and also opening for USB port should be added or just use a drill and some |
| 107 | hot glue to make it stick in the enclosure. | 108 | hot 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 | --- |
| 2 | title: My journey from being an internet über consumer to being a full hominum again | 2 | title: My journey from being an internet über consumer to being a full hominum again |
| 3 | url: from-internet-consumer-to-full-hominum-again.html | 3 | permalink: /from-internet-consumer-to-full-hominum-again.html |
| 4 | date: 2021-07-30T12:00:00+02:00 | 4 | date: 2021-07-30T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: 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 | --- |
| 2 | title: List of essential Linux commands for server management | 2 | title: List of essential Linux commands for server management |
| 3 | url: linux-cheatsheet.html | 3 | permalink: /linux-cheatsheet.html |
| 4 | date: 2021-08-01T12:00:00+02:00 | 4 | date: 2021-08-01T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: 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 | --- |
| 2 | title: Debian based riced up distribution for Developers and DevOps folks | 2 | title: Debian based riced up distribution for Developers and DevOps folks |
| 3 | url: debian-based-riced-up-distribution-for-developers-and-devops-folks.html | 3 | permalink: /debian-based-riced-up-distribution-for-developers-and-devops-folks.html |
| 4 | date: 2021-12-03T12:00:00+02:00 | 4 | date: 2021-12-03T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: false |
| 7 | --- | 8 | --- |
| @@ -76,35 +77,35 @@ Fonts being applied across the distro and things like that. | |||
| 76 | First, I choose terminal installer and left it to load additional components. | 77 | First, I choose terminal installer and left it to load additional components. |
| 77 | Avoid using graphical installer in this case. | 78 | Avoid using graphical installer in this case. |
| 78 | 79 | ||
| 79 |  | 80 |  |
| 80 | 81 | ||
| 81 | After that I selected hostname and created a normal user and set password for | 82 | After that I selected hostname and created a normal user and set password for |
| 82 | that user and root user and choose guided mode for disk partitioning. | 83 | that user and root user and choose guided mode for disk partitioning. |
| 83 | 84 | ||
| 84 |  | 85 |  |
| 85 | 86 | ||
| 86 | I left it run to install all the things required for the base system and opted | 87 | I left it run to install all the things required for the base system and opted |
| 87 | out of scanning additional media for use by the package manager. Those will be | 88 | out of scanning additional media for use by the package manager. Those will be |
| 88 | downloaded from the internet during installation. | 89 | downloaded from the internet during installation. |
| 89 | 90 | ||
| 90 |  | 91 |  |
| 91 | 92 | ||
| 92 | I opted out of the popularity contest, and **now comes the important part**. | 93 | I opted out of the popularity contest, and **now comes the important part**. |
| 93 | Uncheck all the boxes in Software selection and only leave 'standard system | 94 | Uncheck all the boxes in Software selection and only leave 'standard system |
| 94 | utilities'. I also left an SSH server, so I was able to log in to the machine | 95 | utilities'. I also left an SSH server, so I was able to log in to the machine |
| 95 | from my main PC. | 96 | from my main PC. |
| 96 | 97 | ||
| 97 |  | 98 |  |
| 98 | 99 | ||
| 99 | At this point, I installed GRUB bootloader on the disk where I installed the | 100 | At this point, I installed GRUB bootloader on the disk where I installed the |
| 100 | system. | 101 | system. |
| 101 | 102 | ||
| 102 |  | 103 |  |
| 103 | 104 | ||
| 104 | That concluded the installation of base Debian and after restarting the computer | 105 | That concluded the installation of base Debian and after restarting the computer |
| 105 | I was prompted with the login screen. | 106 | I was prompted with the login screen. |
| 106 | 107 | ||
| 107 |  | 108 |  |
| 108 | 109 | ||
| 109 | Now that I had the base installation, it was time to choose what software do I | 110 | Now that I had the base installation, it was time to choose what software do I |
| 110 | want to include in this so-called distribution. I wanted out of the box | 111 | want 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 | |||
| 141 | below. This is my common practice. And if you look at it you can clearly see I | 142 | below. This is my common practice. And if you look at it you can clearly see I |
| 142 | was replicating tiling window manager setup in Gnome. | 143 | was replicating tiling window manager setup in Gnome. |
| 143 | 144 | ||
| 144 |  | 145 |  |
| 145 | 146 | ||
| 146 | That made me look into a bunch of tiling window managers and then tested them | 147 | That made me look into a bunch of tiling window managers and then tested them |
| 147 | out. Candidates I was looking at were: | 148 | out. Candidates I was looking at were: |
| @@ -211,7 +212,7 @@ something similar. | |||
| 211 | 212 | ||
| 212 | This is some of the output from the installation script. | 213 | This is some of the output from the installation script. |
| 213 | 214 | ||
| 214 |  | 215 |  |
| 215 | 216 | ||
| 216 | Let's take a look at some examples in the installation script. | 217 | Let'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 | |||
| 273 | simplicity and clean interface. I will polish the colors and stuff like that, | 274 | simplicity and clean interface. I will polish the colors and stuff like that, |
| 274 | but I really do like the results. | 275 | but I really do like the results. |
| 275 | 276 | ||
| 276 |  | 277 |  |
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 | --- |
| 2 | title: Running Golang application as PID 1 with Linux kernel | 2 | title: Running Golang application as PID 1 with Linux kernel |
| 3 | url: running-golang-application-as-pid1.html | 3 | permalink: /running-golang-application-as-pid1.html |
| 4 | date: 2021-12-25T12:00:00+02:00 | 4 | date: 2021-12-25T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: false |
| 7 | --- | 8 | --- |
| @@ -23,7 +24,7 @@ Really worth a read. | |||
| 23 | If we compare a normal operating system to a unikernel side by side, they would | 24 | If we compare a normal operating system to a unikernel side by side, they would |
| 24 | look something like this. | 25 | look something like this. |
| 25 | 26 | ||
| 26 |  | 27 |  |
| 27 | 28 | ||
| 28 | From this image, we can see how the complexity significantly decreases with | 29 | From this image, we can see how the complexity significantly decreases with |
| 29 | the use of Unikernels. This comes with a price, of course. Unikernels are hard | 30 | the use of Unikernels. This comes with a price, of course. Unikernels are hard |
| @@ -252,7 +253,7 @@ Hello from Golang | |||
| 252 | Hello from Golang | 253 | Hello from Golang |
| 253 | ``` | 254 | ``` |
| 254 | 255 | ||
| 255 | The whole [log file here](/posts/pid1/qemu.log). | 256 | The 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 \ | |||
| 328 | This will produce `GoAsPID1.iso` which you can use with [Virtualbox](https://www.virtualbox.org/) | 329 | This will produce `GoAsPID1.iso` which you can use with [Virtualbox](https://www.virtualbox.org/) |
| 329 | or [Gnome Boxes](https://apps.gnome.org/app/org.gnome.Boxes/). | 330 | or [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 | --- |
| 2 | title: Wireless Application Protocol and the mobile web before the web | 2 | title: Wireless Application Protocol and the mobile web before the web |
| 3 | url: wap-mobile-web-before-the-web.html | 3 | permalink: /wap-mobile-web-before-the-web.html |
| 4 | date: 2021-12-30T12:00:00+02:00 | 4 | date: 2021-12-30T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: false |
| 7 | --- | 8 | --- |
| @@ -32,7 +33,7 @@ These phones were rocking: | |||
| 32 | 33 | ||
| 33 | Let's take a look at these beauties. | 34 | Let's take a look at these beauties. |
| 34 | 35 | ||
| 35 |  | 36 |  |
| 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 | |||
| 184 | Proof](http://wap-proof.sharewarejunction.com/) on shareware junction, and it | 185 | Proof](http://wap-proof.sharewarejunction.com/) on shareware junction, and it |
| 185 | did the job well enough. I will try to find and actual device to test it on. | 186 | did 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 | ||
| 189 | If you are using Nginx to serve the contents, add a directive to the hosts file | 190 | If you are using Nginx to serve the contents, add a directive to the hosts file |
| 190 | that will automatically server `index.wml` file. | 191 | that 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 | --- |
| 2 | title: Trying out Helix code editor as my main editor | 2 | title: Trying out Helix code editor as my main editor |
| 3 | url: tying-out-helix-code-editor.html | 3 | permalink: /tying-out-helix-code-editor.html |
| 4 | date: 2022-06-30T12:00:00+02:00 | 4 | date: 2022-06-30T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: false |
| 7 | --- | 8 | --- |
| @@ -47,7 +48,7 @@ popups that show you what the keyboard shortcuts are. | |||
| 47 | And it comes us packed with many | 48 | And 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 |  | 51 |  |
| 51 | 52 | ||
| 52 | It's still young but has this mature feeling to it. It has sane defaults and | 53 | It's still young but has this mature feeling to it. It has sane defaults and |
| 53 | mimics Vim (works a bit differently, but the overall idea is similar). | 54 | mimics 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 | --- |
| 2 | title: What would DNA sound if synthesized to an audio file | 2 | title: What would DNA sound if synthesized to an audio file |
| 3 | url: what-would-dna-sound-if-synthesized.html | 3 | permalink: /what-would-dna-sound-if-synthesized.html |
| 4 | date: 2022-07-05T12:00:00+02:00 | 4 | date: 2022-07-05T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: false |
| 7 | --- | 8 | --- |
| @@ -174,10 +175,10 @@ sox output.wav -n spectrogram -o spectrogram.png | |||
| 174 | An example spectrogram of Ludwig van Beethoven Symphony No. 6 First movement. | 175 | An 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 |  | 181 |  |
| 181 | 182 | ||
| 182 | The other option could also be in combination with | 183 | The 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 |  | 236 |  |
| 236 | 237 | ||
| 237 | ### Mouse | 238 | ### Mouse |
| 238 | 239 | ||
| @@ -241,10 +242,10 @@ can get [genom data | |||
| 241 | here](http://ftp.ensembl.org/pub/release-106/fasta/mus_musculus/dna/). | 242 | here](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 |  | 248 |  |
| 248 | 249 | ||
| 249 | ### Bison | 250 | ### Bison |
| 250 | 251 | ||
| @@ -253,10 +254,10 @@ get [genom data | |||
| 253 | here](http://ftp.ensembl.org/pub/release-106/fasta/bison_bison_bison/cdna/). | 254 | here](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 |  | 260 |  |
| 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 | |||
| 265 | here](http://ftp.ensembl.org/pub/release-106/fasta/bos_taurus/cdna/). | 266 | here](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 |  | 272 |  |
| 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 | |||
| 281 | Sony Bluetooth speaker I have that supports 3.5 mm audio in. Elektron doesn't | 282 | Sony Bluetooth speaker I have that supports 3.5 mm audio in. Elektron doesn't |
| 282 | have internal speakers. | 283 | have internal speakers. |
| 283 | 284 | ||
| 284 |  | 285 |  |
| 285 | 286 | ||
| 286 |  | 287 |  |
| 287 | 288 | ||
| 288 |  | 289 |  |
| 289 | 290 | ||
| 290 | For communicating with Elektron, I choose `pygame` Python module that has MIDI | 291 | For communicating with Elektron, I choose `pygame` Python module that has MIDI |
| 291 | built in. With this, it was rather simple to send notes to the device. All I did | 292 | built 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. | |||
| 294 | Before all of this I also checked Audio MIDI Setup app under MacOS and checked | 295 | Before all of this I also checked Audio MIDI Setup app under MacOS and checked |
| 295 | MIDI Studio by pressing ⌘-2. | 296 | MIDI Studio by pressing ⌘-2. |
| 296 | 297 | ||
| 297 |  | 298 |  |
| 298 | 299 | ||
| 299 | The whole script that parses and send notes to the Elektron looks like this. | 300 | The whole script that parses and send notes to the Elektron looks like this. |
| 300 | 301 | ||
| @@ -336,7 +337,7 @@ del player | |||
| 336 | pygame.midi.quit() | 337 | pygame.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 | ||
| 341 | All of this could be made much more interesting if I choose different | 342 | All of this could be made much more interesting if I choose different |
| 342 | instruments for different Nucleotides, or doing more funky stuff with Elektron. | 343 | instruments 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 | --- |
| 2 | title: Aerial photography of algae spotted on river Sava | 2 | title: Aerial photography of algae spotted on river Sava |
| 3 | url: aerial-photography-of-algae-spotted-on-river-sava.html | 3 | permalink: /aerial-photography-of-algae-spotted-on-river-sava.html |
| 4 | date: 2022-08-13T12:00:00+02:00 | 4 | date: 2022-08-13T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: false |
| 7 | --- | 8 | --- |
| @@ -14,17 +15,17 @@ This is the first time I've seen something like this in my whole life. | |||
| 14 | 15 | ||
| 15 | Below are some photographs taken from a DJI drone capturing the event. | 16 | Below are some photographs taken from a DJI drone capturing the event. |
| 16 | 17 | ||
| 17 |  | 18 |  |
| 18 | 19 | ||
| 19 |  | 20 |  |
| 20 | 21 | ||
| 21 |  | 22 |  |
| 22 | 23 | ||
| 23 |  | 24 |  |
| 24 | 25 | ||
| 25 |  | 26 |  |
| 26 | 27 | ||
| 27 |  | 28 |  |
| 28 | 29 | ||
| 29 | I will try to get more photos of this in the future days and if something | 30 | I will try to get more photos of this in the future days and if something |
| 30 | intriguing shows up will post it again on the blog. | 31 | intriguing 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 | --- |
| 2 | title: State of Web Technologies and Web development in year 2022 | 2 | title: State of Web Technologies and Web development in year 2022 |
| 3 | url: state-of-web-technologies-and-web-development-in-year-2022.html | 3 | permalink: /state-of-web-technologies-and-web-development-in-year-2022.html |
| 4 | date: 2022-10-06T12:00:00+02:00 | 4 | date: 2022-10-06T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: 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 | --- |
| 2 | title: Microsoundtrack — That sound that machine makes when struggling | 2 | title: Microsoundtrack — That sound that machine makes when struggling |
| 3 | url: that-sound-that-machine-makes-when-struggling.html | 3 | permalink: /that-sound-that-machine-makes-when-struggling.html |
| 4 | date: 2022-10-16T12:00:00+02:00 | 4 | date: 2022-10-16T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: false |
| 7 | --- | 8 | --- |
| @@ -62,5 +63,5 @@ procedure. You can feel your sanity breaking down. | |||
| 62 | I also made this little cow animation. Go into full screen to see the effects in | 63 | I also made this little cow animation. Go into full screen to see the effects in |
| 63 | more details. | 64 | more 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 | --- |
| 2 | title: Trying to build a New kind of terminal emulator for the modern age | 2 | title: Trying to build a New kind of terminal emulator for the modern age |
| 3 | url: trying-to-build-a-new-kind-of-terminal-emulator.html | 3 | permalink: /trying-to-build-a-new-kind-of-terminal-emulator.html |
| 4 | date: 2023-01-26T12:00:00+02:00 | 4 | date: 2023-01-26T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: 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 | --- |
| 2 | title: Cache busting in Hugo | 2 | title: Cache busting in Hugo |
| 3 | url: cachebusting-in-hugo.html | 3 | permalink: /cachebusting-in-hugo.html |
| 4 | date: 2023-05-01T12:00:00+02:00 | 4 | date: 2023-05-01T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: false |
| 7 | tags: [hugo] | 8 | tags: [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 | ||
| 16 | This `6fab11c6669976d759d2992eff1dd5be` can be random string you generate use. | 17 | This `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 | --- |
| 2 | title: Run 9front in Qemu | 2 | title: Run 9front in Qemu |
| 3 | url: run-9front-in-qemu.html | 3 | permalink: /run-9front-in-qemu.html |
| 4 | date: 2023-05-05T12:00:00+02:00 | 4 | date: 2023-05-05T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: false |
| 7 | tags: [plan9, qemu] | 8 | tags: [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 | --- |
| 2 | title: Push to multiple origins at once in Git | 2 | title: Push to multiple origins at once in Git |
| 3 | url: git-push-multiple-origins.html | 3 | permalink: /git-push-multiple-origins.html |
| 4 | date: 2023-05-06T12:00:00+02:00 | 4 | date: 2023-05-06T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: false |
| 7 | tags: [git] | 8 | tags: [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 | --- |
| 2 | title: Mount Plan9 over network | 2 | title: Mount Plan9 over network |
| 3 | url: mount-plan9-over-network.html | 3 | permalink: /mount-plan9-over-network.html |
| 4 | date: 2023-05-07T12:00:00+02:00 | 4 | date: 2023-05-07T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: false |
| 7 | tags: [plan9] | 8 | tags: [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 | --- |
| 2 | title: Write ISO to USB Key | 2 | title: Write ISO to USB Key |
| 3 | url: write-iso-usb.html | 3 | permalink: /write-iso-usb.html |
| 4 | date: 2023-05-08T12:00:00+02:00 | 4 | date: 2023-05-08T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: false |
| 7 | tags: [linux] | 8 | tags: [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 | --- |
| 2 | title: "#cat-v on weechat configuration" | 2 | title: "#cat-v on weechat configuration" |
| 3 | url: catv-weechat-config.html | 3 | permalink: /catv-weechat-config.html |
| 4 | date: 2023-05-09T12:00:00+02:00 | 4 | date: 2023-05-09T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: false |
| 7 | tags: [irc] | 8 | tags: [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 | --- |
| 2 | title: Take a screenshot in Plan9 | 2 | title: Take a screenshot in Plan9 |
| 3 | url: plan9-screenshot.html | 3 | permalink: /plan9-screenshot.html |
| 4 | date: 2023-05-10T12:00:00+02:00 | 4 | date: 2023-05-10T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: false |
| 7 | tags: [plan9] | 8 | tags: [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 | --- |
| 2 | title: Fix bootloader not being written in Plan9 | 2 | title: Fix bootloader not being written in Plan9 |
| 3 | url: fix-plan9-bootloader.html | 3 | permalink: /fix-plan9-bootloader.html |
| 4 | date: 2023-05-11T12:00:00+02:00 | 4 | date: 2023-05-11T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: false |
| 7 | tags: [plan9] | 8 | tags: [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 | --- |
| 2 | title: Install Plan9port on Linux | 2 | title: Install Plan9port on Linux |
| 3 | url: install-plan9port-linux.html | 3 | permalink: /install-plan9port-linux.html |
| 4 | date: 2023-05-12T12:00:00+02:00 | 4 | date: 2023-05-12T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: false |
| 7 | tags: [plan9] | 8 | tags: [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 | --- |
| 2 | title: Download list of YouTube files | 2 | title: Download list of YouTube files |
| 3 | url: download-youtube-videos.html | 3 | permalink: /download-youtube-videos.html |
| 4 | date: 2023-05-13T12:00:00+02:00 | 4 | date: 2023-05-13T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: false |
| 7 | tags: [youtube] | 8 | tags: [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 | --- |
| 2 | title: Convert all MKV files into other formats | 2 | title: Convert all MKV files into other formats |
| 3 | url: convert-mkv.html | 3 | permalink: /convert-mkv.html |
| 4 | date: 2023-05-14T12:00:00+02:00 | 4 | date: 2023-05-14T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: false |
| 7 | tags: [ffmpeg] | 8 | tags: [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 | --- |
| 2 | title: Previews how man page written in Troff will look like | 2 | title: Previews how man page written in Troff will look like |
| 3 | url: preview-troff-man-pages.html | 3 | permalink: /preview-troff-man-pages.html |
| 4 | date: 2023-05-15T12:00:00+02:00 | 4 | date: 2023-05-15T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: false |
| 7 | tags: [troff] | 8 | tags: [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 | --- |
| 2 | title: Change permissions of matching files recursively | 2 | title: Change permissions of matching files recursively |
| 3 | url: mass-set-permission.html | 3 | permalink: /mass-set-permission.html |
| 4 | date: 2023-05-16T12:00:00+02:00 | 4 | date: 2023-05-16T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: false |
| 7 | tags: [linux] | 8 | tags: [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 | --- |
| 2 | title: Rekindling my love for programming and enjoying the act of creating | 2 | title: Rekindling my love for programming and enjoying the act of creating |
| 3 | url: rekindling-my-love-for-programming.html | 3 | permalink: /rekindling-my-love-for-programming.html |
| 4 | date: 2023-05-16T12:00:00+02:00 | 4 | date: 2023-05-16T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: 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 | --- |
| 2 | title: Execute not blocking async shell command in C# | 2 | title: Execute not blocking async shell command in C# |
| 3 | url: non-blocking-shell-exec-csharp.html | 3 | permalink: /non-blocking-shell-exec-csharp.html |
| 4 | date: 2023-05-22T12:00:00+02:00 | 4 | date: 2023-05-22T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: false |
| 7 | tags: [csharp] | 8 | tags: [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 | --- |
| 2 | title: Extend Lua with custom C functions using Clang | 2 | title: Extend Lua with custom C functions using Clang |
| 3 | url: extend-lua-with-custom-c.html | 3 | permalink: /extend-lua-with-custom-c.html |
| 4 | date: 2023-05-23T12:00:00+02:00 | 4 | date: 2023-05-23T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: false |
| 7 | tags: [lua, c] | 8 | tags: [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 | --- |
| 2 | title: I think I was completely wrong about Git workflows | 2 | title: I think I was completely wrong about Git workflows |
| 3 | url: i-was-wrong-about-git-workflows.html | 3 | permalink: /i-was-wrong-about-git-workflows.html |
| 4 | date: 2023-05-23T12:00:00+02:00 | 4 | date: 2023-05-23T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: false |
| 7 | tags: [] | 8 | tags: [] |
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 | --- |
| 2 | title: Parse RSS feeds with Lua | 2 | title: Parse RSS feeds with Lua |
| 3 | url: parse-rss-with-lua.html | 3 | permalink: /parse-rss-with-lua.html |
| 4 | date: 2023-05-23T12:00:00+02:00 | 4 | date: 2023-05-23T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: false |
| 7 | tags: [lua, rss] | 8 | tags: [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 | --- |
| 2 | title: My brand new Plan9/9front desktop | 2 | title: My brand new Plan9/9front desktop |
| 3 | url: fresh-9front-desktop.html | 3 | permalink: /fresh-9front-desktop.html |
| 4 | date: 2023-05-24T12:00:00+02:00 | 4 | date: 2023-05-24T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: false |
| 7 | tags: [plan9] | 8 | tags: [plan9] |
| @@ -10,5 +11,5 @@ tags: [plan9] | |||
| 10 | I have been experimenting with Plan9/9front for a week now. Noice! This is how | 11 | I have been experimenting with Plan9/9front for a week now. Noice! This is how |
| 11 | my desktop looks like. | 12 | my desktop looks like. |
| 12 | 13 | ||
| 13 |  | 14 |  |
| 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 | --- |
| 2 | title: Dungeon Crawl Stone Soup - New player guide | 2 | title: Dungeon Crawl Stone Soup - New player guide |
| 3 | url: dcss-new-player-guide.html | 3 | permalink: /dcss-new-player-guide.html |
| 4 | date: 2023-05-25T22:00:00+02:00 | 4 | date: 2023-05-25T22:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: false |
| 7 | tags: [dcss] | 8 | tags: [dcss] |
| @@ -10,11 +11,11 @@ tags: [dcss] | |||
| 10 | An amazing game deserves an amazing guide. All this material can be find in some | 11 | An amazing game deserves an amazing guide. All this material can be find in some |
| 11 | form on another on [craw's](https://github.com/crawl/crawl) official repository. | 12 | form 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 |  | 18 |  |
| 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 | --- |
| 2 | title: Display xterm color palette | 2 | title: Display xterm color palette |
| 3 | url: xterm-color-palette.html | 3 | permalink: /xterm-color-palette.html |
| 4 | date: 2023-05-25T12:00:00+02:00 | 4 | date: 2023-05-25T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: false |
| 7 | tags: [linux] | 8 | tags: [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 |  | 14 |  |
| 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 | --- |
| 2 | title: Sane defaults for tmux with more visible statusbar | 2 | title: Sane defaults for tmux with more visible statusbar |
| 3 | url: tmux-sane-defaults.html | 3 | permalink: /tmux-sane-defaults.html |
| 4 | date: 2023-05-25T12:00:00+02:00 | 4 | date: 2023-05-25T12:00:00+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: false |
| 7 | tags: [tmux] | 8 | tags: [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 | --- |
| 2 | title: "Cronjobs on Github with Github Actions" | 2 | title: "Cronjobs on Github with Github Actions" |
| 3 | url: cronjobs-github-with-actions.html | 3 | permalink: /cronjobs-github-with-actions.html |
| 4 | date: 2023-05-27T00:35:36+02:00 | 4 | date: 2023-05-27T00:35:36+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: false |
| 7 | tags: [github] | 8 | tags: [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 | --- |
| 2 | title: "Make DCSS playable on 4k displays" | 2 | title: "Make DCSS playable on 4k displays" |
| 3 | url: dcss-on-4k-display.html | 3 | permalink: /dcss-on-4k-display.html |
| 4 | date: 2023-05-27T19:35:11+02:00 | 4 | date: 2023-05-27T19:35:11+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: false |
| 7 | tags: [dcss] | 8 | tags: [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 | --- |
| 2 | title: "Drawing Pixels in Plan9" | 2 | title: "Drawing Pixels in Plan9" |
| 3 | url: drawing-pixels-in-plan9.html | 3 | permalink: /drawing-pixels-in-plan9.html |
| 4 | date: 2023-05-27T17:41:33+02:00 | 4 | date: 2023-05-27T17:41:33+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: false |
| 7 | tags: [plan9, graphics] | 8 | tags: [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 |  | 25 |  |
| 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 | --- |
| 2 | title: "Easy measure time took in a bash script" | 2 | title: "Easy measure time took in a bash script" |
| 3 | url: easy-time-took-in-bash.html | 3 | permalink: /easy-time-took-in-bash.html |
| 4 | date: 2023-05-28T17:53:20+02:00 | 4 | date: 2023-05-28T17:53:20+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: false |
| 7 | tags: [bash] | 8 | tags: [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 | --- |
| 2 | title: "Grep to Less that maintain colors" | 2 | title: "Grep to Less that maintain colors" |
| 3 | url: grep-to-less-maintain-colors.html | 3 | permalink: /grep-to-less-maintain-colors.html |
| 4 | date: 2023-05-29T21:27:07+02:00 | 4 | date: 2023-05-29T21:27:07+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: false |
| 7 | tags: [bash] | 8 | tags: [bash] |
| @@ -22,4 +23,4 @@ string. | |||
| 22 | grep --color=always -rni "TODO:" | less -R | 23 | grep --color=always -rni "TODO:" | less -R |
| 23 | ``` | 24 | ``` |
| 24 | 25 | ||
| 25 |  | 26 |  |
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 | --- |
| 2 | title: "Extending dte editor" | 2 | title: "Extending dte editor" |
| 3 | url: extending-dte-editor.html | 3 | permalink: /extending-dte-editor.html |
| 4 | date: 2023-05-31T08:12:45+02:00 | 4 | date: 2023-05-31T08:12:45+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: false |
| 7 | tags: [dte] | 8 | tags: [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 | --- |
| 2 | title: "Re-Inventing Task Runner That I Actually Used Daily" | 2 | title: "Re-Inventing Task Runner That I Actually Used Daily" |
| 3 | url: re-inventing-task-runner-that-i-actually-used-daily.html | 3 | permalink: /re-inventing-task-runner-that-i-actually-used-daily.html |
| 4 | date: 2023-05-31T12:21:10+02:00 | 4 | date: 2023-05-31T12:21:10+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: 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 | --- |
| 2 | title: "Edsger W. Dijkstra Manuscripts ebook" | 2 | title: "Edsger W. Dijkstra Manuscripts ebook" |
| 3 | url: ewd-manuscripts-ebook.html | 3 | permalink: /ewd-manuscripts-ebook.html |
| 4 | date: 2023-06-01T22:47:56+02:00 | 4 | date: 2023-06-01T22:47:56+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: false |
| 7 | tags: [random] | 8 | tags: [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 | --- |
| 2 | title: "Bulk thumbnails" | 2 | title: "Bulk thumbnails" |
| 3 | url: bulk-make-thumbnails.html | 3 | permalink: /bulk-make-thumbnails.html |
| 4 | date: 2023-06-04T20:46:56+02:00 | 4 | date: 2023-06-04T20:46:56+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: false |
| 7 | tags: [bash] | 8 | tags: [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 | --- |
| 2 | title: "Simple presentations with Markdown" | 2 | title: "Simple presentations with Markdown" |
| 3 | url: presentations-with-markdown.html | 3 | permalink: /presentations-with-markdown.html |
| 4 | date: 2023-06-21T08:54:48+02:00 | 4 | date: 2023-06-21T08:54:48+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: false |
| 7 | tags: [random] | 8 | tags: [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 | --- |
| 2 | title: "Making cgit look nicer" | 2 | title: "Making cgit look nicer" |
| 3 | url: making-cgit-look-nicer.html | 3 | permalink: /making-cgit-look-nicer.html |
| 4 | date: 2023-06-24T13:33:58+02:00 | 4 | date: 2023-06-24T13:33:58+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: false |
| 7 | tags: [git] | 8 | tags: [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 | --- |
| 2 | title: "Alacritty open links with modifier" | 2 | title: "Alacritty open links with modifier" |
| 3 | url: alacritty-open-links-with-modifier.html | 3 | permalink: /alacritty-open-links-with-modifier.html |
| 4 | date: 2023-06-25T17:17:16+02:00 | 4 | date: 2023-06-25T17:17:16+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: false |
| 7 | tags: [linux] | 8 | tags: [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 | --- |
| 2 | title: "Development environments with Nix" | 2 | title: "Development environments with Nix" |
| 3 | url: development-environments-with-nix.html | 3 | permalink: /development-environments-with-nix.html |
| 4 | date: 2023-06-25T16:38:10+02:00 | 4 | date: 2023-06-25T16:38:10+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: false |
| 7 | tags: [random] | 8 | tags: [random] |
| @@ -58,7 +59,7 @@ export PS1="[\033[38;5;9m\]\u@\h\[$(tput sgr0)\]]$(is_inside_nix_shell)\[\033[33 | |||
| 58 | And this is what it looks like when you are in a Nix shell. Otherwise that part | 59 | And this is what it looks like when you are in a Nix shell. Otherwise that part |
| 59 | of prompt is omitted | 60 | of prompt is omitted |
| 60 | 61 | ||
| 61 |  | 62 |  |
| 62 | 63 | ||
| 63 | More resources: | 64 | More 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 | --- |
| 2 | title: "10/GUI 10 Finger Multitouch User Interface" | 2 | title: "10/GUI 10 Finger Multitouch User Interface" |
| 3 | url: 10gui-10-finger-multitouch-user-interface.html | 3 | permalink: /10gui-10-finger-multitouch-user-interface.html |
| 4 | date: 2023-06-29T14:51:39+02:00 | 4 | date: 2023-06-29T14:51:39+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: false |
| 7 | tags: [graphics] | 8 | tags: [graphics] |
| @@ -20,6 +21,6 @@ interaction, but have yet to find a truly viable implementation.* | |||
| 20 | in an intuitive and powerful way.* | 21 | in 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 | --- |
| 2 | title: "60's IBM Computers Commercial" | 2 | title: "60's IBM Computers Commercial" |
| 3 | url: 60s-ibm-computers-commercial.html | 3 | permalink: /60s-ibm-computers-commercial.html |
| 4 | date: 2023-06-29T22:13:45+02:00 | 4 | date: 2023-06-29T22:13:45+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: false |
| 7 | tags: [random] | 8 | tags: [random] |
| @@ -12,6 +13,6 @@ as this typically aired during hour-long programs. They would *not* have aired | |||
| 12 | during a half-hour program. | 13 | during 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 | --- |
| 2 | title: "Bringing all of my projects together under one umbrella" | 2 | title: "Bringing all of my projects together under one umbrella" |
| 3 | url: bringing-all-of-my-projects-together-under-one-umbrella.html | 3 | permalink: /bringing-all-of-my-projects-together-under-one-umbrella.html |
| 4 | date: 2023-07-01T18:49:07+02:00 | 4 | date: 2023-07-01T18:49:07+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: 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 | --- |
| 2 | title: "Who knows what the world will look like tomorrow" | 2 | title: "Who knows what the world will look like tomorrow" |
| 3 | url: who-knows-what-the-world-will-look-like-tomorrow.html | 3 | permalink: /who-knows-what-the-world-will-look-like-tomorrow.html |
| 4 | date: 2023-07-08T18:49:07+02:00 | 4 | date: 2023-07-08T18:49:07+02:00 |
| 5 | layout: post | ||
| 5 | type: post | 6 | type: post |
| 6 | draft: false | 7 | draft: 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 | --- |
| 2 | title: "Fix screen tearing on Debian 12 Xorg and i3" | 2 | title: "Fix screen tearing on Debian 12 Xorg and i3" |
| 3 | url: fix-screen-tearing-on-debian-12-xorg-and-i3.html | 3 | permalink: /fix-screen-tearing-on-debian-12-xorg-and-i3.html |
| 4 | date: 2023-07-10T04:21:48+02:00 | 4 | date: 2023-07-10T04:21:48+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: 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 | --- |
| 2 | title: "Online radio streaming with MPV from terminal" | 2 | title: "Online radio streaming with MPV from terminal" |
| 3 | url: online-radio-streaming-with-mpv-from-terminal.html | 3 | permalink: /online-radio-streaming-with-mpv-from-terminal.html |
| 4 | date: 2023-07-10T03:34:45+02:00 | 4 | date: 2023-07-10T03:34:45+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: 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 | --- |
| 2 | title: "Set color temperature of displays on i3" | 2 | title: "Set color temperature of displays on i3" |
| 3 | url: set-color-temperature-of-displays-on-i3.html | 3 | permalink: /set-color-temperature-of-displays-on-i3.html |
| 4 | date: 2023-07-14T09:19:31+02:00 | 4 | date: 2023-07-14T09:19:31+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: 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 | --- |
| 2 | title: "Make B/W SVG charts with matplotlib" | 2 | title: "Make B/W SVG charts with matplotlib" |
| 3 | url: make-b-w-svg-charts-with-matplotlib.html | 3 | permalink: /make-b-w-svg-charts-with-matplotlib.html |
| 4 | date: 2023-08-01T17:04:10+02:00 | 4 | date: 2023-08-01T17:04:10+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: false |
| 7 | --- | 8 | --- |
| @@ -65,6 +66,6 @@ legend.get_frame().set_linewidth(0) | |||
| 65 | plt.savefig("plot.svg", format="svg") | 66 | plt.savefig("plot.svg", format="svg") |
| 66 | ``` | 67 | ``` |
| 67 | 68 | ||
| 68 |  | 69 |  |
| 69 | 70 | ||
| 70 | The image above is SVG and you can zoom in and out and check that the image is vector. | 71 | The 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 | --- | ||
| 2 | title: "Floods in Slovenia up close" | ||
| 3 | permalink: /floods-in-slovenia.html | ||
| 4 | date: 2023-08-05T07:06:50+02:00 | ||
| 5 | layout: post | ||
| 6 | type: note | ||
| 7 | draft: 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 |  | ||
| 15 | |||
| 16 |  | ||
| 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 | --- |
| 2 | title: "AWS EB PyYAML fix" | 2 | title: "AWS EB PyYAML fix" |
| 3 | url: aws-eb-pyyaml-fix.html | 3 | permalink: /aws-eb-pyyaml-fix.html |
| 4 | date: 2023-09-18T07:27:29+02:00 | 4 | date: 2023-09-18T07:27:29+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: 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 | --- |
| 2 | title: "Compile drawterm on Fedora 38" | 2 | title: "Compile drawterm on Fedora 38" |
| 3 | url: compile-drawterm-on-fedora-38.html | 3 | permalink: /compile-drawterm-on-fedora-38.html |
| 4 | date: 2023-09-25T09:04:28+02:00 | 4 | date: 2023-09-25T09:04:28+02:00 |
| 5 | layout: post | ||
| 5 | type: note | 6 | type: note |
| 6 | draft: false | 7 | draft: 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 @@ | |||
| 1 | require "erb" | ||
| 2 | require "htmlentities" | ||
| 3 | require "open-uri" | ||
| 4 | require "simple-rss" | ||
| 5 | |||
| 6 | summary_max_length = 360 | ||
| 7 | |||
| 8 | feeds = [ | ||
| 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 | |||
| 20 | out_html = "" | ||
| 21 | decoder = HTMLEntities.new | ||
| 22 | |||
| 23 | feeds.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 | ||
| 74 | end | ||
| 75 | |||
| 76 | |||
| 77 | template = ERB.new <<-EOF | ||
| 78 | <h2>Posts from blogs I follow around the net</h2> | ||
| 79 | <ul><%= out_html %></ul> | ||
| 80 | EOF | ||
| 81 | out_html = template.result(binding) | ||
| 82 | File.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 @@ | |||
| 1 | title: "Mitja Felicijan" | ||
| 2 | baseurl: "https://mitjafelicijan.com" | ||
| 3 | description: "You do not learn by relaxing. You learn by violently assaulting your problem until it surrenders its mysteries to you." | ||
| 4 | language: "en-us" | ||
| 5 | |||
| 6 | # Code highlighting. | ||
| 7 | # https://swapoff.org/chroma/playground/ | ||
| 8 | # highlighting: "pygments" | ||
| 9 | highlighting: "vs" | ||
| 10 | |||
| 11 | # Minifies output HTML (including inline CSS, JS). | ||
| 12 | minify: true | ||
| 13 | |||
| 14 | extras: | ||
| 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 | --- | ||
| 2 | title: "Floods in Slovenia up close" | ||
| 3 | url: floods-in-slovenia.html | ||
| 4 | date: 2023-08-05T07:06:50+02:00 | ||
| 5 | type: note | ||
| 6 | draft: 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 |  | ||
| 14 | |||
| 15 |  | ||
| 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 | --- | ||
| 2 | title: Personal vault | ||
| 3 | date: 2022-08-27T12:00:00+02:00 | ||
| 4 | url: vault.html | ||
| 5 | type: page | ||
| 6 | draft: false | ||
| 7 | --- | ||
| 8 | |||
| 9 | **Hi traveler!** | ||
| 10 | |||
| 11 | This is a repository of interesting things I have gathered over time and it also | ||
| 12 | stores binaries etc of my personal projects. | ||
| 13 | |||
| 14 | Be 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 | --- |
| 2 | title: Curriculum Vitae | 2 | title: Curriculum Vitae |
| 3 | date: 2022-08-27T12:00:00+02:00 | 3 | date: 2022-08-27T12:00:00+02:00 |
| 4 | url: curriculum-vitae.html | 4 | permalink: /curriculum-vitae.html |
| 5 | layout: page | ||
| 5 | type: page | 6 | type: page |
| 6 | draft: 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 |  | ||
| 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 | --- | ||
| 2 | layout: index | ||
| 3 | --- | ||
| 4 | |||
| 5 | <p>You do not learn by relaxing. You learn by violently assaulting your problem | ||
| 6 | until 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 | ||
| 10 | interface paradigm we today take for granted.</em><p><em>That it has endured is a testament to the genius of its design. But the | ||
| 11 | industry is now at a crossroads: New technologies promise higher-bandwidth | ||
| 12 | interaction, 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 | ||
| 13 | in 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 | ||
| 14 | a lock on a Linux NFS server, which turned | ||
| 15 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 16 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 17 | owns 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 | ||
| 18 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 19 | list where the're doing | ||
| 20 | bad computer history and insisting that a guy Larry Rosen | ||
| 21 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 22 | somethin…<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: | ||
| 23 | i2c, plan9 | ||
| 24 | Another month, another file system. | ||
| 25 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 26 | you, bme680, we’re not | ||
| 27 | done yet). The show must go on, as they say, and I would like my | ||
| 28 | experiments to go on. | ||
| 29 | So a “new” addition to the environmental sensor family connected to | ||
| 30 | the 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 | ||
| 31 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 32 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 33 | unique 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. | ||
| 34 | My 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 | ||
| 35 | 1.0 has been released: | ||
| 36 | wifi_da-1.0.sit | ||
| 37 | (StuffIt 3 archive) | ||
| 38 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 39 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 40 | classic 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. | ||
| 41 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 42 | Design Goals | ||
| 43 | I 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 | ||
| 44 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 45 | catch 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 | ||
| 46 | specified 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 | ||
| 10 | as this typically aired during hour-long programs. They would <em>not</em> have aired | ||
| 11 | during 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 | ||
| 12 | a lock on a Linux NFS server, which turned | ||
| 13 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 14 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 15 | owns 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 | ||
| 16 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 17 | list where the're doing | ||
| 18 | bad computer history and insisting that a guy Larry Rosen | ||
| 19 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 20 | somethin…<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: | ||
| 21 | i2c, plan9 | ||
| 22 | Another month, another file system. | ||
| 23 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 24 | you, bme680, we’re not | ||
| 25 | done yet). The show must go on, as they say, and I would like my | ||
| 26 | experiments to go on. | ||
| 27 | So a “new” addition to the environmental sensor family connected to | ||
| 28 | the 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 | ||
| 29 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 30 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 31 | unique 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. | ||
| 32 | My 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 | ||
| 33 | 1.0 has been released: | ||
| 34 | wifi_da-1.0.sit | ||
| 35 | (StuffIt 3 archive) | ||
| 36 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 37 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 38 | classic 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. | ||
| 39 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 40 | Design Goals | ||
| 41 | I 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 | ||
| 42 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 43 | catch 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 | ||
| 44 | specified 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 | ||
| 10 | one to me. River Sava has plenty of hydropower plants located down the stream. | ||
| 11 | This makes regulating the strength of a current easier than normally. Because of | ||
| 12 | lower stream strength and high temperatures, algae has formed on the river. | ||
| 13 | This 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 | ||
| 14 | intriguing 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 | ||
| 15 | a lock on a Linux NFS server, which turned | ||
| 16 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 17 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 18 | owns 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 | ||
| 19 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 20 | list where the're doing | ||
| 21 | bad computer history and insisting that a guy Larry Rosen | ||
| 22 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 23 | somethin…<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: | ||
| 24 | i2c, plan9 | ||
| 25 | Another month, another file system. | ||
| 26 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 27 | you, bme680, we’re not | ||
| 28 | done yet). The show must go on, as they say, and I would like my | ||
| 29 | experiments to go on. | ||
| 30 | So a “new” addition to the environmental sensor family connected to | ||
| 31 | the 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 | ||
| 32 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 33 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 34 | unique 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. | ||
| 35 | My 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 | ||
| 36 | 1.0 has been released: | ||
| 37 | wifi_da-1.0.sit | ||
| 38 | (StuffIt 3 archive) | ||
| 39 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 40 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 41 | classic 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. | ||
| 42 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 43 | Design Goals | ||
| 44 | I 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 | ||
| 45 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 46 | catch 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 | ||
| 47 | specified 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 | ||
| 10 | gets annoying rather quickly. I liked the default behavior of Gnome terminal | ||
| 11 | where 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 | ||
| 12 | file. 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>"(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<>\"\\s{-}\\^⟨⟩`]+"</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 | ||
| 22 | change <code>command: xdg-open</code> to something else.<p>Now the links will be visible and clickable only when Control key is being | ||
| 23 | pressed.<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 | ||
| 24 | a lock on a Linux NFS server, which turned | ||
| 25 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 26 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 27 | owns 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 | ||
| 28 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 29 | list where the're doing | ||
| 30 | bad computer history and insisting that a guy Larry Rosen | ||
| 31 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 32 | somethin…<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: | ||
| 33 | i2c, plan9 | ||
| 34 | Another month, another file system. | ||
| 35 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 36 | you, bme680, we’re not | ||
| 37 | done yet). The show must go on, as they say, and I would like my | ||
| 38 | experiments to go on. | ||
| 39 | So a “new” addition to the environmental sensor family connected to | ||
| 40 | the 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 | ||
| 41 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 42 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 43 | unique 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. | ||
| 44 | My 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 | ||
| 45 | 1.0 has been released: | ||
| 46 | wifi_da-1.0.sit | ||
| 47 | (StuffIt 3 archive) | ||
| 48 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 49 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 50 | classic 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. | ||
| 51 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 52 | Design Goals | ||
| 53 | I 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 | ||
| 54 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 55 | catch 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 | ||
| 56 | specified 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> | ||
| 10 | on 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<6.1,>=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> ╰─> [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>'Cython < 3.0'</span> > /tmp/constraint.txt | ||
| 20 | </span></span><span style=display:flex><span>PIP_CONSTRAINT=/tmp/constraint.txt pip install <span style=color:#a31515>'PyYAML==5.4.1'</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 | ||
| 22 | a lock on a Linux NFS server, which turned | ||
| 23 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 24 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 25 | owns 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 | ||
| 26 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 27 | list where the're doing | ||
| 28 | bad computer history and insisting that a guy Larry Rosen | ||
| 29 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 30 | somethin…<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: | ||
| 31 | i2c, plan9 | ||
| 32 | Another month, another file system. | ||
| 33 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 34 | you, bme680, we’re not | ||
| 35 | done yet). The show must go on, as they say, and I would like my | ||
| 36 | experiments to go on. | ||
| 37 | So a “new” addition to the environmental sensor family connected to | ||
| 38 | the 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 | ||
| 39 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 40 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 41 | unique 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. | ||
| 42 | My 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 | ||
| 43 | 1.0 has been released: | ||
| 44 | wifi_da-1.0.sit | ||
| 45 | (StuffIt 3 archive) | ||
| 46 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 47 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 48 | classic 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. | ||
| 49 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 50 | Design Goals | ||
| 51 | I 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 | ||
| 52 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 53 | catch 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 | ||
| 54 | specified 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 | ||
| 10 | default shell. I was previously using <a href=https://fishshell.com/>fish</a> and got | ||
| 11 | used to the cool features it has. But, regardless of that, I wanted to move to a | ||
| 12 | more standard shell because I was hopping back and forth with exporting | ||
| 13 | variables 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> | ||
| 14 | more like <a href=https://fishshell.com/>fish</a> and in the process found that I really | ||
| 15 | missed autosuggest with TAB on changing directories.<p>I found a nice alternative that emulates <a href=http://zsh.sourceforge.net/>zsh</a> like | ||
| 16 | autosuggestion 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>"TAB:menu-complete"</span> | ||
| 17 | </span></span><span style=display:flex><span>bind <span style=color:#a31515>"set show-all-if-ambiguous on"</span> | ||
| 18 | </span></span><span style=display:flex><span>bind <span style=color:#a31515>"set completion-ignore-case on"</span> | ||
| 19 | </span></span><span style=display:flex><span>bind <span style=color:#a31515>"set menu-complete-display-prefix on"</span> | ||
| 20 | </span></span><span style=display:flex><span>bind <span style=color:#a31515>'"\e[Z":menu-complete-backward'</span> | ||
| 21 | </span></span></code></pre><p>I haven't noticed anything wrong with this and all was working fine until I | ||
| 22 | restarted 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 | ||
| 23 | shell</a> and all was working fine, but | ||
| 24 | the error was still bugging me. I started looking for the reason why this is | ||
| 25 | happening and found a solution to this error on <a href=https://superuser.com/a/892682>Remote SSH Commands - bash bind | ||
| 26 | warning: line editing not enabled</a>.<p>So I added a simple <code>if [ -t 1 ]</code> around <code>bind</code> statements to avoid running | ||
| 27 | commands 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>"TAB:menu-complete"</span> | ||
| 29 | </span></span><span style=display:flex><span> bind <span style=color:#a31515>"set show-all-if-ambiguous on"</span> | ||
| 30 | </span></span><span style=display:flex><span> bind <span style=color:#a31515>"set completion-ignore-case on"</span> | ||
| 31 | </span></span><span style=display:flex><span> bind <span style=color:#a31515>"set menu-complete-display-prefix on"</span> | ||
| 32 | </span></span><span style=display:flex><span> bind <span style=color:#a31515>'"\e[Z":menu-complete-backward'</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 | ||
| 35 | a lock on a Linux NFS server, which turned | ||
| 36 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 37 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 38 | owns 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 | ||
| 39 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 40 | list where the're doing | ||
| 41 | bad computer history and insisting that a guy Larry Rosen | ||
| 42 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 43 | somethin…<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: | ||
| 44 | i2c, plan9 | ||
| 45 | Another month, another file system. | ||
| 46 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 47 | you, bme680, we’re not | ||
| 48 | done yet). The show must go on, as they say, and I would like my | ||
| 49 | experiments to go on. | ||
| 50 | So a “new” addition to the environmental sensor family connected to | ||
| 51 | the 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 | ||
| 52 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 53 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 54 | unique 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. | ||
| 55 | My 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 | ||
| 56 | 1.0 has been released: | ||
| 57 | wifi_da-1.0.sit | ||
| 58 | (StuffIt 3 archive) | ||
| 59 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 60 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 61 | classic 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. | ||
| 62 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 63 | Design Goals | ||
| 64 | I 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 | ||
| 65 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 66 | catch 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 | ||
| 67 | specified 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 | ||
| 11 | projects I dabble in. And this has resulted in quite a bill. I mean, I wouldn't | ||
| 12 | care if these projects were actually being used. But there were just being there | ||
| 13 | unused 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 | ||
| 14 | from or to, and for that reason I wrote servers left and right. To be honest, | ||
| 15 | all of those things could have been done with <a href=https://en.wikipedia.org/wiki/Common_Gateway_Interface>CGI | ||
| 16 | scripts</a> and that would | ||
| 17 | have been more than enough.<p>Recently, I decided to stop language hopping and focus on a simpler stack which | ||
| 18 | includes 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 | ||
| 19 | and I had to manage SSL certificates and all that jazz. I am bored with these | ||
| 20 | things. 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 | ||
| 21 | ended up on <a href=https://caddyserver.com/>Caddy server</a>. I've used it in the past | ||
| 22 | but kind of forgotten about it. What I really like about it is an ease of use | ||
| 23 | and 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 | ||
| 24 | default. A hardened TLS stack with modern protocols preserves privacy and | ||
| 25 | exposes MITM attacks.<li><strong>Config API</strong>: As its primary mode of configuration, Caddy's REST API makes | ||
| 26 | it easy to automate and integrate with your apps.<li><strong>No Dependencies</strong>: Because Caddy is written in Go, its binaries are entirely | ||
| 27 | self-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 | ||
| 28 | extended 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 | ||
| 29 | fixed with their modular approach. You can do this on their website and build a | ||
| 30 | custom 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 | ||
| 40 | over 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 | ||
| 41 | particularly import to me because almost all of my experiments and mini projects | ||
| 42 | need this to work.<p>To configure Caddy server, you must provide the server with a configuration | ||
| 43 | file. 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 | ||
| 57 | the top of the configuration file.<li>Also, when you run with Caddy v2, make sure you provide <code>adapter</code> argument | ||
| 58 | like 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 | ||
| 59 | config 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>"Content-type: text/plain\n\n"</span> | ||
| 64 | </span></span><span style=display:flex><span> | ||
| 65 | </span></span><span style=display:flex><span>printf <span style=color:#a31515>"Hello from Bash\n\n"</span> | ||
| 66 | </span></span><span style=display:flex><span>printf <span style=color:#a31515>"PATH_INFO [%s]\n"</span> $PATH_INFO | ||
| 67 | </span></span><span style=display:flex><span>printf <span style=color:#a31515>"QUERY_STRING [%s]\n"</span> $QUERY_STRING | ||
| 68 | </span></span><span style=display:flex><span>printf <span style=color:#a31515>"\n"</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>"> %s\n"</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>"Content-type: text/plain\n"</span> | ||
| 78 | </span></span><span style=display:flex><span> | ||
| 79 | </span></span><span style=display:flex><span>puts <span style=color:#a31515>"Hello from Tcl\n"</span> | ||
| 80 | </span></span><span style=display:flex><span>puts <span style=color:#a31515>"PATH_INFO \[$env(PATH_INFO)\]"</span> | ||
| 81 | </span></span><span style=display:flex><span>puts <span style=color:#a31515>"QUERY_STRING \[$env(QUERY_STRING)\]"</span> | ||
| 82 | </span></span><span style=display:flex><span>puts <span style=color:#a31515>""</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 < 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>"> $i"</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>"Content-type: text/plain</span><span style=color:#a31515>\n</span><span style=color:#a31515>"</span>) | ||
| 92 | </span></span><span style=display:flex><span> | ||
| 93 | </span></span><span style=display:flex><span>print(<span style=color:#a31515>"Hello from Python</span><span style=color:#a31515>\n</span><span style=color:#a31515>"</span>) | ||
| 94 | </span></span><span style=display:flex><span>print(<span style=color:#a31515>"PATH_INFO [</span><span style=color:#a31515>{}</span><span style=color:#a31515>]"</span>.format(os.environ[<span style=color:#a31515>'PATH_INFO'</span>])) | ||
| 95 | </span></span><span style=display:flex><span>print(<span style=color:#a31515>"QUERY_STRING [</span><span style=color:#a31515>{}</span><span style=color:#a31515>]"</span>.format(os.environ[<span style=color:#a31515>'QUERY_STRING'</span>])) | ||
| 96 | </span></span><span style=display:flex><span>print(<span style=color:#a31515>""</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>"> </span><span style=color:#a31515>{}</span><span style=color:#a31515>"</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>"Content-type: text/plain</span><span style=color:#a31515>\n</span><span style=color:#a31515>"</span>) | ||
| 103 | </span></span><span style=display:flex><span> | ||
| 104 | </span></span><span style=display:flex><span>print(<span style=color:#a31515>"Hello from Lua</span><span style=color:#a31515>\n</span><span style=color:#a31515>"</span>) | ||
| 105 | </span></span><span style=display:flex><span>print(string.format(<span style=color:#a31515>"PATH_INFO [%s]"</span>, os.getenv(<span style=color:#a31515>"PATH_INFO"</span>))) | ||
| 106 | </span></span><span style=display:flex><span>print(string.format(<span style=color:#a31515>"QUERY_STRING [%s]"</span>, os.getenv(<span style=color:#a31515>"QUERY_STRING"</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>"> %d"</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 | ||
| 113 | something like <a href=https://en.wikipedia.org/wiki/Basic_access_authentication>Basic access | ||
| 114 | authentication</a> would | ||
| 115 | be more than enough.<p>Thankfully, Caddy supports this out of the box already. Below is an updated | ||
| 116 | example.<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 | ||
| 134 | with 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 | ||
| 135 | you to insert a password twice and spit out a hashed password that you can put | ||
| 136 | in 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 | ||
| 138 | file.<ul><li>I created a <code>/etc/systemd/system/caddy.service</code> and put the following content | ||
| 139 | in 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 | ||
| 161 | new subdomains and domains to the main configuration file and be done with | ||
| 162 | it. 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 | ||
| 163 | a lock on a Linux NFS server, which turned | ||
| 164 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 165 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 166 | owns 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 | ||
| 167 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 168 | list where the're doing | ||
| 169 | bad computer history and insisting that a guy Larry Rosen | ||
| 170 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 171 | somethin…<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: | ||
| 172 | i2c, plan9 | ||
| 173 | Another month, another file system. | ||
| 174 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 175 | you, bme680, we’re not | ||
| 176 | done yet). The show must go on, as they say, and I would like my | ||
| 177 | experiments to go on. | ||
| 178 | So a “new” addition to the environmental sensor family connected to | ||
| 179 | the 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 | ||
| 180 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 181 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 182 | unique 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. | ||
| 183 | My 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 | ||
| 184 | 1.0 has been released: | ||
| 185 | wifi_da-1.0.sit | ||
| 186 | (StuffIt 3 archive) | ||
| 187 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 188 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 189 | classic 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. | ||
| 190 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 191 | Design Goals | ||
| 192 | I 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 | ||
| 193 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 194 | catch 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 | ||
| 195 | specified 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>"./images/"</span> | ||
| 12 | </span></span><span style=display:flex><span>dimensions=<span style=color:#a31515>"360x360"</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>"</span>$directory<span style=color:#a31515>"</span>*.jpg; <span style=color:#00f>do</span> | ||
| 15 | </span></span><span style=display:flex><span> convert <span style=color:#a31515>"</span>$file<span style=color:#a31515>"</span> -resize $dimensions <span style=color:#a31515>"</span>$file<span style=color:#a31515>"</span> <span style=color:#a31515>"</span><span style=color:#a31515>${</span>file%.*<span style=color:#a31515>}</span><span style=color:#a31515>-thumbnail.jpg"</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 | ||
| 18 | a lock on a Linux NFS server, which turned | ||
| 19 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 20 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 21 | owns 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 | ||
| 22 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 23 | list where the're doing | ||
| 24 | bad computer history and insisting that a guy Larry Rosen | ||
| 25 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 26 | somethin…<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: | ||
| 27 | i2c, plan9 | ||
| 28 | Another month, another file system. | ||
| 29 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 30 | you, bme680, we’re not | ||
| 31 | done yet). The show must go on, as they say, and I would like my | ||
| 32 | experiments to go on. | ||
| 33 | So a “new” addition to the environmental sensor family connected to | ||
| 34 | the 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 | ||
| 35 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 36 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 37 | unique 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. | ||
| 38 | My 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 | ||
| 39 | 1.0 has been released: | ||
| 40 | wifi_da-1.0.sit | ||
| 41 | (StuffIt 3 archive) | ||
| 42 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 43 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 44 | classic 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. | ||
| 45 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 46 | Design Goals | ||
| 47 | I 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 | ||
| 48 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 49 | catch 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 | ||
| 50 | specified 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 &#34;6fab11c6669976d759d2992eff1dd5be&#34;) &#34;&#34; )) &#34;&#34; }}&lt;link rel=&#34;stylesheet&#34; href=&#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 "6fab11c6669976d759d2992eff1dd5be") "" )) "" }} | ||
| 10 | </span></span><span style=display:flex><span> | ||
| 11 | </span></span><span style=display:flex><span><link rel=<span style=color:#a31515>"stylesheet"</span> href=<span style=color:#a31515>"/style.css?v={{ $cachebuster }}"</span>> | ||
| 12 | </span></span></code></pre><p>This <code>6fab11c6669976d759d2992eff1dd5be</code> can be random string you generate use. | ||
| 13 | You 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 | ||
| 14 | a lock on a Linux NFS server, which turned | ||
| 15 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 16 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 17 | owns 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 | ||
| 18 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 19 | list where the're doing | ||
| 20 | bad computer history and insisting that a guy Larry Rosen | ||
| 21 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 22 | somethin…<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: | ||
| 23 | i2c, plan9 | ||
| 24 | Another month, another file system. | ||
| 25 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 26 | you, bme680, we’re not | ||
| 27 | done yet). The show must go on, as they say, and I would like my | ||
| 28 | experiments to go on. | ||
| 29 | So a “new” addition to the environmental sensor family connected to | ||
| 30 | the 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 | ||
| 31 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 32 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 33 | unique 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. | ||
| 34 | My 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 | ||
| 35 | 1.0 has been released: | ||
| 36 | wifi_da-1.0.sit | ||
| 37 | (StuffIt 3 archive) | ||
| 38 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 39 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 40 | classic 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. | ||
| 41 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 42 | Design Goals | ||
| 43 | I 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 | ||
| 44 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 45 | catch 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 | ||
| 46 | specified 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>"#cat-v"</span> | ||
| 15 | </span></span><span style=display:flex><span>/set irc.server.oftc.nicks <span style=color:#a31515>"nick1,nick2,nick3"</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 | ||
| 17 | a lock on a Linux NFS server, which turned | ||
| 18 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 19 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 20 | owns 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 | ||
| 21 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 22 | list where the're doing | ||
| 23 | bad computer history and insisting that a guy Larry Rosen | ||
| 24 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 25 | somethin…<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: | ||
| 26 | i2c, plan9 | ||
| 27 | Another month, another file system. | ||
| 28 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 29 | you, bme680, we’re not | ||
| 30 | done yet). The show must go on, as they say, and I would like my | ||
| 31 | experiments to go on. | ||
| 32 | So a “new” addition to the environmental sensor family connected to | ||
| 33 | the 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 | ||
| 34 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 35 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 36 | unique 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. | ||
| 37 | My 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 | ||
| 38 | 1.0 has been released: | ||
| 39 | wifi_da-1.0.sit | ||
| 40 | (StuffIt 3 archive) | ||
| 41 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 42 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 43 | classic 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. | ||
| 44 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 45 | Design Goals | ||
| 46 | I 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 | ||
| 47 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 48 | catch 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 | ||
| 49 | specified 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 | ||
| 14 | a lock on a Linux NFS server, which turned | ||
| 15 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 16 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 17 | owns 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 | ||
| 18 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 19 | list where the're doing | ||
| 20 | bad computer history and insisting that a guy Larry Rosen | ||
| 21 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 22 | somethin…<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: | ||
| 23 | i2c, plan9 | ||
| 24 | Another month, another file system. | ||
| 25 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 26 | you, bme680, we’re not | ||
| 27 | done yet). The show must go on, as they say, and I would like my | ||
| 28 | experiments to go on. | ||
| 29 | So a “new” addition to the environmental sensor family connected to | ||
| 30 | the 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 | ||
| 31 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 32 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 33 | unique 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. | ||
| 34 | My 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 | ||
| 35 | 1.0 has been released: | ||
| 36 | wifi_da-1.0.sit | ||
| 37 | (StuffIt 3 archive) | ||
| 38 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 39 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 40 | classic 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. | ||
| 41 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 42 | Design Goals | ||
| 43 | I 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 | ||
| 44 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 45 | catch 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 | ||
| 46 | specified 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 | ||
| 10 | into 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>'*.mkv'</span> -exec bash -c <span style=color:#a31515>'ffmpeg -i "$0" -vcodec libvpx -acodec libvorbis -cpu-used 5 -threads 8 "${0%%.mp4}.webm"'</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>'*.mkv'</span> -exec bash -c <span style=color:#a31515>'ffmpeg -i "$0" c:a copy -c:v copy -cpu-used 5 -threads 8 "${0%%.mp4}.mp4"'</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 | ||
| 15 | a lock on a Linux NFS server, which turned | ||
| 16 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 17 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 18 | owns 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 | ||
| 19 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 20 | list where the're doing | ||
| 21 | bad computer history and insisting that a guy Larry Rosen | ||
| 22 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 23 | somethin…<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: | ||
| 24 | i2c, plan9 | ||
| 25 | Another month, another file system. | ||
| 26 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 27 | you, bme680, we’re not | ||
| 28 | done yet). The show must go on, as they say, and I would like my | ||
| 29 | experiments to go on. | ||
| 30 | So a “new” addition to the environmental sensor family connected to | ||
| 31 | the 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 | ||
| 32 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 33 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 34 | unique 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. | ||
| 35 | My 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 | ||
| 36 | 1.0 has been released: | ||
| 37 | wifi_da-1.0.sit | ||
| 38 | (StuffIt 3 archive) | ||
| 39 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 40 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 41 | classic 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. | ||
| 42 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 43 | Design Goals | ||
| 44 | I 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 | ||
| 45 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 46 | catch 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 | ||
| 47 | specified 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 | ||
| 8 | like this editor and wanted to write something here that will remind me to use | ||
| 9 | it 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 | ||
| 10 | hope 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 | ||
| 11 | my Mac. Zed is a high-performance, multiplayer code editor developed by the | ||
| 12 | creators of Atom and Tree-sitter. Written in Rust so it has to be blazingly | ||
| 13 | fast! 😊 It's a joke, calm down.<p>Over the past year, I have switched between <a href=https://helix-editor.com/>Helix | ||
| 14 | editor</a> and <a href=https://code.visualstudio.com/>VS | ||
| 15 | Code</a>, but for the last couple of months, I have | ||
| 16 | been using Helix exclusively.<p>I've been genuinely impressed by Zed. When you open a file, it automatically | ||
| 17 | detects its type and downloads the corresponding <a href=https://en.wikipedia.org/wiki/Language_Server_Protocol>LSP (language | ||
| 18 | server)</a>. The list of | ||
| 19 | supported languages is not extensive, but it's still impressive. It's a great | ||
| 20 | example 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 | ||
| 21 | up 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 | ||
| 23 | project, don’t worry about it.<p>If you are going to give this a try and you are using C, I suggest checking two | ||
| 24 | files 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 | ||
| 27 | use <code>pkg-config</code> and in my case <code>pkg-config SDL2 --cflags-only-I</code>. But this is | ||
| 28 | nothing new to C/C++ devs. Just a noter for people who are using Visual Studio.<p><strong>.clang-format</strong><pre><code>ColumnLimit: 220 | ||
| 29 | BasedOnStyle: 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 | ||
| 31 | for Linux yet, I will stick to Helix. This impressive piece of engineering is, | ||
| 32 | above all, an amazing example of craftsmanship.<p>They have a bunch of amazing integrated functionalities like live desktop | ||
| 33 | sharing, code sharing in a live coding session. There is a lot of pretentious | ||
| 34 | marketing speak there but the product is still amazing!<p>For me the speed and the simplicity of the product was the most impressive | ||
| 35 | thing. 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> | ||
| 36 | in a non obtrusive way. To me, everything feels very intentional and | ||
| 37 | specifically 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 | ||
| 38 | or Helix.<p>I just hope they <strong>DON’T</strong> add plugin support and keep it like it is. They as a | ||
| 39 | vendor should add stuff to it with great deliberation and thought. And this way | ||
| 40 | the 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 | ||
| 41 | project I started back in 2017 to make it easier to build good Wayland | ||
| 42 | compositors. 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. | ||
| 43 | Conventional 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 | ||
| 44 | Vintage Computer Festival Midwest 18 | ||
| 45 | and made some things. | ||
| 46 | Your browser doesn't seem to support HTML video. | ||
| 47 | You 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: | ||
| 49 | plan9 | ||
| 50 | There’s no shame in that. Yes, there is documentation, code to be | ||
| 51 | read, and debuggers to be used. But sometimes you just need to “see” | ||
| 52 | what is happening. | ||
| 53 | So… — <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 | ||
| 54 | at <a href=mailto:m@mitjafelicijan.com>m@mitjafelicijan.com</a> or | ||
| 55 | catch 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 | ||
| 56 | the <a href=https://creativecommons.org/licenses/by/4.0/ target=_blank rel=noreferrer>CC BY 4.0 license</a> unless specified | ||
| 57 | otherwise. 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 | ||
| 10 | image server I needed to develop that resizes images on S3. I though this would | ||
| 11 | be 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 | ||
| 12 | something written in C or Rust or even Golang would be the correct way to do | ||
| 13 | this 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 | ||
| 15 | processing</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>'sharp'</span>); | ||
| 16 | </span></span><span style=display:flex><span><span style=color:#00f>const</span> aws = require(<span style=color:#a31515>'aws-sdk'</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>'secretAccessKey'</span>, | ||
| 23 | </span></span><span style=display:flex><span> accessKeyId: <span style=color:#a31515>'accessKeyId'</span>, | ||
| 24 | </span></span><span style=display:flex><span> region: <span style=color:#a31515>'region'</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>'some-bucket-name'</span>, | ||
| 29 | </span></span><span style=display:flex><span> Key: <span style=color:#a31515>'image.jpg'</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>'some-bucket-name'</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>'image/jpeg'</span>, | ||
| 42 | </span></span><span style=display:flex><span> ACL: <span style=color:#a31515>'public-read'</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 | ||
| 45 | checks 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 | ||
| 46 | key is missing or x,y are not allowed by the server etc. I could have created | ||
| 47 | PNG in Gimp and just serve them but I wanted to respect aspect ratio and I | ||
| 48 | didn't want to return some mangled images.<blockquote><p>Main problem with finding a clean solution I could copy and paste and change a | ||
| 49 | bit was a task. API is changing constantly and there weren't clear examples or | ||
| 50 | I 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 | ||
| 51 | used composition to combine both layers. Response returned by this function is a | ||
| 52 | buffer 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) => { | ||
| 53 | </span></span><span style=display:flex><span> <span style=color:#00f>const</span> overlay = <span style=color:#a31515>`<svg width="</span><span style=color:#a31515>${</span>width - 20<span style=color:#a31515>}</span><span style=color:#a31515>" height="</span><span style=color:#a31515>${</span>height - 20<span style=color:#a31515>}</span><span style=color:#a31515>"> | ||
| 54 | </span></span></span><span style=display:flex><span><span style=color:#a31515> <text x="50%" y="50%" font-family="sans-serif" font-size="16" text-anchor="middle"></span><span style=color:#a31515>${</span>message<span style=color:#a31515>}</span><span style=color:#a31515></text> | ||
| 55 | </span></span></span><span style=display:flex><span><span style=color:#a31515> </svg>`</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>'center'</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 | ||
| 73 | changing <code>background</code> and if you want to change text styling you can adapt SVG | ||
| 74 | to your needs.<blockquote><p>Also be careful about the length of the text. This function positions text at | ||
| 75 | the center and adds <code>20px</code> padding on all sides. If text is longer than the | ||
| 76 | image 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 | ||
| 77 | a lock on a Linux NFS server, which turned | ||
| 78 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 79 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 80 | owns 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 | ||
| 81 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 82 | list where the're doing | ||
| 83 | bad computer history and insisting that a guy Larry Rosen | ||
| 84 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 85 | somethin…<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: | ||
| 86 | i2c, plan9 | ||
| 87 | Another month, another file system. | ||
| 88 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 89 | you, bme680, we’re not | ||
| 90 | done yet). The show must go on, as they say, and I would like my | ||
| 91 | experiments to go on. | ||
| 92 | So a “new” addition to the environmental sensor family connected to | ||
| 93 | the 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 | ||
| 94 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 95 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 96 | unique 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. | ||
| 97 | My 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 | ||
| 98 | 1.0 has been released: | ||
| 99 | wifi_da-1.0.sit | ||
| 100 | (StuffIt 3 archive) | ||
| 101 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 102 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 103 | classic 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. | ||
| 104 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 105 | Design Goals | ||
| 106 | I 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 | ||
| 107 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 108 | catch 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 | ||
| 109 | specified 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 | ||
| 10 | folder create a file a file <code>cron.yaml</code>. This file can be named whatever you | ||
| 11 | wish. 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 | ||
| 12 | every six hours and it will curl example.com.<p>However. Be sure that you have enough credits. Free account is not that generous | ||
| 13 | with the minutes they give you for free. Check more about GitHub Actions usage | ||
| 14 | on 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>'0 */6 * * *'</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 'https://example.com' | ||
| 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 | ||
| 26 | a lock on a Linux NFS server, which turned | ||
| 27 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 28 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 29 | owns 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 | ||
| 30 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 31 | list where the're doing | ||
| 32 | bad computer history and insisting that a guy Larry Rosen | ||
| 33 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 34 | somethin…<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: | ||
| 35 | i2c, plan9 | ||
| 36 | Another month, another file system. | ||
| 37 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 38 | you, bme680, we’re not | ||
| 39 | done yet). The show must go on, as they say, and I would like my | ||
| 40 | experiments to go on. | ||
| 41 | So a “new” addition to the environmental sensor family connected to | ||
| 42 | the 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 | ||
| 43 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 44 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 45 | unique 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. | ||
| 46 | My 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 | ||
| 47 | 1.0 has been released: | ||
| 48 | wifi_da-1.0.sit | ||
| 49 | (StuffIt 3 archive) | ||
| 50 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 51 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 52 | classic 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. | ||
| 53 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 54 | Design Goals | ||
| 55 | I 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 | ||
| 56 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 57 | catch 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 | ||
| 58 | specified 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 | ||
| 20 | a lock on a Linux NFS server, which turned | ||
| 21 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 22 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 23 | owns 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 | ||
| 24 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 25 | list where the're doing | ||
| 26 | bad computer history and insisting that a guy Larry Rosen | ||
| 27 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 28 | somethin…<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: | ||
| 29 | i2c, plan9 | ||
| 30 | Another month, another file system. | ||
| 31 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 32 | you, bme680, we’re not | ||
| 33 | done yet). The show must go on, as they say, and I would like my | ||
| 34 | experiments to go on. | ||
| 35 | So a “new” addition to the environmental sensor family connected to | ||
| 36 | the 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 | ||
| 37 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 38 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 39 | unique 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. | ||
| 40 | My 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 | ||
| 41 | 1.0 has been released: | ||
| 42 | wifi_da-1.0.sit | ||
| 43 | (StuffIt 3 archive) | ||
| 44 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 45 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 46 | classic 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. | ||
| 47 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 48 | Design Goals | ||
| 49 | I 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 | ||
| 50 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 51 | catch 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 | ||
| 52 | specified 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 | ||
| 10 | form 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 | ||
| 11 | game<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 | ||
| 12 | clicking with the mouse. Arrow keys work, though you can't move diagonally | ||
| 13 | with them. Pressing Shift and a direction will move until you see/hit | ||
| 14 | something.<li>Pressing <code>></code> will take you down a staircase, and <code><</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 | ||
| 15 | untrained).</ul><li>Attack monsters in melee by walking in their direction (or with | ||
| 16 | Ctrl-direction).<li>You can wait with <code>.</code> or <code>s</code>, passing your turn - such as to get monsters into | ||
| 17 | a corridor with you.<li>You can rest with <code>5</code>, waiting until you are fully healed, or something | ||
| 18 | noteworthy happens.<li>Either mouseover and rightclick, or use <code>x</code> then <code>v</code> on the monster to examine | ||
| 19 | monsters. Monsters with a red border are 'dangerous' relative to your current | ||
| 20 | XP 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 | ||
| 22 | launchers (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 | ||
| 23 | done with this menu.<li>You can wear amour with <code>W;</code> amour gives <code>AC</code>, while heavier body armour | ||
| 24 | reduces <code>EV</code>.<li>Autoexplore will automatically pick up useful items, such as potions and | ||
| 25 | scrolls, 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 | ||
| 26 | blue when unidentified.<li>Equipment items may be artifacts, often with unique properties, and are | ||
| 27 | unmodifiable. 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><</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 | ||
| 28 | addition 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 | ||
| 29 | also 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, | ||
| 30 | in 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><</code>). | ||
| 31 | After 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 | ||
| 32 | also 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 | ||
| 35 | usually very strong. Trog's Berserk gives you 1.5x health, 1.5x speed (to all | ||
| 36 | valid actions), and a big damage boost. Note that Berserk prevents most | ||
| 37 | actions other than move and melee attack, and runs out very quickly if you | ||
| 38 | aren't attacking. And after berserk ends, you are slowed down and can't | ||
| 39 | berserk again for a short time.<li>In addition, the vast majority of abilities consume piety in the process. | ||
| 40 | Regardless, this ability is very cheap, and the benefits are incredible, so | ||
| 41 | don'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 | ||
| 42 | a lock on a Linux NFS server, which turned | ||
| 43 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 44 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 45 | owns 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 | ||
| 46 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 47 | list where the're doing | ||
| 48 | bad computer history and insisting that a guy Larry Rosen | ||
| 49 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 50 | somethin…<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: | ||
| 51 | i2c, plan9 | ||
| 52 | Another month, another file system. | ||
| 53 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 54 | you, bme680, we’re not | ||
| 55 | done yet). The show must go on, as they say, and I would like my | ||
| 56 | experiments to go on. | ||
| 57 | So a “new” addition to the environmental sensor family connected to | ||
| 58 | the 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 | ||
| 59 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 60 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 61 | unique 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. | ||
| 62 | My 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 | ||
| 63 | 1.0 has been released: | ||
| 64 | wifi_da-1.0.sit | ||
| 65 | (StuffIt 3 archive) | ||
| 66 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 67 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 68 | classic 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. | ||
| 69 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 70 | Design Goals | ||
| 71 | I 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 | ||
| 72 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 73 | catch 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 | ||
| 74 | specified 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 | ||
| 10 | is 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 | ||
| 19 | Guide</a> | ||
| 20 | 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 | ||
| 21 | a lock on a Linux NFS server, which turned | ||
| 22 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 23 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 24 | owns 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 | ||
| 25 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 26 | list where the're doing | ||
| 27 | bad computer history and insisting that a guy Larry Rosen | ||
| 28 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 29 | somethin…<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: | ||
| 30 | i2c, plan9 | ||
| 31 | Another month, another file system. | ||
| 32 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 33 | you, bme680, we’re not | ||
| 34 | done yet). The show must go on, as they say, and I would like my | ||
| 35 | experiments to go on. | ||
| 36 | So a “new” addition to the environmental sensor family connected to | ||
| 37 | the 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 | ||
| 38 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 39 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 40 | unique 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. | ||
| 41 | My 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 | ||
| 42 | 1.0 has been released: | ||
| 43 | wifi_da-1.0.sit | ||
| 44 | (StuffIt 3 archive) | ||
| 45 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 46 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 47 | classic 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. | ||
| 48 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 49 | Design Goals | ||
| 50 | I 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 | ||
| 51 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 52 | catch 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 | ||
| 53 | specified 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 | ||
| 10 | used <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 | ||
| 12 | some 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 | ||
| 13 | having them be stable than run bleeding edge rolling release. For that reason, I | ||
| 14 | stuck with Ubuntu for a couple of years now. I am also at a point in my life | ||
| 15 | where I just don't care what is cool or hip anymore. I just want a stable system | ||
| 16 | that doesn't get in my way.<p>During all this, I noticed that these distributions were getting very bloated | ||
| 17 | and a lot of software got included that I usually uninstall on fresh | ||
| 18 | installation. Maybe this is my OCD speaking, but why do I have to give fresh | ||
| 19 | installation min 1 GB of ram out of the box just to have a blank screen in front | ||
| 20 | of me? I get it, there are many things included in the distro to make my life | ||
| 21 | easier. I understand. But at this point I have a feeling that modern Linux | ||
| 22 | distributions are becoming similar to <a href=https://devhumor.com/content/uploads/images/August2017/node-modules.jpg>Node.js project with | ||
| 23 | node_modules</a>. | ||
| 24 | Just a crazy number of packages serving very little or no purpose, just | ||
| 25 | supporting other software.<p>I felt I needed a fresh start. To start over with something minimal and clean. | ||
| 26 | Something 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 | ||
| 27 | that 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 | ||
| 38 | start. No reason to go through changing the installer and also testing all that | ||
| 39 | behemoth of a thing. So, some sort of ricing was the only logical option to get | ||
| 40 | this thing of the grounds somewhat quickly.<blockquote><p><strong>What is ricing anyway?</strong> | ||
| 41 | The term “RICE” stands for Race Inspired Cosmetic Enhancement. A group of | ||
| 42 | people (could be one, idk) decided to see if they could tweak their own | ||
| 43 | distros like they/others did their cars. This gave rise to a community of | ||
| 44 | Linux/Unix enthusiasts trying to make their distros look cooler and better | ||
| 45 | than 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 | ||
| 47 | wanted this to include a set of pre-installed tools and services that are being | ||
| 48 | used all the time by a modern developer. Theming is just a tiny part of it. | ||
| 49 | Fonts being applied across the distro and things like that.<p>First, I choose terminal installer and left it to load additional components. | ||
| 50 | Avoid 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 | ||
| 51 | that 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 | ||
| 52 | out of scanning additional media for use by the package manager. Those will be | ||
| 53 | downloaded 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>. | ||
| 54 | Uncheck all the boxes in Software selection and only leave 'standard system | ||
| 55 | utilities'. I also left an SSH server, so I was able to log in to the machine | ||
| 56 | from 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 | ||
| 57 | system.<figure><img src=/posts/dfd-rice/install-04.png alt></figure><p>That concluded the installation of base Debian and after restarting the computer | ||
| 58 | I 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 | ||
| 59 | want to include in this so-called distribution. I wanted out of the box | ||
| 60 | developer 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 | ||
| 61 | version 2 forward. It's been quite a ride. I hated version 3 when it came out | ||
| 62 | and replaced version 2. But I got used to it. And now with version 40+ they also | ||
| 63 | made 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 | ||
| 64 | windows 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 | ||
| 66 | 100px deep. Vertical space is one of the most important things for a | ||
| 67 | developer. The more real estate you have, the more code you can have in a | ||
| 68 | viewport.<p>But on the other hand, I still love how Gnome feels and looks. I gotta give them | ||
| 69 | that. 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 | ||
| 70 | managers for some time, but never had the nerve to actually go with it. But now | ||
| 71 | was 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 | ||
| 72 | strange monitor with aspect ratio of 32:9. So relying on included layouts most | ||
| 73 | of them have is a non-starter.<p>What I was doing in Gnome was having windows in a layout like the diagram | ||
| 74 | below. This is my common practice. And if you look at it you can clearly see I | ||
| 75 | was 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 | ||
| 76 | out. 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 | ||
| 77 | Linux</a> I was | ||
| 78 | referencing while testing them out.<p>While all of them provided what I needed, I liked i3 the most. What particular | ||
| 79 | caught my eye was the ease to use and tree based layouts which allows flexible | ||
| 80 | layouts. 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 | ||
| 81 | somebody 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: | ||
| 83 | essentials 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>"</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>"</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 | ||
| 87 | me since I never use bleeding edge features of a package. But if something major | ||
| 88 | would come to light, I will replace it with a possible compilation script or | ||
| 89 | something 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>"Installing Docker"</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>"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"</span> | tee /etc/apt/sources.list.d/docker.list > /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 | ||
| 102 | I used it, I constantly needed to be aware of it and running bash scripts was a | ||
| 103 | pain. So, I was really delighted when I found out that a version for bash | ||
| 104 | existed called <a href=https://ohmybash.nntoan.com/>Oh My Bash</a>. Let's take a look at | ||
| 105 | the 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>"Enabling OhMyBash"</span> | ||
| 107 | </span></span><span style=display:flex><span>sudo -u $USERNAME sh -c <span style=color:#a31515>"</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>"</span> & | ||
| 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 | ||
| 111 | another shell and our script cannot continue. For that reason, I executed this | ||
| 112 | in background. But that presents a new problem. Because this is executed in | ||
| 113 | background, 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 | ||
| 115 | continuing 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> | ||
| 116 | for 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 | ||
| 118 | to get familiar with it. This is just a first iteration and I will continue to | ||
| 119 | update 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 | ||
| 120 | desktop environment loads in 2s. So, its fast, very fast. And on clean boot, I | ||
| 121 | measured ~230 MB of RAM usage.<p>And this is how it looks with two terminals side by side. I really like the | ||
| 122 | simplicity and clean interface. I will polish the colors and stuff like that, | ||
| 123 | but 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 | ||
| 124 | a lock on a Linux NFS server, which turned | ||
| 125 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 126 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 127 | owns 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 | ||
| 128 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 129 | list where the're doing | ||
| 130 | bad computer history and insisting that a guy Larry Rosen | ||
| 131 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 132 | somethin…<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: | ||
| 133 | i2c, plan9 | ||
| 134 | Another month, another file system. | ||
| 135 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 136 | you, bme680, we’re not | ||
| 137 | done yet). The show must go on, as they say, and I would like my | ||
| 138 | experiments to go on. | ||
| 139 | So a “new” addition to the environmental sensor family connected to | ||
| 140 | the 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 | ||
| 141 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 142 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 143 | unique 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. | ||
| 144 | My 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 | ||
| 145 | 1.0 has been released: | ||
| 146 | wifi_da-1.0.sit | ||
| 147 | (StuffIt 3 archive) | ||
| 148 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 149 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 150 | classic 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. | ||
| 151 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 152 | Design Goals | ||
| 153 | I 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 | ||
| 154 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 155 | catch 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 | ||
| 156 | specified 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 | ||
| 10 | manager</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 | ||
| 11 | be 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><nixpkgs></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 | ||
| 19 | you 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 | ||
| 20 | overwritten and your prompt will look differently. In that case you need to | ||
| 21 | either 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 | ||
| 23 | to <code>1</code>.<p>I also have a modified <code>PS1</code> prompt for Bash that I use and it also catches the | ||
| 24 | usage 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> /dev/null | sed -e <span style=color:#a31515>'/^[^*]/d'</span> -e <span style=color:#a31515>'s/* \(.*\)/ (\1)/'</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>"</span><span style=color:#00f>$(</span>basename <span style=color:#a31515>"</span>$IN_NIX_SHELL<span style=color:#a31515>"</span> 2>/dev/null<span style=color:#00f>)</span><span style=color:#a31515>"</span> | ||
| 32 | </span></span><span style=display:flex><span> <span style=color:#00f>if</span> [[ -n <span style=color:#a31515>"</span>$nix_shell_name<span style=color:#a31515>"</span> ]]; <span style=color:#00f>then</span> | ||
| 33 | </span></span><span style=display:flex><span> echo <span style=color:#a31515>" \e[0;36m(nix-shell)\e[0m"</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>"[\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> "</span> | ||
| 38 | </span></span></code></pre><p>And this is what it looks like when you are in a Nix shell. Otherwise that part | ||
| 39 | of 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 | ||
| 40 | a lock on a Linux NFS server, which turned | ||
| 41 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 42 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 43 | owns 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 | ||
| 44 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 45 | list where the're doing | ||
| 46 | bad computer history and insisting that a guy Larry Rosen | ||
| 47 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 48 | somethin…<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: | ||
| 49 | i2c, plan9 | ||
| 50 | Another month, another file system. | ||
| 51 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 52 | you, bme680, we’re not | ||
| 53 | done yet). The show must go on, as they say, and I would like my | ||
| 54 | experiments to go on. | ||
| 55 | So a “new” addition to the environmental sensor family connected to | ||
| 56 | the 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 | ||
| 57 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 58 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 59 | unique 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. | ||
| 60 | My 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 | ||
| 61 | 1.0 has been released: | ||
| 62 | wifi_da-1.0.sit | ||
| 63 | (StuffIt 3 archive) | ||
| 64 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 65 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 66 | classic 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. | ||
| 67 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 68 | Design Goals | ||
| 69 | I 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 | ||
| 70 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 71 | catch 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 | ||
| 72 | specified 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&#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&#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> | ||
| 10 | now and I-ve became so used to it that it runs in the background that I don't | ||
| 11 | even 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 | ||
| 12 | solution for excluding synchronization for this folder was to manually exclude a | ||
| 13 | specific folder which is not really scalable. FYI, my whole project folder is | ||
| 14 | synced on <a href=https://www.dropbox.com/>Dropbox</a>. This of course introduced a lot | ||
| 15 | of syncing of files and folders that are not needed or even break things on | ||
| 16 | other machines. In the case of <strong>Python</strong>, I couldn't use that on my second | ||
| 17 | machine. I needed to delete <code>.venv</code> folder and pip it again which synced files | ||
| 18 | again to the main machine. This was very frustrating. <strong>Nodejs</strong> handles this | ||
| 19 | much nicer and I can just run the scripts without deleting <code>node_modules</code> again | ||
| 20 | and reinstalling. However, <code>node_modules</code> is a beast of its own. It creates so | ||
| 21 | many files that OS has a problem counting them when you check the folder | ||
| 22 | contents for size.<p>I wanted something similar to Dropbox. I could without the instant syncing but | ||
| 23 | it 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> | ||
| 25 | and 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 | ||
| 26 | drive</a> or <a href=https://onedrive.live.com/>One drive</a> | ||
| 27 | since they are even more draconian than Dropbox.<blockquote><p>All this does not stem from me being paranoid but recently these companies | ||
| 28 | have became more and more aggressive and they keep violating our privacy when | ||
| 29 | they 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 | ||
| 30 | syncing. And before we go into "<em>But you have git, isn't that enough?</em>", I must | ||
| 31 | say, that many of the files (PDFs, spreadsheets, etc) I have in a <code>git</code> repo | ||
| 32 | don't get pushed upstream to Git and I still want to have them synced across my | ||
| 33 | computers.<p>I initially wanted to use <a href=https://linux.die.net/man/1/rsync>rsync</a> but I would | ||
| 34 | need to then have a remote VPS or transfer between my computers directly. I | ||
| 35 | wanted a solution where all my files could be accessible to me without my | ||
| 36 | machine.<blockquote><p><strong>WARNING: This solution will cost you money!</strong> DigitalOcean Spaces are $5 per | ||
| 37 | month and there are some bandwidth limitations and if you go beyond that you get | ||
| 38 | billed 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 | ||
| 40 | fully managed. I didn't want to go down the AWS rabbit hole with this so I | ||
| 41 | choose <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 | ||
| 42 | this nice tool <a href=https://s3tools.org/s3cmd>s3cmd</a> and it is in the Ubuntu | ||
| 43 | repositories.<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 | ||
| 45 | the 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 & | ||
| 47 | API</a> and generated <strong>Spaces | ||
| 48 | access keys</strong>. Save both key and secret somewhere safe because when you will | ||
| 49 | leave the page secret will not be available anymore to you and you will need to | ||
| 50 | re-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 | ||
| 55 | command.<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>'node_modules/*'</span> --exclude <span style=color:#a31515>'.git/*'</span> --exclude <span style=color:#a31515>'.venv/*'</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 | ||
| 60 | are directories.</blockquote><p>I am planning to implement some sort of a <code>.ignore</code> file that will enable me to | ||
| 61 | have a project-specific exclude options.<p>I am currently running this every hour as a cronjob which is perfectly fine for | ||
| 62 | now 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 | ||
| 63 | when/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 | ||
| 64 | a lock on a Linux NFS server, which turned | ||
| 65 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 66 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 67 | owns 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 | ||
| 68 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 69 | list where the're doing | ||
| 70 | bad computer history and insisting that a guy Larry Rosen | ||
| 71 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 72 | somethin…<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: | ||
| 73 | i2c, plan9 | ||
| 74 | Another month, another file system. | ||
| 75 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 76 | you, bme680, we’re not | ||
| 77 | done yet). The show must go on, as they say, and I would like my | ||
| 78 | experiments to go on. | ||
| 79 | So a “new” addition to the environmental sensor family connected to | ||
| 80 | the 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 | ||
| 81 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 82 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 83 | unique 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. | ||
| 84 | My 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 | ||
| 85 | 1.0 has been released: | ||
| 86 | wifi_da-1.0.sit | ||
| 87 | (StuffIt 3 archive) | ||
| 88 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 89 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 90 | classic 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. | ||
| 91 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 92 | Design Goals | ||
| 93 | I 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 | ||
| 94 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 95 | catch 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 | ||
| 96 | specified 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 | ||
| 10 | X220</a> just as a | ||
| 11 | joke on eBay to test Linux distributions and play around with things and not | ||
| 12 | destroy my main machine. Little to my knowledge I felt in love with it. Man, | ||
| 13 | they really made awesome machines back then.<p>After changing disk that came with it to SSD and installing Ubuntu to test if | ||
| 14 | everything works I noticed that even after a single touch of my external mouse | ||
| 15 | the 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&h=262">LED | ||
| 16 | sleep indicator</a>. | ||
| 17 | I 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 | ||
| 19 | with a touchscreen and while traveling it decided to wake up and started cooking | ||
| 20 | in my backpack to the point that the digitizer responsible for touch actually | ||
| 21 | glue 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 | ||
| 22 | specific devices to perform wake up. Why is this not under the power management | ||
| 23 | tab 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 | ||
| 24 | solution</a> | ||
| 25 | that worked for me. The only problem with this solution was that he added his | ||
| 26 | solution to <code>.bashrc</code> and this triggers <code>sudo</code> that asks for a password each | ||
| 27 | time new terminal is opened, which get annoying quickly since I open a lot of | ||
| 28 | terminals 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 | ||
| 29 | replaced <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 "echo 'disabled' > /sys/bus/usb/devices/2-1.1/power/wakeup"</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. | ||
| 47 | If you have many devices you would like to surpress from waking up your machine | ||
| 48 | I would create a shell script and call that instead of direclty doing it in | ||
| 49 | service 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 | ||
| 50 | a lock on a Linux NFS server, which turned | ||
| 51 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 52 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 53 | owns 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 | ||
| 54 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 55 | list where the're doing | ||
| 56 | bad computer history and insisting that a guy Larry Rosen | ||
| 57 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 58 | somethin…<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: | ||
| 59 | i2c, plan9 | ||
| 60 | Another month, another file system. | ||
| 61 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 62 | you, bme680, we’re not | ||
| 63 | done yet). The show must go on, as they say, and I would like my | ||
| 64 | experiments to go on. | ||
| 65 | So a “new” addition to the environmental sensor family connected to | ||
| 66 | the 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 | ||
| 67 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 68 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 69 | unique 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. | ||
| 70 | My 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 | ||
| 71 | 1.0 has been released: | ||
| 72 | wifi_da-1.0.sit | ||
| 73 | (StuffIt 3 archive) | ||
| 74 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 75 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 76 | classic 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. | ||
| 77 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 78 | Design Goals | ||
| 79 | I 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 | ||
| 80 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 81 | catch 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 | ||
| 82 | specified 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&#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 | ||
| 10 | actual 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's from YouTube's video tab'. | ||
| 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>'#contents a.ytd-thumbnail.style-scope.ytd-thumbnail'</span>).forEach(el => 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 | ||
| 16 | a lock on a Linux NFS server, which turned | ||
| 17 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 18 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 19 | owns 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 | ||
| 20 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 21 | list where the're doing | ||
| 22 | bad computer history and insisting that a guy Larry Rosen | ||
| 23 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 24 | somethin…<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: | ||
| 25 | i2c, plan9 | ||
| 26 | Another month, another file system. | ||
| 27 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 28 | you, bme680, we’re not | ||
| 29 | done yet). The show must go on, as they say, and I would like my | ||
| 30 | experiments to go on. | ||
| 31 | So a “new” addition to the environmental sensor family connected to | ||
| 32 | the 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 | ||
| 33 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 34 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 35 | unique 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. | ||
| 36 | My 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 | ||
| 37 | 1.0 has been released: | ||
| 38 | wifi_da-1.0.sit | ||
| 39 | (StuffIt 3 archive) | ||
| 40 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 41 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 42 | classic 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. | ||
| 43 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 44 | Design Goals | ||
| 45 | I 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 | ||
| 46 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 47 | catch 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 | ||
| 48 | specified 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&#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 | ||
| 10 | alternative 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> | ||
| 11 | contains all the drawing functions<li><a href=https://9fans.github.io/plan9port/man/man3/draw.html>draw man page</a> | ||
| 12 | has 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> | ||
| 13 | has a bit more digestable descriptions of the graphics functions<li><a href=https://9fans.github.io/plan9port/man/man3/>all man pages</a> | ||
| 14 | can 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><u.h></span><span style=color:#00f> | ||
| 16 | </span></span></span><span style=display:flex><span><span style=color:#00f>#include</span> <span style=color:#00f><libc.h></span><span style=color:#00f> | ||
| 17 | </span></span></span><span style=display:flex><span><span style=color:#00f>#include</span> <span style=color:#00f><draw.h></span><span style=color:#00f> | ||
| 18 | </span></span></span><span style=display:flex><span><span style=color:#00f>#include</span> <span style=color:#00f><cursor.h></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) < 0) | ||
| 28 | </span></span><span style=display:flex><span> { | ||
| 29 | </span></span><span style=display:flex><span> sysfatal(<span style=color:#a31515>"%s: %r"</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>"not enough memory"</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->r, bg, nil, ZP); | ||
| 41 | </span></span><span style=display:flex><span> draw(screen, screen->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></$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 | ||
| 61 | is 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 | ||
| 62 | a lock on a Linux NFS server, which turned | ||
| 63 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 64 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 65 | owns 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 | ||
| 66 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 67 | list where the're doing | ||
| 68 | bad computer history and insisting that a guy Larry Rosen | ||
| 69 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 70 | somethin…<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: | ||
| 71 | i2c, plan9 | ||
| 72 | Another month, another file system. | ||
| 73 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 74 | you, bme680, we’re not | ||
| 75 | done yet). The show must go on, as they say, and I would like my | ||
| 76 | experiments to go on. | ||
| 77 | So a “new” addition to the environmental sensor family connected to | ||
| 78 | the 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 | ||
| 79 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 80 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 81 | unique 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. | ||
| 82 | My 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 | ||
| 83 | 1.0 has been released: | ||
| 84 | wifi_da-1.0.sit | ||
| 85 | (StuffIt 3 archive) | ||
| 86 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 87 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 88 | classic 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. | ||
| 89 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 90 | Design Goals | ||
| 91 | I 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 | ||
| 92 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 93 | catch 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 | ||
| 94 | specified 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 | ||
| 10 | track of the number of seconds since the current shell or script started | ||
| 11 | executing. 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>"Time taken: </span>$SECONDS<span style=color:#a31515> seconds"</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 | ||
| 22 | a lock on a Linux NFS server, which turned | ||
| 23 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 24 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 25 | owns 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 | ||
| 26 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 27 | list where the're doing | ||
| 28 | bad computer history and insisting that a guy Larry Rosen | ||
| 29 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 30 | somethin…<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: | ||
| 31 | i2c, plan9 | ||
| 32 | Another month, another file system. | ||
| 33 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 34 | you, bme680, we’re not | ||
| 35 | done yet). The show must go on, as they say, and I would like my | ||
| 36 | experiments to go on. | ||
| 37 | So a “new” addition to the environmental sensor family connected to | ||
| 38 | the 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 | ||
| 39 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 40 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 41 | unique 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. | ||
| 42 | My 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 | ||
| 43 | 1.0 has been released: | ||
| 44 | wifi_da-1.0.sit | ||
| 45 | (StuffIt 3 archive) | ||
| 46 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 47 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 48 | classic 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. | ||
| 49 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 50 | Design Goals | ||
| 51 | I 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 | ||
| 52 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 53 | catch 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 | ||
| 54 | specified 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 | ||
| 10 | it through your personal DNA sequencer and get data like music, videos or | ||
| 11 | computer programs from it. Well, this is all possible now. It was not done on a | ||
| 12 | large scale because it is quite expensive to create DNA strands but it's | ||
| 13 | possible.<p>Encoding data into DNA sequence is relatively simple process once you understand | ||
| 14 | the relationship between binary data and nucleotides and scientists have been | ||
| 15 | making large leaps in this field in order to provide viable long-term storage | ||
| 16 | solution for our data that would potentially survive our specie if case of | ||
| 17 | global disaster. We could imprint all the world's knowledge into plants and | ||
| 18 | ensure the survival of our knowledge.<p>More optimistic usage for this technology would be easier storage of ever | ||
| 19 | growing data we produce every day. Once machines for sequencing DNA become fast | ||
| 20 | enough and cheaper this could mean the next evolution of storing data and | ||
| 21 | abandoning 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 | ||
| 22 | cool technology.<p>My interests in this field are purely in encoding processes and experimental | ||
| 23 | testing mainly because I don't have the access to this expensive machines. My | ||
| 24 | initial goal was to create a toolkit that can be used by everybody to encode | ||
| 25 | their 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 | ||
| 26 | hydroxyl 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 | ||
| 27 | wind around each other in a spiral shape.<p><strong>nitrogenous base</strong> A nitrogen-containing molecule that acts as a base; often | ||
| 28 | referring 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 | ||
| 29 | bound to four oxygen atoms.<p><strong>RGB</strong> The RGB color model is an additive color model in which red, green and | ||
| 30 | blue light are added together in various ways to reproduce a broad array of | ||
| 31 | colors.<p><strong>GCC</strong> The GNU Compiler Collection is a compiler system produced by the GNU | ||
| 32 | Project 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 | ||
| 33 | form that can be used by an external process.<p>Encoding is the process of converting data into a format required for a number | ||
| 34 | of 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, | ||
| 35 | such as letters, symbols and numbers, to data for conversion into an | ||
| 36 | equivalent 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 | ||
| 37 | all 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, | ||
| 39 | the carbon in our apple pies were made in the interiors of collapsing stars. | ||
| 40 | We 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. | ||
| 43 | Cytosine and thymine are pyrimidine bases, while adenine and guanine are purine | ||
| 44 | bases. 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 | ||
| 45 | cytosine pairs with guanine. (credit a: modification of work by Jerome Walker, | ||
| 46 | Dennis 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 | ||
| 47 | could 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 | ||
| 48 | is composed of 4 nucleotides (Adenine, Cytosine, Guanine, Thymine; usually | ||
| 49 | referred 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 | ||
| 50 | compose 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 | ||
| 51 | conversion.<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>'08b'</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>'A'</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>'G'</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>'C'</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>'T'</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 | ||
| 70 | Nonsense mutation (amino acids replaced by a stop codon) that occurs and is the | ||
| 71 | most problematic during translation because it leads to truncated amino acid | ||
| 72 | sequences, 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 | ||
| 73 | nucleotide sequences or peptide sequences, in which nucleotides or amino acids | ||
| 74 | are represented using single-letter codes. The format also allows for sequence | ||
| 75 | names and comments to precede the sequences. The format originates from the | ||
| 76 | FASTA software package, but has now become a standard in the field of | ||
| 77 | bioinformatics.<p>The first line in a FASTA file started either with a ">" (greater-than) symbol | ||
| 78 | or, less frequently, a ";" (semicolon) was taken as a comment. Subsequent lines | ||
| 79 | starting with a semicolon would be ignored by software. Since the only comment | ||
| 80 | used was the first, it quickly became used to hold a summary description of the | ||
| 81 | sequence, often starting with a unique library accession number, and with time | ||
| 82 | it 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>>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>>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> | ||
| 102 | format 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 | ||
| 103 | of 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>'A'</span>: color := RGB(0, 0, 255) { Blue } | ||
| 111 | </span></span><span style=display:flex><span> <span style=color:#a31515>'G'</span>: color := RGB(0, 100, 0) { Green } | ||
| 112 | </span></span><span style=display:flex><span> <span style=color:#a31515>'C'</span>: color := RGB(255, 0, 0) { Red } | ||
| 113 | </span></span><span style=display:flex><span> <span style=color:#a31515>'T'</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 | ||
| 118 | encoding. 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 | ||
| 119 | making 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>>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 | ||
| 148 | like</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><stdio.h></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>"Hello, world!</span><span style=color:#a31515>\n</span><span style=color:#a31515>"</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>> ./dnae-encode --help | ||
| 157 | </span></span><span style=display:flex><span>usage: dnae-encode --input=INPUT [<flags>] | ||
| 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>"out.fa"</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>> ./dnae-png --help | ||
| 169 | </span></span><span style=display:flex><span>usage: dnae-png --input=INPUT [<flags>] | ||
| 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>"out.png"</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>=<(openssl enc -aes-256-ctr -pass pass:<span style=color:#a31515>"</span><span style=color:#00f>$(</span>dd <span style=color:#00f>if</span>=/dev/urandom bs=128 count=1 2>/dev/null | base64<span style=color:#00f>)</span><span style=color:#a31515>"</span> -nosalt < /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 | ||
| 181 | garbage 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 | ||
| 182 | into 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 < 10MB.fa > 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 | ||
| 185 | a lock on a Linux NFS server, which turned | ||
| 186 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 187 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 188 | owns 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 | ||
| 189 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 190 | list where the're doing | ||
| 191 | bad computer history and insisting that a guy Larry Rosen | ||
| 192 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 193 | somethin…<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: | ||
| 194 | i2c, plan9 | ||
| 195 | Another month, another file system. | ||
| 196 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 197 | you, bme680, we’re not | ||
| 198 | done yet). The show must go on, as they say, and I would like my | ||
| 199 | experiments to go on. | ||
| 200 | So a “new” addition to the environmental sensor family connected to | ||
| 201 | the 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 | ||
| 202 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 203 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 204 | unique 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. | ||
| 205 | My 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 | ||
| 206 | 1.0 has been released: | ||
| 207 | wifi_da-1.0.sit | ||
| 208 | (StuffIt 3 archive) | ||
| 209 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 210 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 211 | classic 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. | ||
| 212 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 213 | Design Goals | ||
| 214 | I 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 | ||
| 215 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 216 | catch 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 | ||
| 217 | specified 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 | ||
| 12 | around 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> | ||
| 13 | but I could easily choose | ||
| 14 | <a href=https://www.espressif.com/en/products/socs/esp8266>ESP8266</a>. This guide | ||
| 15 | contains 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 | ||
| 17 | mine 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 | ||
| 18 | executing <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> | ||
| 19 | group. 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> | ||
| 22 | and 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 | ||
| 27 | board.<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 | ||
| 33 | REPL.</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>> <span style=color:#00f>import</span> machine | ||
| 34 | </span></span><span style=display:flex><span>> 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 | ||
| 37 | that 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 | ||
| 48 | much 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 | ||
| 52 | commands. You can check what is supported with <code>help</code> once you are inside of a | ||
| 53 | shell.<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> help | ||
| 66 | </span></span><span style=display:flex><span> | ||
| 67 | </span></span><span style=display:flex><span>Documented commands (type help <topic>): | ||
| 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 | ||
| 74 | of files on flash folder <code>/pyboard</code> is remapped inside the shell. To list files | ||
| 75 | on 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 | ||
| 78 | there 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 | ||
| 79 | device.<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>> 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 | ||
| 94 | a lock on a Linux NFS server, which turned | ||
| 95 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 96 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 97 | owns 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 | ||
| 98 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 99 | list where the're doing | ||
| 100 | bad computer history and insisting that a guy Larry Rosen | ||
| 101 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 102 | somethin…<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: | ||
| 103 | i2c, plan9 | ||
| 104 | Another month, another file system. | ||
| 105 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 106 | you, bme680, we’re not | ||
| 107 | done yet). The show must go on, as they say, and I would like my | ||
| 108 | experiments to go on. | ||
| 109 | So a “new” addition to the environmental sensor family connected to | ||
| 110 | the 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 | ||
| 111 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 112 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 113 | unique 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. | ||
| 114 | My 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 | ||
| 115 | 1.0 has been released: | ||
| 116 | wifi_da-1.0.sit | ||
| 117 | (StuffIt 3 archive) | ||
| 118 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 119 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 120 | classic 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. | ||
| 121 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 122 | Design Goals | ||
| 123 | I 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 | ||
| 124 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 125 | catch 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 | ||
| 126 | specified 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 | ||
| 10 | available online at the University of Texas at Austin website, but I also found | ||
| 11 | MOBI 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 | ||
| 12 | a lock on a Linux NFS server, which turned | ||
| 13 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 14 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 15 | owns 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 | ||
| 16 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 17 | list where the're doing | ||
| 18 | bad computer history and insisting that a guy Larry Rosen | ||
| 19 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 20 | somethin…<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: | ||
| 21 | i2c, plan9 | ||
| 22 | Another month, another file system. | ||
| 23 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 24 | you, bme680, we’re not | ||
| 25 | done yet). The show must go on, as they say, and I would like my | ||
| 26 | experiments to go on. | ||
| 27 | So a “new” addition to the environmental sensor family connected to | ||
| 28 | the 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 | ||
| 29 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 30 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 31 | unique 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. | ||
| 32 | My 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 | ||
| 33 | 1.0 has been released: | ||
| 34 | wifi_da-1.0.sit | ||
| 35 | (StuffIt 3 archive) | ||
| 36 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 37 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 38 | classic 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. | ||
| 39 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 40 | Design Goals | ||
| 41 | I 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 | ||
| 42 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 43 | catch 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 | ||
| 44 | specified 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 | ||
| 10 | Clang and Lua 5.1 to be installed. GCC can be used instead of Clang, but the | ||
| 11 | Makefile 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><lua.h></span><span style=color:#00f> | ||
| 12 | </span></span></span><span style=display:flex><span><span style=color:#00f>#include</span> <span style=color:#00f><lauxlib.h></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>"mult50"</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>"nativelib"</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>"nativefunc"</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 | ||
| 38 | a lock on a Linux NFS server, which turned | ||
| 39 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 40 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 41 | owns 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 | ||
| 42 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 43 | list where the're doing | ||
| 44 | bad computer history and insisting that a guy Larry Rosen | ||
| 45 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 46 | somethin…<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: | ||
| 47 | i2c, plan9 | ||
| 48 | Another month, another file system. | ||
| 49 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 50 | you, bme680, we’re not | ||
| 51 | done yet). The show must go on, as they say, and I would like my | ||
| 52 | experiments to go on. | ||
| 53 | So a “new” addition to the environmental sensor family connected to | ||
| 54 | the 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 | ||
| 55 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 56 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 57 | unique 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. | ||
| 58 | My 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 | ||
| 59 | 1.0 has been released: | ||
| 60 | wifi_da-1.0.sit | ||
| 61 | (StuffIt 3 archive) | ||
| 62 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 63 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 64 | classic 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. | ||
| 65 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 66 | Design Goals | ||
| 67 | I 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 | ||
| 68 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 69 | catch 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 | ||
| 70 | specified 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 | ||
| 10 | using 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 | ||
| 12 | needed comment/uncomment feature so I created a small utility that does this for | ||
| 13 | me. Code lives on repository <a href=https://git.mitjafelicijan.com/dte-extensions.git/about/>dte | ||
| 14 | extensions</a> but this | ||
| 15 | utilities can be used for whatever you want. Make sure you have version 1.11 or | ||
| 16 | above.<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>'exec -s -i line -o buffer -e errmsg ~/.dte/bin/comment'</span> | ||
| 22 | </span></span><span style=display:flex><span>alias m_format <span style=color:#a31515>'save; exec go fmt .; reload'</span> | ||
| 23 | </span></span><span style=display:flex><span>alias m_duplicate <span style=color:#a31515>'copy;paste'</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>'quit -f'</span>; | ||
| 27 | </span></span><span style=display:flex><span>alias m_reload <span style=color:#a31515>'close; open $FILE'</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 | ||
| 45 | a lock on a Linux NFS server, which turned | ||
| 46 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 47 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 48 | owns 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 | ||
| 49 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 50 | list where the're doing | ||
| 51 | bad computer history and insisting that a guy Larry Rosen | ||
| 52 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 53 | somethin…<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: | ||
| 54 | i2c, plan9 | ||
| 55 | Another month, another file system. | ||
| 56 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 57 | you, bme680, we’re not | ||
| 58 | done yet). The show must go on, as they say, and I would like my | ||
| 59 | experiments to go on. | ||
| 60 | So a “new” addition to the environmental sensor family connected to | ||
| 61 | the 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 | ||
| 62 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 63 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 64 | unique 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. | ||
| 65 | My 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 | ||
| 66 | 1.0 has been released: | ||
| 67 | wifi_da-1.0.sit | ||
| 68 | (StuffIt 3 archive) | ||
| 69 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 70 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 71 | classic 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. | ||
| 72 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 73 | Design Goals | ||
| 74 | I 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 | ||
| 75 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 76 | catch 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 | ||
| 77 | specified 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 | ||
| 10 | harware 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'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 </dev/zero >/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 | ||
| 16 | a lock on a Linux NFS server, which turned | ||
| 17 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 18 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 19 | owns 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 | ||
| 20 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 21 | list where the're doing | ||
| 22 | bad computer history and insisting that a guy Larry Rosen | ||
| 23 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 24 | somethin…<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: | ||
| 25 | i2c, plan9 | ||
| 26 | Another month, another file system. | ||
| 27 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 28 | you, bme680, we’re not | ||
| 29 | done yet). The show must go on, as they say, and I would like my | ||
| 30 | experiments to go on. | ||
| 31 | So a “new” addition to the environmental sensor family connected to | ||
| 32 | the 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 | ||
| 33 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 34 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 35 | unique 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. | ||
| 36 | My 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 | ||
| 37 | 1.0 has been released: | ||
| 38 | wifi_da-1.0.sit | ||
| 39 | (StuffIt 3 archive) | ||
| 40 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 41 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 42 | classic 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. | ||
| 43 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 44 | Design Goals | ||
| 45 | I 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 | ||
| 46 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 47 | catch 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 | ||
| 48 | specified 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 | ||
| 10 | under Debian 12 with Xorg and i3. Using <code>picom</code> compositor didn't help. To fix | ||
| 11 | this issue create new file <code>/etc/X11/xorg.conf.d/20-intel.conf</code> as root and put | ||
| 12 | the following in the file.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>Section "Device" | ||
| 13 | </span></span><span style=display:flex><span> Identifier "Intel Graphics" | ||
| 14 | </span></span><span style=display:flex><span> Driver "intel" | ||
| 15 | </span></span><span style=display:flex><span> Option "TearFree" "true" | ||
| 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 | ||
| 18 | a lock on a Linux NFS server, which turned | ||
| 19 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 20 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 21 | owns 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 | ||
| 22 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 23 | list where the're doing | ||
| 24 | bad computer history and insisting that a guy Larry Rosen | ||
| 25 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 26 | somethin…<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: | ||
| 27 | i2c, plan9 | ||
| 28 | Another month, another file system. | ||
| 29 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 30 | you, bme680, we’re not | ||
| 31 | done yet). The show must go on, as they say, and I would like my | ||
| 32 | experiments to go on. | ||
| 33 | So a “new” addition to the environmental sensor family connected to | ||
| 34 | the 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 | ||
| 35 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 36 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 37 | unique 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. | ||
| 38 | My 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 | ||
| 39 | 1.0 has been released: | ||
| 40 | wifi_da-1.0.sit | ||
| 41 | (StuffIt 3 archive) | ||
| 42 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 43 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 44 | classic 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. | ||
| 45 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 46 | Design Goals | ||
| 47 | I 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 | ||
| 48 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 49 | catch 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 | ||
| 50 | specified 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 | ||
| 10 | a lock on a Linux NFS server, which turned | ||
| 11 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 12 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 13 | owns 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 | ||
| 14 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 15 | list where the're doing | ||
| 16 | bad computer history and insisting that a guy Larry Rosen | ||
| 17 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 18 | somethin…<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: | ||
| 19 | i2c, plan9 | ||
| 20 | Another month, another file system. | ||
| 21 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 22 | you, bme680, we’re not | ||
| 23 | done yet). The show must go on, as they say, and I would like my | ||
| 24 | experiments to go on. | ||
| 25 | So a “new” addition to the environmental sensor family connected to | ||
| 26 | the 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 | ||
| 27 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 28 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 29 | unique 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. | ||
| 30 | My 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 | ||
| 31 | 1.0 has been released: | ||
| 32 | wifi_da-1.0.sit | ||
| 33 | (StuffIt 3 archive) | ||
| 34 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 35 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 36 | classic 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. | ||
| 37 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 38 | Design Goals | ||
| 39 | I 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 | ||
| 40 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 41 | catch 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 | ||
| 42 | specified 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 | ||
| 10 | my 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 | ||
| 11 | a lock on a Linux NFS server, which turned | ||
| 12 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 13 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 14 | owns 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 | ||
| 15 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 16 | list where the're doing | ||
| 17 | bad computer history and insisting that a guy Larry Rosen | ||
| 18 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 19 | somethin…<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: | ||
| 20 | i2c, plan9 | ||
| 21 | Another month, another file system. | ||
| 22 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 23 | you, bme680, we’re not | ||
| 24 | done yet). The show must go on, as they say, and I would like my | ||
| 25 | experiments to go on. | ||
| 26 | So a “new” addition to the environmental sensor family connected to | ||
| 27 | the 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 | ||
| 28 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 29 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 30 | unique 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. | ||
| 31 | My 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 | ||
| 32 | 1.0 has been released: | ||
| 33 | wifi_da-1.0.sit | ||
| 34 | (StuffIt 3 archive) | ||
| 35 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 36 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 37 | classic 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. | ||
| 38 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 39 | Design Goals | ||
| 40 | I 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 | ||
| 41 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 42 | catch 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 | ||
| 43 | specified 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&#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 | ||
| 10 | going down this rabbit hole of being almost independent of the current internet | ||
| 11 | machine. Even though I initially thought that I will have problems adapting, | ||
| 12 | I was pleasantly surprised that the transition went so smoothly. Even better, | ||
| 13 | it brought many benefits to my life. Such as increased focus, less stress | ||
| 14 | about trivial things, etc.<p>It all started with me doing small changes like unsubscribing from emails that I | ||
| 15 | have either subscribed to by accepting terms and conditions. Or even some more | ||
| 16 | malicious emails that I was getting because I was on a shared mailing list. And | ||
| 17 | the later ones I hate the most of all. How the hell do they keep sharing my | ||
| 18 | email and sending me unsolicited emails and get away with it? I have a suspicion | ||
| 19 | that these marketing people share an Excel file between them and keep | ||
| 20 | resubscribing 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 | ||
| 21 | paying attention. It got so bad that my primary Gmail address is a full of junk | ||
| 22 | and need constant monitoring and cleaning up. And because I want to have Inbox | ||
| 23 | Zero, 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 | ||
| 24 | noticing that I was unable to go through one single hour without hysterically | ||
| 25 | refreshing email. And if somebody wrote me something, I needed to see it right | ||
| 26 | then, even though I didn't immediately reply to it. I can only describe this | ||
| 27 | with FOMO (fear of missing out). I have no other explanation than that. It was | ||
| 28 | crippling, and I was constantly context switching, which I will address further | ||
| 29 | down this post in more details.<p>This was one of the reasons why I spawned up my personal email server, and I am | ||
| 30 | using it now as my primary and person email. I still have Gmail as my “junk” | ||
| 31 | email that I use for throw away stuff. I log in to Gmail once a week and check | ||
| 32 | if there are any important emails that I got, but apart from that, it's sitting | ||
| 33 | dormant and collecting dust.<p>The more I was watching the world loose it's self with allowing anti freedom | ||
| 34 | things to happen to it, the more I started to realize that something has to | ||
| 35 | change. I don't have the power to change the world. And I also don't have a | ||
| 36 | grandiose opinion of myself to even think to try it. But what I can do is to not | ||
| 37 | subscribe to this consumer way of thinking. I will not be complicit in this. My | ||
| 38 | moral and ethical stances won't allow it. So, this brings us to the second part | ||
| 39 | of my journey.<p>I was using all these 3rd party services because I was either lazy or OK with | ||
| 40 | the drawbacks of them. I watched these services and companies became more and | ||
| 41 | privacy policies and everybody is OK with accepting them, and they pray on that | ||
| 42 | more evil. It is evil if you sell your user's data in this manner. Nobody reads | ||
| 43 | flaw in human nature. I really hate the hypocrisy they manage to muster. These | ||
| 44 | companies prey on our laziness, and we are at fault here. Nobody else. And I | ||
| 45 | truly understand the reasons why we rather accept and move on, and not object | ||
| 46 | and have our lives a little more difficult. They have perfected this through | ||
| 47 | years of small changes that make us a little more dependent on them. You could | ||
| 48 | not convince a person to give away all his rights and data in one day. This was | ||
| 49 | gradual and slow. And it caught us all in surprise. When I really stopped and | ||
| 50 | thought about it, I felt repulsed. By really stopping and thinking about it, I | ||
| 51 | really 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 | ||
| 52 | by bit without understanding what it all meant. What it meant to be a full | ||
| 53 | person, not divided by all this bought attention they want from me. They don't | ||
| 54 | just get your data, but they also take your attention away from you. They | ||
| 55 | scatter your and go with the divide and conquer tactic from there. And a person | ||
| 56 | divided 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 | ||
| 57 | what being a full person is again, I can see that I was not at my 100% back | ||
| 58 | then.<p>A revolt was inevitable. There was no other way of continuing my story without | ||
| 59 | it. Without taking back my attention, my thoughts, my time, and my privacy, | ||
| 60 | regardless of how too late it maybe is.<p>This has nothing to do with conspiracy theories. Even less with changing the | ||
| 61 | world. All I wanted was to get my life back in order and not waste the energy | ||
| 62 | that could be spent in other, better places.<p>I started reading more. I can focus now fully on things I work on. Furthermore, | ||
| 63 | I have the mental acuity that I never had before. My mind feels sharp. I don't | ||
| 64 | get angry so much. I can cherish the finer things in life now without the need | ||
| 65 | to interpret them intellectually. Not only that, but I have a feeling of | ||
| 66 | belonging again. Sense of purpose has returned with a vengeance. And I can now | ||
| 67 | help people without depleting myself.<p>The last step so far was to finish closing all the remaining online accounts | ||
| 68 | that I still had. And when I was thinking what value they bring me, I wasn't | ||
| 69 | surprised that the answer was none. I wasn't logging in them and using them. I | ||
| 70 | stopped being afraid of FOMO. If somebody wants to get in contact me, they will | ||
| 71 | find a way. I am one search away.<p>We are not beholden to anybody. Our lives are our own. So dare yourself to | ||
| 72 | delete Facebook, LinkedIn. To unsubscribe. Dare yourself to take your time and | ||
| 73 | attention back. Use that time and energy to go for a walk without thinking about | ||
| 74 | work. Read a book instead of reading comment on social media that you will | ||
| 75 | forget in an hour. Enrich your life instead of wasting it. It only requires a | ||
| 76 | small step. And you will feel the benefits immediately. Lose the weight of the | ||
| 77 | world 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 | ||
| 78 | a lock on a Linux NFS server, which turned | ||
| 79 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 80 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 81 | owns 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 | ||
| 82 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 83 | list where the're doing | ||
| 84 | bad computer history and insisting that a guy Larry Rosen | ||
| 85 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 86 | somethin…<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: | ||
| 87 | i2c, plan9 | ||
| 88 | Another month, another file system. | ||
| 89 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 90 | you, bme680, we’re not | ||
| 91 | done yet). The show must go on, as they say, and I would like my | ||
| 92 | experiments to go on. | ||
| 93 | So a “new” addition to the environmental sensor family connected to | ||
| 94 | the 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 | ||
| 95 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 96 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 97 | unique 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. | ||
| 98 | My 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 | ||
| 99 | 1.0 has been released: | ||
| 100 | wifi_da-1.0.sit | ||
| 101 | (StuffIt 3 archive) | ||
| 102 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 103 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 104 | classic 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. | ||
| 105 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 106 | Design Goals | ||
| 107 | I 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 | ||
| 108 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 109 | catch 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 | ||
| 110 | specified 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 | ||
| 10 | have a mirror of your repository on another server. You can do this by adding | ||
| 11 | multiple 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>'!sh -c "git remote | xargs -L1 git push --all"'</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 | ||
| 13 | a lock on a Linux NFS server, which turned | ||
| 14 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 15 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 16 | owns 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 | ||
| 17 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 18 | list where the're doing | ||
| 19 | bad computer history and insisting that a guy Larry Rosen | ||
| 20 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 21 | somethin…<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: | ||
| 22 | i2c, plan9 | ||
| 23 | Another month, another file system. | ||
| 24 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 25 | you, bme680, we’re not | ||
| 26 | done yet). The show must go on, as they say, and I would like my | ||
| 27 | experiments to go on. | ||
| 28 | So a “new” addition to the environmental sensor family connected to | ||
| 29 | the 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 | ||
| 30 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 31 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 32 | unique 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. | ||
| 33 | My 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 | ||
| 34 | 1.0 has been released: | ||
| 35 | wifi_da-1.0.sit | ||
| 36 | (StuffIt 3 archive) | ||
| 37 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 38 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 39 | classic 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. | ||
| 40 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 41 | Design Goals | ||
| 42 | I 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 | ||
| 43 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 44 | catch 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 | ||
| 45 | specified 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 | ||
| 10 | proper tutorial regarding this. Almost all of them are missing some part of | ||
| 11 | important information and it gets pretty frustrating when you have a deadline | ||
| 12 | and are not finding simple distilled solution.<p>Nevertheless, after searching and experimenting I have found a solution that | ||
| 13 | works 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 | ||
| 14 | where this files are generated programmatically in your golang code as we will | ||
| 15 | see 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 | ||
| 16 | executing long enough. Programs, that execute too quickly don’t produce pprof | ||
| 17 | file 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 | ||
| 18 | ensure 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 | ||
| 20 | main function when calling profile.Start are different. When we set | ||
| 21 | profile.ProfilePath(“.”) we tell profiler to store pprof files in the same | ||
| 22 | folder 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>"fmt"</span> | ||
| 26 | </span></span><span style=display:flex><span> <span style=color:#a31515>"time"</span> | ||
| 27 | </span></span><span style=display:flex><span> <span style=color:#a31515>"github.com/pkg/profile"</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>"first set ..."</span>) | ||
| 33 | </span></span><span style=display:flex><span> <span style=color:#00f>for</span> i := 0; i < 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> <-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>"sencond set ..."</span>) | ||
| 41 | </span></span><span style=display:flex><span> <span style=color:#00f>for</span> i := 0; i < 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>"."</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>"fmt"</span> | ||
| 55 | </span></span><span style=display:flex><span> <span style=color:#a31515>"time"</span> | ||
| 56 | </span></span><span style=display:flex><span> <span style=color:#a31515>"github.com/pkg/profile"</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>"first set ..."</span>) | ||
| 62 | </span></span><span style=display:flex><span> <span style=color:#00f>for</span> i := 0; i < 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> <-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>"sencond set ..."</span>) | ||
| 70 | </span></span><span style=display:flex><span> <span style=color:#00f>for</span> i := 0; i < 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>"."</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 > 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 > 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 | ||
| 90 | a lock on a Linux NFS server, which turned | ||
| 91 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 92 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 93 | owns 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 | ||
| 94 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 95 | list where the're doing | ||
| 96 | bad computer history and insisting that a guy Larry Rosen | ||
| 97 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 98 | somethin…<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: | ||
| 99 | i2c, plan9 | ||
| 100 | Another month, another file system. | ||
| 101 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 102 | you, bme680, we’re not | ||
| 103 | done yet). The show must go on, as they say, and I would like my | ||
| 104 | experiments to go on. | ||
| 105 | So a “new” addition to the environmental sensor family connected to | ||
| 106 | the 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 | ||
| 107 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 108 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 109 | unique 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. | ||
| 110 | My 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 | ||
| 111 | 1.0 has been released: | ||
| 112 | wifi_da-1.0.sit | ||
| 113 | (StuffIt 3 archive) | ||
| 114 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 115 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 116 | classic 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. | ||
| 117 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 118 | Design Goals | ||
| 119 | I 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 | ||
| 120 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 121 | catch 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 | ||
| 122 | specified 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&#39;s in my code and other people&#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 | ||
| 10 | then 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 | ||
| 11 | create todo function in your <code>.bashrc</code> that accepts first argument as search | ||
| 12 | string.<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>"TODO:"</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 | ||
| 15 | a lock on a Linux NFS server, which turned | ||
| 16 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 17 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 18 | owns 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 | ||
| 19 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 20 | list where the're doing | ||
| 21 | bad computer history and insisting that a guy Larry Rosen | ||
| 22 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 23 | somethin…<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: | ||
| 24 | i2c, plan9 | ||
| 25 | Another month, another file system. | ||
| 26 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 27 | you, bme680, we’re not | ||
| 28 | done yet). The show must go on, as they say, and I would like my | ||
| 29 | experiments to go on. | ||
| 30 | So a “new” addition to the environmental sensor family connected to | ||
| 31 | the 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 | ||
| 32 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 33 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 34 | unique 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. | ||
| 35 | My 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 | ||
| 36 | 1.0 has been released: | ||
| 37 | wifi_da-1.0.sit | ||
| 38 | (StuffIt 3 archive) | ||
| 39 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 40 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 41 | classic 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. | ||
| 42 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 43 | Design Goals | ||
| 44 | I 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 | ||
| 45 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 46 | catch 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 | ||
| 47 | specified 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 | ||
| 10 | Flow</a> for years now and never really | ||
| 11 | questioned it to be honest. When I create a repo I create develop branch and set | ||
| 12 | it 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 | ||
| 13 | always end up making a huge mess when they need to be merged eventually into | ||
| 14 | master. So by that reason, what is the develop branch if not the longest living | ||
| 15 | feature branch. And from my personal experience there was never a situation | ||
| 16 | where 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 | ||
| 17 | is there a better way. Well the solution was always there. And it comes in a | ||
| 18 | form 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 | ||
| 19 | repository's history. They are used to mark important milestones, such as | ||
| 20 | releases or significant commits, making it easier to identify and access | ||
| 21 | specific versions of a project.<p>Somehow we have all hijacked the meaning of the master branch that it has to be | ||
| 22 | the most releasable version of code. And this is also where the confusing about | ||
| 23 | versioning the software kicks in. Because master branch implicitly says that we | ||
| 24 | are dealing with the rolling release type of a software. And by having a develop | ||
| 25 | branch we are hacking around this confusion. With a separation of develop and | ||
| 26 | master we lock functionalities into place and forcing a stable vs development | ||
| 27 | version of the software.<p>But if that is true and the long living branches are the devil then why have | ||
| 28 | develop at all. I think that most of this comes to how continuous integration is | ||
| 29 | being done. There usually is no granular access to tags and CD software deploys | ||
| 30 | what is present on a specific branch, may that be master for production and | ||
| 31 | develop for staging. This is a gross simplification and by having this in place | ||
| 32 | we have completely removed tagging as a viable option to create a fix point in | ||
| 33 | software 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 | ||
| 34 | behave very similarly as branches in that regard. And you don’t have the | ||
| 35 | overhead of having two mainstream branches.<p>So what is the solution? One approach is to use development workflow, where all | ||
| 36 | changes are made on the smaller branches and continuously merged into | ||
| 37 | master. Where the software is ready to be pushed to production you tag the | ||
| 38 | master branch. This approach eliminates the need for long-lived branches and | ||
| 39 | simplifies the development process. It also encourages developers to make small, | ||
| 40 | incremental changes that can be tested and deployed quickly. However, this | ||
| 41 | approach may not be suitable for all projects or teams that heavily rely on | ||
| 42 | automated deployment based on branch names only.<p>This also requires that developers always keep production in mind. No more | ||
| 43 | living on an island of the develop branch. All your actions and code need to be | ||
| 44 | ready to meet production standards on a much smaller timescale.<p>I think that we have complicated the workflow in an honest attempt to make | ||
| 45 | things more streamlined but in the process of doing this, we have inadvertently | ||
| 46 | made our lives much more complicated.<p>In conclusion, it's important to re-evaluate our workflows from time to time to | ||
| 47 | see if they still make sense and if there are better alternatives available. | ||
| 48 | Long-living branches can be problematic, and using tags to mark important | ||
| 49 | milestones 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 | ||
| 50 | a lock on a Linux NFS server, which turned | ||
| 51 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 52 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 53 | owns 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 | ||
| 54 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 55 | list where the're doing | ||
| 56 | bad computer history and insisting that a guy Larry Rosen | ||
| 57 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 58 | somethin…<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: | ||
| 59 | i2c, plan9 | ||
| 60 | Another month, another file system. | ||
| 61 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 62 | you, bme680, we’re not | ||
| 63 | done yet). The show must go on, as they say, and I would like my | ||
| 64 | experiments to go on. | ||
| 65 | So a “new” addition to the environmental sensor family connected to | ||
| 66 | the 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 | ||
| 67 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 68 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 69 | unique 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. | ||
| 70 | My 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 | ||
| 71 | 1.0 has been released: | ||
| 72 | wifi_da-1.0.sit | ||
| 73 | (StuffIt 3 archive) | ||
| 74 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 75 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 76 | classic 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. | ||
| 77 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 78 | Design Goals | ||
| 79 | I 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 | ||
| 80 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 81 | catch 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 | ||
| 82 | specified 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 | ||
| 10 | a lock on a Linux NFS server, which turned | ||
| 11 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 12 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 13 | owns 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 | ||
| 14 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 15 | list where the're doing | ||
| 16 | bad computer history and insisting that a guy Larry Rosen | ||
| 17 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 18 | somethin…<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: | ||
| 19 | i2c, plan9 | ||
| 20 | Another month, another file system. | ||
| 21 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 22 | you, bme680, we’re not | ||
| 23 | done yet). The show must go on, as they say, and I would like my | ||
| 24 | experiments to go on. | ||
| 25 | So a “new” addition to the environmental sensor family connected to | ||
| 26 | the 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 | ||
| 27 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 28 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 29 | unique 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. | ||
| 30 | My 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 | ||
| 31 | 1.0 has been released: | ||
| 32 | wifi_da-1.0.sit | ||
| 33 | (StuffIt 3 archive) | ||
| 34 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 35 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 36 | classic 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. | ||
| 37 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 38 | Design Goals | ||
| 39 | I 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 | ||
| 40 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 41 | catch 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 | ||
| 42 | specified 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 +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><p>This site has gone through a lot of changes over the years. From being written | ||
| 31 | in Flask and Bottle to moving on to static site generators. I have used and | ||
| 32 | tested probably 10s of them my now. From homebrew solutions to the biggest and | ||
| 33 | the baddest. From Bash scripts to Node.js disasters. I've seen some things, no | ||
| 34 | doubt. Not all bad.</p> | ||
| 35 | <p>I have been closely observing the web and where the trends are going, and I | ||
| 36 | don't like what I see. Instead of internet being this weird place where | ||
| 37 | experimentation is happening, it all became stale and formulized. Boring, | ||
| 38 | actually. Really boring. And sad. Where is that old, revolutionary FU spirit I | ||
| 39 | remember? It's still there, I know. But it's being drowned by the voices of | ||
| 40 | mediocrity and formulaic boredom.</p> | ||
| 41 | <p>It almost feels like that the internet stopped for 10 years and only now | ||
| 42 | something has started happening. With all the insanity around the world. People | ||
| 43 | hating people without actual reasons, just because it's fashionable to hate and | ||
| 44 | crowd is saying so. Sad state of affairs.</p> | ||
| 45 | <p>All this is contributing to this overall negativity masked as apathy. Everybody | ||
| 46 | walking in lockstep. Instead of being creative and bold, we are just | ||
| 47 | re-inventing the world and making the same mistakes. Maybe, just maybe, some | ||
| 48 | things are good enough and there is no need to try to be too smart for our own | ||
| 49 | good. After N-attempts, maybe something should click inside our heads to maybe | ||
| 50 | say: &quot;This thing, opinion, etc. is actually really good, and even after several | ||
| 51 | attempts it still holds.&quot;</p> | ||
| 52 | <p>The older I get, the more careful I am of my own thoughts and why I think the | ||
| 53 | way I think. More and more, I try to understand people with opposite | ||
| 54 | opinions. Far from perfect, but closer to bearable. And then I see people | ||
| 55 | hearing or reading a thing on internet and let's fucking goooooo! Strong | ||
| 56 | opinions are a sign of a weak and uneducated mind. I am more and more sure of | ||
| 57 | this.</p> | ||
| 58 | <p>It's gotten to a point where you can with great certainty deduce a person's | ||
| 59 | personality based on one or two opinions. How boring have we become. No wonder | ||
| 60 | people can't talk to each other. These would be very quick conversations anyway.</p> | ||
| 61 | <p>I just got remembered of a song, <a href="https://www.youtube.com/watch?v=s_nc1IVoMxc">&quot;Hi | ||
| 62 | Ren&quot;</a>. The ending talks about being | ||
| 63 | stiff and not being able to dance. Such an amazing metaphor. And we as people | ||
| 64 | have gone so far, we can't even walk or even crawl normally anymore. We have | ||
| 65 | forgotten that the most beautiful things in life have a great deal of | ||
| 66 | uncertainty about them. We want instant gratification. Not only that, but we | ||
| 67 | want absolute obedience. Complete control over others, because we have zero | ||
| 68 | control of ourselves. And all the lies we could tell ourselves will not help us | ||
| 69 | out of this situation.</p> | ||
| 70 | <p>It is funny how I catch myself from time to time being a complete idiot. It's | ||
| 71 | like having an outer body experience. I can see myself being an idiot, and | ||
| 72 | cannot stop myself. It serves as a learning lesson to stop before speaking. To | ||
| 73 | think before saying. And to crawl before walking.</p> | ||
| 74 | <p>So there is still time. We can dance once more. All we need to do is stop for a | ||
| 75 | second. Me and you. Us two is a start. Let's not try to change the world, but | ||
| 76 | rather nudge ourselves just a tiny bit. And if we only did that?! Just | ||
| 77 | imagine. Each of us nudged ourselves a small, tiny bit, the world would heal. If | ||
| 78 | we would just put down the phones and ignored Internet for a day or two. Put | ||
| 79 | visiting websites that feed on us on hold. Listened to just one sentence and try | ||
| 80 | to understand it from a person who we completely disagree with. I truly believe | ||
| 81 | that this is possible.</p> | ||
| 82 | <p>Life is about suffering and joy. And instead of wishing suffering on others and | ||
| 83 | excepting joy for yourselves, we should for a brief moment want suffering for | ||
| 84 | ourselves and wish joy on others. Wouldn't that be an amazing sight to see?</p> | ||
| 85 | <p>I caught myself hating on Rust. And I deeply thought about it afterward. Why did | ||
| 86 | I do it? It is obviously not for me. So why the hell was I being so negative | ||
| 87 | towards it? I think that I know the answer. I was negative because that is | ||
| 88 | easy. Because it's much easier to hate on things than to say to yourself: &quot;Well, | ||
| 89 | you know what? This is not for me. I will focus on creation and not | ||
| 90 | destruction. This is who I want to be. This is what fills me with joy and | ||
| 91 | purpose.&quot; Where joy is keeping me happy and purpose scares the shit out of me | ||
| 92 | and keeps me honest. This is who I want to be. Admit to myself when I am wrong | ||
| 93 | and accept the faults that I have without reservation and with courage march on.</p> | ||
| 94 | <p>I just realized that this blog post is a sort of therapy for me. It's | ||
| 95 | cathartic. Going thought the history of this site and remembering all the | ||
| 96 | decisions and annoyances that came with it. When I was cursing at the tools. And | ||
| 97 | time moved on, and the site is still here. It serves as a reminder that | ||
| 98 | perseverance wins at the end. If we just let things go.</p> | ||
| 99 | <p>This came with a decision that simplifying life and removing all the unnecessary | ||
| 100 | negativity is key. Rather than worrying about what the internet is saying, what | ||
| 101 | the world is trying to take from you, you are the only one who can say no. And | ||
| 102 | create instead of destroy.</p> | ||
| 103 | <p>I don't have an ending for this post, so I will say this. We live in the most | ||
| 104 | amazing times in the recorded history, and we should be internally grateful for | ||
| 105 | it. Create and study, this should be my mantra. Just create and let the world | ||
| 106 | happen. And when you feel yourself to be too certain, stop and check how deep in the | ||
| 107 | shit you are already. Strong opinions are a sign of a weak and uneducated | ||
| 108 | mind. Hate and disdain is for the weak.</p> | ||
| 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 +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><h2 id="what-is-the-issue-anyway">What is the issue anyway?</h2> | ||
| 121 | <p>Over the years, I have accumulated a bunch of virtual servers on my | ||
| 122 | <a href="https://www.digitalocean.com/">DigitalOcean</a> account for small experimental | ||
| 123 | projects I dabble in. And this has resulted in quite a bill. I mean, I wouldn't | ||
| 124 | care if these projects were actually being used. But there were just being there | ||
| 125 | unused and wasting resources. Which makes this an unnecessary burden for me.</p> | ||
| 126 | <p>Most of them are just small HTML pages that have an endpoint or two to read data | ||
| 127 | from or to, and for that reason I wrote servers left and right. To be honest, | ||
| 128 | all of those things could have been done with <a href="https://en.wikipedia.org/wiki/Common_Gateway_Interface">CGI | ||
| 129 | scripts</a> and that would | ||
| 130 | have been more than enough.</p> | ||
| 131 | <p>Recently, I decided to stop language hopping and focus on a simpler stack which | ||
| 132 | includes C, Go and Lua. And I can accomplish all the things I am interested in.</p> | ||
| 133 | <h2 id="finding-a-web-server-replacement">Finding a web server replacement</h2> | ||
| 134 | <p>Usually I had <a href="https://nginx.org/en/">Nginx</a> in front of these small web servers | ||
| 135 | and I had to manage SSL certificates and all that jazz. I am bored with these | ||
| 136 | things. I don't want to manage any of this bullshit anymore.</p> | ||
| 137 | <p>So the logical move forward was to find a solid alternative for this. I have | ||
| 138 | ended up on <a href="https://caddyserver.com/">Caddy server</a>. I've used it in the past | ||
| 139 | but kind of forgotten about it. What I really like about it is an ease of use | ||
| 140 | and a bunch of out of the box functionalities that come with it.</p> | ||
| 141 | <p>These are the <em>pitch</em> points from their website:</p> | ||
| 142 | <ul> | ||
| 143 | <li><strong>Secure by Default</strong>: Caddy is the only web server that uses HTTPS by | ||
| 144 | default. A hardened TLS stack with modern protocols preserves privacy and | ||
| 145 | exposes MITM attacks.</li> | ||
| 146 | <li><strong>Config API</strong>: As its primary mode of configuration, Caddy's REST API makes | ||
| 147 | it easy to automate and integrate with your apps.</li> | ||
| 148 | <li><strong>No Dependencies</strong>: Because Caddy is written in Go, its binaries are entirely | ||
| 149 | self-contained and run on every platform, including containers without libc.</li> | ||
| 150 | <li><strong>Modular Stack</strong>: Take back control over your compute edge. Caddy can be | ||
| 151 | extended with everything you need using plugins.</li> | ||
| 152 | </ul> | ||
| 153 | <p>I had just a few requirements:</p> | ||
| 154 | <ul> | ||
| 155 | <li>Automatic SSL</li> | ||
| 156 | <li>Static file server</li> | ||
| 157 | <li>Basic authentication</li> | ||
| 158 | <li>CGI script support</li> | ||
| 159 | </ul> | ||
| 160 | <p>And the vanilla version does all of it, but CGI scripts. But that can easily be | ||
| 161 | fixed with their modular approach. You can do this on their website and build a | ||
| 162 | custom version of the server, or do it with Docker.</p> | ||
| 163 | <p>This is a <code>Dockerfile</code> I used to build a custom server.</p> | ||
| 164 | <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 style=""> | ||
| 165 | </span></span></span><span style="display:flex;"><span><span style=""> | ||
| 166 | </span></span></span><span style="display:flex;"><span><span style=""></span><span style="color:#00f">RUN</span> xcaddy build <span style="color:#a31515">\ | ||
| 167 | </span></span></span><span style="display:flex;"><span><span style="color:#a31515"></span> --with github.com/aksdb/caddy-cgi<span style=""> | ||
| 168 | </span></span></span><span style="display:flex;"><span><span style=""> | ||
| 169 | </span></span></span><span style="display:flex;"><span><span style=""></span><span style="color:#00f">FROM</span><span style="color:#a31515"> caddy:latest</span><span style=""> | ||
| 170 | </span></span></span><span style="display:flex;"><span><span style=""></span><span style="color:#00f">RUN</span> apk add --no-cache nano<span style=""> | ||
| 171 | </span></span></span><span style="display:flex;"><span><span style=""> | ||
| 172 | </span></span></span><span style="display:flex;"><span><span style=""></span><span style="color:#00f">COPY</span> --from=builder /usr/bin/caddy /usr/bin/caddy<span style=""> | ||
| 173 | </span></span></span></code></pre><h2 id="getting-rid-of-all-the-unnecessary-virtual-machines">Getting rid of all the unnecessary virtual machines</h2> | ||
| 174 | <p>The next step was to get a handle on the number of virtual servers I have all | ||
| 175 | over the place.</p> | ||
| 176 | <p>I decided to move all the projects and services into two main VMs:</p> | ||
| 177 | <ul> | ||
| 178 | <li>personal server (still Nginx) | ||
| 179 | <ul> | ||
| 180 | <li>git server</li> | ||
| 181 | <li>static file server</li> | ||
| 182 | <li>personal blog</li> | ||
| 183 | </ul> | ||
| 184 | </li> | ||
| 185 | <li>projects server (Caddy server) | ||
| 186 | <ul> | ||
| 187 | <li>personal experiments</li> | ||
| 188 | <li>other projects</li> | ||
| 189 | </ul> | ||
| 190 | </li> | ||
| 191 | </ul> | ||
| 192 | <p>I will focus on projects' server in this post since it's more interesting.</p> | ||
| 193 | <h2 id="testing-cgi-scripts">Testing CGI scripts</h2> | ||
| 194 | <p>The first thing I tested was how CGI scripts work under Caddy. This is | ||
| 195 | particularly import to me because almost all of my experiments and mini projects | ||
| 196 | need this to work.</p> | ||
| 197 | <p>To configure Caddy server, you must provide the server with a configuration | ||
| 198 | file. By default, it's called <code>Caaddyfile</code>.</p> | ||
| 199 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>{ | ||
| 200 | </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> | ||
| 201 | </span></span><span style="display:flex;"><span>} | ||
| 202 | </span></span><span style="display:flex;"><span> | ||
| 203 | </span></span><span style="display:flex;"><span><span style="font-weight:bold">examples.mitjafelicijan.com</span> { | ||
| 204 | </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> | ||
| 205 | </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> | ||
| 206 | </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> | ||
| 207 | </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> | ||
| 208 | </span></span><span style="display:flex;"><span> | ||
| 209 | </span></span><span style="display:flex;"><span> <span style="color:#00f">root</span> * <span style="color:#a31515">/opt/projects/examples</span> | ||
| 210 | </span></span><span style="display:flex;"><span> <span style="color:#00f">file_server</span> | ||
| 211 | </span></span><span style="display:flex;"><span>} | ||
| 212 | </span></span></code></pre><ul> | ||
| 213 | <li>The order is very important. Make sure that <code>order cgi before respond</code> is at | ||
| 214 | the top of the configuration file.</li> | ||
| 215 | <li>Also, when you run with Caddy v2, make sure you provide <code>adapter</code> argument | ||
| 216 | like 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 | ||
| 217 | config file.</li> | ||
| 218 | </ul> | ||
| 219 | <p>I did a small batch of tests with <a href="https://www.gnu.org/software/bash/">Bash</a>, | ||
| 220 | <a href="https://www.tcl-lang.org/">Tcl</a>, <a href="https://www.lua.org/">Lua</a> and | ||
| 221 | <a href="https://www.python.org/">Python</a>. Here is a cheat sheet if you need it.</p> | ||
| 222 | <p>Let's get Bash out of the way first.</p> | ||
| 223 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#00f">#!/usr/bin/bash | ||
| 224 | </span></span></span><span style="display:flex;"><span><span style="color:#00f"></span> | ||
| 225 | </span></span><span style="display:flex;"><span>printf <span style="color:#a31515">&#34;Content-type: text/plain\n\n&#34;</span> | ||
| 226 | </span></span><span style="display:flex;"><span> | ||
| 227 | </span></span><span style="display:flex;"><span>printf <span style="color:#a31515">&#34;Hello from Bash\n\n&#34;</span> | ||
| 228 | </span></span><span style="display:flex;"><span>printf <span style="color:#a31515">&#34;PATH_INFO [%s]\n&#34;</span> $PATH_INFO | ||
| 229 | </span></span><span style="display:flex;"><span>printf <span style="color:#a31515">&#34;QUERY_STRING [%s]\n&#34;</span> $QUERY_STRING | ||
| 230 | </span></span><span style="display:flex;"><span>printf <span style="color:#a31515">&#34;\n&#34;</span> | ||
| 231 | </span></span><span style="display:flex;"><span> | ||
| 232 | </span></span><span style="display:flex;"><span><span style="color:#00f">for</span> i in {0..9..1}; <span style="color:#00f">do</span> | ||
| 233 | </span></span><span style="display:flex;"><span> printf <span style="color:#a31515">&#34;&gt; %s\n&#34;</span> $i | ||
| 234 | </span></span><span style="display:flex;"><span><span style="color:#00f">done</span> | ||
| 235 | </span></span><span style="display:flex;"><span> | ||
| 236 | </span></span><span style="display:flex;"><span>exit 0 | ||
| 237 | </span></span></code></pre><p>This one is for Tcl script.</p> | ||
| 238 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000">#!/usr/bin/tclsh | ||
| 239 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"> | ||
| 240 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span>puts <span style="color:#a31515">&#34;Content-type: text/plain\n&#34;</span> | ||
| 241 | </span></span><span style="display:flex;"><span> | ||
| 242 | </span></span><span style="display:flex;"><span>puts <span style="color:#a31515">&#34;Hello from Tcl\n&#34;</span> | ||
| 243 | </span></span><span style="display:flex;"><span>puts <span style="color:#a31515">&#34;PATH_INFO \[$env(PATH_INFO)\]&#34;</span> | ||
| 244 | </span></span><span style="display:flex;"><span>puts <span style="color:#a31515">&#34;QUERY_STRING \[$env(QUERY_STRING)\]&#34;</span> | ||
| 245 | </span></span><span style="display:flex;"><span>puts <span style="color:#a31515">&#34;&#34;</span> | ||
| 246 | </span></span><span style="display:flex;"><span> | ||
| 247 | </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> | ||
| 248 | </span></span><span style="display:flex;"><span> puts <span style="color:#a31515">&#34;&gt; $i&#34;</span> | ||
| 249 | </span></span><span style="display:flex;"><span><span style="color:#00f">}</span> | ||
| 250 | </span></span></code></pre><p>And for all you Python enjoyers.</p> | ||
| 251 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000">#!/usr/bin/python3</span> | ||
| 252 | </span></span><span style="display:flex;"><span> | ||
| 253 | </span></span><span style="display:flex;"><span><span style="color:#00f">import</span> os | ||
| 254 | </span></span><span style="display:flex;"><span> | ||
| 255 | </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>) | ||
| 256 | </span></span><span style="display:flex;"><span> | ||
| 257 | </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>) | ||
| 258 | </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>])) | ||
| 259 | </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>])) | ||
| 260 | </span></span><span style="display:flex;"><span>print(<span style="color:#a31515">&#34;&#34;</span>) | ||
| 261 | </span></span><span style="display:flex;"><span> | ||
| 262 | </span></span><span style="display:flex;"><span><span style="color:#00f">for</span> i <span style="color:#00f">in</span> range(10): | ||
| 263 | </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)) | ||
| 264 | </span></span></code></pre><p>And for the final example, Lua.</p> | ||
| 265 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#00f">#!/usr/bin/lua</span> | ||
| 266 | </span></span><span style="display:flex;"><span> | ||
| 267 | </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>) | ||
| 268 | </span></span><span style="display:flex;"><span> | ||
| 269 | </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>) | ||
| 270 | </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>))) | ||
| 271 | </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>))) | ||
| 272 | </span></span><span style="display:flex;"><span>print() | ||
| 273 | </span></span><span style="display:flex;"><span> | ||
| 274 | </span></span><span style="display:flex;"><span><span style="color:#00f">for</span> i = 0, 9 <span style="color:#00f">do</span> | ||
| 275 | </span></span><span style="display:flex;"><span> print(string.format(<span style="color:#a31515">&#34;&gt; %d&#34;</span>, i)) | ||
| 276 | </span></span><span style="display:flex;"><span><span style="color:#00f">end</span> | ||
| 277 | </span></span></code></pre><h2 id="basic-authentication">Basic authentication</h2> | ||
| 278 | <p>One thing was also to have an option for some sort of authentication, and | ||
| 279 | something like <a href="https://en.wikipedia.org/wiki/Basic_access_authentication">Basic access | ||
| 280 | authentication</a> would | ||
| 281 | be more than enough.</p> | ||
| 282 | <p>Thankfully, Caddy supports this out of the box already. Below is an updated | ||
| 283 | example.</p> | ||
| 284 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>{ | ||
| 285 | </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> | ||
| 286 | </span></span><span style="display:flex;"><span>} | ||
| 287 | </span></span><span style="display:flex;"><span> | ||
| 288 | </span></span><span style="display:flex;"><span><span style="font-weight:bold">examples.mitjafelicijan.com</span> { | ||
| 289 | </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> | ||
| 290 | </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> | ||
| 291 | </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> | ||
| 292 | </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> | ||
| 293 | </span></span><span style="display:flex;"><span> | ||
| 294 | </span></span><span style="display:flex;"><span> <span style="color:#00f">root</span> * <span style="color:#a31515">/opt/projects/examples</span> | ||
| 295 | </span></span><span style="display:flex;"><span> <span style="color:#00f">file_server</span> | ||
| 296 | </span></span><span style="display:flex;"><span> | ||
| 297 | </span></span><span style="display:flex;"><span> <span style="color:#00f">basicauth</span> * { | ||
| 298 | </span></span><span style="display:flex;"><span> <span style="color:#00f">bob</span> <span style="">$</span><span style="color:#a31515">2a</span><span style="">$</span>14<span style="">$</span><span style="color:#a31515">/wCgaf9oMnmQa20txB76u.nI1AldGMBT/1J7fXCfgOiRShwz/JOkK</span> | ||
| 299 | </span></span><span style="display:flex;"><span> } | ||
| 300 | </span></span><span style="display:flex;"><span>} | ||
| 301 | </span></span></code></pre><p><code>basicauth *</code> matches everything under this domain/sub-domain and protects it | ||
| 302 | with Basic Authentication.</p> | ||
| 303 | <ul> | ||
| 304 | <li><code>bob</code> is the username</li> | ||
| 305 | <li><code>hash</code> is the password</li> | ||
| 306 | </ul> | ||
| 307 | <p>To generate these passwords, execute <code>caddy hash-password</code> and this will prompt | ||
| 308 | you to insert a password twice and spit out a hashed password that you can put | ||
| 309 | in your configuration file.</p> | ||
| 310 | <p>Restart the server and you are ready to go.</p> | ||
| 311 | <h2 id="making-caddy-a-service-with-systemd">Making Caddy a service with systemd</h2> | ||
| 312 | <p>After the tests were successful, I copied <code>caddy</code> to <code>/usr/bin/caddy</code> and copied | ||
| 313 | <code>Caddyfile</code> to <code>/etc/caddy/Caddyfile</code>.</p> | ||
| 314 | <p>Now off to the systemd. Each systemd service requires you to create a service | ||
| 315 | file.</p> | ||
| 316 | <ul> | ||
| 317 | <li>I created a <code>/etc/systemd/system/caddy.service</code> and put the following content | ||
| 318 | in the file.</li> | ||
| 319 | </ul> | ||
| 320 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#00f">[Unit]</span> | ||
| 321 | </span></span><span style="display:flex;"><span>Description=<span style="color:#a31515">Caddy</span> | ||
| 322 | </span></span><span style="display:flex;"><span>Documentation=<span style="color:#a31515">https://caddyserver.com/docs/</span> | ||
| 323 | </span></span><span style="display:flex;"><span>After=<span style="color:#a31515">network.target network-online.target</span> | ||
| 324 | </span></span><span style="display:flex;"><span>Requires=<span style="color:#a31515">network-online.target</span> | ||
| 325 | </span></span><span style="display:flex;"><span> | ||
| 326 | </span></span><span style="display:flex;"><span><span style="color:#00f">[Service]</span> | ||
| 327 | </span></span><span style="display:flex;"><span>Type=<span style="color:#a31515">notify</span> | ||
| 328 | </span></span><span style="display:flex;"><span>User=<span style="color:#a31515">root</span> | ||
| 329 | </span></span><span style="display:flex;"><span>Group=<span style="color:#a31515">root</span> | ||
| 330 | </span></span><span style="display:flex;"><span>ExecStart=<span style="color:#a31515">/usr/bin/caddy run --environ --config /etc/caddy/Caddyfile --adapter caddyfile</span> | ||
| 331 | </span></span><span style="display:flex;"><span>ExecReload=<span style="color:#a31515">/usr/bin/caddy reload --config /etc/caddy/Caddyfile --force --adapter caddyfile</span> | ||
| 332 | </span></span><span style="display:flex;"><span>TimeoutStopSec=<span style="color:#a31515">5s</span> | ||
| 333 | </span></span><span style="display:flex;"><span>LimitNOFILE=<span style="color:#a31515">1048576</span> | ||
| 334 | </span></span><span style="display:flex;"><span>LimitNPROC=<span style="color:#a31515">512</span> | ||
| 335 | </span></span><span style="display:flex;"><span>PrivateTmp=<span style="color:#a31515">true</span> | ||
| 336 | </span></span><span style="display:flex;"><span>ProtectSystem=<span style="color:#a31515">full</span> | ||
| 337 | </span></span><span style="display:flex;"><span>AmbientCapabilities=<span style="color:#a31515">CAP_NET_ADMIN CAP_NET_BIND_SERVICE</span> | ||
| 338 | </span></span><span style="display:flex;"><span> | ||
| 339 | </span></span><span style="display:flex;"><span><span style="color:#00f">[Install]</span> | ||
| 340 | </span></span><span style="display:flex;"><span>WantedBy=<span style="color:#a31515">multi-user.target</span> | ||
| 341 | </span></span></code></pre><ul> | ||
| 342 | <li>You might need to reload systemd with <code>systemctl daemon-reload</code>.</li> | ||
| 343 | <li>Then I enabled the service with <code>systemctl enable caddy.service</code>.</li> | ||
| 344 | <li>And then I started the service with <code>systemctl start caddy.service</code>.</li> | ||
| 345 | </ul> | ||
| 346 | <p>This was about all that I needed to do to get it running. Now I can easily add | ||
| 347 | new subdomains and domains to the main configuration file and be done with | ||
| 348 | it. No manual Let's Encrypt shenanigans needed.</p> | ||
| 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 +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><p>Couple of months ago I had this brilliant idea of re-inventing the wheel by | ||
| 377 | making an alternative for make. And so I went. Boldly into the battle. And to my | ||
| 378 | big surprise my attempt resulted in not a completely useless piece of software.</p> | ||
| 379 | <p>My initial requirements were quite simple but soon grow into something more | ||
| 380 | ambitious. And looking back I should have stuck to the simple version. My | ||
| 381 | laziness was on my side this time though. Because I haven’t implemented some of | ||
| 382 | the features I now realise I really didn’t need them and they would bog the | ||
| 383 | whole program and make it be something it was never meant to be.</p> | ||
| 384 | <p>My basic requirements were following:</p> | ||
| 385 | <ul> | ||
| 386 | <li>Syntax should be a tiny bit inspired by Rake and Rakefiles.</li> | ||
| 387 | <li>Should borrow the overall feel of a unit test experience.</li> | ||
| 388 | <li>Using something like Python would be a bit of an overkill.</li> | ||
| 389 | <li>The program must be statically compiled, so it can run on same architecture | ||
| 390 | without libc, musl dependencies or things like that.</li> | ||
| 391 | <li>Install ruby for rake is a bit overkill and can not be done with certain | ||
| 392 | really lightweight distributions like Alpine Linux. This tool would be usable | ||
| 393 | on such lightweight systems for remote debugging.</li> | ||
| 394 | <li>I want to use it for more than just compiling things. I want to use it as an | ||
| 395 | entry-point into a project, and I want this to help me indirectly document the | ||
| 396 | project as well.</li> | ||
| 397 | <li>It should be an abstraction over bash shell or the default system shell. | ||
| 398 | <ul> | ||
| 399 | <li>Each task essentially becomes its own shell instance.</li> | ||
| 400 | </ul> | ||
| 401 | </li> | ||
| 402 | <li>Must work on Linux and macOS systems.</li> | ||
| 403 | <li>By default, running <code>erd</code> list all the available tasks (when I use make, I | ||
| 404 | usually put a disclaimer that you should check Makefile to see all available | ||
| 405 | target).</li> | ||
| 406 | <li>Should support passing arguments when you run it from a shell.</li> | ||
| 407 | <li>Normal variable as the same as environmental variables. There is no | ||
| 408 | distinction. Every variable is also essentially an environment variable and | ||
| 409 | can be used by other programs.</li> | ||
| 410 | <li>State between tasks is not shared, and this makes this “pure” shell instances.</li> | ||
| 411 | <li>Should be single-threaded for the start and later expanded with <code>@spawn</code> | ||
| 412 | command.</li> | ||
| 413 | <li>Variables behave like macros and are preprocessed before evaluation.</li> | ||
| 414 | <li>Should support something like <code>assure</code> that would check if programs like C | ||
| 415 | compiler or Python (whatever the project requires) are installed on a machine.</li> | ||
| 416 | </ul> | ||
| 417 | <p>Quite a reasonable list of requirements. I do this things already in my | ||
| 418 | Makefiles or/and Bash scripts. But I would like to avoid repeating myself every | ||
| 419 | time I start working on something new.</p> | ||
| 420 | <p>So I started with the following syntax.</p> | ||
| 421 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>@env on | ||
| 422 | </span></span><span style="display:flex;"><span> | ||
| 423 | </span></span><span style="display:flex;"><span><span style="color:#008000"># Override the default shell.</span> | ||
| 424 | </span></span><span style="display:flex;"><span>@shell <span style="color:#a31515">/bin/</span>bash | ||
| 425 | </span></span><span style="display:flex;"><span> | ||
| 426 | </span></span><span style="display:flex;"><span><span style="color:#008000"># Assure that program is installed.</span> | ||
| 427 | </span></span><span style="display:flex;"><span>@assure docker-compose pip python3 | ||
| 428 | </span></span><span style="display:flex;"><span> | ||
| 429 | </span></span><span style="display:flex;"><span><span style="color:#008000"># Load local dotenv files (these are then globally available).</span> | ||
| 430 | </span></span><span style="display:flex;"><span>@dotenv .env | ||
| 431 | </span></span><span style="display:flex;"><span>@dotenv .env.sample | ||
| 432 | </span></span><span style="display:flex;"><span>@dotenv some_other_file | ||
| 433 | </span></span><span style="display:flex;"><span> | ||
| 434 | </span></span><span style="display:flex;"><span><span style="color:#008000"># This are local variables but still accessible in tasks.</span> | ||
| 435 | </span></span><span style="display:flex;"><span>@var HI = <span style="color:#a31515">&#34;hey&#34;</span> | ||
| 436 | </span></span><span style="display:flex;"><span>@var TOKEN = <span style="color:#a31515">&#34;sometoken&#34;</span> | ||
| 437 | </span></span><span style="display:flex;"><span>@var EMAIL = <span style="color:#a31515">&#34;m@m.com&#34;</span> | ||
| 438 | </span></span><span style="display:flex;"><span>@var PASSWORD = <span style="color:#a31515">&#34;pass&#34;</span> | ||
| 439 | </span></span><span style="display:flex;"><span>@var EDITOR = <span style="color:#a31515">&#34;vim&#34;</span> | ||
| 440 | </span></span><span style="display:flex;"><span> | ||
| 441 | </span></span><span style="display:flex;"><span>@task dev <span style="color:#a31515">&#34;Test chars .:&#39;}{]!//&#34;</span> does | ||
| 442 | </span></span><span style="display:flex;"><span> echo <span style="color:#a31515">&#34;...&#34;</span> $HI | ||
| 443 | </span></span><span style="display:flex;"><span><span style="color:#00f">end</span> | ||
| 444 | </span></span><span style="display:flex;"><span> | ||
| 445 | </span></span><span style="display:flex;"><span>@task clean <span style="color:#a31515">&#34;Cleans the obj files&#34;</span> does | ||
| 446 | </span></span><span style="display:flex;"><span> rm .obj | ||
| 447 | </span></span><span style="display:flex;"><span><span style="color:#00f">end</span> | ||
| 448 | </span></span><span style="display:flex;"><span> | ||
| 449 | </span></span><span style="display:flex;"><span>@task greet <span style="color:#a31515">&#34;Greets the user&#34;</span> does | ||
| 450 | </span></span><span style="display:flex;"><span> echo <span style="color:#a31515">&#34;Hi user $TOKEN or $WINDOWID $EMAIL&#34;</span> | ||
| 451 | </span></span><span style="display:flex;"><span><span style="color:#00f">end</span> | ||
| 452 | </span></span><span style="display:flex;"><span> | ||
| 453 | </span></span><span style="display:flex;"><span>@task stack <span style="color:#a31515">&#34;Starts Docker stack&#34;</span> does | ||
| 454 | </span></span><span style="display:flex;"><span> docker-compose -f stack.yml up | ||
| 455 | </span></span><span style="display:flex;"><span><span style="color:#00f">end</span> | ||
| 456 | </span></span><span style="display:flex;"><span> | ||
| 457 | </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 | ||
| 458 | </span></span><span style="display:flex;"><span> grep -ir <span style="color:#a31515">&#34;TODO|FIXME&#34;</span> . | wc -l | ||
| 459 | </span></span><span style="display:flex;"><span><span style="color:#00f">end</span> | ||
| 460 | </span></span><span style="display:flex;"><span> | ||
| 461 | </span></span><span style="display:flex;"><span>@task test1 <span style="color:#a31515">&#34;For testing 1&#34;</span> does | ||
| 462 | </span></span><span style="display:flex;"><span> unknown-command | ||
| 463 | </span></span><span style="display:flex;"><span> echo <span style="color:#a31515">&#34;test1&#34;</span> | ||
| 464 | </span></span><span style="display:flex;"><span> ls -lha | ||
| 465 | </span></span><span style="display:flex;"><span><span style="color:#00f">end</span> | ||
| 466 | </span></span><span style="display:flex;"><span> | ||
| 467 | </span></span><span style="display:flex;"><span>@task test2 <span style="color:#a31515">&#34;For testing 2&#34;</span> does | ||
| 468 | </span></span><span style="display:flex;"><span> echo <span style="color:#a31515">&#34;test1&#34;</span> | ||
| 469 | </span></span><span style="display:flex;"><span> ls -lha | ||
| 470 | </span></span><span style="display:flex;"><span> docker-compose -f samples/stack.yml up | ||
| 471 | </span></span><span style="display:flex;"><span><span style="color:#00f">end</span> | ||
| 472 | </span></span></code></pre><p>One thing that I really like about Errand. Yes, this is what it is called. And | ||
| 473 | it is available at <a href="https://git.mitjafelicijan.com/errand.git/about/">https://git.mitjafelicijan.com/errand.git/about/</a>. Moving | ||
| 474 | on. One thing that I really like is that a task is a persistent shell. By that I | ||
| 475 | mean, that the whole task, even if it contains multiple command in one shell. | ||
| 476 | In make each line in a target is that and you need to combine lines or add <code>\</code> | ||
| 477 | at the end of the line.</p> | ||
| 478 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># How you do this things in make.</span> | ||
| 479 | </span></span><span style="display:flex;"><span>target: | ||
| 480 | </span></span><span style="display:flex;"><span> source .venv/bin/activate <span style="color:#a31515">\ | ||
| 481 | </span></span></span><span style="display:flex;"><span><span style="color:#a31515"></span> python script.py | ||
| 482 | </span></span></code></pre><p>This solves this problem. Consider each task and what is being executed in that | ||
| 483 | task a shell that will only close when all the tasks are completed.</p> | ||
| 484 | <p>By self-documenting I mean that if you are in a directory with <code>Errandfile</code> in, | ||
| 485 | if you only type <code>erd</code> and press enter it should by default display all the | ||
| 486 | possible targets. In make i was doing this by having a first target be something | ||
| 487 | like <code>default</code> that echos the message “Check Makefile for all available target.” | ||
| 488 | Because all of the tasks in Errand require a message I use that to display let’s | ||
| 489 | call it table of contents.</p> | ||
| 490 | <p>Because I don’t use any external dependencies this whole thing can be statically | ||
| 491 | compiled. So that also checked one of the boxes.</p> | ||
| 492 | <p>It works on Linux and on a Mac so that’s also a bonus. I don’t believe this | ||
| 493 | would work on Windows machines because of the way that I use shell instances. By | ||
| 494 | you could use something like Windows Subsystem for Linux and run it in | ||
| 495 | there. That is a valid option.</p> | ||
| 496 | <p>To finish this essay off, how was it to use it in “real life”. I have to be | ||
| 497 | honest. Some of the missing features still bother me. <code>@dotenv</code> directive is | ||
| 498 | still missing and I need to implement this ASAP.</p> | ||
| 499 | <p>Another thing that needs to happen is support for streaming output. Currently | ||
| 500 | commands like <code>docker-compose</code> that runs in foreground mode is not compatible | ||
| 501 | with Errand. So commands that stream output are an issue. I need to revisit how | ||
| 502 | I initiate shell and how I read stdout and stderr. But that shouldn’t be a | ||
| 503 | problem.</p> | ||
| 504 | <p>I have been very satisfied with this thing. I am pleasantly surprised by how | ||
| 505 | useful it is. I really wanted to test this in the wild before I commit to it. I | ||
| 506 | have more abandoned project than Google and it’s bringing a massive shame to my | ||
| 507 | family at this point. So I wanted to be sure that this is even useful. And it | ||
| 508 | actually is. Quite surprised at myself.</p> | ||
| 509 | <p>I really need to package this now and write proper docs. And maybe rewrite | ||
| 510 | tokeniser. Its atrocious right now. Site to behold! But that is an issue for | ||
| 511 | another time.</p> | ||
| 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 +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><p>I have been using some approximation of <a href="https://jeffkreeftmeijer.com/git-flow/">Git | ||
| 544 | Flow</a> for years now and never really | ||
| 545 | questioned it to be honest. When I create a repo I create develop branch and set | ||
| 546 | it as default one and then merge to master from there. Seems reasonable enough.</p> | ||
| 547 | <p>One thing that I have learned is that long living branches are the devil. They | ||
| 548 | always end up making a huge mess when they need to be merged eventually into | ||
| 549 | master. So by that reason, what is the develop branch if not the longest living | ||
| 550 | feature branch. And from my personal experience there was never a situation | ||
| 551 | where I wasn’t sweating bullets when I had to merge develop back to master.</p> | ||
| 552 | <p>This realisation started to give me pause. So why the hell am I doing this, and | ||
| 553 | is there a better way. Well the solution was always there. And it comes in a | ||
| 554 | form of <a href="https://git-scm.com/book/en/v2/Git-Basics-Tagging">git tags</a>.</p> | ||
| 555 | <p>So what are git tags? Git tags are references to specific points in a Git | ||
| 556 | repository's history. They are used to mark important milestones, such as | ||
| 557 | releases or significant commits, making it easier to identify and access | ||
| 558 | specific versions of a project.</p> | ||
| 559 | <p>Somehow we have all hijacked the meaning of the master branch that it has to be | ||
| 560 | the most releasable version of code. And this is also where the confusing about | ||
| 561 | versioning the software kicks in. Because master branch implicitly says that we | ||
| 562 | are dealing with the rolling release type of a software. And by having a develop | ||
| 563 | branch we are hacking around this confusion. With a separation of develop and | ||
| 564 | master we lock functionalities into place and forcing a stable vs development | ||
| 565 | version of the software.</p> | ||
| 566 | <p>But if that is true and the long living branches are the devil then why have | ||
| 567 | develop at all. I think that most of this comes to how continuous integration is | ||
| 568 | being done. There usually is no granular access to tags and CD software deploys | ||
| 569 | what is present on a specific branch, may that be master for production and | ||
| 570 | develop for staging. This is a gross simplification and by having this in place | ||
| 571 | we have completely removed tagging as a viable option to create a fix point in | ||
| 572 | software cycle that says, this is the production ready code.</p> | ||
| 573 | <p>One cool thing about tags are that you can checkout a specific tag. So they | ||
| 574 | behave very similarly as branches in that regard. And you don’t have the | ||
| 575 | overhead of having two mainstream branches.</p> | ||
| 576 | <p>So what is the solution? One approach is to use development workflow, where all | ||
| 577 | changes are made on the smaller branches and continuously merged into | ||
| 578 | master. Where the software is ready to be pushed to production you tag the | ||
| 579 | master branch. This approach eliminates the need for long-lived branches and | ||
| 580 | simplifies the development process. It also encourages developers to make small, | ||
| 581 | incremental changes that can be tested and deployed quickly. However, this | ||
| 582 | approach may not be suitable for all projects or teams that heavily rely on | ||
| 583 | automated deployment based on branch names only.</p> | ||
| 584 | <p>This also requires that developers always keep production in mind. No more | ||
| 585 | living on an island of the develop branch. All your actions and code need to be | ||
| 586 | ready to meet production standards on a much smaller timescale.</p> | ||
| 587 | <p>I think that we have complicated the workflow in an honest attempt to make | ||
| 588 | things more streamlined but in the process of doing this, we have inadvertently | ||
| 589 | made our lives much more complicated.</p> | ||
| 590 | <p>In conclusion, it's important to re-evaluate our workflows from time to time to | ||
| 591 | see if they still make sense and if there are better alternatives available. | ||
| 592 | Long-living branches can be problematic, and using tags to mark important | ||
| 593 | milestones can simplify the development process.</p> | ||
| 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 +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&#39;seasy to feel burnt out or disinterested.</description> | ||
| 613 | <content:encoded><p>Programming can be a challenging and rewarding experience, but sometimes it's | ||
| 614 | easy to feel burnt out or disinterested. I have lost the passion for coding over | ||
| 615 | the past couple of months and it looked like I will never enjoy the coding as | ||
| 616 | much as I did.</p> | ||
| 617 | <p>I was feeling burnt out with programming. I thought taking a break from it and | ||
| 618 | focusing on other activities that I enjoy might be helpful. This way, I could | ||
| 619 | come back to programming with a fresh perspective and renewed energy. I also | ||
| 620 | thought about learning a new programming language or technology to keep things | ||
| 621 | interesting and challenging.</p> | ||
| 622 | <p>However, what I didn't realize was that learning a new language or technology | ||
| 623 | wasn't going to solve the underlying issue. I needed to take a step back and | ||
| 624 | re-evaluate why I had lost my passion for programming in the first place. This | ||
| 625 | involved taking a deep look into what I was doing that resulted in this rut.</p> | ||
| 626 | <p>Sometimes, it's easy to get caught up in the hype of new technologies or | ||
| 627 | languages, and we can feel like we're missing out if we're not constantly | ||
| 628 | learning and experimenting. However, it's important to remember that the latest | ||
| 629 | and greatest isn't always the best fit for our projects or our | ||
| 630 | interests. Instead of constantly chasing the next big thing, it can be helpful | ||
| 631 | to focus on what truly interests us and what we're passionate about. This can | ||
| 632 | help us stay motivated and engaged with our work, rather than feeling like we're | ||
| 633 | just going through the motions.</p> | ||
| 634 | <p>I expressed that I had lost my passion for coding over the past couple of | ||
| 635 | months, and I realized that the reason behind it was my tendency to spread | ||
| 636 | myself too thin and not focus on completing interesting projects. In order to | ||
| 637 | regain my passion for coding, I need to focus on projects that truly interest me | ||
| 638 | and give me a sense of purpose and motivation.</p> | ||
| 639 | <p>Recently, I have been playing World of Warcraft more frequently and have become | ||
| 640 | interested in developing addons for the game.</p> | ||
| 641 | <p>This quickly resulted in me creating three addons that improve the quality of | ||
| 642 | life, and I subsequently developed a more useful add-on that encapsulates all | ||
| 643 | the others I made.</p> | ||
| 644 | <p>I found it interesting that this action sparked a new interest in me. | ||
| 645 | Additionally, I discovered the Lua language, which reminded me that coding | ||
| 646 | should be fun rather than just a struggle with a language. It should be pure, | ||
| 647 | unadulterated fun.</p> | ||
| 648 | <p>I wasn't fighting the syntax, nor was I focused on finding the most optimal | ||
| 649 | solution. I simply created things without the pressure of making them the best | ||
| 650 | they could possibly be.</p> | ||
| 651 | <p>This made me realize that I actually adore simple languages that get out of the | ||
| 652 | way and let you express what you want to do. It forced me to rethink a lot about | ||
| 653 | what I use and what I actually enjoy.</p> | ||
| 654 | <p>I have decided to stick to the basics. For a scripting language, I will use | ||
| 655 | Lua. For networking, I will use Golang. And for any special needs, I will rely | ||
| 656 | on C. I do not require Rust, Nim, or Zig. This selection is more than sufficient | ||
| 657 | for my needs. I have to stay true to this simplicity. There is something to the | ||
| 658 | Occam's Razor.</p> | ||
| 659 | <p>I've been struggling with a lack of creativity lately, but now I'm experiencing | ||
| 660 | a real change. I realized I needed to take a step back and stop actively trying | ||
| 661 | to address the issue. I needed to stop worrying and overthinking it. I simply | ||
| 662 | needed some time. Looking back, I don't think I've taken any significant time | ||
| 663 | off in the last 10 years.</p> | ||
| 664 | <p>Suddenly, I find myself with the energy and passion to complete multiple small | ||
| 665 | projects. It doesn't feel like a chore at all. Who knew I needed WoW to | ||
| 666 | kickstart everything. Inspiration really does come from the strangest places.</p> | ||
| 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 +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><p>Over the past few weeks, I have been really thinking about terminal emulators, | ||
| 703 | how we interact with computers, the separation of text-based programs and GUI | ||
| 704 | ones. To be perfectly honest, I got pissed off one evening when I was cleaning | ||
| 705 | up files on my computer. Normally, I go into console and do <code>ncdu</code> and check | ||
| 706 | where the junk is. Then I start deleting stuff. Without any discrimination, | ||
| 707 | usually. But when it comes to screenshots, I have learned that it's good to keep | ||
| 708 | them somewhere near if I need to refer to something that I was doing. I am an | ||
| 709 | avid screenshot taker. So at that point I checked Pictures folder and also did a | ||
| 710 | basic search <code>find . -type f -name &quot;*.jpg&quot;</code> for all the JPEG files in my home | ||
| 711 | directory and immediately got pissed off. Why can’t I see thumbnails in my | ||
| 712 | terminal? I know why, but why in the year of 2022 this is still a problem. I am | ||
| 713 | used to traversing my disk via terminal. I am faster, and I am more comfortable | ||
| 714 | this way. But when it comes to visualization, I then need to revert to GUI | ||
| 715 | applications and again find the same file to see it. I know that programs like | ||
| 716 | <code>feh</code> and <code>sxiv</code> are available, but I would just like to see the preview. Like | ||
| 717 | <a href="https://jupyter.org/">Jupyter notebook</a> or something similar. Just having it | ||
| 718 | inline. Part of a result.</p> | ||
| 719 | <p>It also didn’t help that I was spending some time with the <a href="https://plan9.io/plan9/">Plan | ||
| 720 | 9</a> Operating system. More specifically | ||
| 721 | <a href="http://9front.org/">9FRONT</a>. The way that <a href="http://acme.cat-v.org/">ACME editor</a> | ||
| 722 | handles text editing is just wonderful. Different and fresh somehow, even though | ||
| 723 | it’s super old.</p> | ||
| 724 | <p>So, I went on a lookout for an interesting way of visualizing results of some | ||
| 725 | query. I found these applications to be outstanding examples of how not to be a | ||
| 726 | captive of a predetermined way of doing things.</p> | ||
| 727 | <ul> | ||
| 728 | <li><a href="https://www.wolfram.com/mathematica/">Wolfram Mathematica</a></li> | ||
| 729 | <li><a href="https://jupyter.org/">Jupyter notebooks</a></li> | ||
| 730 | <li><a href="http://www.9front.org">Plan 9 / 9FRONT</a></li> | ||
| 731 | <li><a href="https://templeos.org/">Temple OS</a></li> | ||
| 732 | <li><a href="https://www.gnu.org/software/emacs/">Emacs</a></li> | ||
| 733 | </ul> | ||
| 734 | <p>My idea is not as out there as ACME is, but it is a spin on the terminal | ||
| 735 | emulators. I like the modes that Vi/Vim provides you with. I like the way the | ||
| 736 | Emacs does its own <code>M-x</code> <code>M-c</code>. Furthermore, I really like how Mathematica and | ||
| 737 | Jupyter present the data in a free flowing form. And I love how Temple OS is | ||
| 738 | basically a C interpreter on some level.</p> | ||
| 739 | <blockquote> | ||
| 740 | <p><strong>Note:</strong> This is part 1 of the journey. Nowhere finished yet. I am just | ||
| 741 | tinkering with this at the moment. This whole thing can easily spectacularly | ||
| 742 | fail.</p> | ||
| 743 | </blockquote> | ||
| 744 | <p>So I started. I knew that I wanted to have the couple of modes, but I didn’t | ||
| 745 | like the repetition of keystrokes, so the only option was to have some sort of | ||
| 746 | toggle and indicate to the user that they are in a special mode. Like Vi does | ||
| 747 | for Normal and Visual mode.</p> | ||
| 748 | <p>These modes would for the first version be:</p> | ||
| 749 | <ul> | ||
| 750 | <li><em>Preview mode</em> (toggle with Ctrl + P) | ||
| 751 | <ul> | ||
| 752 | <li>When this mode would be enabled, the <code>ls</code> command would try to find images | ||
| 753 | from the results and display thumbnails from them in the terminal itself. | ||
| 754 | No ASCII art. Proper images. In a grid!</li> | ||
| 755 | </ul> | ||
| 756 | </li> | ||
| 757 | <li><em>Detach mode</em> (toggle with Ctrl + D) | ||
| 758 | <ul> | ||
| 759 | <li>When this mode would be enabled, every command would open a new window | ||
| 760 | and execute that command in it. This would be useful for starting <code>htop</code> | ||
| 761 | in a separate window.</li> | ||
| 762 | </ul> | ||
| 763 | </li> | ||
| 764 | </ul> | ||
| 765 | <p>The reason for having these modes togglable is to not ask for previews every | ||
| 766 | time. You enable a mode and until you disable it, it behaves that way. Purely | ||
| 767 | out of ergonomic reasons.</p> | ||
| 768 | <p>I would like to treat every terminal I open as a session mentally. When I start | ||
| 769 | using the terminal, I start digging deeper into the issue I am trying to | ||
| 770 | resolve. And while I am doing this, I would like to open detached windows | ||
| 771 | etc. A lot of these things can be done easily with something like | ||
| 772 | <a href="https://i3wm.org/">i3</a>, but also that pull you out of the context of what you | ||
| 773 | were doing. I would like to orchestrate everything from one single point.</p> | ||
| 774 | <p>In planning for this project, I knew that I would need to use a language like C | ||
| 775 | and a library such as <a href="https://www.libsdl.org/">SDL2</a> in order to achieve the | ||
| 776 | desired results. I had considered other options, but ultimately determined that | ||
| 777 | <a href="https://www.libsdl.org/">SDL2</a> was the best fit based on its capabilities and | ||
| 778 | reputation in the programming community.</p> | ||
| 779 | <p>At first, I thought the idea of a hardware accelerated terminal was a bit of a | ||
| 780 | joke. It seemed like such a niche and unnecessary feature, especially given the | ||
| 781 | fact that terminal emulators have been around for decades and have always relied | ||
| 782 | on software rendering. But to be fair, <a href="https://alacritty.org/">Alacritty</a> is | ||
| 783 | doing the same thing. Well, they are doing a remarkable job at it.</p> | ||
| 784 | <p>So, I embarked on a journey. Everything has to start somewhere. For me, it | ||
| 785 | started with creating a window! It has to start somewhere. 🙂</p> | ||
| 786 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000">// Oh, Hi Mark! | ||
| 787 | </span></span></span><span style="display:flex;"><span><span style="color:#008000">// Create the window, obviously. | ||
| 788 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span>SDL_Window *window = SDL_CreateWindow( | ||
| 789 | </span></span><span style="display:flex;"><span> WINDOW_TITLE, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, | ||
| 790 | </span></span><span style="display:flex;"><span> WINDOW_WIDTH, WINDOW_HEIGHT, | ||
| 791 | </span></span><span style="display:flex;"><span> SDL_WINDOW_RESIZABLE | SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN); | ||
| 792 | </span></span></code></pre><p>I continued like this to get some text displayed on the screen.</p> | ||
| 793 | <p>I noted that | ||
| 794 | <a href="https://wiki.libsdl.org/SDL_ttf/TTF_RenderText_Solid"><code>TTF_RenderText_Solid</code></a> | ||
| 795 | rendered text really poorly. There were no antialiasing at all. In my wisdom, I | ||
| 796 | never checked the documentation. Well, that was a fail. To uneducated like me: | ||
| 797 | <code>TTF_RenderText_Solid</code> renders Latin1 text at fast quality to a new 8-bit | ||
| 798 | surface. So, that's why the texts looked like shit. No wonder.</p> | ||
| 799 | <p>Remarks on <code>TTF_RenderText_Solid</code>: This function will allocate a new 8-bit, | ||
| 800 | palettized surface. The surface's 0 pixel will be the colorkey, giving a | ||
| 801 | transparent background. The 1 pixel will be set to the text color.</p> | ||
| 802 | <p>After I replaced it with | ||
| 803 | <a href="https://wiki.libsdl.org/SDL_ttf/TTF_RenderText_LCD"><code>TTF_RenderText_LCD</code></a> which | ||
| 804 | renders Latin1 text at LCD subpixel quality to a new ARGB surface, the text | ||
| 805 | started looking good. Really make sure you read the documentation. It’s actually | ||
| 806 | good. As a side note, you can find all the documentation regarding <a href="https://wiki.libsdl.org/">SDL2 on | ||
| 807 | their Wiki</a>.</p> | ||
| 808 | <p>After that was done, I started working on displaying other things like <code>Preview</code> | ||
| 809 | and <code>Detach</code> modes. This wasn’t really that hard. In SDL2 you can check all the | ||
| 810 | available events with <code>while (SDL_PollEvent(&amp;event) &gt; 0)</code> and have a bunch of | ||
| 811 | switch statements to determine which key is currently being pressed. More about | ||
| 812 | keys, <a href="https://documentation.help/SDL/sdlkey.html">SDLKey</a> and mroe about | ||
| 813 | pooling the events on | ||
| 814 | <a href="https://documentation.help/SDL/sdlpollevent.html">SDL_PollEvent</a>.</p> | ||
| 815 | <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) | ||
| 816 | </span></span><span style="display:flex;"><span>{ | ||
| 817 | </span></span><span style="display:flex;"><span> <span style="color:#00f">switch</span> (event.type) | ||
| 818 | </span></span><span style="display:flex;"><span> { | ||
| 819 | </span></span><span style="display:flex;"><span> <span style="color:#00f">case</span> SDL_QUIT: | ||
| 820 | </span></span><span style="display:flex;"><span> running = false; | ||
| 821 | </span></span><span style="display:flex;"><span> <span style="color:#00f">break</span>; | ||
| 822 | </span></span><span style="display:flex;"><span> | ||
| 823 | </span></span><span style="display:flex;"><span> <span style="color:#00f">case</span> SDL_TEXTINPUT: | ||
| 824 | </span></span><span style="display:flex;"><span> <span style="color:#00f">if</span> (!meta_key_pressed) | ||
| 825 | </span></span><span style="display:flex;"><span> { | ||
| 826 | </span></span><span style="display:flex;"><span> strncat(input_prompt_text, event.text.text, 1); | ||
| 827 | </span></span><span style="display:flex;"><span> update_input_prompt = true; | ||
| 828 | </span></span><span style="display:flex;"><span> } | ||
| 829 | </span></span><span style="display:flex;"><span> <span style="color:#00f">break</span>; | ||
| 830 | </span></span><span style="display:flex;"><span> } | ||
| 831 | </span></span><span style="display:flex;"><span>} | ||
| 832 | </span></span></code></pre><p>After that was somewhat working correctly, I started creating a struct that | ||
| 833 | would hold all the commands and results and I call them Cells. Yes, I stole that | ||
| 834 | naming idea from Jupyter.</p> | ||
| 835 | <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> | ||
| 836 | </span></span><span style="display:flex;"><span>{ | ||
| 837 | </span></span><span style="display:flex;"><span> <span style="color:#2b91af">char</span> *command; | ||
| 838 | </span></span><span style="display:flex;"><span> <span style="color:#2b91af">char</span> *result; | ||
| 839 | </span></span><span style="display:flex;"><span> SDL_Surface *surface; | ||
| 840 | </span></span><span style="display:flex;"><span> SDL_Texture *texture; | ||
| 841 | </span></span><span style="display:flex;"><span> SDL_Rect rect; | ||
| 842 | </span></span><span style="display:flex;"><span>} Cell; | ||
| 843 | </span></span></code></pre><p>I am at a place now where I am starting to implement scrolling. This will for | ||
| 844 | sure be fun to code. Memory management in C is super easy. 😂</p> | ||
| 845 | <p>I have also added a simple <a href="https://en.wikipedia.org/wiki/INI_file">INI file like | ||
| 846 | configuration</a> support. It is done in an | ||
| 847 | <a href="https://github.com/nothings/stb/blob/master/docs/stb_howto.txt">STB style of | ||
| 848 | header</a> and maps | ||
| 849 | to specific options supported by the terminal. It is not universal, and the code | ||
| 850 | below demonstrates how I will use it in the future.</p> | ||
| 851 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#00f">#ifndef CONFIG_H | ||
| 852 | </span></span></span><span style="display:flex;"><span><span style="color:#00f">#define CONFIG_H | ||
| 853 | </span></span></span><span style="display:flex;"><span><span style="color:#00f"></span> | ||
| 854 | </span></span><span style="display:flex;"><span><span style="color:#008000">/* | ||
| 855 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"># This is a comment | ||
| 856 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"> | ||
| 857 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"># This is the first configuration option | ||
| 858 | </span></span></span><span style="display:flex;"><span><span style="color:#008000">dettach=value11111 | ||
| 859 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"> | ||
| 860 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"># This is the second configuration option | ||
| 861 | </span></span></span><span style="display:flex;"><span><span style="color:#008000">preview=value22222 | ||
| 862 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"> | ||
| 863 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"># This is the third configuration option | ||
| 864 | </span></span></span><span style="display:flex;"><span><span style="color:#008000">debug=value33333 | ||
| 865 | </span></span></span><span style="display:flex;"><span><span style="color:#008000">*/</span> | ||
| 866 | </span></span><span style="display:flex;"><span> | ||
| 867 | </span></span><span style="display:flex;"><span><span style="color:#008000">// Define a struct to hold the configuration options | ||
| 868 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span><span style="color:#00f">typedef</span> <span style="color:#00f">struct</span> | ||
| 869 | </span></span><span style="display:flex;"><span>{ | ||
| 870 | </span></span><span style="display:flex;"><span> <span style="color:#2b91af">char</span> dettach[256]; | ||
| 871 | </span></span><span style="display:flex;"><span> <span style="color:#2b91af">char</span> preview[256]; | ||
| 872 | </span></span><span style="display:flex;"><span> <span style="color:#2b91af">char</span> debug[256]; | ||
| 873 | </span></span><span style="display:flex;"><span>} Config; | ||
| 874 | </span></span><span style="display:flex;"><span> | ||
| 875 | </span></span><span style="display:flex;"><span><span style="color:#008000">// Read the configuration file and return the options as a struct | ||
| 876 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span><span style="color:#00f">extern</span> Config read_config_file(<span style="color:#00f">const</span> <span style="color:#2b91af">char</span> *filename) | ||
| 877 | </span></span><span style="display:flex;"><span>{ | ||
| 878 | </span></span><span style="display:flex;"><span> <span style="color:#008000">// Create a struct to hold the configuration options | ||
| 879 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span> Config config = {0}; | ||
| 880 | </span></span><span style="display:flex;"><span> | ||
| 881 | </span></span><span style="display:flex;"><span> <span style="color:#008000">// Open the configuration file | ||
| 882 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span> FILE *file = fopen(filename, <span style="color:#a31515">&#34;r&#34;</span>); | ||
| 883 | </span></span><span style="display:flex;"><span> | ||
| 884 | </span></span><span style="display:flex;"><span> <span style="color:#008000">// Read each line from the file | ||
| 885 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span> <span style="color:#2b91af">char</span> line[256]; | ||
| 886 | </span></span><span style="display:flex;"><span> <span style="color:#00f">while</span> (fgets(line, <span style="color:#00f">sizeof</span>(line), file)) | ||
| 887 | </span></span><span style="display:flex;"><span> { | ||
| 888 | </span></span><span style="display:flex;"><span> <span style="color:#008000">// Check if this line is a comment or empty | ||
| 889 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></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>) | ||
| 890 | </span></span><span style="display:flex;"><span> <span style="color:#00f">continue</span>; | ||
| 891 | </span></span><span style="display:flex;"><span> | ||
| 892 | </span></span><span style="display:flex;"><span> <span style="color:#008000">// Parse the line to get the option and value | ||
| 893 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span> <span style="color:#2b91af">char</span> option[128], value[128]; | ||
| 894 | </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) | ||
| 895 | </span></span><span style="display:flex;"><span> <span style="color:#00f">continue</span>; | ||
| 896 | </span></span><span style="display:flex;"><span> | ||
| 897 | </span></span><span style="display:flex;"><span> <span style="color:#008000">// Set the value of the appropriate option in the config struct | ||
| 898 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span> <span style="color:#00f">if</span> (strcmp(option, <span style="color:#a31515">&#34;dettach&#34;</span>) == 0) | ||
| 899 | </span></span><span style="display:flex;"><span> { | ||
| 900 | </span></span><span style="display:flex;"><span> strncpy(config.option1, value, <span style="color:#00f">sizeof</span>(config.option1)); | ||
| 901 | </span></span><span style="display:flex;"><span> } | ||
| 902 | </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) | ||
| 903 | </span></span><span style="display:flex;"><span> { | ||
| 904 | </span></span><span style="display:flex;"><span> strncpy(config.option2, value, <span style="color:#00f">sizeof</span>(config.option2)); | ||
| 905 | </span></span><span style="display:flex;"><span> } | ||
| 906 | </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) | ||
| 907 | </span></span><span style="display:flex;"><span> { | ||
| 908 | </span></span><span style="display:flex;"><span> strncpy(config.option3, value, <span style="color:#00f">sizeof</span>(config.option3)); | ||
| 909 | </span></span><span style="display:flex;"><span> } | ||
| 910 | </span></span><span style="display:flex;"><span> } | ||
| 911 | </span></span><span style="display:flex;"><span> | ||
| 912 | </span></span><span style="display:flex;"><span> <span style="color:#008000">// Close the configuration file | ||
| 913 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span> fclose(file); | ||
| 914 | </span></span><span style="display:flex;"><span> | ||
| 915 | </span></span><span style="display:flex;"><span> <span style="color:#008000">// Return the configuration options | ||
| 916 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span> <span style="color:#00f">return</span> config; | ||
| 917 | </span></span><span style="display:flex;"><span>} | ||
| 918 | </span></span><span style="display:flex;"><span> | ||
| 919 | </span></span><span style="display:flex;"><span><span style="color:#00f">#endif | ||
| 920 | </span></span></span></code></pre><p>This is as far as I managed to get for now. I have a daily job and this | ||
| 921 | prohibits me to work on these things full time. But I should probably get back | ||
| 922 | and finish this. At least have a simple version working out, so I can start | ||
| 923 | testing it on my machines. Fingers crossed. 🕵️♂️</p> | ||
| 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 +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><p>A couple of months ago, I got an idea about micro soundtracks. In this concept, | ||
| 936 | you are the observer, director, and audience in this tiny movies.</p> | ||
| 937 | <p>What you do is to attempt to imagine what would be happening around you based on | ||
| 938 | a title of the song and let the song help you fill the void in your story.</p> | ||
| 939 | <p>I made these songs is Logic Pro X. Every year or so I do this kind of thing and | ||
| 940 | make a couple of songs similar to this. But this is the first time I am posting | ||
| 941 | about it.</p> | ||
| 942 | <p>You can listen to the whole set on | ||
| 943 | <a href="https://www.youtube.com/watch?v=_5oXBhSmF3c">Youtube</a> or scroll down the page | ||
| 944 | and there are embedded players for each song.</p> | ||
| 945 | <h2 id="a-bunch-of-inter-dimensional-people-with-loud-clocks">A bunch of inter-dimensional people with loud clocks</h2> | ||
| 946 | <p>A group of inter-dimensional people are going up and down the elevator with you | ||
| 947 | while having loud clocks around their necks. Each clock ticks on a different | ||
| 948 | frequency. A lot of other sounds are getting drawn into your dimension, | ||
| 949 | resulting in a strange merging of dimensions.</p> | ||
| 950 | <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> | ||
| 951 | <h2 id="two-black-holes-conversing-about-the-weather">Two black holes conversing about the weather</h2> | ||
| 952 | <p>You are a traveler in a spaceship flying very close to two colliding black holes | ||
| 953 | having a discussion about the weather while tearing each other apart. During all | ||
| 954 | this your ship is getting pulled into the event horizon of both black holes, | ||
| 955 | putting a lot of strain on your spaceship.</p> | ||
| 956 | <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> | ||
| 957 | <h2 id="a-planet-where-every-organism-is-a-plant">A planet where every organism is a plant</h2> | ||
| 958 | <p>You land on a planet where every living organism is a plant and among those | ||
| 959 | plants some of them are highly intelligent, and you were asked to make first | ||
| 960 | contact with the native species. Your visit takes place in a giant cave where | ||
| 961 | you are meeting these plants, and they are talking to you.</p> | ||
| 962 | <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> | ||
| 963 | <h2 id="bio-implants-having-a-fit-and-reprogramming-your-brain">Bio implants having a fit and reprogramming your brain</h2> | ||
| 964 | <p>In a distant future where everybody has bio implants, you have just received | ||
| 965 | your first one, which happens to be a brain implant. Something goes wrong, and | ||
| 966 | your implant is starting to misbehave, and you are experiencing brain | ||
| 967 | malfunctions. You are on the streets at night a couple of hours after your | ||
| 968 | procedure. You can feel your sanity breaking down.</p> | ||
| 969 | <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> | ||
| 970 | <h2 id="cow-animation">Cow animation</h2> | ||
| 971 | <p>I also made this little cow animation. Go into full screen to see the effects in | ||
| 972 | more details.</p> | ||
| 973 | <p><video src="/posts/microsoundtrack/cow.m4v" controls loop></video></p> | ||
| 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 +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><h2 id="initial-thoughts">Initial thoughts</h2> | ||
| 986 | <p><em>This post is a critique on the current state of web development. It is an | ||
| 987 | opinionated post! I will learn more about this in the future, and probably | ||
| 988 | slightly change my mind about some of the things I criticize.</em></p> | ||
| 989 | <p>I have started working on a hobby project about two weeks ago, and I wanted to | ||
| 990 | use that situation as a learning one. Trying new things, new technologies, new | ||
| 991 | tools. I always considered myself to be an adventurous person when it comes to | ||
| 992 | technology. I never shy away from trying new languages, new operating systems | ||
| 993 | etc. Likewise, I find the whole experience satisfying, and it tickles that part | ||
| 994 | of my brain that finds discovery the highest of the mountains to climb.</p> | ||
| 995 | <p>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 | ||
| 997 | level up your character and go into these scriptable battles. You know, RPG | ||
| 998 | elements.</p> | ||
| 999 | <p>So, the natural way to go would be some sort of SPA (single page application) | ||
| 1000 | with basic routing and some state management. Nothing crazy.</p> | ||
| 1001 | <blockquote> | ||
| 1002 | <p><strong>Before we move on</strong>, I have to be transparent. Take my views on this with | ||
| 1003 | a grain of salt. I have only scratched the surface with these technologies, | ||
| 1004 | and my knowledge is full of gaps. This is my experience using some of these | ||
| 1005 | products for the first time or in a limited capacity.</p> | ||
| 1006 | </blockquote> | ||
| 1007 | <p>Having this out of the way, I got myself a fresh pot of coffee and down the | ||
| 1008 | rabbit hole I went.</p> | ||
| 1009 | <h2 id="giving-react-js-a-spin">Giving React JS a spin</h2> | ||
| 1010 | <p>I first tried <a href="https://reactjs.org/">React JS</a>. I kind of like it. Furthermore, | ||
| 1011 | I have worked with libraries like this in the past and also wrote a couple of | ||
| 1012 | them (nothing compared to that level), but I had the basic understanding of what | ||
| 1013 | was going on. I rolled up a project quickly and had basic things done in a | ||
| 1014 | matter of two hours, which was impressive.</p> | ||
| 1015 | <p>I prefer using <a href="https://tailwindcss.com/">Tailwind CSS</a> for my styling | ||
| 1016 | pleasures, and integrating that was also a painless experience. It was actually | ||
| 1017 | nice to see that some things got better with time. In about 2 minutes I got | ||
| 1018 | Tailwind working, and I was able to use classes at my disposal. All that | ||
| 1019 | <code>postcss</code> stuff was taken care of by adding a couple of things in config files | ||
| 1020 | (all described really well in their documentation).</p> | ||
| 1021 | <p>It is not that different from Vue which I have had more encounters with in the | ||
| 1022 | past People will probably call me a lunatic for saying this. But you know, it is | ||
| 1023 | the truth. Same same, but different. I still believe that using libraries like | ||
| 1024 | this is beneficial. I am not a JavaScript purist. They all have their quirks, | ||
| 1025 | but at the end of the day, I truly believe it’s worth it.</p> | ||
| 1026 | <h2 id="bundlers-and-transpilers">Bundlers and Transpilers</h2> | ||
| 1027 | <p>I still reject calling <a href="https://www.typescriptlang.org/">Typescript</a> to | ||
| 1028 | <a href="https://www.javascript.com/">JavaScript</a> conversion a &quot;compilation process&quot;. I | ||
| 1029 | call them <a href="https://devopedia.org/transpiler">transpilers</a>, and I don’t care! 😈</p> | ||
| 1030 | <p>The first one that I ever used was <a href="https://webpack.js.org/">webpack</a>, and it | ||
| 1031 | was an absolute horrific experience. Saying this, it is an absolutely fantastic | ||
| 1032 | tool. I felt more like a config editor than actually a programmer. To be fair, | ||
| 1033 | I am a huge fan of <a href="https://www.gnu.org/software/make/">make</a>, and you can do as | ||
| 1034 | you wish with this information. I like my build systems simple.</p> | ||
| 1035 | <p>Also, isn’t it interesting that we need something like | ||
| 1036 | <a href="https://babeljs.io/">Babel</a> to make JavaScript code work in a browser that has | ||
| 1037 | only one client side scripting available, which is by no accident also | ||
| 1038 | JavaScript. Why? I know why it’s needed, but seriously, why.</p> | ||
| 1039 | <p>I haven’t used Babel for years now. Or if I did, it was packaged together by | ||
| 1040 | some other bundler thingy. Which does not make things better, but at least I | ||
| 1041 | didn’t need to worry about it.</p> | ||
| 1042 | <p>I really don’t like complicated build systems. I really don’t like abstracting | ||
| 1043 | code and making things appear magical. The older I get, the more I appreciate | ||
| 1044 | clear and clean, expressive code. No one-liners, if possible.</p> | ||
| 1045 | <p>But I have to give props to <a href="https://vitejs.dev/">Vite</a>! This was one of the | ||
| 1046 | best developer experiences I have ever had. Granted, it still has magical | ||
| 1047 | properties. And yes, it still is a bundler and abstracts things to the nth | ||
| 1048 | degree. But at least it didn’t force me to configure 700 lines of JSON. And I | ||
| 1049 | know that this makes me a hypocrite. You can’t have it all. Nonetheless, my | ||
| 1050 | reasoning here is, if using bundlers is inevitable, then at least they should | ||
| 1051 | provide an excellent developer experience.</p> | ||
| 1052 | <p>I also noticed that now the catch-all phrase is “blazingly fast” and “lightning | ||
| 1053 | fast” and “next generation” and stuff like that. I mean, yeah, tools should get | ||
| 1054 | faster with time. But saying that starting a project now takes 2 seconds instead | ||
| 1055 | of 20 seconds is something that is a break it or make it kind of a deal is | ||
| 1056 | ridiculous. I don’t mind waiting a couple of seconds every couple of days. I | ||
| 1057 | also don’t create 700 projects every day, and also who does? This argument has | ||
| 1058 | no bite. All I want is a decent reload time (~100ms is more than good enough for | ||
| 1059 | me) and that is it.</p> | ||
| 1060 | <p>You don’t need to sell me benefits if I only get them when I start a fresh | ||
| 1061 | project, and then try to convince me that this is somehow changing the fate of | ||
| 1062 | the universe. First of all, it is not. And second, if this is your only argument | ||
| 1063 | for your tool, I would advise you to maybe re-focus your efforts to something | ||
| 1064 | else. Vite says that startup times are really fast. And if that would be the | ||
| 1065 | only thing differentiating it from other tools, I would ignore it. But it has | ||
| 1066 | some really compelling features like <a href="https://www.geeksforgeeks.org/reactjs-hot-module-replacement/">Hot Module | ||
| 1067 | Replacement</a> that | ||
| 1068 | really works well. It was a joy to use.</p> | ||
| 1069 | <p>So, I will be definitely using Vite in the future.</p> | ||
| 1070 | <h2 id="jam-stack-mach-stack-no-snack">Jam Stack, Mach Stack no snack</h2> | ||
| 1071 | <p>Let's get a couple of the acronyms out of the way, so we all know what we are | ||
| 1072 | talking about:</p> | ||
| 1073 | <ul> | ||
| 1074 | <li>Jam Stack - JavaScript, API and Markup</li> | ||
| 1075 | <li>Mach Stack - Microservices, API-first, Cloud-Native SaaS, Headless</li> | ||
| 1076 | </ul> | ||
| 1077 | <p>It is so hard to follow all these new trendy things happening around you, that | ||
| 1078 | it makes you have a massive <strong>FOMO</strong> all the time. But on the other hand, you | ||
| 1079 | also don’t want to be that old fart that doesn’t move with the times and still | ||
| 1080 | writes his trusty jQuery code while listening to Blink 182 All the small things | ||
| 1081 | on full blast. It’s a good song, don’t get me wrong, but there are other songs | ||
| 1082 | out there.</p> | ||
| 1083 | <p>I have to admit. <a href="https://vercel.com/">Vercel</a> is really cool! Love the | ||
| 1084 | simplicity of the service. You could compare it to | ||
| 1085 | <a href="https://www.netlify.com/">Netlify</a>. I haven’t tried Netlify extensively, but | ||
| 1086 | from a couple of experimental deployments I still prefer Vercel. It is much more | ||
| 1087 | streamlined, but maybe this is bias in me. I really like Vercel’s Analytics, | ||
| 1088 | which give you a <a href="https://web.dev/vitals/">Core Web Vitals report</a> in their | ||
| 1089 | admin console. Kind of cool, I’m not going to lie.</p> | ||
| 1090 | <p>This whole idea about frontend and backend merging into <a href="https://www.debugbear.com/blog/server-side-rendering">SSR (server-side | ||
| 1091 | rendering)</a> looks so good | ||
| 1092 | on paper. It almost doesn’t come with any major flaws.</p> | ||
| 1093 | <p>But when it comes to the actual implementation, there is much to be desired. | ||
| 1094 | I’m going to lump <a href="https://nextjs.org/">Next.js</a> and | ||
| 1095 | <a href="https://nuxtjs.org/">Nuxt.js</a> together because they are essentially the same | ||
| 1096 | thing, just a different library.</p> | ||
| 1097 | <p>Now comes the reality. Mixing backend and frontend in this manner creates this | ||
| 1098 | weird mental model where you kind of rely on magical properties of these | ||
| 1099 | libraries. You relinquish control over to them for better developer experience. | ||
| 1100 | But is that really true? Initially, I was so stoked about it. However, the more | ||
| 1101 | I used them, the more I felt uncomfortable. I felt dirty, actually. Maybe this | ||
| 1102 | is because I come from old ways of doing things where you control every step of | ||
| 1103 | request, and allowing something to hijack it feels like blasphemy.</p> | ||
| 1104 | <p>More than that, some pretty significant technical issues arose from this. How do | ||
| 1105 | you do JWT token authentication? You put it in <code>api</code> folder and then do some | ||
| 1106 | fetching and storing into local state management. But doing this also requires | ||
| 1107 | some tinkering with await/async stuff on the React/Vue side of things. And then | ||
| 1108 | you need to write middleware for it. And the more I look at it, the more I see | ||
| 1109 | that this whole thing was not meant to be used like this, and it all feels and | ||
| 1110 | looks like a huge hack.</p> | ||
| 1111 | <p>The issue I have with this is that they over-promise and under-deliver. They | ||
| 1112 | want to be an all-in-one replacement for everything, and they don’t deliver on | ||
| 1113 | this promise. And how could they?! We have to be fair. It is an impossible task.</p> | ||
| 1114 | <p>They sell you <a href="https://www.geeksforgeeks.org/overview-of-noops/">NoOps</a>, but | ||
| 1115 | when you need to accomplish something a little bit more out of the scope of | ||
| 1116 | Hello World, you have to make hacky decisions to make it work. And having a | ||
| 1117 | deployment strategy that relies on many moving parts is never a good idea. | ||
| 1118 | Abstracting too much is usually a sign of bad architecture.</p> | ||
| 1119 | <p>Lately, this has become a huge trend that will for sure bite us in the future. | ||
| 1120 | And let’s not get it twisted. By doing this, PaaS providers like | ||
| 1121 | <a href="https://aws.amazon.com/">AWS</a>, <a href="https://cloud.google.com/">GCS</a>, etc. obscure | ||
| 1122 | their billing, and you end up paying more than you really should. And even if | ||
| 1123 | that is not an issue, it comes down to the principle of things. AWS is known for | ||
| 1124 | having multiple “currencies“ inside their projects like write operations, read | ||
| 1125 | operations, etc. which add up, and it creates this impossible to track billing | ||
| 1126 | scheme. It all behaves suspiciously like a pay-to-win game you could find on | ||
| 1127 | mobile phones that scams you out of your money.</p> | ||
| 1128 | <p>And as far as I am concerned, the most important thing was me not coding the | ||
| 1129 | functionalities for the game I want to make. I was battling libraries and cloud | ||
| 1130 | providers. How to deploy, what settings are relevant. Bad documentation or | ||
| 1131 | multiple versions of achieving the same thing. You are getting bombarded by all | ||
| 1132 | this information, and you don’t really have any control over it. | ||
| 1133 | Production-ready code becomes a joke, essentially. Especially if you tend to | ||
| 1134 | work on that project for a prolonged period of time.</p> | ||
| 1135 | <p>All of these options end up creating a fatigue. What to choose, what not to | ||
| 1136 | choose. Unnecessary worrying about if the stack will still be deemed worthy in | ||
| 1137 | six months. There is elegance in simplicity.</p> | ||
| 1138 | <blockquote> | ||
| 1139 | <p>JavaScript UI frameworks and libraries work in cycles. Every six months or | ||
| 1140 | so, a new one pops up, claiming that it has revolutionized UI development. | ||
| 1141 | Thousands of developers adopt it into their new projects, blog posts are | ||
| 1142 | written, 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</p> | ||
| 1145 | </blockquote> | ||
| 1146 | <p>And this jab at these libraries and cloud providers is not done out of malice. | ||
| 1147 | It is a real concern that I have about them. In my life, I have seen | ||
| 1148 | technologies come and go, but the basics always stick around. So surrendering | ||
| 1149 | all the power you have to a library or a cloud provider is in my opinion a | ||
| 1150 | stupid move.</p> | ||
| 1151 | <h2 id="tailwind-css-still-rocks">Tailwind CSS still rocks!</h2> | ||
| 1152 | <p>You know, many people say negative things about Tailwind. And after a lot of | ||
| 1153 | deliberation, I came to the conclusion that Tailwind is good for two types of | ||
| 1154 | developers. Tailwind is good for a complete noob or a senior developer. A | ||
| 1155 | complete noob doesn’t really care about inner workings of CSS, and a senior | ||
| 1156 | developer also doesn’t care about CSS. Well, at least, not anymore. And | ||
| 1157 | developers in between usually have the biggest issues with it. Not always of | ||
| 1158 | course, but in a lot of cases.</p> | ||
| 1159 | <p>I like the creature comforts of Tailwind. Being utility first would make me | ||
| 1160 | argue that it is actually more similar to <a href="https://sass-lang.com/">Sass</a> or | ||
| 1161 | <a href="https://lesscss.org/">Less</a> than something like Bootstrap. Not technically, but | ||
| 1162 | ideologically. After I started using it, I never looked back. I use it every | ||
| 1163 | time I need to do something web related.</p> | ||
| 1164 | <p>Writing CSS for general things feels like going several steps back. Instead of | ||
| 1165 | focusing on what you are actually trying to achieve, you focus on notations like | ||
| 1166 | <a href="https://en.bem.info/methodology/css/">BEM</a>, code structuring, optimizing HTML | ||
| 1167 | size. Just doing things that make 0.1% difference. You know that saying: Early | ||
| 1168 | optimization is the root of all evil. Exactly that.</p> | ||
| 1169 | <p>I am also not saying that Tailwind is the cure for everything. Sometimes custom | ||
| 1170 | CSS is necessary. But from what I found out in using it for almost two years in | ||
| 1171 | a production environment (on a site getting quite a lot of traffic and | ||
| 1172 | constantly being changed), I can say without any reservations that Tailwind | ||
| 1173 | saved our asses countless times. We would be rewriting CSS all the time without | ||
| 1174 | it. And I don’t really think writing CSS is the best way to spend my time.</p> | ||
| 1175 | <p>I have also noticed that people who criticize Tailwind the most never actually | ||
| 1176 | used it in a real project that has a long lifetime with plenty of changes that | ||
| 1177 | will happen in the future.</p> | ||
| 1178 | <p>But you know, whatever floats your boat!</p> | ||
| 1179 | <h2 id="code-maintainability">Code maintainability</h2> | ||
| 1180 | <p>Somehow, people also stopped talking about maintenance. If you constantly try to | ||
| 1181 | catch the latest and greatest train, you are by that logic always trying new | ||
| 1182 | things. Which is a good thing if you want to learn about technologies and try | ||
| 1183 | them. But for the production environment, you have to have a stable stack that | ||
| 1184 | doesn’t change every 6 months.</p> | ||
| 1185 | <p>You can lock dependencies for sure. Nevertheless, the hype train moves along | ||
| 1186 | anyway. And the mindset this breeds goes against locking the code. This | ||
| 1187 | bleeding-edge rolling release cycle is not helping. That is why enterprise | ||
| 1188 | solutions usually look down on these popular stacks and only do bare minimum to | ||
| 1189 | appear hip and cool.</p> | ||
| 1190 | <p>With that said, I still think that progress is good, but should be taken with a | ||
| 1191 | grain of salt. If your project is something that should be built once and then | ||
| 1192 | rarely updated, going with the latest stack is a possible way to go. But, if you | ||
| 1193 | are working on a project that lasts for years, you should probably approach it | ||
| 1194 | with some level of caution. Web development is often times too volatile.</p> | ||
| 1195 | <h2 id="web-development-has-a-marketing-issue">Web development has a marketing issue</h2> | ||
| 1196 | <p>I noticed that almost every project now has this marketing spin put on it. | ||
| 1197 | Everything is blazingly fast now. I get it, they are competing for your | ||
| 1198 | attention, but what happened to just being truthful and not inflating reality.</p> | ||
| 1199 | <p>And in order to appeal to mass market, they leave things out of their marketing | ||
| 1200 | materials. These open-source projects are now behaving more and more like | ||
| 1201 | companies do. Which is a scary thought on its self.</p> | ||
| 1202 | <p>And we are also seeing a rise in a concept of building a company in the open, | ||
| 1203 | which is a good thing, don't get me wrong. But when it is using open-source to | ||
| 1204 | lure people and then lock them in their ecosystem, there is where I have issues | ||
| 1205 | with it.</p> | ||
| 1206 | <p>This might be because I have been using GNU/Linux for 20 years now and have been | ||
| 1207 | so beholden for my success to open-source that I see issues when open-source is | ||
| 1208 | being used to trick people into a false sense of security that these projects | ||
| 1209 | are built in the spirit of open-source. Because there is a difference. They are | ||
| 1210 | NOT! They have a really specific goal in mind. And the open-source is being used | ||
| 1211 | as a delivery system. Which is in my opinion disgusting!</p> | ||
| 1212 | <h2 id="conclusion">Conclusion</h2> | ||
| 1213 | <p>I will end my post with this. Web development is running now in circles. People | ||
| 1214 | are discovering <a href="https://www.tutorialspoint.com/remote-procedure-call-rpc">RPC</a> | ||
| 1215 | now and this is the now the next big thing. <a href="https://graphql.org/">GraphQL</a> is | ||
| 1216 | so passé. And I am so tired of it all. Of blazingly fast libraries, of all these | ||
| 1217 | new technologies that are actually just a remake of old ones. Of just the | ||
| 1218 | general spirit of the web. I will just use what I already know. Which worked 10 | ||
| 1219 | years ago and will work 10 years after this. I will adopt a couple of little | ||
| 1220 | tools like Vite. But I will not waste my time on this anymore.</p> | ||
| 1221 | <p>It was a good exercise to get in touch with what’s new now. Nothing really | ||
| 1222 | changed that much. FOMO is now cured! Now I have to get my ass back to actually | ||
| 1223 | code and make the project that I wanted to make in the first place.</p> | ||
| 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 +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><p>This is a bit of a different post than I usually write, but quite interesting | ||
| 1240 | one to me. River Sava has plenty of hydropower plants located down the stream. | ||
| 1241 | This makes regulating the strength of a current easier than normally. Because of | ||
| 1242 | lower stream strength and high temperatures, algae has formed on the river. | ||
| 1243 | This is the first time I've seen something like this in my whole life.</p> | ||
| 1244 | <p>Below are some photographs taken from a DJI drone capturing the event.</p> | ||
| 1245 | <figure> | ||
| 1246 | <img src="/posts/algae-sava/dji-algae-0.jpg" alt="Algae on Sava" /> | ||
| 1247 | </figure> | ||
| 1248 | <figure> | ||
| 1249 | <img src="/posts/algae-sava/dji-algae-1.jpg" alt="Algae on Sava" /> | ||
| 1250 | </figure> | ||
| 1251 | <figure> | ||
| 1252 | <img src="/posts/algae-sava/dji-algae-2.jpg" alt="Algae on Sava" /> | ||
| 1253 | </figure> | ||
| 1254 | <figure> | ||
| 1255 | <img src="/posts/algae-sava/dji-algae-3.jpg" alt="Algae on Sava" /> | ||
| 1256 | </figure> | ||
| 1257 | <figure> | ||
| 1258 | <img src="/posts/algae-sava/dji-algae-4.jpg" alt="Algae on Sava" /> | ||
| 1259 | </figure> | ||
| 1260 | <figure> | ||
| 1261 | <img src="/posts/algae-sava/dji-algae-5.jpg" alt="Algae on Sava" /> | ||
| 1262 | </figure> | ||
| 1263 | <p>I will try to get more photos of this in the future days and if something | ||
| 1264 | intriguing shows up will post it again on the blog.</p> | ||
| 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 +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><h2 id="introduction">Introduction</h2> | ||
| 1277 | <p>Lately, I have been thinking a lot about the nature of life, what are the | ||
| 1278 | foundation blocks of life and things like that. It's remarkable how complex and | ||
| 1279 | on the other hand simple the creation is when you look at it. The miracle of | ||
| 1280 | life keeps us grounded when our imagination goes wild. If the DNA are the blocks | ||
| 1281 | of life, you could consider them to be an API nature provided us to better | ||
| 1282 | understand all of this chaos masquerading as order.</p> | ||
| 1283 | <p>I have been reading a lot about superintelligence and our somehow misguided path | ||
| 1284 | to create general artificial intelligence. What would the building blocks or our | ||
| 1285 | creation look like? Is the compression really the ultimate storage of | ||
| 1286 | information? Will our creation also ponder this questions when creating new | ||
| 1287 | worlds for themselves, or will we just disappear into the vastness of | ||
| 1288 | possibilities? It is a little offensive that we are playing God whilst being | ||
| 1289 | completely ignorant of our own reality. Who knows! Like many other | ||
| 1290 | breakthroughs, this one will also come at a cost not known to us when it finally | ||
| 1291 | happens.</p> | ||
| 1292 | <p>To keep things a bit lighter, I decided to convert some popular DNA sequences | ||
| 1293 | into an audio files for us to listen to. I am not the first one, nor I will be | ||
| 1294 | the last one to do this. But it is an interesting exercise in better | ||
| 1295 | understanding the relationship between art and science. Maybe listening to DNA | ||
| 1296 | instead of parsing it will find a way into better understanding, or at least | ||
| 1297 | enjoying the creation and cryptic nature of life.</p> | ||
| 1298 | <h2 id="dna-encoding-and-primer-example">DNA encoding and primer example</h2> | ||
| 1299 | <p>I have been exploring DNA in the past in my post from about 3 years ago in | ||
| 1300 | <a href="/encoding-binary-data-into-dna-sequence.html">Encoding binary data into DNA | ||
| 1301 | sequence</a> where I have been | ||
| 1302 | converting all sorts of data into DNA sequences.</p> | ||
| 1303 | <p>This will be a similar exercise but instead of converting to DNA, I will be | ||
| 1304 | generating tones from Nucleotides.</p> | ||
| 1305 | <table> | ||
| 1306 | <thead> | ||
| 1307 | <tr> | ||
| 1308 | <th>Nucleotides</th> | ||
| 1309 | <th>Note</th> | ||
| 1310 | <th>Frequency</th> | ||
| 1311 | </tr> | ||
| 1312 | </thead> | ||
| 1313 | <tbody> | ||
| 1314 | <tr> | ||
| 1315 | <td><strong>A</strong> (Adenine)</td> | ||
| 1316 | <td>A</td> | ||
| 1317 | <td>440 Hz</td> | ||
| 1318 | </tr> | ||
| 1319 | <tr> | ||
| 1320 | <td><strong>C</strong> (Cytosine)</td> | ||
| 1321 | <td>C</td> | ||
| 1322 | <td>783.99 Hz</td> | ||
| 1323 | </tr> | ||
| 1324 | <tr> | ||
| 1325 | <td><strong>G</strong> (Guanine)</td> | ||
| 1326 | <td>G</td> | ||
| 1327 | <td>523.25 Hz</td> | ||
| 1328 | </tr> | ||
| 1329 | <tr> | ||
| 1330 | <td><strong>T</strong> (Thymine)</td> | ||
| 1331 | <td>D</td> | ||
| 1332 | <td>587.33 Hz</td> | ||
| 1333 | </tr> | ||
| 1334 | </tbody> | ||
| 1335 | </table> | ||
| 1336 | <p>Since we do not have T in equal-tempered scale, I choose D to represent T note.</p> | ||
| 1337 | <p>You can check <a href="https://pages.mtu.edu/~suits/notefreqs.html">Frequencies for equal-tempered scale, A4 = 440 | ||
| 1338 | Hz</a>. For this tuning, we also | ||
| 1339 | choose <code>Speed of Sound = 345 m/s = 1130 ft/s = 770 miles/hr</code>.</p> | ||
| 1340 | <p>Now that we have this out of the way, we can also brush up on the DNA sequencing | ||
| 1341 | a bit. This is a famous quote I also used for the encoding tests, and it goes | ||
| 1342 | like this.</p> | ||
| 1343 | <blockquote> | ||
| 1344 | <p>How wonderful that we have met with a paradox. Now we have some hope of | ||
| 1345 | making progress. | ||
| 1346 | ― Niels Bohr</p> | ||
| 1347 | </blockquote> | ||
| 1348 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>&gt;SEQ1 | ||
| 1349 | </span></span><span style="display:flex;"><span>GACAGCTTGTGTACAAGTGTGCTTGCTCGCGAGCGGGTACGCGCGTGGGCTAACAAGTGA | ||
| 1350 | </span></span><span style="display:flex;"><span>GCCAGCAGGTGAACAAGTGTGCGGACAAGCCAGCAGGTGCGCGGACAAGCTGGCGGGTGA | ||
| 1351 | </span></span><span style="display:flex;"><span>ACAAGTGTGCCGGTGAGCCAACAAGCAGACAAGTAAGCAGGTACGCAGGCGAGCTTGTCA | ||
| 1352 | </span></span><span style="display:flex;"><span>ACTCACAAGATCGCTTGTGTACAAGTGTGCGGACAAGCCAGCAGGTGCGCGGACAAGTAT | ||
| 1353 | </span></span><span style="display:flex;"><span>GCTTGCTGGCGGACAAGCCAGCTTGTAAGCGGACAAGCTTGCGCACAAGCTGGCAGGCCT | ||
| 1354 | </span></span><span style="display:flex;"><span>GCCGGCTCGCGTACAAATTCACAAGTAAGTACGCTTGCGTGTACGCGGGTATGTATACTC | ||
| 1355 | </span></span><span style="display:flex;"><span>AACCTCACCAAACGGGACAAGATCGCCGGCGGGCTAGTATACAAGAACGCTTGCCAGTAC | ||
| 1356 | </span></span><span style="display:flex;"><span>AACC | ||
| 1357 | </span></span></code></pre><p>This is what we gonna work with to get things rolling forward, when creating | ||
| 1358 | parser and waveform generator.</p> | ||
| 1359 | <h2 id="parsing-dna-data">Parsing DNA data</h2> | ||
| 1360 | <p>This step is rather simple one. All we need to do is parse input DNA sequence in | ||
| 1361 | <a href="https://en.wikipedia.org/wiki/FASTA_format">FASTA format</a> well known in | ||
| 1362 | <a href="https://en.wikipedia.org/wiki/Bioinformatics">Bioinformatics</a> to extract single | ||
| 1363 | Nucleotides that will be converted into separate tones based on equal-tempered | ||
| 1364 | scale explained above.</p> | ||
| 1365 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>nucleotide_tone_map = { | ||
| 1366 | </span></span><span style="display:flex;"><span> <span style="color:#a31515">&#39;A&#39;</span>: 440, | ||
| 1367 | </span></span><span style="display:flex;"><span> <span style="color:#a31515">&#39;C&#39;</span>: 523.25, | ||
| 1368 | </span></span><span style="display:flex;"><span> <span style="color:#a31515">&#39;G&#39;</span>: 783.99, | ||
| 1369 | </span></span><span style="display:flex;"><span> <span style="color:#a31515">&#39;T&#39;</span>: 587.33, <span style="color:#008000"># converted to D</span> | ||
| 1370 | </span></span><span style="display:flex;"><span>} | ||
| 1371 | </span></span><span style="display:flex;"><span> | ||
| 1372 | </span></span><span style="display:flex;"><span><span style="color:#00f">def</span> split(word): | ||
| 1373 | </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] | ||
| 1374 | </span></span><span style="display:flex;"><span> | ||
| 1375 | </span></span><span style="display:flex;"><span><span style="color:#00f">def</span> generate_from_dna_sequence(sequence): | ||
| 1376 | </span></span><span style="display:flex;"><span> <span style="color:#00f">for</span> nucleotide <span style="color:#00f">in</span> split(sequence): | ||
| 1377 | </span></span><span style="display:flex;"><span> print(nucleotide, nucleotide_tone_map[nucleotide]) | ||
| 1378 | </span></span></code></pre><h2 id="generating-sine-wave">Generating sine wave</h2> | ||
| 1379 | <p>Because we are essentially creating a long stream of notes we will be appending | ||
| 1380 | sine notes to a global array we will later use for creating a WAV file out of | ||
| 1381 | it.</p> | ||
| 1382 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#00f">import</span> math | ||
| 1383 | </span></span><span style="display:flex;"><span> | ||
| 1384 | </span></span><span style="display:flex;"><span><span style="color:#00f">def</span> append_sinewave(freq=440.0, duration_milliseconds=500, volume=1.0): | ||
| 1385 | </span></span><span style="display:flex;"><span> <span style="color:#00f">global</span> audio | ||
| 1386 | </span></span><span style="display:flex;"><span> | ||
| 1387 | </span></span><span style="display:flex;"><span> num_samples = duration_milliseconds * (sample_rate / 1000.0) | ||
| 1388 | </span></span><span style="display:flex;"><span> | ||
| 1389 | </span></span><span style="display:flex;"><span> <span style="color:#00f">for</span> x <span style="color:#00f">in</span> range(int(num_samples)): | ||
| 1390 | </span></span><span style="display:flex;"><span> audio.append(volume * math.sin(2 * math.pi * freq * (x / sample_rate))) | ||
| 1391 | </span></span><span style="display:flex;"><span> | ||
| 1392 | </span></span><span style="display:flex;"><span> <span style="color:#00f">return</span> | ||
| 1393 | </span></span></code></pre><p>The sine wave generated here is the standard beep. If you want something more | ||
| 1394 | aggressive, you could try a square or saw tooth waveform.</p> | ||
| 1395 | <h2 id="generating-a-wav-file-from-accumulated-sine-waves">Generating a WAV file from accumulated sine waves</h2> | ||
| 1396 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#00f">import</span> wave | ||
| 1397 | </span></span><span style="display:flex;"><span><span style="color:#00f">import</span> struct | ||
| 1398 | </span></span><span style="display:flex;"><span> | ||
| 1399 | </span></span><span style="display:flex;"><span><span style="color:#00f">def</span> save_wav(file_name): | ||
| 1400 | </span></span><span style="display:flex;"><span> wav_file = wave.open(file_name, <span style="color:#a31515">&#39;w&#39;</span>) | ||
| 1401 | </span></span><span style="display:flex;"><span> nchannels = 1 | ||
| 1402 | </span></span><span style="display:flex;"><span> sampwidth = 2 | ||
| 1403 | </span></span><span style="display:flex;"><span> | ||
| 1404 | </span></span><span style="display:flex;"><span> nframes = len(audio) | ||
| 1405 | </span></span><span style="display:flex;"><span> comptype = <span style="color:#a31515">&#39;NONE&#39;</span> | ||
| 1406 | </span></span><span style="display:flex;"><span> compname = <span style="color:#a31515">&#39;not compressed&#39;</span> | ||
| 1407 | </span></span><span style="display:flex;"><span> wav_file.setparams((nchannels, sampwidth, sample_rate, nframes, comptype, compname)) | ||
| 1408 | </span></span><span style="display:flex;"><span> | ||
| 1409 | </span></span><span style="display:flex;"><span> <span style="color:#00f">for</span> sample <span style="color:#00f">in</span> audio: | ||
| 1410 | </span></span><span style="display:flex;"><span> wav_file.writeframes(struct.pack(<span style="color:#a31515">&#39;h&#39;</span>, int(sample * 32767.0))) | ||
| 1411 | </span></span><span style="display:flex;"><span> | ||
| 1412 | </span></span><span style="display:flex;"><span> wav_file.close() | ||
| 1413 | </span></span></code></pre><p>44100 is the industry standard sample rate - CD quality. If you need to save on | ||
| 1414 | file size, you can adjust it downwards. The standard for low quality is, 8000 or | ||
| 1415 | 8kHz.</p> | ||
| 1416 | <p>WAV files here are using short, 16 bit, signed integers for the sample size. | ||
| 1417 | So, we multiply the floating-point data we have by 32767, the maximum value for | ||
| 1418 | a short integer.</p> | ||
| 1419 | <blockquote> | ||
| 1420 | <p>It is theoretically possible to use the floating point -1.0 to 1.0 data | ||
| 1421 | directly in a WAV file, but not obvious how to do that using the wave module | ||
| 1422 | in Python.</p> | ||
| 1423 | </blockquote> | ||
| 1424 | <h2 id="generating-spectograms">Generating Spectograms</h2> | ||
| 1425 | <p>I have tried two methods of doing this and both were just fine. I however opted | ||
| 1426 | out to use the <a href="https://linux.die.net/man/1/sox">SoX - Sound eXchange, the Swiss Army knife of audio | ||
| 1427 | manipulation</a> one because it didn't require | ||
| 1428 | anything else.</p> | ||
| 1429 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>sox output.wav -n spectrogram -o spectrogram.png | ||
| 1430 | </span></span></code></pre><p>An example spectrogram of Ludwig van Beethoven Symphony No. 6 First movement.</p> | ||
| 1431 | <audio controls> | ||
| 1432 | <source src="/posts/dna-synthesized/symphony-no6-1st-movement.mp3" type="audio/mpeg"> | ||
| 1433 | </audio> | ||
| 1434 | <figure> | ||
| 1435 | <img src="/posts/dna-synthesized/symphony-no6-1st-movement.png" alt="Ludwig van Beethoven Symphony No. 6 First movement" /> | ||
| 1436 | </figure> | ||
| 1437 | <p>The other option could also be in combination with | ||
| 1438 | <a href="http://www.gnuplot.info/">gnuplot</a>. This would require an intermediary step, | ||
| 1439 | however.</p> | ||
| 1440 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>sox output.wav audio.dat | ||
| 1441 | </span></span><span style="display:flex;"><span>tail -n+3 audio.dat &gt; audio_only.dat | ||
| 1442 | </span></span><span style="display:flex;"><span>gnuplot audio.gpi | ||
| 1443 | </span></span></code></pre><p>And input file <code>audio.gpi</code> that would be passed to gnuplot looks something like | ||
| 1444 | this.</p> | ||
| 1445 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span># set output format and size | ||
| 1446 | </span></span><span style="display:flex;"><span>set term png size 1000,280 | ||
| 1447 | </span></span><span style="display:flex;"><span> | ||
| 1448 | </span></span><span style="display:flex;"><span># set output file | ||
| 1449 | </span></span><span style="display:flex;"><span>set output &#34;audio.png&#34; | ||
| 1450 | </span></span><span style="display:flex;"><span> | ||
| 1451 | </span></span><span style="display:flex;"><span># set y range | ||
| 1452 | </span></span><span style="display:flex;"><span>set yr [-1:1] | ||
| 1453 | </span></span><span style="display:flex;"><span> | ||
| 1454 | </span></span><span style="display:flex;"><span># we want just the data | ||
| 1455 | </span></span><span style="display:flex;"><span>unset key | ||
| 1456 | </span></span><span style="display:flex;"><span>unset tics | ||
| 1457 | </span></span><span style="display:flex;"><span>unset border | ||
| 1458 | </span></span><span style="display:flex;"><span>set lmargin 0 | ||
| 1459 | </span></span><span style="display:flex;"><span>set rmargin 0 | ||
| 1460 | </span></span><span style="display:flex;"><span>set tmargin 0 | ||
| 1461 | </span></span><span style="display:flex;"><span>set bmargin 0 | ||
| 1462 | </span></span><span style="display:flex;"><span> | ||
| 1463 | </span></span><span style="display:flex;"><span># draw rectangle to change background color | ||
| 1464 | </span></span><span style="display:flex;"><span>set obj 1 rectangle behind from screen 0,0 to screen 1,1 | ||
| 1465 | </span></span><span style="display:flex;"><span>set obj 1 fillstyle solid 1.0 fillcolor rgbcolor &#34;#ffffff&#34; | ||
| 1466 | </span></span><span style="display:flex;"><span> | ||
| 1467 | </span></span><span style="display:flex;"><span># draw data with foreground color | ||
| 1468 | </span></span><span style="display:flex;"><span>plot &#34;audio_only.dat&#34; with lines lt rgb &#39;red&#39; | ||
| 1469 | </span></span></code></pre><h2 id="pre-generated-sequences">Pre-generated sequences</h2> | ||
| 1470 | <p>What I did was take interesting parts from an animal's genome and feed it to a | ||
| 1471 | tone generator script. This then generated a WAV file and I converted those to | ||
| 1472 | MP3, so they can be played in a browser. The last step was creating a | ||
| 1473 | spectrogram based on a WAV file.</p> | ||
| 1474 | <h3 id="niels-bohr-quote">Niels Bohr quote</h3> | ||
| 1475 | <audio controls> | ||
| 1476 | <source src="/posts/dna-synthesized/quote/out.mp3" type="audio/mpeg"> | ||
| 1477 | </audio> | ||
| 1478 | <figure> | ||
| 1479 | <img src="/posts/dna-synthesized/quote/spectogram.png" alt="Spectogram" /> | ||
| 1480 | </figure> | ||
| 1481 | <h3 id="mouse">Mouse</h3> | ||
| 1482 | <p>This is part of a mouse genome <code>Mus_musculus.GRCm39.dna.nonchromosomal</code>. You | ||
| 1483 | can get <a href="http://ftp.ensembl.org/pub/release-106/fasta/mus_musculus/dna/">genom data | ||
| 1484 | here</a>.</p> | ||
| 1485 | <audio controls> | ||
| 1486 | <source src="/posts/dna-synthesized/mouse/out.mp3" type="audio/mpeg"> | ||
| 1487 | </audio> | ||
| 1488 | <figure> | ||
| 1489 | <img src="/posts/dna-synthesized/mouse/spectogram.png" alt="Spectogram" /> | ||
| 1490 | </figure> | ||
| 1491 | <h3 id="bison">Bison</h3> | ||
| 1492 | <p>This is part of a bison genome <code>Bison_bison_bison.Bison_UMD1.0.cdna</code>. You can | ||
| 1493 | get <a href="http://ftp.ensembl.org/pub/release-106/fasta/bison_bison_bison/cdna/">genom data | ||
| 1494 | here</a>.</p> | ||
| 1495 | <audio controls> | ||
| 1496 | <source src="/posts/dna-synthesized/bison/out.mp3" type="audio/mpeg"> | ||
| 1497 | </audio> | ||
| 1498 | <figure> | ||
| 1499 | <img src="/posts/dna-synthesized/bison/spectogram.png" alt="Spectogram" /> | ||
| 1500 | </figure> | ||
| 1501 | <h3 id="taurus">Taurus</h3> | ||
| 1502 | <p>This is part of a taurus genome <code>Bos_taurus.ARS-UCD1.2.cdna</code>. You can get | ||
| 1503 | <a href="http://ftp.ensembl.org/pub/release-106/fasta/bos_taurus/cdna/">genom data | ||
| 1504 | here</a>.</p> | ||
| 1505 | <audio controls> | ||
| 1506 | <source src="/posts/dna-synthesized/taurus/out.mp3" type="audio/mpeg"> | ||
| 1507 | </audio> | ||
| 1508 | <figure> | ||
| 1509 | <img src="/posts/dna-synthesized/taurus/spectogram.png" alt="Spectogram" /> | ||
| 1510 | </figure> | ||
| 1511 | <h2 id="making-a-drummer-out-of-a-dna-sequence">Making a drummer out of a DNA sequence</h2> | ||
| 1512 | <p>To make things even more interesting, I decided to send this data via MIDI to my | ||
| 1513 | <a href="https://www.elektron.se/en/model-samples">Elektron Model:Samples</a>. This is a | ||
| 1514 | really cool piece of equipment that supports MIDI in via USB and 3.5 mm audio | ||
| 1515 | jack.</p> | ||
| 1516 | <p>Elektron is connected to my MacBook via USB cable and audio out is patched to a | ||
| 1517 | Sony Bluetooth speaker I have that supports 3.5 mm audio in. Elektron doesn't | ||
| 1518 | have internal speakers.</p> | ||
| 1519 | <figure> | ||
| 1520 | <img src="/posts/dna-synthesized/elektron/IMG_0619.jpg" alt="" /> | ||
| 1521 | </figure> | ||
| 1522 | <figure> | ||
| 1523 | <img src="/posts/dna-synthesized/elektron/IMG_0620.jpg" alt="" /> | ||
| 1524 | </figure> | ||
| 1525 | <figure> | ||
| 1526 | <img src="/posts/dna-synthesized/elektron/IMG_0622.jpg" alt="" /> | ||
| 1527 | </figure> | ||
| 1528 | <p>For communicating with Elektron, I choose <code>pygame</code> Python module that has MIDI | ||
| 1529 | built in. With this, it was rather simple to send notes to the device. All I did | ||
| 1530 | was map MIDI notes to the actual Nucleotides.</p> | ||
| 1531 | <p>Before all of this I also checked Audio MIDI Setup app under MacOS and checked | ||
| 1532 | MIDI Studio by pressing ⌘-2.</p> | ||
| 1533 | <figure> | ||
| 1534 | <img src="/posts/dna-synthesized/elektron/midi-studio.jpg" alt="" /> | ||
| 1535 | </figure> | ||
| 1536 | <p>The whole script that parses and send notes to the Elektron looks like this.</p> | ||
| 1537 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#00f">import</span> pygame.midi | ||
| 1538 | </span></span><span style="display:flex;"><span><span style="color:#00f">import</span> time | ||
| 1539 | </span></span><span style="display:flex;"><span> | ||
| 1540 | </span></span><span style="display:flex;"><span>pygame.midi.init() | ||
| 1541 | </span></span><span style="display:flex;"><span> | ||
| 1542 | </span></span><span style="display:flex;"><span>print(pygame.midi.get_default_output_id()) | ||
| 1543 | </span></span><span style="display:flex;"><span>print(pygame.midi.get_device_info(0)) | ||
| 1544 | </span></span><span style="display:flex;"><span> | ||
| 1545 | </span></span><span style="display:flex;"><span>player = pygame.midi.Output(1) | ||
| 1546 | </span></span><span style="display:flex;"><span>player.set_instrument(2) | ||
| 1547 | </span></span><span style="display:flex;"><span> | ||
| 1548 | </span></span><span style="display:flex;"><span><span style="color:#00f">def</span> send_note(note, velocity): | ||
| 1549 | </span></span><span style="display:flex;"><span> <span style="color:#00f">global</span> player | ||
| 1550 | </span></span><span style="display:flex;"><span> player.note_on(note, velocity) | ||
| 1551 | </span></span><span style="display:flex;"><span> time.sleep(0.3) | ||
| 1552 | </span></span><span style="display:flex;"><span> player.note_off(note, velocity) | ||
| 1553 | </span></span><span style="display:flex;"><span> | ||
| 1554 | </span></span><span style="display:flex;"><span> | ||
| 1555 | </span></span><span style="display:flex;"><span>nucleotide_midi_map = { | ||
| 1556 | </span></span><span style="display:flex;"><span> <span style="color:#a31515">&#39;A&#39;</span>: 60, | ||
| 1557 | </span></span><span style="display:flex;"><span> <span style="color:#a31515">&#39;C&#39;</span>: 90, | ||
| 1558 | </span></span><span style="display:flex;"><span> <span style="color:#a31515">&#39;G&#39;</span>: 160, | ||
| 1559 | </span></span><span style="display:flex;"><span> <span style="color:#a31515">&#39;T&#39;</span>: 180, <span style="color:#008000"># is D</span> | ||
| 1560 | </span></span><span style="display:flex;"><span>} | ||
| 1561 | </span></span><span style="display:flex;"><span> | ||
| 1562 | </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: | ||
| 1563 | </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>) | ||
| 1564 | </span></span><span style="display:flex;"><span> | ||
| 1565 | </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]: | ||
| 1566 | </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( | ||
| 1567 | </span></span><span style="display:flex;"><span> nucleotide, nucleotide_midi_map[nucleotide])) | ||
| 1568 | </span></span><span style="display:flex;"><span> send_note(nucleotide_midi_map[nucleotide], 127) | ||
| 1569 | </span></span><span style="display:flex;"><span> | ||
| 1570 | </span></span><span style="display:flex;"><span><span style="color:#00f">del</span> player | ||
| 1571 | </span></span><span style="display:flex;"><span>pygame.midi.quit() | ||
| 1572 | </span></span></code></pre><p><video src="/posts/dna-synthesized/elektron/elektron.mp4" controls></video></p> | ||
| 1573 | <p>All of this could be made much more interesting if I choose different | ||
| 1574 | instruments for different Nucleotides, or doing more funky stuff with Elektron. | ||
| 1575 | But for now, this should be enough. It is just a proof of concept. Something to | ||
| 1576 | play around with.</p> | ||
| 1577 | <h2 id="going-even-further">Going even further</h2> | ||
| 1578 | <p>As you probably notice, the end results are quite similar to each other. This is | ||
| 1579 | to be expected because we are operating only with 4 notes essentially. What | ||
| 1580 | could make this more interesting is using something like | ||
| 1581 | <a href="https://supercollider.github.io/">Supercollider</a> to create more interesting | ||
| 1582 | sounds. By transposing notes or using effects based on repeated data in a | ||
| 1583 | sequence. Possibilities are endless.</p> | ||
| 1584 | <p>It is really astonishing what can be achieved with a little bit of code and an | ||
| 1585 | idea. I could see this becoming an interesting background soundscape instrument | ||
| 1586 | if done properly. It could replace random note generator with something more | ||
| 1587 | intriguing, biological, natural.</p> | ||
| 1588 | <p>I actually find the results fascinating. I took some time and listened to this | ||
| 1589 | music of nature. Even though it's quite the same, it's also quite different. | ||
| 1590 | The subtle differences on repeat kind of creates music on its own. Makes you | ||
| 1591 | wonder. It kind of puts Occam’s Razor in its place. Nature for sure loves to | ||
| 1592 | make things as energy efficient as possible.</p> | ||
| 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 +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><p>I have been searching for a lightweight code editor for quite some time. One of | ||
| 1605 | the main reasons was that I wanted something that doesn't burn through CPU and | ||
| 1606 | RAM usage is not through the roof. I have been mostly using Visual Studio Code. | ||
| 1607 | It's been an outstanding editor. I have no quarrel with it at all. It's just | ||
| 1608 | time to spice life up with something new.</p> | ||
| 1609 | <p>I have been on this search for a couple of years. I have tried Vim, Neovim, | ||
| 1610 | Emacs, Doom Emacs, Micro and couple more. Among most of them, I liked Micro and | ||
| 1611 | Doom Emacs the most. Micro editor was a little too basic for me. And Doom Emacs | ||
| 1612 | was a bit too hardcore. This does not reflect on any of the editors. It's just | ||
| 1613 | my personal preference.</p> | ||
| 1614 | <blockquote> | ||
| 1615 | <p>I tried Helix Editor about a year ago. But I didn't pay attention to it. | ||
| 1616 | Tried it and saw it's similar to Vi and just said no. I was premature to | ||
| 1617 | dismiss it.</p> | ||
| 1618 | </blockquote> | ||
| 1619 | <p>One of the things I actually miss is line wrapping for certain files. When | ||
| 1620 | writing Markdown, line wrapping would be very helpful. Editing such a document | ||
| 1621 | is frustrating to say the least. Some of the Markdown to HTML converters don't | ||
| 1622 | take kindly of new lines between sentences. Not paragraphs, sentences. And I use | ||
| 1623 | Markdown to write this blog you are reading.</p> | ||
| 1624 | <p>But other than this, I have been extremely satisfied by it. It's been a pleasant | ||
| 1625 | surprise. There have been zero issues with the editor.</p> | ||
| 1626 | <p>One thing to do before you are able to use autocompletion and make use Language | ||
| 1627 | Server support is to install the language server with NPM.</p> | ||
| 1628 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>npm install -g typescript typescript-language-server | ||
| 1629 | </span></span></code></pre><p>I am still getting used to the keyboard shortcuts and getting better. What Helix | ||
| 1630 | does really well is packing in sane defaults and even though because currently | ||
| 1631 | there is no plugin support I haven't found any need for them. It has all that | ||
| 1632 | you would need. It goes to extreme measures to show a user what is going on with | ||
| 1633 | popups that show you what the keyboard shortcuts are.</p> | ||
| 1634 | <p>And it comes us packed with many | ||
| 1635 | <a href="https://github.com/helix-editor/helix/wiki/Themes">really good themes</a>.</p> | ||
| 1636 | <figure> | ||
| 1637 | <img src="/posts/helix-editor/editor.png" alt="Editor" /> | ||
| 1638 | </figure> | ||
| 1639 | <p>It's still young but has this mature feeling to it. It has sane defaults and | ||
| 1640 | mimics Vim (works a bit differently, but the overall idea is similar).</p> | ||
| 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 +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><h2 id="a-little-stroll-down-the-history-lane">A little stroll down the history lane</h2> | ||
| 1653 | <p>About two weeks ago, I watched this outstanding documentary on YouTube | ||
| 1654 | <a href="https://www.youtube.com/watch?v=b9_Vh9h3Ohw">Springboard: the secret history of the first real | ||
| 1655 | smartphone</a> about the history of | ||
| 1656 | smartphones and phones in general. It brought back so many memories. I never had | ||
| 1657 | an actual smartphone before the Android. The closest to smartphone was <a href="https://www.gsmarena.com/sony_ericsson_p1-1982.php">Sony | ||
| 1658 | Ericsson P1</a>. A fantastic | ||
| 1659 | phone and I broke it in Prague after a party and that was one of those rare | ||
| 1660 | occasions where I was actually mad at myself. But nevertheless, after that | ||
| 1661 | phone, the next one was an Android one.</p> | ||
| 1662 | <p>Before that, I only owned normal phones from Nokia and Siemens etc. Nothing | ||
| 1663 | special, actually. These are the phones we are talking about. Before 2007. | ||
| 1664 | Apple and Android phones didn't exist yet.</p> | ||
| 1665 | <p>These phones were rocking:</p> | ||
| 1666 | <ul> | ||
| 1667 | <li>No selfie cameras.</li> | ||
| 1668 | <li>~2 inch displays.</li> | ||
| 1669 | <li>~120 MHz beast CPU's.</li> | ||
| 1670 | <li>144p main cameras.</li> | ||
| 1671 | <li>But they had a headphone jack.</li> | ||
| 1672 | </ul> | ||
| 1673 | <p>Let's take a look at these beauties.</p> | ||
| 1674 | <figure> | ||
| 1675 | <img src="/posts/wap/phones.gif" alt="Old phones" /> | ||
| 1676 | </figure> | ||
| 1677 | <h2 id="wap---wireless-application-protocol">WAP - Wireless Application Protocol</h2> | ||
| 1678 | <p>Not that one! We are talking about Wireless Application Protocol and not Cardi | ||
| 1679 | B's song 😃</p> | ||
| 1680 | <p>WAP stands for Wireless Application Protocol. It is a protocol designed for | ||
| 1681 | micro-browsers, and it enables the access of internet in the mobile devices. It | ||
| 1682 | uses the mark-up language WML (Wireless Markup Language and not HTML), WML is | ||
| 1683 | defined as XML 1.0 application. Furthermore, it enables creating web | ||
| 1684 | applications for mobile devices. In 1998, WAP Forum was founded by Ericson, | ||
| 1685 | Motorola, Nokia and Unwired Planet whose aim was to standardize the various | ||
| 1686 | wireless technologies via protocols. | ||
| 1687 | <a href="https://www.geeksforgeeks.org/wireless-application-protocol/">(source)</a></p> | ||
| 1688 | <p>WAP protocol was resulted by the joint efforts of the various members of WAP | ||
| 1689 | Forum. In 2002, WAP forum was merged with various other forums of the industry, | ||
| 1690 | resulting in the formation of Open Mobile Alliance (OMA). | ||
| 1691 | <a href="https://www.geeksforgeeks.org/wireless-application-protocol/">(source)</a></p> | ||
| 1692 | <p>These were some wild times. Devices had tiny screens and data transmission rates | ||
| 1693 | were abominable. But they were capable of rendering WML (Wireless Markup | ||
| 1694 | Language). This was very similar to HTML, actually. It is a markup language, | ||
| 1695 | after all.</p> | ||
| 1696 | <p>These pages could be served by <a href="https://apache.org/">Apache</a> and could be | ||
| 1697 | generated by CGI scripts on the backend. The only difference was the limited | ||
| 1698 | markup language.</p> | ||
| 1699 | <h2 id="wml---wireless-markup-language">WML - Wireless Markup Language</h2> | ||
| 1700 | <p>Just like web browsers use HTML for content structure, older mobile device | ||
| 1701 | browsers use WML - if you need to support really old mobile phones using WML | ||
| 1702 | browsers, you will need to know about it. WML is XML-based (an XML vocabulary | ||
| 1703 | just like XHTML and MathML, but not HTML) and does not use the same metaphor as | ||
| 1704 | HTML. HTML is a single document with some metadata packed away in the head, and | ||
| 1705 | a body encapsulating the visible page. With WML, the metaphor does not envisage | ||
| 1706 | a page, but rather a deck of cards. A WML file might have several pages or cards | ||
| 1707 | contained within it. | ||
| 1708 | <a href="https://www.w3.org/wiki/Introduction_to_mobile_web">(source)</a></p> | ||
| 1709 | <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> | ||
| 1710 | </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> | ||
| 1711 | </span></span><span style="display:flex;"><span>&lt;wml&gt; | ||
| 1712 | </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; | ||
| 1713 | </span></span><span style="display:flex;"><span> &lt;p&gt;Welcome to the Example homepage&lt;/p&gt; | ||
| 1714 | </span></span><span style="display:flex;"><span> &lt;/card&gt; | ||
| 1715 | </span></span><span style="display:flex;"><span>&lt;/wml&gt; | ||
| 1716 | </span></span></code></pre><p>There is an amazing tutorial on <a href="https://www.tutorialspoint.com/wml/index.htm">Tutorialpoint about | ||
| 1717 | WML</a>.</p> | ||
| 1718 | <h2 id="converting-digg-to-wml">Converting Digg to WML</h2> | ||
| 1719 | <p>This task is completely useless and not really feasible nowadays, but I had to | ||
| 1720 | give it a try for old-time sake. Since the data is already there in a form of | ||
| 1721 | RSS feed, I could take this feed and parse it and create a WML version of the | ||
| 1722 | homepage.</p> | ||
| 1723 | <p>We will need:</p> | ||
| 1724 | <ul> | ||
| 1725 | <li>Python3 + Pip</li> | ||
| 1726 | <li>ImageMagick</li> | ||
| 1727 | <li>feedparser and mako templating</li> | ||
| 1728 | </ul> | ||
| 1729 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># for fedora 35</span> | ||
| 1730 | </span></span><span style="display:flex;"><span>sudo dnf install ImageMagick python3-pip | ||
| 1731 | </span></span><span style="display:flex;"><span> | ||
| 1732 | </span></span><span style="display:flex;"><span><span style="color:#008000"># tempalting engine for python</span> | ||
| 1733 | </span></span><span style="display:flex;"><span>pip install mako --user | ||
| 1734 | </span></span><span style="display:flex;"><span> | ||
| 1735 | </span></span><span style="display:flex;"><span><span style="color:#008000"># for parsing rss feeds</span> | ||
| 1736 | </span></span><span style="display:flex;"><span>pip install feedparser --user | ||
| 1737 | </span></span></code></pre><p>Project folder structure should look like the following.</p> | ||
| 1738 | <pre><code>12:43:53 m@khan wap → tree -L 1 | ||
| 1739 | . | ||
| 1740 | ├── generate.py | ||
| 1741 | └── template.wml | ||
| 1742 | |||
| 1743 | </code></pre> | ||
| 1744 | <p>After that, I created a small template for the homepage.</p> | ||
| 1745 | <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> | ||
| 1746 | </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> | ||
| 1747 | </span></span><span style="display:flex;"><span> | ||
| 1748 | </span></span><span style="display:flex;"><span>&lt;wml&gt; | ||
| 1749 | </span></span><span style="display:flex;"><span> | ||
| 1750 | </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; | ||
| 1751 | </span></span><span style="display:flex;"><span> | ||
| 1752 | </span></span><span style="display:flex;"><span> % for item in entries: | ||
| 1753 | </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; | ||
| 1754 | </span></span><span style="display:flex;"><span> &lt;p&gt;&lt;small&gt;${item.kicker}&lt;/small&gt;&lt;/p&gt; | ||
| 1755 | </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; | ||
| 1756 | </span></span><span style="display:flex;"><span> &lt;p&gt;${item.description}&lt;/p&gt; | ||
| 1757 | </span></span><span style="display:flex;"><span> % endfor | ||
| 1758 | </span></span><span style="display:flex;"><span> | ||
| 1759 | </span></span><span style="display:flex;"><span> &lt;/card&gt; | ||
| 1760 | </span></span><span style="display:flex;"><span> | ||
| 1761 | </span></span><span style="display:flex;"><span>&lt;/wml&gt; | ||
| 1762 | </span></span></code></pre><p>And the parser that parses RSS feed looks like this.</p> | ||
| 1763 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#00f">import</span> os | ||
| 1764 | </span></span><span style="display:flex;"><span><span style="color:#00f">import</span> feedparser | ||
| 1765 | </span></span><span style="display:flex;"><span><span style="color:#00f">from</span> mako.template <span style="color:#00f">import</span> Template | ||
| 1766 | </span></span><span style="display:flex;"><span> | ||
| 1767 | </span></span><span style="display:flex;"><span>os.system(<span style="color:#a31515">&#39;mkdir -p www/images&#39;</span>) | ||
| 1768 | </span></span><span style="display:flex;"><span> | ||
| 1769 | </span></span><span style="display:flex;"><span>template = Template(filename=<span style="color:#a31515">&#39;template.wml&#39;</span>) | ||
| 1770 | </span></span><span style="display:flex;"><span> | ||
| 1771 | </span></span><span style="display:flex;"><span>feed = feedparser.parse(<span style="color:#a31515">&#39;https://digg.com/rss/top.xml&#39;</span>) | ||
| 1772 | </span></span><span style="display:flex;"><span> | ||
| 1773 | </span></span><span style="display:flex;"><span>entries = feed.entries[:15] | ||
| 1774 | </span></span><span style="display:flex;"><span> | ||
| 1775 | </span></span><span style="display:flex;"><span><span style="color:#00f">for</span> entry <span style="color:#00f">in</span> entries: | ||
| 1776 | </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)) | ||
| 1777 | </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)) | ||
| 1778 | </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)) | ||
| 1779 | </span></span><span style="display:flex;"><span> | ||
| 1780 | </span></span><span style="display:flex;"><span>html = template.render(entries = entries) | ||
| 1781 | </span></span><span style="display:flex;"><span> | ||
| 1782 | </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: | ||
| 1783 | </span></span><span style="display:flex;"><span> fp.write(html) | ||
| 1784 | </span></span></code></pre><p>This script will create a folder <code>www</code> and in the folder <code>www/images</code> for | ||
| 1785 | storing resized images.</p> | ||
| 1786 | <blockquote> | ||
| 1787 | <p>Be sure you don't use SSL and use just normal HTTP for serving the content. | ||
| 1788 | These old phones will have problems with TLS 1.3 etc.</p> | ||
| 1789 | </blockquote> | ||
| 1790 | <p>If you look at the python file, I convert all the images into tiny B&amp;W images. | ||
| 1791 | They should be WBMP (Wireless BitMaP) but I choose JPEGs for this, and it seems | ||
| 1792 | to work properly.</p> | ||
| 1793 | <p>Because I currently don't have a phone old enough to test it on, I used an | ||
| 1794 | emulator. And it was really hard to find one. I found <a href="http://wap-proof.sharewarejunction.com/">WAP | ||
| 1795 | Proof</a> on shareware junction, and it | ||
| 1796 | did the job well enough. I will try to find and actual device to test it on.</p> | ||
| 1797 | <p><video src="/posts/wap/emulator.mp4" controls></video></p> | ||
| 1798 | <p>If you are using Nginx to serve the contents, add a directive to the hosts file | ||
| 1799 | that will automatically server <code>index.wml</code> file.</p> | ||
| 1800 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#00f">server</span> { | ||
| 1801 | </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>; | ||
| 1802 | </span></span><span style="display:flex;"><span>} | ||
| 1803 | </span></span></code></pre><h2 id="conclusion">Conclusion</h2> | ||
| 1804 | <p>Well, this was pointless, but very fun! I hope you enjoyed it as much as I did. | ||
| 1805 | I will try to find an old phone to test it on. If you have any questions, feel | ||
| 1806 | free to ask in the comments.</p> | ||
| 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 +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><h2 id="unikernels-kernels-and-alike">Unikernels, kernels, and alike</h2> | ||
| 1819 | <p>I have been reading a lot about | ||
| 1820 | <a href="https://en.wikipedia.org/wiki/Unikernel">unikernernels</a> lately and found them | ||
| 1821 | very intriguing. When you push away all the marketing speak and look at the | ||
| 1822 | idea, it makes a lot of sense.</p> | ||
| 1823 | <blockquote> | ||
| 1824 | <p>A unikernel is a specialized, single address space machine image constructed | ||
| 1825 | by using library operating systems. (<a href="https://en.wikipedia.org/wiki/Unikernel">Wikipedia</a>)</p> | ||
| 1826 | </blockquote> | ||
| 1827 | <p>I really like the explanation from the article | ||
| 1828 | <a href="https://queue.acm.org/detail.cfm?id=2566628">Unikernels: Rise of the Virtual Library Operating System</a>. | ||
| 1829 | Really worth a read.</p> | ||
| 1830 | <p>If we compare a normal operating system to a unikernel side by side, they would | ||
| 1831 | look something like this.</p> | ||
| 1832 | <figure> | ||
| 1833 | <img src="/posts/pid1/unikernels.webp" alt="Virtual machines vs Containers vs Unikernels" /> | ||
| 1834 | </figure> | ||
| 1835 | <p>From this image, we can see how the complexity significantly decreases with | ||
| 1836 | the use of Unikernels. This comes with a price, of course. Unikernels are hard | ||
| 1837 | to get running and require a lot of work since you don't have an actual proper | ||
| 1838 | kernel running in the background providing network access and drivers etc.</p> | ||
| 1839 | <p>So as a half step to make the stack simpler, I started looking into using | ||
| 1840 | Linux kernel as a base and going from there. I came across this | ||
| 1841 | <a href="https://www.youtube.com/watch?v=Sk9TatW9ino">Youtube video talking about Building the Simplest Possible Linux System</a> | ||
| 1842 | by <a href="https://landley.net">Rob Landley</a> and apart from statically compiling the | ||
| 1843 | application to be run as PID1 there was really no other obstacles.</p> | ||
| 1844 | <h2 id="what-is-pid-1">What is PID 1?</h2> | ||
| 1845 | <p>PID 1 is the first process that Linux kernel starts after the boot process. | ||
| 1846 | It also has a couple of unique properties that are unique to it.</p> | ||
| 1847 | <ul> | ||
| 1848 | <li>When the process with PID 1 dies for any reason, all other processes are | ||
| 1849 | killed with KILL signal.</li> | ||
| 1850 | <li>When any process having children dies for any reason, its children are | ||
| 1851 | re-parented to process with PID 1.</li> | ||
| 1852 | <li>Many signals which have default action of Term do not have one for PID 1.</li> | ||
| 1853 | <li>When the process with PID 1 dies for any reason, kernel panics, which | ||
| 1854 | result in system crash.</li> | ||
| 1855 | </ul> | ||
| 1856 | <p>PID 1 is considered as an Init application which takes care of running other | ||
| 1857 | and handling services like:</p> | ||
| 1858 | <ul> | ||
| 1859 | <li>sshd,</li> | ||
| 1860 | <li>nginx,</li> | ||
| 1861 | <li>pulseaudio,</li> | ||
| 1862 | <li>etc.</li> | ||
| 1863 | </ul> | ||
| 1864 | <p>If you are on a Linux machine, you can check what your process is with PID 1 | ||
| 1865 | by running the following.</p> | ||
| 1866 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>$ cat /proc/1/status | ||
| 1867 | </span></span><span style="display:flex;"><span>Name: systemd | ||
| 1868 | </span></span><span style="display:flex;"><span>Umask: 0000 | ||
| 1869 | </span></span><span style="display:flex;"><span>State: S (sleeping) | ||
| 1870 | </span></span><span style="display:flex;"><span>Tgid: 1 | ||
| 1871 | </span></span><span style="display:flex;"><span>Ngid: 0 | ||
| 1872 | </span></span><span style="display:flex;"><span>Pid: 1 | ||
| 1873 | </span></span><span style="display:flex;"><span>PPid: 0 | ||
| 1874 | </span></span><span style="display:flex;"><span>... | ||
| 1875 | </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> | ||
| 1876 | which is a software suite that provides an array of system components for Linux | ||
| 1877 | operating systems. If you look closely you can also see that the <code>PPid</code> | ||
| 1878 | (process id of the parent process) is <code>0</code> which additionally confirms that | ||
| 1879 | this process doesn't have a parent.</p> | ||
| 1880 | <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> | ||
| 1881 | <p>Containers are wonderful, but they come with a lot of baggage. And because they | ||
| 1882 | are in their nature layered, the images require quite a lot of space and also a | ||
| 1883 | lot of additional software to handle them. They are not as lightweight as they | ||
| 1884 | seem, and many popular images require 500 MB plus disk space.</p> | ||
| 1885 | <p>The idea of running this as PID 1 would result in a significantly smaller footprint, | ||
| 1886 | as we will see later in the post.</p> | ||
| 1887 | <blockquote> | ||
| 1888 | <p>You could run a simple init system inside Docker container described more | ||
| 1889 | in 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>.</p> | ||
| 1890 | </blockquote> | ||
| 1891 | <h2 id="the-master-plan">The master plan</h2> | ||
| 1892 | <ol> | ||
| 1893 | <li>Compile Linux kernel with the default definitions.</li> | ||
| 1894 | <li>Prepare a Hello World application in Golang that is statically compiled.</li> | ||
| 1895 | <li>Run it with <a href="https://www.qemu.org/">QEMU</a> and providing Golang application | ||
| 1896 | as init application / PID 1.</li> | ||
| 1897 | </ol> | ||
| 1898 | <p>For the sake of simplicity we will not be cross-compiling any of it and just | ||
| 1899 | use the 64bit version.</p> | ||
| 1900 | <h2 id="compiling-linux-kernel">Compiling Linux kernel</h2> | ||
| 1901 | <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 | ||
| 1902 | </span></span><span style="display:flex;"><span>$ tar xf linux-5.15.7.tar.xz | ||
| 1903 | </span></span><span style="display:flex;"><span> | ||
| 1904 | </span></span><span style="display:flex;"><span>$ cd linux-5.15.7 | ||
| 1905 | </span></span><span style="display:flex;"><span> | ||
| 1906 | </span></span><span style="display:flex;"><span>$ make clean | ||
| 1907 | </span></span><span style="display:flex;"><span> | ||
| 1908 | </span></span><span style="display:flex;"><span><span style="color:#008000"># read more about this https://stackoverflow.com/a/41886394</span> | ||
| 1909 | </span></span><span style="display:flex;"><span>$ make defconfig | ||
| 1910 | </span></span><span style="display:flex;"><span> | ||
| 1911 | </span></span><span style="display:flex;"><span>$ time make -j <span style="color:#a31515">`</span>nproc<span style="color:#a31515">`</span> | ||
| 1912 | </span></span><span style="display:flex;"><span> | ||
| 1913 | </span></span><span style="display:flex;"><span>$ cd .. | ||
| 1914 | </span></span></code></pre><p>At this point we have kernel image that is located in <code>arch/x86_64/boot/bzImage</code>. | ||
| 1915 | We will use this in QEMU later.</p> | ||
| 1916 | <p>To make our lives a bit easier lets move the kernel image to another place. | ||
| 1917 | Lets create a folder <code>bin/</code> in the root of our project with <code>mkdir -p bin</code>.</p> | ||
| 1918 | <p>At this point we can copy <code>bzImage</code> to <code>bin/</code> folder with | ||
| 1919 | <code>cp linux-5.15.7/arch/x86_64/boot/bzImage bin/bzImage</code>.</p> | ||
| 1920 | <p>The folder structure of this experiment should look like this.</p> | ||
| 1921 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>pid1/ | ||
| 1922 | </span></span><span style="display:flex;"><span> bin/ | ||
| 1923 | </span></span><span style="display:flex;"><span> bzImage | ||
| 1924 | </span></span><span style="display:flex;"><span> linux-5.15.7/ | ||
| 1925 | </span></span><span style="display:flex;"><span> linux-5.15.7.tar.xz | ||
| 1926 | </span></span></code></pre><h2 id="preparing-pid-1-application-in-golang">Preparing PID 1 application in Golang</h2> | ||
| 1927 | <p>This step is relatively easy. The only thing we must have in mind that we will | ||
| 1928 | need to compile the binary as a static one.</p> | ||
| 1929 | <p>Let's create <code>init.go</code> file in the root of the project.</p> | ||
| 1930 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#00f">package</span> main | ||
| 1931 | </span></span><span style="display:flex;"><span> | ||
| 1932 | </span></span><span style="display:flex;"><span><span style="color:#00f">import</span> ( | ||
| 1933 | </span></span><span style="display:flex;"><span> <span style="color:#a31515">&#34;fmt&#34;</span> | ||
| 1934 | </span></span><span style="display:flex;"><span> <span style="color:#a31515">&#34;time&#34;</span> | ||
| 1935 | </span></span><span style="display:flex;"><span>) | ||
| 1936 | </span></span><span style="display:flex;"><span> | ||
| 1937 | </span></span><span style="display:flex;"><span><span style="color:#00f">func</span> main() { | ||
| 1938 | </span></span><span style="display:flex;"><span> <span style="color:#00f">for</span> { | ||
| 1939 | </span></span><span style="display:flex;"><span> fmt.Println(<span style="color:#a31515">&#34;Hello from Golang&#34;</span>) | ||
| 1940 | </span></span><span style="display:flex;"><span> time.Sleep(1 * time.Second) | ||
| 1941 | </span></span><span style="display:flex;"><span> } | ||
| 1942 | </span></span><span style="display:flex;"><span>} | ||
| 1943 | </span></span></code></pre><p>If you notice, we have a forever loop in the main, with a simple sleep of 1 | ||
| 1944 | second to not overwhelm the CPU. This is because PID 1 should never complete | ||
| 1945 | and/or exit. That would result in a kernel panic. Which is BAD!</p> | ||
| 1946 | <p>There are two ways of compiling Golang application. Statically and dynamically.</p> | ||
| 1947 | <p>To statically compile the binary, use the following command.</p> | ||
| 1948 | <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 | ||
| 1949 | </span></span></code></pre><p>We can also check if the binary is statically compiled with:</p> | ||
| 1950 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>$ file init | ||
| 1951 | </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 | ||
| 1952 | </span></span><span style="display:flex;"><span> | ||
| 1953 | </span></span><span style="display:flex;"><span>$ ldd init | ||
| 1954 | </span></span><span style="display:flex;"><span>not a dynamic executable | ||
| 1955 | </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> | ||
| 1956 | (abbreviated from &quot;initial RAM file system&quot;, is the successor of initrd. It | ||
| 1957 | is a cpio archive of the initial file system that gets loaded into memory | ||
| 1958 | during the Linux startup process).</p> | ||
| 1959 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>$ echo init | cpio -o --format=newc &gt; initramfs | ||
| 1960 | </span></span><span style="display:flex;"><span>$ mv initramfs bin/initramfs | ||
| 1961 | </span></span></code></pre><p>The projects at this stage should look like this.</p> | ||
| 1962 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>pid1/ | ||
| 1963 | </span></span><span style="display:flex;"><span> bin/ | ||
| 1964 | </span></span><span style="display:flex;"><span> bzImage | ||
| 1965 | </span></span><span style="display:flex;"><span> initramfs | ||
| 1966 | </span></span><span style="display:flex;"><span> linux-5.15.7/ | ||
| 1967 | </span></span><span style="display:flex;"><span> linux-5.15.7.tar.xz | ||
| 1968 | </span></span><span style="display:flex;"><span> init.go | ||
| 1969 | </span></span></code></pre><h2 id="running-all-of-it-with-qemu">Running all of it with QEMU</h2> | ||
| 1970 | <p><a href="https://www.qemu.org/">QEMU</a> is a free and open-source hypervisor. It emulates | ||
| 1971 | the machine's processor through dynamic binary translation and provides a set | ||
| 1972 | of different hardware and device models for the machine, enabling it to run a | ||
| 1973 | variety of guest operating systems.</p> | ||
| 1974 | <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 | ||
| 1975 | </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 | ||
| 1976 | </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:#008000">#7 SMP Mon Dec 13 10:23:25 CET 2021</span> | ||
| 1977 | </span></span><span style="display:flex;"><span>[ 0.000000] Command line: console=ttyS0 | ||
| 1978 | </span></span><span style="display:flex;"><span>[ 0.000000] x86/fpu: x87 FPU will use FXSAVE | ||
| 1979 | </span></span><span style="display:flex;"><span>[ 0.000000] signal: max sigframe size: 1440 | ||
| 1980 | </span></span><span style="display:flex;"><span>[ 0.000000] BIOS-provided physical RAM map: | ||
| 1981 | </span></span><span style="display:flex;"><span>[ 0.000000] BIOS-e820: [mem 0x0000000000000000-0x000000000009fbff] usable | ||
| 1982 | </span></span><span style="display:flex;"><span>[ 0.000000] BIOS-e820: [mem 0x000000000009fc00-0x000000000009ffff] reserved | ||
| 1983 | </span></span><span style="display:flex;"><span>[ 0.000000] BIOS-e820: [mem 0x00000000000f0000-0x00000000000fffff] reserved | ||
| 1984 | </span></span><span style="display:flex;"><span>[ 0.000000] BIOS-e820: [mem 0x0000000000100000-0x0000000007fdffff] usable | ||
| 1985 | </span></span><span style="display:flex;"><span>[ 0.000000] BIOS-e820: [mem 0x0000000007fe0000-0x0000000007ffffff] reserved | ||
| 1986 | </span></span><span style="display:flex;"><span>[ 0.000000] BIOS-e820: [mem 0x00000000fffc0000-0x00000000ffffffff] reserved | ||
| 1987 | </span></span><span style="display:flex;"><span>[ 0.000000] NX (Execute Disable) protection: active | ||
| 1988 | </span></span><span style="display:flex;"><span>[ 0.000000] SMBIOS 2.8 present. | ||
| 1989 | </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 | ||
| 1990 | </span></span><span style="display:flex;"><span>[ 0.000000] tsc: Fast TSC calibration failed | ||
| 1991 | </span></span><span style="display:flex;"><span>... | ||
| 1992 | </span></span><span style="display:flex;"><span>[ 2.016106] ALSA device list: | ||
| 1993 | </span></span><span style="display:flex;"><span>[ 2.016329] No soundcards found. | ||
| 1994 | </span></span><span style="display:flex;"><span>[ 2.053176] Freeing unused kernel image (initmem) memory: 1368K | ||
| 1995 | </span></span><span style="display:flex;"><span>[ 2.056095] Write protecting the kernel read-only data: 20480k | ||
| 1996 | </span></span><span style="display:flex;"><span>[ 2.058248] Freeing unused kernel image (text/rodata gap) memory: 2032K | ||
| 1997 | </span></span><span style="display:flex;"><span>[ 2.058811] Freeing unused kernel image (rodata/data gap) memory: 500K | ||
| 1998 | </span></span><span style="display:flex;"><span>[ 2.059164] Run /init as init process | ||
| 1999 | </span></span><span style="display:flex;"><span>Hello from Golang | ||
| 2000 | </span></span><span style="display:flex;"><span>[ 2.386879] tsc: Refined TSC clocksource calibration: 3192.032 MHz | ||
| 2001 | </span></span><span style="display:flex;"><span>[ 2.387114] clocksource: tsc: mask: 0xffffffffffffffff max_cycles: 0x2e02e31fa14, max_idle_ns: 440795264947 ns | ||
| 2002 | </span></span><span style="display:flex;"><span>[ 2.387380] clocksource: Switched to clocksource tsc | ||
| 2003 | </span></span><span style="display:flex;"><span>[ 2.587895] input: ImExPS/2 Generic Explorer Mouse as /devices/platform/i8042/serio1/input/input3 | ||
| 2004 | </span></span><span style="display:flex;"><span>Hello from Golang | ||
| 2005 | </span></span><span style="display:flex;"><span>Hello from Golang | ||
| 2006 | </span></span><span style="display:flex;"><span>Hello from Golang | ||
| 2007 | </span></span></code></pre><p>The whole <a href="/posts/pid1/qemu.log">log file here</a>.</p> | ||
| 2008 | <h2 id="size-comparison">Size comparison</h2> | ||
| 2009 | <p>The cool thing about this approach is that the Linux kernel and the application | ||
| 2010 | together only take around 12 MB, which is impressive as hell. And we need to | ||
| 2011 | also know that the size of bzImage (Linux kernel) could be greatly decreased | ||
| 2012 | by going into <code>make menuconfig</code> and removing a ton of features from the kernel, | ||
| 2013 | making the size even smaller. I managed to get kernel size down to 2 MB and | ||
| 2014 | still working properly.</p> | ||
| 2015 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>total 12M | ||
| 2016 | </span></span><span style="display:flex;"><span>-rw-r--r--. 1 m m 9.3M Dec 13 10:24 bzImage | ||
| 2017 | </span></span><span style="display:flex;"><span>-rw-r--r--. 1 m m 1.9M Dec 27 01:19 initramfs | ||
| 2018 | </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> | ||
| 2019 | <p>First we need to create proper folder structure with <code>mkdir -p iso/boot/grub</code>.</p> | ||
| 2020 | <p>Then we need to download the <a href="https://github.com/littleosbook/littleosbook/raw/master/files/stage2_eltorito">grub binary</a>. | ||
| 2021 | You can read more about this program on <a href="https://github.com/littleosbook/littleosbook">https://github.com/littleosbook/littleosbook</a>.</p> | ||
| 2022 | <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 | ||
| 2023 | </span></span></code></pre><pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>$ tree iso/boot/ | ||
| 2024 | </span></span><span style="display:flex;"><span>iso/boot/ | ||
| 2025 | </span></span><span style="display:flex;"><span>├── bzImage | ||
| 2026 | </span></span><span style="display:flex;"><span>├── grub | ||
| 2027 | </span></span><span style="display:flex;"><span>│ ├── menu.lst | ||
| 2028 | </span></span><span style="display:flex;"><span>│ └── stage2_eltorito | ||
| 2029 | </span></span><span style="display:flex;"><span>└── initramfs | ||
| 2030 | </span></span></code></pre><p>Let's copy files into proper folders.</p> | ||
| 2031 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>$ cp stage2_eltorito iso/boot/grub/ | ||
| 2032 | </span></span><span style="display:flex;"><span>$ cp bin/bzImage iso/boot/ | ||
| 2033 | </span></span><span style="display:flex;"><span>$ cp bin/initramfs iso/boot/ | ||
| 2034 | </span></span></code></pre><p>Lets create a GRUB config file at <code>nano iso/boot/grub/menu.lst</code> with contents.</p> | ||
| 2035 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>default=<span style="color:#a31515">0</span> | ||
| 2036 | </span></span><span style="display:flex;"><span>timeout=<span style="color:#a31515">5</span> | ||
| 2037 | </span></span><span style="display:flex;"><span> | ||
| 2038 | </span></span><span style="display:flex;"><span>title GoAsPID1 | ||
| 2039 | </span></span><span style="display:flex;"><span>kernel /boot/bzImage | ||
| 2040 | </span></span><span style="display:flex;"><span>initrd /boot/initramfs | ||
| 2041 | </span></span></code></pre><p>Let's create iso file by using genisoimage:</p> | ||
| 2042 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>genisoimage -R <span style="color:#a31515">\ | ||
| 2043 | </span></span></span><span style="display:flex;"><span><span style="color:#a31515"></span> -b boot/grub/stage2_eltorito <span style="color:#a31515">\ | ||
| 2044 | </span></span></span><span style="display:flex;"><span><span style="color:#a31515"></span> -no-emul-boot <span style="color:#a31515">\ | ||
| 2045 | </span></span></span><span style="display:flex;"><span><span style="color:#a31515"></span> -boot-load-size 4 <span style="color:#a31515">\ | ||
| 2046 | </span></span></span><span style="display:flex;"><span><span style="color:#a31515"></span> -A os <span style="color:#a31515">\ | ||
| 2047 | </span></span></span><span style="display:flex;"><span><span style="color:#a31515"></span> -input-charset utf8 <span style="color:#a31515">\ | ||
| 2048 | </span></span></span><span style="display:flex;"><span><span style="color:#a31515"></span> -quiet <span style="color:#a31515">\ | ||
| 2049 | </span></span></span><span style="display:flex;"><span><span style="color:#a31515"></span> -boot-info-table <span style="color:#a31515">\ | ||
| 2050 | </span></span></span><span style="display:flex;"><span><span style="color:#a31515"></span> -o GoAsPID1.iso <span style="color:#a31515">\ | ||
| 2051 | </span></span></span><span style="display:flex;"><span><span style="color:#a31515"></span> iso | ||
| 2052 | </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> | ||
| 2053 | or <a href="https://apps.gnome.org/app/org.gnome.Boxes/">Gnome Boxes</a>.</p> | ||
| 2054 | <p><video src="/posts/pid1/boxes.mp4" controls></video></p> | ||
| 2055 | <h2 id="is-running-applications-as-pid-1-even-worth-it">Is running applications as PID 1 even worth it?</h2> | ||
| 2056 | <p>Well, the answer to this is not as simple as one would think. Sometimes it is | ||
| 2057 | and sometimes it's not. For embedded systems and very specialized applications | ||
| 2058 | it is worth for sure. But in normal uses, I don't think so. It was an interesting | ||
| 2059 | exercise in compiling kernels and looking at the guts of the Linux kernel, | ||
| 2060 | but sticking to containers for most of the things is a better option in my | ||
| 2061 | opinion.</p> | ||
| 2062 | <p>An interesting experiment would be creating an image that supports networking | ||
| 2063 | and could be deployed to AWS as an EC2 instance and observing how it fares. | ||
| 2064 | But in that case, we would need to write some sort of supervisor that would | ||
| 2065 | run on a separate EC2 that would check if other EC2 instances are running | ||
| 2066 | properly. Remember that if your application fails, kernel panics and the | ||
| 2067 | whole machine is inoperable in this case.</p> | ||
| 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 +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><h2 id="introduction">Introduction</h2> | ||
| 2080 | <p>I have been using <a href="https://ubuntu.com/">Ubuntu</a> for quite a longtime now. I have | ||
| 2081 | used <a href="https://www.debian.org/">Debian</a> in the past and | ||
| 2082 | <a href="https://manjaro.org/">Manjaro</a>. Also had <a href="https://archlinux.org/">Arch</a> for | ||
| 2083 | some time and even ran <a href="https://www.gentoo.org/">Gentoo</a> way back.</p> | ||
| 2084 | <p>What I learned from all this is that I prefer running a bit older versions and | ||
| 2085 | having them be stable than run bleeding edge rolling release. For that reason, I | ||
| 2086 | stuck with Ubuntu for a couple of years now. I am also at a point in my life | ||
| 2087 | where I just don't care what is cool or hip anymore. I just want a stable system | ||
| 2088 | that doesn't get in my way.</p> | ||
| 2089 | <p>During all this, I noticed that these distributions were getting very bloated | ||
| 2090 | and a lot of software got included that I usually uninstall on fresh | ||
| 2091 | installation. Maybe this is my OCD speaking, but why do I have to give fresh | ||
| 2092 | installation min 1 GB of ram out of the box just to have a blank screen in front | ||
| 2093 | of me? I get it, there are many things included in the distro to make my life | ||
| 2094 | easier. I understand. But at this point I have a feeling that modern Linux | ||
| 2095 | distributions are becoming similar to <a href="https://devhumor.com/content/uploads/images/August2017/node-modules.jpg">Node.js project with | ||
| 2096 | node_modules</a>. | ||
| 2097 | Just a crazy number of packages serving very little or no purpose, just | ||
| 2098 | supporting other software.</p> | ||
| 2099 | <p>I felt I needed a fresh start. To start over with something minimal and clean. | ||
| 2100 | Something that would put a little more joy into using a computer again.</p> | ||
| 2101 | <p>For the first version, I wanted to target the following machines I have at home | ||
| 2102 | that I want this thing to work on.</p> | ||
| 2103 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># My main stationary work machine</span> | ||
| 2104 | </span></span><span style="display:flex;"><span>Resolution: 3840x1080 (Super Ultrawide Monitor 32:9) | ||
| 2105 | </span></span><span style="display:flex;"><span>CPU: Intel i7-8700 (12) @ 4.600GHz | ||
| 2106 | </span></span><span style="display:flex;"><span>GPU: AMD ATI Radeon RX 470/480/570/570X/580/580X/590 | ||
| 2107 | </span></span><span style="display:flex;"><span>Memory: 32020MiB | ||
| 2108 | </span></span></code></pre><pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># Thinkpad x220 for testing things and goofing around</span> | ||
| 2109 | </span></span><span style="display:flex;"><span>Resolution: 1366x768 | ||
| 2110 | </span></span><span style="display:flex;"><span>CPU: Intel i5-2520M (4) @ 3.200GHz | ||
| 2111 | </span></span><span style="display:flex;"><span>GPU: Intel 2nd Generation Core Processor Family | ||
| 2112 | </span></span><span style="display:flex;"><span>Memory: 15891MiB | ||
| 2113 | </span></span></code></pre><h2 id="how-should-i-approach-this">How should I approach this?</h2> | ||
| 2114 | <p>I knew I wanted to use <a href="https://www.debian.org/CD/netinst/">minimal Debian netinst | ||
| 2115 | </a> for the base to give myself a head | ||
| 2116 | start. No reason to go through changing the installer and also testing all that | ||
| 2117 | behemoth of a thing. So, some sort of ricing was the only logical option to get | ||
| 2118 | this thing of the grounds somewhat quickly.</p> | ||
| 2119 | <blockquote> | ||
| 2120 | <p><strong>What is ricing anyway?</strong> | ||
| 2121 | The term “RICE” stands for Race Inspired Cosmetic Enhancement. A group of | ||
| 2122 | people (could be one, idk) decided to see if they could tweak their own | ||
| 2123 | distros like they/others did their cars. This gave rise to a community of | ||
| 2124 | Linux/Unix enthusiasts trying to make their distros look cooler and better | ||
| 2125 | than others... For more information, read this article | ||
| 2126 | <a href="https://pesos.github.io/2020/07/14/what-is-ricing.html">What in the world is ricing!?</a>.</p> | ||
| 2127 | </blockquote> | ||
| 2128 | <p>I didn't want this to just be a set of config files for theming purpose. I | ||
| 2129 | wanted this to include a set of pre-installed tools and services that are being | ||
| 2130 | used all the time by a modern developer. Theming is just a tiny part of it. | ||
| 2131 | Fonts being applied across the distro and things like that.</p> | ||
| 2132 | <p>First, I choose terminal installer and left it to load additional components. | ||
| 2133 | Avoid using graphical installer in this case.</p> | ||
| 2134 | <figure> | ||
| 2135 | <img src="/posts/dfd-rice/install-00.png" alt="" /> | ||
| 2136 | </figure> | ||
| 2137 | <p>After that I selected hostname and created a normal user and set password for | ||
| 2138 | that user and root user and choose guided mode for disk partitioning.</p> | ||
| 2139 | <figure> | ||
| 2140 | <img src="/posts/dfd-rice/install-01.png" alt="" /> | ||
| 2141 | </figure> | ||
| 2142 | <p>I left it run to install all the things required for the base system and opted | ||
| 2143 | out of scanning additional media for use by the package manager. Those will be | ||
| 2144 | downloaded from the internet during installation.</p> | ||
| 2145 | <figure> | ||
| 2146 | <img src="/posts/dfd-rice/install-02.png" alt="" /> | ||
| 2147 | </figure> | ||
| 2148 | <p>I opted out of the popularity contest, and <strong>now comes the important part</strong>. | ||
| 2149 | Uncheck all the boxes in Software selection and only leave 'standard system | ||
| 2150 | utilities'. I also left an SSH server, so I was able to log in to the machine | ||
| 2151 | from my main PC.</p> | ||
| 2152 | <figure> | ||
| 2153 | <img src="/posts/dfd-rice/install-03.png" alt="" /> | ||
| 2154 | </figure> | ||
| 2155 | <p>At this point, I installed GRUB bootloader on the disk where I installed the | ||
| 2156 | system.</p> | ||
| 2157 | <figure> | ||
| 2158 | <img src="/posts/dfd-rice/install-04.png" alt="" /> | ||
| 2159 | </figure> | ||
| 2160 | <p>That concluded the installation of base Debian and after restarting the computer | ||
| 2161 | I was prompted with the login screen.</p> | ||
| 2162 | <figure> | ||
| 2163 | <img src="/posts/dfd-rice/install-05.png" alt="" /> | ||
| 2164 | </figure> | ||
| 2165 | <p>Now that I had the base installation, it was time to choose what software do I | ||
| 2166 | want to include in this so-called distribution. I wanted out of the box | ||
| 2167 | developer experience, so I had plenty to choose.</p> | ||
| 2168 | <p>Let's not waste time and go through the list.</p> | ||
| 2169 | <h2 id="desktop-environments">Desktop environments</h2> | ||
| 2170 | <p>I have been using <a href="https://www.gnome.org/">Gnome</a> for my whole Linux life. From | ||
| 2171 | version 2 forward. It's been quite a ride. I hated version 3 when it came out | ||
| 2172 | and replaced version 2. But I got used to it. And now with version 40+ they also | ||
| 2173 | made couple of changes which I found both frustrating and presently surprised.</p> | ||
| 2174 | <p>The amount of vertical space you loose because of the beefy title bars on | ||
| 2175 | windows is ridiculous. And then in case of | ||
| 2176 | <a href="https://gnunn1.github.io/tilix-web/">Tilix</a> you also have tabs, and you are | ||
| 2177 | 100px deep. Vertical space is one of the most important things for a | ||
| 2178 | developer. The more real estate you have, the more code you can have in a | ||
| 2179 | viewport.</p> | ||
| 2180 | <p>But on the other hand, I still love how Gnome feels and looks. I gotta give them | ||
| 2181 | that. They really are trying to make Gnome feel unified and modern.</p> | ||
| 2182 | <p>Regardless of all the nice things Gnome has, I was looking at the tiling window | ||
| 2183 | managers for some time, but never had the nerve to actually go with it. But now | ||
| 2184 | was the ideal time to give it a go. No guts, no glory kind of a thing.</p> | ||
| 2185 | <p>One of the requirements for me was easy custom layouts because I use a really | ||
| 2186 | strange monitor with aspect ratio of 32:9. So relying on included layouts most | ||
| 2187 | of them have is a non-starter.</p> | ||
| 2188 | <p>What I was doing in Gnome was having windows in a layout like the diagram | ||
| 2189 | below. This is my common practice. And if you look at it you can clearly see I | ||
| 2190 | was replicating tiling window manager setup in Gnome.</p> | ||
| 2191 | <figure> | ||
| 2192 | <img src="/posts/dfd-rice/layout.png" alt="" /> | ||
| 2193 | </figure> | ||
| 2194 | <p>That made me look into a bunch of tiling window managers and then tested them | ||
| 2195 | out. Candidates I was looking at were:</p> | ||
| 2196 | <ul> | ||
| 2197 | <li><a href="https://i3wm.org/">i3</a></li> | ||
| 2198 | <li><a href="https://github.com/baskerville/bspwm">bspwm</a></li> | ||
| 2199 | <li><a href="https://awesomewm.org/index.html">awesome</a></li> | ||
| 2200 | <li><a href="https://xmonad.org/">XMonad</a></li> | ||
| 2201 | <li><a href="https://swaywm.org/">sway</a></li> | ||
| 2202 | <li><a href="http://www.qtile.org/">Qtile</a></li> | ||
| 2203 | <li><a href="https://dwm.suckless.org/">dwm</a></li> | ||
| 2204 | </ul> | ||
| 2205 | <p>You can also check article <a href="https://www.tecmint.com/best-tiling-window-managers-for-linux/">13 Best Tiling Window Managers for | ||
| 2206 | Linux</a> I was | ||
| 2207 | referencing while testing them out.</p> | ||
| 2208 | <p>While all of them provided what I needed, I liked i3 the most. What particular | ||
| 2209 | caught my eye was the ease to use and tree based layouts which allows flexible | ||
| 2210 | layouts. I know others can be set up also to have custom layouts other than<br /> | ||
| 2211 | spiral, dwindle etc. I think i3 is a good entry-level window manager for | ||
| 2212 | somebody like me.</p> | ||
| 2213 | <h2 id="batteries-included">Batteries included</h2> | ||
| 2214 | <p>The source for the whole thing is located on Github | ||
| 2215 | <a href="https://github.com/mitjafelicijan/dfd-rice">https://github.com/mitjafelicijan/dfd-rice</a>.</p> | ||
| 2216 | <p>Currenly included:</p> | ||
| 2217 | <ul> | ||
| 2218 | <li><code>non-free</code> (enables non-free packages in apt)</li> | ||
| 2219 | <li><code>sudo</code> (adds sudo and adds user to sudo group)</li> | ||
| 2220 | <li><code>essentials</code> (gcc, htop, zip, curl, etc...)</li> | ||
| 2221 | <li><code>wifi</code> (network manager nmtui)</li> | ||
| 2222 | <li><code>desktop</code> (i3, dmenu, fonts, configurations)</li> | ||
| 2223 | <li><code>pulseaudio</code> (pulseaudio with pavucontrol)</li> | ||
| 2224 | <li><code>code-editors</code> (vim, micro, vscode)</li> | ||
| 2225 | <li><code>ohmybash</code> (make bash pretty)</li> | ||
| 2226 | <li><code>file-managers</code> (mc)</li> | ||
| 2227 | <li><code>git-ui</code> (terminal git gui)</li> | ||
| 2228 | <li><code>meld</code> (diff tool)</li> | ||
| 2229 | <li><code>profiling</code> (kcachegrind, valgrind, strace, ltrace)</li> | ||
| 2230 | <li><code>browsers</code> (brave, firefox, chromium)</li> | ||
| 2231 | <li>programming languages: | ||
| 2232 | <ul> | ||
| 2233 | <li><code>python</code></li> | ||
| 2234 | <li><code>golang</code></li> | ||
| 2235 | <li><code>nodejs</code></li> | ||
| 2236 | <li><code>rust</code></li> | ||
| 2237 | <li><code>nim</code></li> | ||
| 2238 | <li><code>php</code></li> | ||
| 2239 | <li><code>ruby</code></li> | ||
| 2240 | </ul> | ||
| 2241 | </li> | ||
| 2242 | <li><code>docker</code> (with docker-compose)</li> | ||
| 2243 | <li><code>ansible</code></li> | ||
| 2244 | </ul> | ||
| 2245 | <p>Install script also allows you to install only specific packages (example for: | ||
| 2246 | essentials ohmybash docker rust).</p> | ||
| 2247 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>su - root <span style="color:#a31515">\ | ||
| 2248 | </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">\ | ||
| 2249 | </span></span></span><span style="display:flex;"><span><span style="color:#a31515"></span> essentials ohmybash docker rust | ||
| 2250 | </span></span></code></pre><p>Currently, most of these recipes use what Debian and this is totally fine with | ||
| 2251 | me since I never use bleeding edge features of a package. But if something major | ||
| 2252 | would come to light, I will replace it with a possible compilation script or | ||
| 2253 | something similar.</p> | ||
| 2254 | <p>This is some of the output from the installation script.</p> | ||
| 2255 | <figure> | ||
| 2256 | <img src="/posts/dfd-rice/script.png" alt="" /> | ||
| 2257 | </figure> | ||
| 2258 | <p>Let's take a look at some examples in the installation script.</p> | ||
| 2259 | <h3 id="docker-recipe">Docker recipe</h3> | ||
| 2260 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># docker</span> | ||
| 2261 | </span></span><span style="display:flex;"><span>print_header <span style="color:#a31515">&#34;Installing Docker&#34;</span> | ||
| 2262 | </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 | ||
| 2263 | </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 | ||
| 2264 | </span></span><span style="display:flex;"><span>apt update | ||
| 2265 | </span></span><span style="display:flex;"><span>apt -y install docker-ce docker-ce-cli containerd.io docker-compose | ||
| 2266 | </span></span><span style="display:flex;"><span> | ||
| 2267 | </span></span><span style="display:flex;"><span>systemctl start docker | ||
| 2268 | </span></span><span style="display:flex;"><span>systemctl enable docker | ||
| 2269 | </span></span><span style="display:flex;"><span>systemctl status docker --no-pager | ||
| 2270 | </span></span><span style="display:flex;"><span> | ||
| 2271 | </span></span><span style="display:flex;"><span>/sbin/usermod -aG docker $USERNAME | ||
| 2272 | </span></span></code></pre><h3 id="making-bash-pretty">Making bash pretty</h3> | ||
| 2273 | <p>I really like <a href="https://ohmyz.sh/">Oh My Zsh</a>, but I don't like zsh shell. When | ||
| 2274 | I used it, I constantly needed to be aware of it and running bash scripts was a | ||
| 2275 | pain. So, I was really delighted when I found out that a version for bash | ||
| 2276 | existed called <a href="https://ohmybash.nntoan.com/">Oh My Bash</a>. Let's take a look at | ||
| 2277 | the recipe for installing it.</p> | ||
| 2278 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># ohmybash</span> | ||
| 2279 | </span></span><span style="display:flex;"><span>print_header <span style="color:#a31515">&#34;Enabling OhMyBash&#34;</span> | ||
| 2280 | </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; | ||
| 2281 | </span></span><span style="display:flex;"><span>T1=<span style="color:#a31515">${</span>!<span style="color:#a31515">}</span> | ||
| 2282 | </span></span><span style="display:flex;"><span>wait <span style="color:#a31515">${</span>T1<span style="color:#a31515">}</span> | ||
| 2283 | </span></span></code></pre><p>Because OhMyBash does <code>exec bash</code> at the end, this traps our script inside | ||
| 2284 | another shell and our script cannot continue. For that reason, I executed this | ||
| 2285 | in background. But that presents a new problem. Because this is executed in | ||
| 2286 | background, we lose track of progress naturally. And that strange trick with | ||
| 2287 | <code>T1=${!}</code> and <code>wait ${T1}</code> waits for the background process to finish before | ||
| 2288 | continuing to another task in bash script.</p> | ||
| 2289 | <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> | ||
| 2290 | for more details.</p> | ||
| 2291 | <h2 id="conclusion">Conclusion</h2> | ||
| 2292 | <p>Take a look at | ||
| 2293 | <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 | ||
| 2294 | to get familiar with it. This is just a first iteration and I will continue to | ||
| 2295 | update it because I need this in my life.</p> | ||
| 2296 | <p>The current version boots in 4s to the login prompt, and after you log in, the | ||
| 2297 | desktop environment loads in 2s. So, its fast, very fast. And on clean boot, I | ||
| 2298 | measured ~230 MB of RAM usage.</p> | ||
| 2299 | <p>And this is how it looks with two terminals side by side. I really like the | ||
| 2300 | simplicity and clean interface. I will polish the colors and stuff like that, | ||
| 2301 | but I really do like the results.</p> | ||
| 2302 | <figure> | ||
| 2303 | <img src="/posts/dfd-rice/desktop.png" alt="" /> | ||
| 2304 | </figure> | ||
| 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 +0200</pubDate> | ||
| 2314 | <guid>https://mitjafelicijan.com/linux-cheatsheet.html</guid> | ||
| 2315 | <description>Generate SSH keyssh-keygen -t ed25519 -C &#34;your_email@example.</description> | ||
| 2316 | <content:encoded><p><strong>Generate SSH key</strong></p> | ||
| 2317 | <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> | ||
| 2318 | </span></span><span style="display:flex;"><span> | ||
| 2319 | </span></span><span style="display:flex;"><span><span style="color:#008000"># when no support for Ed25519 present</span> | ||
| 2320 | </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> | ||
| 2321 | </span></span></code></pre><p>Note: By default SSH keys get stored to <code>/home/&lt;username&gt;/.ssh/</code> folder.</p> | ||
| 2322 | <p><strong>Login to host via SSH</strong></p> | ||
| 2323 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># connect to host as your local username</span> | ||
| 2324 | </span></span><span style="display:flex;"><span>ssh host | ||
| 2325 | </span></span><span style="display:flex;"><span> | ||
| 2326 | </span></span><span style="display:flex;"><span><span style="color:#008000"># connect to host as user</span> | ||
| 2327 | </span></span><span style="display:flex;"><span>ssh &lt;user&gt;@&lt;host&gt; | ||
| 2328 | </span></span><span style="display:flex;"><span> | ||
| 2329 | </span></span><span style="display:flex;"><span><span style="color:#008000"># connect to host using port</span> | ||
| 2330 | </span></span><span style="display:flex;"><span>ssh -p &lt;port&gt; &lt;user&gt;@&lt;host&gt; | ||
| 2331 | </span></span></code></pre><p><strong>Execute command on a server through SSH</strong></p> | ||
| 2332 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># execute one command</span> | ||
| 2333 | </span></span><span style="display:flex;"><span>ssh root@100.100.100.100 <span style="color:#a31515">&#34;ls /root&#34;</span> | ||
| 2334 | </span></span><span style="display:flex;"><span> | ||
| 2335 | </span></span><span style="display:flex;"><span><span style="color:#008000"># execute many commands</span> | ||
| 2336 | </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> | ||
| 2337 | </span></span></code></pre><p><strong>Displays currently logged in users in the system</strong></p> | ||
| 2338 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>w | ||
| 2339 | </span></span></code></pre><p><strong>Displays Linux system information</strong></p> | ||
| 2340 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>uname | ||
| 2341 | </span></span></code></pre><p><strong>Displays kernel release information</strong></p> | ||
| 2342 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>uname -r | ||
| 2343 | </span></span></code></pre><p><strong>Shows the system hostname</strong></p> | ||
| 2344 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>hostname | ||
| 2345 | </span></span></code></pre><p><strong>Shows system reboot history</strong></p> | ||
| 2346 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>last reboot | ||
| 2347 | </span></span></code></pre><p><strong>Displays information about the user</strong></p> | ||
| 2348 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>sudo apt install finger | ||
| 2349 | </span></span><span style="display:flex;"><span>finger &lt;username&gt; | ||
| 2350 | </span></span></code></pre><p><strong>Displays IP addresses and all the network interfaces</strong></p> | ||
| 2351 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>ip addr show | ||
| 2352 | </span></span></code></pre><p><strong>Downloads a file from an online source</strong></p> | ||
| 2353 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>wget https://example.com/example.tgz | ||
| 2354 | </span></span></code></pre><p>Note: If URL contains ?, &amp; enclose the URL in double quotes.</p> | ||
| 2355 | <p><strong>Compress a file with gzip</strong></p> | ||
| 2356 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># will not keep the original file</span> | ||
| 2357 | </span></span><span style="display:flex;"><span>gzip file.txt | ||
| 2358 | </span></span><span style="display:flex;"><span> | ||
| 2359 | </span></span><span style="display:flex;"><span><span style="color:#008000"># will keep the original file</span> | ||
| 2360 | </span></span><span style="display:flex;"><span>gzip --keep file.txt | ||
| 2361 | </span></span></code></pre><p><strong>Interactive disk usage analyzer</strong></p> | ||
| 2362 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>sudo apt install ncdu | ||
| 2363 | </span></span><span style="display:flex;"><span> | ||
| 2364 | </span></span><span style="display:flex;"><span>ncdu | ||
| 2365 | </span></span><span style="display:flex;"><span>ncdu &lt;path/to/directory&gt; | ||
| 2366 | </span></span></code></pre><p><strong>Install Node.js using the Node Version Manager</strong></p> | ||
| 2367 | <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 | ||
| 2368 | </span></span><span style="display:flex;"><span>source ~/.bashrc | ||
| 2369 | </span></span><span style="display:flex;"><span> | ||
| 2370 | </span></span><span style="display:flex;"><span>nvm install v13 | ||
| 2371 | </span></span></code></pre><p><strong>Too long; didn't read</strong></p> | ||
| 2372 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>npm install -g tldr | ||
| 2373 | </span></span><span style="display:flex;"><span> | ||
| 2374 | </span></span><span style="display:flex;"><span>tldr tar | ||
| 2375 | </span></span></code></pre><p><strong>Combine all Nginx access logs to one big log file</strong></p> | ||
| 2376 | <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 | ||
| 2377 | </span></span></code></pre><p><strong>Set up Redis server</strong></p> | ||
| 2378 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>sudo apt install redis-server redis-tools | ||
| 2379 | </span></span><span style="display:flex;"><span> | ||
| 2380 | </span></span><span style="display:flex;"><span><span style="color:#008000"># check if server is running</span> | ||
| 2381 | </span></span><span style="display:flex;"><span>sudo service redis status | ||
| 2382 | </span></span><span style="display:flex;"><span> | ||
| 2383 | </span></span><span style="display:flex;"><span><span style="color:#008000"># set and get a key value</span> | ||
| 2384 | </span></span><span style="display:flex;"><span>redis-cli set mykey myvalue | ||
| 2385 | </span></span><span style="display:flex;"><span>redis-cli get mykey | ||
| 2386 | </span></span><span style="display:flex;"><span> | ||
| 2387 | </span></span><span style="display:flex;"><span><span style="color:#008000"># interactive shell</span> | ||
| 2388 | </span></span><span style="display:flex;"><span>redis-cli | ||
| 2389 | </span></span></code></pre><p><strong>Generate statistics of your webserver</strong></p> | ||
| 2390 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>sudo apt install goaccess | ||
| 2391 | </span></span><span style="display:flex;"><span> | ||
| 2392 | </span></span><span style="display:flex;"><span><span style="color:#008000"># check if installed</span> | ||
| 2393 | </span></span><span style="display:flex;"><span>goaccess -v | ||
| 2394 | </span></span><span style="display:flex;"><span> | ||
| 2395 | </span></span><span style="display:flex;"><span><span style="color:#008000"># combine logs</span> | ||
| 2396 | </span></span><span style="display:flex;"><span>zcat -f /var/log/nginx/access.log* &gt; /var/log/nginx/access-all.log | ||
| 2397 | </span></span><span style="display:flex;"><span> | ||
| 2398 | </span></span><span style="display:flex;"><span><span style="color:#008000"># export to single html</span> | ||
| 2399 | </span></span><span style="display:flex;"><span>goaccess <span style="color:#a31515">\ | ||
| 2400 | </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">\ | ||
| 2401 | </span></span></span><span style="display:flex;"><span><span style="color:#a31515"></span> --log-format=COMBINED <span style="color:#a31515">\ | ||
| 2402 | </span></span></span><span style="display:flex;"><span><span style="color:#a31515"></span> --exclude-ip=0.0.0.0 <span style="color:#a31515">\ | ||
| 2403 | </span></span></span><span style="display:flex;"><span><span style="color:#a31515"></span> --ignore-crawlers <span style="color:#a31515">\ | ||
| 2404 | </span></span></span><span style="display:flex;"><span><span style="color:#a31515"></span> --real-os <span style="color:#a31515">\ | ||
| 2405 | </span></span></span><span style="display:flex;"><span><span style="color:#a31515"></span> --output=/var/www/html/stats.html | ||
| 2406 | </span></span><span style="display:flex;"><span> | ||
| 2407 | </span></span><span style="display:flex;"><span><span style="color:#008000"># cleanup afterwards</span> | ||
| 2408 | </span></span><span style="display:flex;"><span>rm /var/log/nginx/access-all.log | ||
| 2409 | </span></span></code></pre><p><strong>Search for a given pattern in files</strong></p> | ||
| 2410 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>grep -r ‘pattern’ files | ||
| 2411 | </span></span></code></pre><p><strong>Find proccess ID for a specific program</strong></p> | ||
| 2412 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>pgrep nginx | ||
| 2413 | </span></span></code></pre><p><strong>Print name of current/working directory</strong></p> | ||
| 2414 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>pwd | ||
| 2415 | </span></span></code></pre><p><strong>Creates a blank new file</strong></p> | ||
| 2416 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>touch newfile.txt | ||
| 2417 | </span></span></code></pre><p><strong>Displays first lines in a file</strong></p> | ||
| 2418 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># -n &lt;x&gt; presents the number of lines (10 by default)</span> | ||
| 2419 | </span></span><span style="display:flex;"><span>head -n 20 somefile.txt | ||
| 2420 | </span></span></code></pre><p><strong>Displays last lines in a file</strong></p> | ||
| 2421 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># -n &lt;x&gt; presents the number of lines (10 by default)</span> | ||
| 2422 | </span></span><span style="display:flex;"><span>tail -n 20 somefile.txt | ||
| 2423 | </span></span><span style="display:flex;"><span> | ||
| 2424 | </span></span><span style="display:flex;"><span><span style="color:#008000"># -f follows the changes in file (doesn&#39;t closes)</span> | ||
| 2425 | </span></span><span style="display:flex;"><span>tail -f somefile.txt | ||
| 2426 | </span></span></code></pre><p><strong>Count lines in a file</strong></p> | ||
| 2427 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>wc -l somefile.txt | ||
| 2428 | </span></span></code></pre><p><strong>Find all instances of the file</strong></p> | ||
| 2429 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>sudo apt install mlocate | ||
| 2430 | </span></span><span style="display:flex;"><span> | ||
| 2431 | </span></span><span style="display:flex;"><span>locate somefile.txt | ||
| 2432 | </span></span></code></pre><p><strong>Find file names that begin with ‘index’ in /home folder</strong></p> | ||
| 2433 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>find /home/ -name <span style="color:#a31515">&#34;index&#34;</span> | ||
| 2434 | </span></span></code></pre><p><strong>Find files larger than 100MB in the home folder</strong></p> | ||
| 2435 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>find /home -size +100M | ||
| 2436 | </span></span></code></pre><p><strong>Displays block devices related information</strong></p> | ||
| 2437 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>lsblk | ||
| 2438 | </span></span></code></pre><p><strong>Displays free space on mounted systems</strong></p> | ||
| 2439 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>df -h | ||
| 2440 | </span></span></code></pre><p><strong>Displays free and used memory in the system</strong></p> | ||
| 2441 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>free -h | ||
| 2442 | </span></span></code></pre><p><strong>Displays all active listening ports</strong></p> | ||
| 2443 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>sudo apt install net-tools | ||
| 2444 | </span></span><span style="display:flex;"><span> | ||
| 2445 | </span></span><span style="display:flex;"><span>netstat -pnltu | ||
| 2446 | </span></span></code></pre><p><strong>Kill a process violently</strong></p> | ||
| 2447 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>kill -9 &lt;pid&gt; | ||
| 2448 | </span></span></code></pre><p><strong>List files opened by user</strong></p> | ||
| 2449 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>lsof -u &lt;user&gt; | ||
| 2450 | </span></span></code></pre><p><strong>Execute &quot;df -h&quot;, showing periodic updates</strong></p> | ||
| 2451 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># -n 1 means every second</span> | ||
| 2452 | </span></span><span style="display:flex;"><span>watch -n 1 df -h | ||
| 2453 | </span></span></code></pre></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 +0200</pubDate> | ||
| 2462 | <guid>https://mitjafelicijan.com/from-internet-consumer-to-full-hominum-again.html</guid> | ||
| 2463 | <description>It&#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><p>It's been almost a year since I started purging all my online accounts and | ||
| 2465 | going down this rabbit hole of being almost independent of the current internet | ||
| 2466 | machine. Even though I initially thought that I will have problems adapting, | ||
| 2467 | I was pleasantly surprised that the transition went so smoothly. Even better, | ||
| 2468 | it brought many benefits to my life. Such as increased focus, less stress | ||
| 2469 | about trivial things, etc.</p> | ||
| 2470 | <p>It all started with me doing small changes like unsubscribing from emails that I | ||
| 2471 | have either subscribed to by accepting terms and conditions. Or even some more | ||
| 2472 | malicious emails that I was getting because I was on a shared mailing list. And | ||
| 2473 | the later ones I hate the most of all. How the hell do they keep sharing my | ||
| 2474 | email and sending me unsolicited emails and get away with it? I have a suspicion | ||
| 2475 | that these marketing people share an Excel file between them and keep | ||
| 2476 | resubscribing me when they import lists into Mailchimp or similar software.</p> | ||
| 2477 | <p>It's fascinating to see how much crap you get subscribed to when you are not | ||
| 2478 | paying attention. It got so bad that my primary Gmail address is a full of junk | ||
| 2479 | and need constant monitoring and cleaning up. And because I want to have Inbox | ||
| 2480 | Zero, this presents an additional problem for me.</p> | ||
| 2481 | <p>The stress that email presented for me didn't occur to me for a long time. I was | ||
| 2482 | noticing that I was unable to go through one single hour without hysterically | ||
| 2483 | refreshing email. And if somebody wrote me something, I needed to see it right | ||
| 2484 | then, even though I didn't immediately reply to it. I can only describe this | ||
| 2485 | with FOMO (fear of missing out). I have no other explanation than that. It was | ||
| 2486 | crippling, and I was constantly context switching, which I will address further | ||
| 2487 | down this post in more details.</p> | ||
| 2488 | <p>This was one of the reasons why I spawned up my personal email server, and I am | ||
| 2489 | using it now as my primary and person email. I still have Gmail as my “junk” | ||
| 2490 | email that I use for throw away stuff. I log in to Gmail once a week and check | ||
| 2491 | if there are any important emails that I got, but apart from that, it's sitting | ||
| 2492 | dormant and collecting dust.</p> | ||
| 2493 | <p>The more I was watching the world loose it's self with allowing anti freedom | ||
| 2494 | things to happen to it, the more I started to realize that something has to | ||
| 2495 | change. I don't have the power to change the world. And I also don't have a | ||
| 2496 | grandiose opinion of myself to even think to try it. But what I can do is to not | ||
| 2497 | subscribe to this consumer way of thinking. I will not be complicit in this. My | ||
| 2498 | moral and ethical stances won't allow it. So, this brings us to the second part | ||
| 2499 | of my journey.</p> | ||
| 2500 | <p>I was using all these 3rd party services because I was either lazy or OK with | ||
| 2501 | the drawbacks of them. I watched these services and companies became more and | ||
| 2502 | privacy policies and everybody is OK with accepting them, and they pray on that | ||
| 2503 | more evil. It is evil if you sell your user's data in this manner. Nobody reads | ||
| 2504 | flaw in human nature. I really hate the hypocrisy they manage to muster. These | ||
| 2505 | companies prey on our laziness, and we are at fault here. Nobody else. And I | ||
| 2506 | truly understand the reasons why we rather accept and move on, and not object | ||
| 2507 | and have our lives a little more difficult. They have perfected this through | ||
| 2508 | years of small changes that make us a little more dependent on them. You could | ||
| 2509 | not convince a person to give away all his rights and data in one day. This was | ||
| 2510 | gradual and slow. And it caught us all in surprise. When I really stopped and | ||
| 2511 | thought about it, I felt repulsed. By really stopping and thinking about it, I | ||
| 2512 | really mean stopping and thinking about it. Thoroughly and in depth.</p> | ||
| 2513 | <p>Each step I took depleted my character a bit more. Like I was trading myself bit | ||
| 2514 | by bit without understanding what it all meant. What it meant to be a full | ||
| 2515 | person, not divided by all this bought attention they want from me. They don't | ||
| 2516 | just get your data, but they also take your attention away from you. They | ||
| 2517 | scatter your and go with the divide and conquer tactic from there. And a person | ||
| 2518 | divided is a person not fully there. Not at the moment. Not alive fully.</p> | ||
| 2519 | <p>I was unable to form long thoughts. Well, I thought I was. But now that I see | ||
| 2520 | what being a full person is again, I can see that I was not at my 100% back | ||
| 2521 | then.</p> | ||
| 2522 | <p>A revolt was inevitable. There was no other way of continuing my story without | ||
| 2523 | it. Without taking back my attention, my thoughts, my time, and my privacy, | ||
| 2524 | regardless of how too late it maybe is.</p> | ||
| 2525 | <p>This has nothing to do with conspiracy theories. Even less with changing the | ||
| 2526 | world. All I wanted was to get my life back in order and not waste the energy | ||
| 2527 | that could be spent in other, better places.</p> | ||
| 2528 | <p>I started reading more. I can focus now fully on things I work on. Furthermore, | ||
| 2529 | I have the mental acuity that I never had before. My mind feels sharp. I don't | ||
| 2530 | get angry so much. I can cherish the finer things in life now without the need | ||
| 2531 | to interpret them intellectually. Not only that, but I have a feeling of | ||
| 2532 | belonging again. Sense of purpose has returned with a vengeance. And I can now | ||
| 2533 | help people without depleting myself.</p> | ||
| 2534 | <p>The last step so far was to finish closing all the remaining online accounts | ||
| 2535 | that I still had. And when I was thinking what value they bring me, I wasn't | ||
| 2536 | surprised that the answer was none. I wasn't logging in them and using them. I | ||
| 2537 | stopped being afraid of FOMO. If somebody wants to get in contact me, they will | ||
| 2538 | find a way. I am one search away.</p> | ||
| 2539 | <p>We are not beholden to anybody. Our lives are our own. So dare yourself to | ||
| 2540 | delete Facebook, LinkedIn. To unsubscribe. Dare yourself to take your time and | ||
| 2541 | attention back. Use that time and energy to go for a walk without thinking about | ||
| 2542 | work. Read a book instead of reading comment on social media that you will | ||
| 2543 | forget in an hour. Enrich your life instead of wasting it. It only requires a | ||
| 2544 | small step. And you will feel the benefits immediately. Lose the weight of the | ||
| 2545 | world that is crushing you without your consent.</p> | ||
| 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 +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><p>Our team is spread across the world, from the USA all the way to Australia, so | ||
| 2558 | having some sort of world clock makes sense.</p> | ||
| 2559 | <p>Currently, I am using an extension for Gnome called <a href="https://extensions.gnome.org/extension/2657/timezones-extension/">Timezone | ||
| 2560 | extension</a>, | ||
| 2561 | and it serves the purpose quite well.</p> | ||
| 2562 | <p>But I also have a bunch of electronics that I bought through the time, and I am | ||
| 2563 | not using any of them, and it's time to stop hording this stuff and use it in a | ||
| 2564 | project.</p> | ||
| 2565 | <p>A while ago I bought a small eInk display <a href="https://shop.pimoroni.com/products/inky-phat?variant=12549254217811">Inky | ||
| 2566 | pHAT</a> and I | ||
| 2567 | have a bunch of <a href="https://www.raspberrypi.org/products/raspberry-pi-zero/">Raspberry Pi's | ||
| 2568 | Zero</a> lying around that | ||
| 2569 | I really need to use.</p> | ||
| 2570 | <figure> | ||
| 2571 | <img src="/posts/world-clock/hardware.jpg" alt="Inky pHAT, Raspberry Pi Zero" /> | ||
| 2572 | </figure> | ||
| 2573 | <p>Since the Inky <a href="https://shop.pimoroni.com/products/inky-phat?variant=12549254217811">Inky | ||
| 2574 | pHAT</a> is | ||
| 2575 | essentially a HAT, it can easily be added on top of the <a href="https://www.raspberrypi.org/products/raspberry-pi-zero/">Raspberry Pi | ||
| 2576 | Zero</a>.</p> | ||
| 2577 | <p>First, I installed the necessary software on Raspberry Pi with <code>pip3 install inky</code>.</p> | ||
| 2578 | <p>And then I created a file <code>clock.py</code> in home directory <code>/home/pi</code>.</p> | ||
| 2579 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000">#!/usr/bin/env python</span> | ||
| 2580 | </span></span><span style="display:flex;"><span><span style="color:#008000"># -*- coding: utf-8 -*-</span> | ||
| 2581 | </span></span><span style="display:flex;"><span> | ||
| 2582 | </span></span><span style="display:flex;"><span><span style="color:#00f">import</span> sys | ||
| 2583 | </span></span><span style="display:flex;"><span><span style="color:#00f">import</span> os | ||
| 2584 | </span></span><span style="display:flex;"><span><span style="color:#00f">from</span> inky.auto <span style="color:#00f">import</span> auto | ||
| 2585 | </span></span><span style="display:flex;"><span><span style="color:#00f">from</span> PIL <span style="color:#00f">import</span> Image, ImageFont, ImageDraw | ||
| 2586 | </span></span><span style="display:flex;"><span><span style="color:#00f">from</span> font_fredoka_one <span style="color:#00f">import</span> FredokaOne | ||
| 2587 | </span></span><span style="display:flex;"><span> | ||
| 2588 | </span></span><span style="display:flex;"><span>clocks = [ | ||
| 2589 | </span></span><span style="display:flex;"><span> <span style="color:#a31515">&#39;America/New_York&#39;</span>, | ||
| 2590 | </span></span><span style="display:flex;"><span> <span style="color:#a31515">&#39;Europe/Ljubljana&#39;</span>, | ||
| 2591 | </span></span><span style="display:flex;"><span> <span style="color:#a31515">&#39;Australia/Brisbane&#39;</span>, | ||
| 2592 | </span></span><span style="display:flex;"><span>] | ||
| 2593 | </span></span><span style="display:flex;"><span> | ||
| 2594 | </span></span><span style="display:flex;"><span>board = auto() | ||
| 2595 | </span></span><span style="display:flex;"><span>board.set_border(board.WHITE) | ||
| 2596 | </span></span><span style="display:flex;"><span>board.rotation = 90 | ||
| 2597 | </span></span><span style="display:flex;"><span> | ||
| 2598 | </span></span><span style="display:flex;"><span>img = Image.new(<span style="color:#a31515">&#39;P&#39;</span>, (board.WIDTH, board.HEIGHT)) | ||
| 2599 | </span></span><span style="display:flex;"><span>draw = ImageDraw.Draw(img) | ||
| 2600 | </span></span><span style="display:flex;"><span> | ||
| 2601 | </span></span><span style="display:flex;"><span>big_font = ImageFont.truetype(FredokaOne, 18) | ||
| 2602 | </span></span><span style="display:flex;"><span>small_font = ImageFont.truetype(FredokaOne, 13) | ||
| 2603 | </span></span><span style="display:flex;"><span> | ||
| 2604 | </span></span><span style="display:flex;"><span>x = board.WIDTH / 3 | ||
| 2605 | </span></span><span style="display:flex;"><span>y = board.HEIGHT / 3 | ||
| 2606 | </span></span><span style="display:flex;"><span> | ||
| 2607 | </span></span><span style="display:flex;"><span>idx = 1 | ||
| 2608 | </span></span><span style="display:flex;"><span><span style="color:#00f">for</span> clock <span style="color:#00f">in</span> clocks: | ||
| 2609 | </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)) | ||
| 2610 | </span></span><span style="display:flex;"><span> ctime = ctime.read().strip().split(<span style="color:#a31515">&#39;,&#39;</span>) | ||
| 2611 | </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>) | ||
| 2612 | </span></span><span style="display:flex;"><span> | ||
| 2613 | </span></span><span style="display:flex;"><span> draw.text((15, (idx*y)-y+10), city, fill=board.BLACK, font=small_font) | ||
| 2614 | </span></span><span style="display:flex;"><span> draw.text((110, (idx*y)-y+7), str(ctime[0]), fill=board.BLACK, font=big_font) | ||
| 2615 | </span></span><span style="display:flex;"><span> draw.text((155, (idx*y)-y+7), str(ctime[1]), fill=board.BLACK, font=big_font) | ||
| 2616 | </span></span><span style="display:flex;"><span> | ||
| 2617 | </span></span><span style="display:flex;"><span> idx += 1 | ||
| 2618 | </span></span><span style="display:flex;"><span> | ||
| 2619 | </span></span><span style="display:flex;"><span>board.set_image(img) | ||
| 2620 | </span></span><span style="display:flex;"><span>board.show() | ||
| 2621 | </span></span></code></pre><p>And because eInk displays are rather slow to refresh and the clock requires | ||
| 2622 | refreshing only once a minute, this can be done through cronjob.</p> | ||
| 2623 | <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> | ||
| 2624 | <p>Then we add a cronjob with <code>crontab -e</code>.</p> | ||
| 2625 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>* * * * * /home/pi/clock.py | ||
| 2626 | </span></span></code></pre><p>So, we end up with a result like this.</p> | ||
| 2627 | <figure> | ||
| 2628 | <img src="/posts/world-clock/world-clock.jpg" alt="World Clock" /> | ||
| 2629 | </figure> | ||
| 2630 | <p>And for the enclosure that can be 3D printed, but I haven't yet something like | ||
| 2631 | this can be used.</p> | ||
| 2632 | <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> | ||
| 2633 | <p>You can download my <a href="/posts/world-clock/enclosure.stl">STL file for the enclosure | ||
| 2634 | here</a>, but make sure that dimensions make | ||
| 2635 | sense and also opening for USB port should be added or just use a drill and some | ||
| 2636 | hot glue to make it stick in the enclosure.</p> | ||
| 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 +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><h2 id="introduction">Introduction</h2> | ||
| 2649 | <p>I know! You cannot simply replace Google Analytics with parsing access logs and | ||
| 2650 | displaying a couple of charts. But to be honest, I actually never used Google | ||
| 2651 | Analytics to the fullest extent and was usually interested in seeing page hits | ||
| 2652 | and which pages were visited most often.</p> | ||
| 2653 | <p>I recently moved my blog from Firebase to a VPS and also decided to remove | ||
| 2654 | Google Analytics tracking code from the site since its quite malicious and | ||
| 2655 | tracks users across other pages also and is creating a profile of a user, and | ||
| 2656 | I've had it. But I also need some insight of what is happening on a server and | ||
| 2657 | which content is being read the most etc.</p> | ||
| 2658 | <p>I have looked at many existing solutions like:</p> | ||
| 2659 | <ul> | ||
| 2660 | <li><a href="https://umami.is/">Umami</a></li> | ||
| 2661 | <li><a href="https://github.com/sheshbabu/freshlytics">Freshlytics</a></li> | ||
| 2662 | <li><a href="https://matomo.org/">Matomo</a></li> | ||
| 2663 | </ul> | ||
| 2664 | <p>But the more I looked at them the more I noticed that I am replacing one evil | ||
| 2665 | with another one. Don't get me wrong. Some of these solutions are absolutely | ||
| 2666 | fantastic but would require installation of databases and something like PHP or | ||
| 2667 | Node. And I was not ready to put those things on my fresh server. Also having | ||
| 2668 | Docker installed is out of the question.</p> | ||
| 2669 | <h2 id="opting-for-log-parsing">Opting for log parsing</h2> | ||
| 2670 | <p>So, I defaulted to parsing already existing logs and generating HTML reports | ||
| 2671 | from this data.</p> | ||
| 2672 | <p>I found this amazing software <a href="https://goaccess.io/">GoAccess</a> which provides | ||
| 2673 | all the functionalities I need, and it's a single binary. Written in Go.</p> | ||
| 2674 | <p>GoAccess can be used in two different modes.</p> | ||
| 2675 | <figure> | ||
| 2676 | <img src="/posts/goaccess/goaccess-dash-term.png" alt="GoAccess Terminal" /> | ||
| 2677 | </figure> | ||
| 2678 | <p><em>Running in a terminal</em></p> | ||
| 2679 | <figure> | ||
| 2680 | <img src="/posts/goaccess/goaccess-dash-html.png" alt="GoAccess HTML" /> | ||
| 2681 | </figure> | ||
| 2682 | <p><em>Running in a browser</em></p> | ||
| 2683 | <p>I, however, need this to run in a browser. So, the second option is the way to | ||
| 2684 | go. The Idea is to periodically run cronjob and export this report into a folder | ||
| 2685 | that gets then server by Nginx behind a Basic authentication.</p> | ||
| 2686 | <h2 id="getting-nginx-ready">Getting Nginx ready</h2> | ||
| 2687 | <p>I choose Ubuntu on <a href="https://www.digitalocean.com/">DigitalOcean</a>. First I | ||
| 2688 | installed <a href="https://nginx.org/en/">Nginx</a>, and | ||
| 2689 | <a href="https://letsencrypt.org/getting-started/">Letsencrypt</a> certbot and all the | ||
| 2690 | necessary dependencies.</p> | ||
| 2691 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># log in as root user</span> | ||
| 2692 | </span></span><span style="display:flex;"><span>sudo su - | ||
| 2693 | </span></span><span style="display:flex;"><span> | ||
| 2694 | </span></span><span style="display:flex;"><span><span style="color:#008000"># first let&#39;s update the system</span> | ||
| 2695 | </span></span><span style="display:flex;"><span>apt update &amp;&amp; apt upgrade -y | ||
| 2696 | </span></span><span style="display:flex;"><span> | ||
| 2697 | </span></span><span style="display:flex;"><span><span style="color:#008000"># let&#39;s install</span> | ||
| 2698 | </span></span><span style="display:flex;"><span>apt install nginx certbot python3-certbot-nginx apache2-utils | ||
| 2699 | </span></span></code></pre><p>After all this is installed we can create a new configuration for a statistics. | ||
| 2700 | Stats will be available at <code>stats.domain.com</code>.</p> | ||
| 2701 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># creates directory where html will be hosted</span> | ||
| 2702 | </span></span><span style="display:flex;"><span>mkdir -p /var/www/html/stats.domain.com | ||
| 2703 | </span></span><span style="display:flex;"><span> | ||
| 2704 | </span></span><span style="display:flex;"><span>cp /etc/nginx/sites-available/default /etc/nginx/sites-available/stats.domain.com | ||
| 2705 | </span></span><span style="display:flex;"><span>nano /etc/nginx/sites-available/stats.domain.com | ||
| 2706 | </span></span></code></pre><pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#00f">server</span> { | ||
| 2707 | </span></span><span style="display:flex;"><span> <span style="color:#00f">root</span> <span style="color:#a31515">/var/www/html/stats.domain.com</span>; | ||
| 2708 | </span></span><span style="display:flex;"><span> <span style="color:#00f">server_name</span> <span style="color:#a31515">stats.domain.com</span>; | ||
| 2709 | </span></span><span style="display:flex;"><span> | ||
| 2710 | </span></span><span style="display:flex;"><span> <span style="color:#00f">index</span> <span style="color:#a31515">index.html</span>; | ||
| 2711 | </span></span><span style="display:flex;"><span> <span style="color:#00f">location</span> <span style="color:#a31515">/</span> { | ||
| 2712 | </span></span><span style="display:flex;"><span> <span style="color:#00f">try_files</span> $uri $uri/ =404; | ||
| 2713 | </span></span><span style="display:flex;"><span> } | ||
| 2714 | </span></span><span style="display:flex;"><span>} | ||
| 2715 | </span></span></code></pre><p>Now we check if the configuration is ok. We can do this with <code>nginx -t</code>. If all | ||
| 2716 | is ok, we can restart Nginx with <code>service nginx restart</code>.</p> | ||
| 2717 | <p>After all that you should add A record for this domain that points to IP of a | ||
| 2718 | droplet.</p> | ||
| 2719 | <p>Before enabling SSL you should test if DNS records have propagated with <code>curl stats.domain.com</code>.</p> | ||
| 2720 | <p>Now, it's time to provision TLS certificate. To achieve this, you execute | ||
| 2721 | command <code>certbot --nginx</code>. Follow the wizard and when you are asked about | ||
| 2722 | redirection always choose 2 (always redirect to HTTPS).</p> | ||
| 2723 | <p>When this is done you can visit <a href="https://stats.domain.com">https://stats.domain.com</a> and you should get 404 | ||
| 2724 | not found error which is correct.</p> | ||
| 2725 | <h2 id="getting-goaccess-ready">Getting GoAccess ready</h2> | ||
| 2726 | <p>If you are using Debian like system GoAccess should be available in repository. | ||
| 2727 | Otherwise refer to the official website.</p> | ||
| 2728 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>apt install goaccess | ||
| 2729 | </span></span></code></pre><p>To enable Geo location we also need one additiona thing.</p> | ||
| 2730 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>cd /var/www/html/stats.stats.com | ||
| 2731 | </span></span><span style="display:flex;"><span>wget https://github.com/P3TERX/GeoLite.mmdb/raw/download/GeoLite2-City.mmdb | ||
| 2732 | </span></span></code></pre><p>Now we create a shell script that will be executed every 10 minutes.</p> | ||
| 2733 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>nano /var/www/html/stats.domain.com/generate-stats.sh | ||
| 2734 | </span></span></code></pre><p>Contents of this file should look like this.</p> | ||
| 2735 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#00f">#!/bin/sh | ||
| 2736 | </span></span></span><span style="display:flex;"><span><span style="color:#00f"></span> | ||
| 2737 | </span></span><span style="display:flex;"><span>zcat -f /var/log/nginx/access.log* &gt; /var/log/nginx/access-all.log | ||
| 2738 | </span></span><span style="display:flex;"><span> | ||
| 2739 | </span></span><span style="display:flex;"><span>goaccess <span style="color:#a31515">\ | ||
| 2740 | </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">\ | ||
| 2741 | </span></span></span><span style="display:flex;"><span><span style="color:#a31515"></span> --log-format=COMBINED <span style="color:#a31515">\ | ||
| 2742 | </span></span></span><span style="display:flex;"><span><span style="color:#a31515"></span> --exclude-ip=0.0.0.0 <span style="color:#a31515">\ | ||
| 2743 | </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">\ | ||
| 2744 | </span></span></span><span style="display:flex;"><span><span style="color:#a31515"></span> --ignore-crawlers <span style="color:#a31515">\ | ||
| 2745 | </span></span></span><span style="display:flex;"><span><span style="color:#a31515"></span> --real-os <span style="color:#a31515">\ | ||
| 2746 | </span></span></span><span style="display:flex;"><span><span style="color:#a31515"></span> --output=/var/www/html/stats.domain.com/index.html | ||
| 2747 | </span></span><span style="display:flex;"><span> | ||
| 2748 | </span></span><span style="display:flex;"><span>rm /var/log/nginx/access-all.log | ||
| 2749 | </span></span></code></pre><p>Because after a while nginx creates multiple files with access logs we use | ||
| 2750 | <a href="https://linux.die.net/man/1/zcat"><code>zcat</code></a> to extract Gziped contents and create | ||
| 2751 | a file that has all the access logs. After this file is used we delete it.</p> | ||
| 2752 | <p>If you want to exclude your home IP's result look at the <code>--exclude-ip</code> option | ||
| 2753 | in script and instead of <code>0.0.0.0</code> add your own home IP address. You can find | ||
| 2754 | your home IP by executing <code>curl ifconfig.me</code> from your local machine and NOT | ||
| 2755 | from the droplet.</p> | ||
| 2756 | <p>Test the script by executing <code>sh /var/www/html/stats.domain.com/generate-stats.sh</code> and then checking | ||
| 2757 | <code>https://stats.domain.com</code>. If you can see stats instead of 404 than you are | ||
| 2758 | set.</p> | ||
| 2759 | <p>It's time to add this script to cron with <code>cron -e</code>.</p> | ||
| 2760 | <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 | ||
| 2761 | </span></span></code></pre><h2 id="securing-with-basic-authentication">Securing with Basic authentication</h2> | ||
| 2762 | <p>You probably don't want stats to be publicly available, so we should create a | ||
| 2763 | user and a password for Basic authentication.</p> | ||
| 2764 | <p>First we create a password for a user <code>stats</code> with <code>htpasswd -c /etc/nginx/.htpasswd stats</code>.</p> | ||
| 2765 | <p>Now we update config file with <code>nano /etc/nginx/sites-available/stats.domain.com</code>. You probably noticed that the | ||
| 2766 | file looks a bit different from before. This is because <code>certbot</code> added | ||
| 2767 | additional rules for SSL.</p> | ||
| 2768 | <p>Your location portion the config file should now look like. You should add | ||
| 2769 | <code>auth_basic</code> and <code>auth_basic_user_file</code> lines to the file.</p> | ||
| 2770 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#00f">location</span> <span style="color:#a31515">/</span> { | ||
| 2771 | </span></span><span style="display:flex;"><span> <span style="color:#00f">try_files</span> $uri $uri/ =404; | ||
| 2772 | </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>; | ||
| 2773 | </span></span><span style="display:flex;"><span> <span style="color:#00f">auth_basic_user_file</span> <span style="color:#a31515">/etc/nginx/.htpasswd</span>; | ||
| 2774 | </span></span><span style="display:flex;"><span>} | ||
| 2775 | </span></span></code></pre><p>Test if config is still ok with <code>nginx -t</code> and if it is you can restart Nginx | ||
| 2776 | with <code>service nginx restart</code>.</p> | ||
| 2777 | <p>If you now visit <code>https://stats.domain.com</code> you should be prompted for username | ||
| 2778 | and password. If not, try reopening your browser.</p> | ||
| 2779 | <p>That is all. You now have analytics for your server that gets refreshed every 10 | ||
| 2780 | minutes.</p> | ||
| 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 +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><p>A few months ago I experimented with DigitalOcean spaces as my backup solution | ||
| 2793 | that could <a href="/digitalocean-spaces-to-sync-between-computers.html">replace Dropbox | ||
| 2794 | eventually</a>. That solution | ||
| 2795 | worked quite nicely, and I was amazed how smashing together a couple of existing | ||
| 2796 | solutions would work this fine.</p> | ||
| 2797 | <p>I have been running that solution in the background for a couple of months now | ||
| 2798 | and kind of forgot about it. But recent developments around deplatforming and | ||
| 2799 | having us people hostages of technology and big companies speed up my goals to | ||
| 2800 | become less dependent on | ||
| 2801 | <a href="https://edition.cnn.com/2020/12/17/tech/google-antitrust-lawsuit/index.html">Google</a>, | ||
| 2802 | <a href="https://www.pcworld.com/article/2048680/dropbox-takes-a-peek-at-files.html">Dropbox</a> | ||
| 2803 | etc and take back some control.</p> | ||
| 2804 | <p>I am not a conspiracy theory nut, but to be honest, what these companies are | ||
| 2805 | doing lately is out of control. It is a matter of principle at this point. I | ||
| 2806 | have almost completely degoogled my life all the way from ditching Gmail, | ||
| 2807 | YouTube and most of the services surrounding Google. And I must tell you, I feel | ||
| 2808 | so good. I haven't felt this way for a long time.</p> | ||
| 2809 | <p><strong>Anyways. Let's get to the meat of things.</strong></p> | ||
| 2810 | <p>Before you continue you should read my post about <a href="/digitalocean-spaces-to-sync-between-computers.html">syncing to | ||
| 2811 | Dropbox</a>.</p> | ||
| 2812 | <blockquote> | ||
| 2813 | <p>Also to note, I am using Linux on my machine with Gnome desktop environment. | ||
| 2814 | This should work on MacOS too. To use this on Windows I suggest using | ||
| 2815 | <a href="https://docs.microsoft.com/en-us/windows/wsl/install-win10">Subsystem for Linux</a> | ||
| 2816 | or <a href="https://www.cygwin.com/">Cygwin</a>.</p> | ||
| 2817 | </blockquote> | ||
| 2818 | <h2 id="folder-structure">Folder structure</h2> | ||
| 2819 | <p>I liked structure from Dropbox. One folder where everything is located and | ||
| 2820 | synced. So, that's why adopted this also for my sync setup.</p> | ||
| 2821 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="">~</span>/Vault | ||
| 2822 | </span></span><span style="display:flex;"><span> <span style="">↳</span> backup | ||
| 2823 | </span></span><span style="display:flex;"><span> <span style="">↳</span> bin | ||
| 2824 | </span></span><span style="display:flex;"><span> <span style="">↳</span> documents | ||
| 2825 | </span></span><span style="display:flex;"><span> <span style="">↳</span> projects | ||
| 2826 | </span></span></code></pre><p>All of my code is located in <code>~/Vault/projects</code> folder. And most of the projects | ||
| 2827 | are Git repositories. I do not use this sync method for backup per see but in | ||
| 2828 | case I reinstall my machine I can easily recreate all the important folder | ||
| 2829 | structure with one quick command. No external drives needed that can fail etc.</p> | ||
| 2830 | <h2 id="sync-script">Sync script</h2> | ||
| 2831 | <p>My sync script is located in <code>~/Vault/bin/vault-backup.sh</code></p> | ||
| 2832 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#00f">#!/bin/bash | ||
| 2833 | </span></span></span><span style="display:flex;"><span><span style="color:#00f"></span> | ||
| 2834 | </span></span><span style="display:flex;"><span><span style="color:#008000"># dconf load /com/gexperts/Tilix/ &lt; tilix.dconf</span> | ||
| 2835 | </span></span><span style="display:flex;"><span><span style="color:#008000"># 0 2 * * * sh ~/Vault/bin/vault-backup.sh</span> | ||
| 2836 | </span></span><span style="display:flex;"><span> | ||
| 2837 | </span></span><span style="display:flex;"><span>cd ~/Vault/backup/dotfiles | ||
| 2838 | </span></span><span style="display:flex;"><span> | ||
| 2839 | </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> | ||
| 2840 | </span></span><span style="display:flex;"><span>mkdir -p $MACHINE | ||
| 2841 | </span></span><span style="display:flex;"><span>cd $MACHINE | ||
| 2842 | </span></span><span style="display:flex;"><span> | ||
| 2843 | </span></span><span style="display:flex;"><span>cp ~/.config/VSCodium/User/settings.json settings.json | ||
| 2844 | </span></span><span style="display:flex;"><span>cp ~/.s3cfg s3cfg | ||
| 2845 | </span></span><span style="display:flex;"><span>cp ~/.bash_extended bash_extended | ||
| 2846 | </span></span><span style="display:flex;"><span>cp ~/.ssh ssh -rf | ||
| 2847 | </span></span><span style="display:flex;"><span> | ||
| 2848 | </span></span><span style="display:flex;"><span>codium --list-extensions &gt; vscode-extension.txt | ||
| 2849 | </span></span><span style="display:flex;"><span>dconf dump /com/gexperts/Tilix/ &gt; tilix.dconf | ||
| 2850 | </span></span><span style="display:flex;"><span> | ||
| 2851 | </span></span><span style="display:flex;"><span>cd ~/Vault | ||
| 2852 | </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/ | ||
| 2853 | </span></span><span style="display:flex;"><span> | ||
| 2854 | </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 | ||
| 2855 | </span></span><span style="display:flex;"><span> | ||
| 2856 | </span></span><span style="display:flex;"><span>notify-send <span style="color:#a31515">\ | ||
| 2857 | </span></span></span><span style="display:flex;"><span><span style="color:#a31515"></span> -u normal <span style="color:#a31515">\ | ||
| 2858 | </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">\ | ||
| 2859 | </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> | ||
| 2860 | </span></span></code></pre><p>This script also backups some of the dotfiles I use and sends notification to | ||
| 2861 | Gnome notification center. It is a straightforward solution. Nothing special | ||
| 2862 | going on.</p> | ||
| 2863 | <blockquote> | ||
| 2864 | <p>One obvious benefit of this is that I can omit syncing Node's <code>node_modules</code> | ||
| 2865 | or Python's <code>.venv</code> and <code>.git</code> folders.</p> | ||
| 2866 | </blockquote> | ||
| 2867 | <p>You can use this script in a combination with <a href="https://en.wikipedia.org/wiki/Cron">Cron</a>.</p> | ||
| 2868 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>0 2 * * * sh ~/Vault/bin/vault-backup.sh | ||
| 2869 | </span></span></code></pre><p>When you start syncing your local stuff with a remote server you can review your | ||
| 2870 | items on DigitalOcean.</p> | ||
| 2871 | <figure> | ||
| 2872 | <img src="/posts/dropbox-sync/dropbox-spaces.png" alt="Dropbox Spaces" /> | ||
| 2873 | </figure> | ||
| 2874 | <p>I have been using this script now for quite some time, and it's working | ||
| 2875 | flawlessly. I also uninstalled Dropbox and stopped using it completely.</p> | ||
| 2876 | <p>All I need to do is write a Bash script that does the reverse and downloads from | ||
| 2877 | remote server to local folder. This could be another post.</p> | ||
| 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 +0200</pubDate> | ||
| 2887 | <guid>https://mitjafelicijan.com/digitalocean-spaces-to-sync-between-computers.html</guid> | ||
| 2888 | <description>I&#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&#39;teven imagine a world without it.</description> | ||
| 2889 | <content:encoded><p>I've been using <a href="https://www.dropbox.com/">Dropbox</a> for probably <strong>10+ years</strong> | ||
| 2890 | now and I-ve became so used to it that it runs in the background that I don't | ||
| 2891 | even imagine a world without it. But it's not without problems.</p> | ||
| 2892 | <p>At first I had problems with <code>.venv</code> environments for Python and the only | ||
| 2893 | solution for excluding synchronization for this folder was to manually exclude a | ||
| 2894 | specific folder which is not really scalable. FYI, my whole project folder is | ||
| 2895 | synced on <a href="https://www.dropbox.com/">Dropbox</a>. This of course introduced a lot | ||
| 2896 | of syncing of files and folders that are not needed or even break things on | ||
| 2897 | other machines. In the case of <strong>Python</strong>, I couldn't use that on my second | ||
| 2898 | machine. I needed to delete <code>.venv</code> folder and pip it again which synced files | ||
| 2899 | again to the main machine. This was very frustrating. <strong>Nodejs</strong> handles this | ||
| 2900 | much nicer and I can just run the scripts without deleting <code>node_modules</code> again | ||
| 2901 | and reinstalling. However, <code>node_modules</code> is a beast of its own. It creates so | ||
| 2902 | many files that OS has a problem counting them when you check the folder | ||
| 2903 | contents for size.</p> | ||
| 2904 | <p>I wanted something similar to Dropbox. I could without the instant syncing but | ||
| 2905 | it would need to be fast and had the option for me to exclude folders like | ||
| 2906 | <code>node_modules, .venv, .git</code> and folders like that.</p> | ||
| 2907 | <p>I went on a hunt for an alternative to <a href="https://www.dropbox.com/">Dropbox</a> | ||
| 2908 | and found:</p> | ||
| 2909 | <ul> | ||
| 2910 | <li><a href="https://tresorit.com/">Tresorit</a></li> | ||
| 2911 | <li><a href="https://sync.com">Sync.com</a></li> | ||
| 2912 | <li><a href="https://www.box.com/">Box</a></li> | ||
| 2913 | </ul> | ||
| 2914 | <p>You know, the usual list of suspects. I didn't include <a href="https://drive.google.com">Google | ||
| 2915 | drive</a> or <a href="https://onedrive.live.com/">One drive</a> | ||
| 2916 | since they are even more draconian than Dropbox.</p> | ||
| 2917 | <blockquote> | ||
| 2918 | <p>All this does not stem from me being paranoid but recently these companies | ||
| 2919 | have became more and more aggressive and they keep violating our privacy when | ||
| 2920 | they share our data with 3rd party services. It is getting out of control.</p> | ||
| 2921 | </blockquote> | ||
| 2922 | <p>So, my main problem was still there. No way of excluding a specific folder from | ||
| 2923 | syncing. And before we go into &quot;<em>But you have git, isn't that enough?</em>&quot;, I must | ||
| 2924 | say, that many of the files (PDFs, spreadsheets, etc) I have in a <code>git</code> repo | ||
| 2925 | don't get pushed upstream to Git and I still want to have them synced across my | ||
| 2926 | computers.</p> | ||
| 2927 | <p>I initially wanted to use <a href="https://linux.die.net/man/1/rsync">rsync</a> but I would | ||
| 2928 | need to then have a remote VPS or transfer between my computers directly. I | ||
| 2929 | wanted a solution where all my files could be accessible to me without my | ||
| 2930 | machine.</p> | ||
| 2931 | <blockquote> | ||
| 2932 | <p><strong>WARNING: This solution will cost you money!</strong> DigitalOcean Spaces are $5 per | ||
| 2933 | month and there are some bandwidth limitations and if you go beyond that you get | ||
| 2934 | billed additionally.</p> | ||
| 2935 | </blockquote> | ||
| 2936 | <p>Then I remembered that I could use something like | ||
| 2937 | <a href="https://en.wikipedia.org/wiki/Amazon_S3">S3</a> since it has versioning and is | ||
| 2938 | fully managed. I didn't want to go down the AWS rabbit hole with this so I | ||
| 2939 | choose <a href="https://www.digitalocean.com/products/spaces/">DigitalOcean Spaces</a>.</p> | ||
| 2940 | <p>Then I needed a command-line tool to sync between source and target. I found | ||
| 2941 | this nice tool <a href="https://s3tools.org/s3cmd">s3cmd</a> and it is in the Ubuntu | ||
| 2942 | repositories.</p> | ||
| 2943 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>sudo apt install s3cmd | ||
| 2944 | </span></span></code></pre><p>After installation will I create a new Space bucket on DigitalOcean. Remember | ||
| 2945 | the zone you will choose because you will need it when you will configure | ||
| 2946 | <code>s3cmd</code>.</p> | ||
| 2947 | <p>Then I visited <a href="https://cloud.digitalocean.com/account/api/tokens">Digitalocean Applications &amp; | ||
| 2948 | API</a> and generated <strong>Spaces | ||
| 2949 | access keys</strong>. Save both key and secret somewhere safe because when you will | ||
| 2950 | leave the page secret will not be available anymore to you and you will need to | ||
| 2951 | re-generate it.</p> | ||
| 2952 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># enter your key and secret and correct endpoint</span> | ||
| 2953 | </span></span><span style="display:flex;"><span><span style="color:#008000"># my endpoint is ams3.digitaloceanspaces.com because</span> | ||
| 2954 | </span></span><span style="display:flex;"><span><span style="color:#008000"># I created my bucket in Amsterdam regiin</span> | ||
| 2955 | </span></span><span style="display:flex;"><span>s3cmd --configure | ||
| 2956 | </span></span></code></pre><p>After that I played around with options for <code>s3cmd</code> and got to the following | ||
| 2957 | command.</p> | ||
| 2958 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># I executed this command from my projects folder</span> | ||
| 2959 | </span></span><span style="display:flex;"><span>cd projects | ||
| 2960 | </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/ | ||
| 2961 | </span></span></code></pre><p>When syncing int he other direction you will need to change the order of the | ||
| 2962 | <code>SOURCE</code> and <code>TARGET</code> to <code>s3://my-bucket-name/projects/</code> and <code>./</code>.</p> | ||
| 2963 | <blockquote> | ||
| 2964 | <p>Be sure that all the paths have trailing slash so that sync knows that this | ||
| 2965 | are directories.</p> | ||
| 2966 | </blockquote> | ||
| 2967 | <p>I am planning to implement some sort of a <code>.ignore</code> file that will enable me to | ||
| 2968 | have a project-specific exclude options.</p> | ||
| 2969 | <p>I am currently running this every hour as a cronjob which is perfectly fine for | ||
| 2970 | now when I am testing how this whole thing works and how it all will turn out.</p> | ||
| 2971 | <p>I have also created a small Gnome extension which is still very unstable, but | ||
| 2972 | when/if this whole experiment pays of I will share on Github.</p> | ||
| 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 +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><p>Recently I moved back to <a href="https://www.gnu.org/software/bash/">bash</a> as my | ||
| 2985 | default shell. I was previously using <a href="https://fishshell.com/">fish</a> and got | ||
| 2986 | used to the cool features it has. But, regardless of that, I wanted to move to a | ||
| 2987 | more standard shell because I was hopping back and forth with exporting | ||
| 2988 | variables and stuff like that which got pretty annoying.</p> | ||
| 2989 | <p>So I embarked on a mission to make <a href="https://www.gnu.org/software/bash/">bash</a> | ||
| 2990 | more like <a href="https://fishshell.com/">fish</a> and in the process found that I really | ||
| 2991 | missed autosuggest with TAB on changing directories.</p> | ||
| 2992 | <p>I found a nice alternative that emulates <a href="http://zsh.sourceforge.net/">zsh</a> like | ||
| 2993 | autosuggestion and autocomplete so I added the following to my <code>.bashrc</code> file.</p> | ||
| 2994 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>bind <span style="color:#a31515">&#34;TAB:menu-complete&#34;</span> | ||
| 2995 | </span></span><span style="display:flex;"><span>bind <span style="color:#a31515">&#34;set show-all-if-ambiguous on&#34;</span> | ||
| 2996 | </span></span><span style="display:flex;"><span>bind <span style="color:#a31515">&#34;set completion-ignore-case on&#34;</span> | ||
| 2997 | </span></span><span style="display:flex;"><span>bind <span style="color:#a31515">&#34;set menu-complete-display-prefix on&#34;</span> | ||
| 2998 | </span></span><span style="display:flex;"><span>bind <span style="color:#a31515">&#39;&#34;\e[Z&#34;:menu-complete-backward&#39;</span> | ||
| 2999 | </span></span></code></pre><p>I haven't noticed anything wrong with this and all was working fine until I | ||
| 3000 | restarted my machine and then I got this error.</p> | ||
| 3001 | <figure> | ||
| 3002 | <img src="/posts/profile-bind-error/error.jpg" alt="Profile bind error" /> | ||
| 3003 | </figure> | ||
| 3004 | <p>When I pressed OK, I got into the <a href="https://wiki.gnome.org/Projects/GnomeShell">Gnome | ||
| 3005 | shell</a> and all was working fine, but | ||
| 3006 | the error was still bugging me. I started looking for the reason why this is | ||
| 3007 | happening and found a solution to this error on <a href="https://superuser.com/a/892682">Remote SSH Commands - bash bind | ||
| 3008 | warning: line editing not enabled</a>.</p> | ||
| 3009 | <p>So I added a simple <code>if [ -t 1 ]</code> around <code>bind</code> statements to avoid running | ||
| 3010 | commands that presume the session is interactive when it isn't.</p> | ||
| 3011 | <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> | ||
| 3012 | </span></span><span style="display:flex;"><span> bind <span style="color:#a31515">&#34;TAB:menu-complete&#34;</span> | ||
| 3013 | </span></span><span style="display:flex;"><span> bind <span style="color:#a31515">&#34;set show-all-if-ambiguous on&#34;</span> | ||
| 3014 | </span></span><span style="display:flex;"><span> bind <span style="color:#a31515">&#34;set completion-ignore-case on&#34;</span> | ||
| 3015 | </span></span><span style="display:flex;"><span> bind <span style="color:#a31515">&#34;set menu-complete-display-prefix on&#34;</span> | ||
| 3016 | </span></span><span style="display:flex;"><span> bind <span style="color:#a31515">&#39;&#34;\e[Z&#34;:menu-complete-backward&#39;</span> | ||
| 3017 | </span></span><span style="display:flex;"><span><span style="color:#00f">fi</span> | ||
| 3018 | </span></span></code></pre><p>After logging out and back in the problem was gone.</p> | ||
| 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 +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><h2 id="introduction">Introduction</h2> | ||
| 3031 | <p>A while ago I bought some | ||
| 3032 | <a href="https://www.espressif.com/en/products/socs/esp8266">ESP8266</a> and | ||
| 3033 | <a href="https://www.espressif.com/en/products/socs/esp32">ESP32</a> dev boards to play | ||
| 3034 | around with and I finally found a project to try it out.</p> | ||
| 3035 | <p>For my project, I used <a href="https://www.espressif.com/en/products/socs/esp32">ESP32</a> | ||
| 3036 | but I could easily choose | ||
| 3037 | <a href="https://www.espressif.com/en/products/socs/esp8266">ESP8266</a>. This guide | ||
| 3038 | contains which tools I use and how I prepared my workspace to code for | ||
| 3039 | <a href="https://www.espressif.com/en/products/socs/esp8266">ESP8266</a>.</p> | ||
| 3040 | <figure> | ||
| 3041 | <img src="/posts/esp8366-micropython/boards.jpg" alt="ESP8266 and ESP32 boards" /> | ||
| 3042 | </figure> | ||
| 3043 | <p>This guide covers:</p> | ||
| 3044 | <ul> | ||
| 3045 | <li>flashing SOC</li> | ||
| 3046 | <li>install proper tooling</li> | ||
| 3047 | <li>deploying a simple script</li> | ||
| 3048 | </ul> | ||
| 3049 | <blockquote> | ||
| 3050 | <p>Make sure that you are using <strong>a good USB cable</strong>. I had some problems with | ||
| 3051 | mine and once I replaced it everything started to work.</p> | ||
| 3052 | </blockquote> | ||
| 3053 | <h2 id="flashing-the-soc">Flashing the SOC</h2> | ||
| 3054 | <p>Plug your ESP8266 to USB port and check if the device was recognized with | ||
| 3055 | executing <code>dmesg | grep ch341-uart</code>.</p> | ||
| 3056 | <p>Then check if the device is available under <code>/dev/</code> by running <code>ls /dev/ttyUSB*</code>.</p> | ||
| 3057 | <blockquote> | ||
| 3058 | <p><strong>Linux users</strong>: if a device is not available be sure you are in <code>dialout</code> | ||
| 3059 | group. You can check this by executing <code>groups $USER</code>. You can add a user to | ||
| 3060 | <code>dialout</code> group with <code>sudo adduser $USER dialout</code>.</p> | ||
| 3061 | </blockquote> | ||
| 3062 | <p>After these conditions are meet go to the navigate to | ||
| 3063 | <a href="https://micropython.org/download/esp8266/">https://micropython.org/download/esp8266/</a> | ||
| 3064 | and download <code>esp8266-20200902-v1.13.bin</code>.</p> | ||
| 3065 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>mkdir esp8266-test | ||
| 3066 | </span></span><span style="display:flex;"><span>cd esp8266-test | ||
| 3067 | </span></span><span style="display:flex;"><span> | ||
| 3068 | </span></span><span style="display:flex;"><span>wget https://micropython.org/resources/firmware/esp8266-20200902-v1.13.bin | ||
| 3069 | </span></span></code></pre><p>After obtaining firmware we will need some tooling to flash the firmware to the | ||
| 3070 | board.</p> | ||
| 3071 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>sudo pip3 install esptool | ||
| 3072 | </span></span></code></pre><p>You can read more about <code>esptool</code> at | ||
| 3073 | <a href="https://github.com/espressif/esptool/">https://github.com/espressif/esptool/</a>.</p> | ||
| 3074 | <p>Before flashing the firmware we need to erase the flash on device. Substitute | ||
| 3075 | <code>USB0</code> with the device listed in output of <code>ls /dev/ttyUSB*</code>.</p> | ||
| 3076 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>esptool.py --port /dev/ttyUSB0 erase_flash | ||
| 3077 | </span></span></code></pre><p>If flash was successfully erased it is now time to flash the new firmware to it.</p> | ||
| 3078 | <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 | ||
| 3079 | </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>.</p> | ||
| 3080 | <blockquote> | ||
| 3081 | <p>Sometimes you will need to press <code>ENTER</code> in <code>screen</code> or <code>picocom</code> to access | ||
| 3082 | REPL.</p> | ||
| 3083 | </blockquote> | ||
| 3084 | <p>When you are in REPL you can test if all is working properly following steps.</p> | ||
| 3085 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>&gt; <span style="color:#00f">import</span> machine | ||
| 3086 | </span></span><span style="display:flex;"><span>&gt; machine.freq() | ||
| 3087 | </span></span></code></pre><p>This should output a number representing a frequency of the CPU (mine was | ||
| 3088 | <code>80000000</code>).</p> | ||
| 3089 | <p>When you are in <code>screen</code> or <code>picocom</code> these can help you a bit.</p> | ||
| 3090 | <table> | ||
| 3091 | <thead> | ||
| 3092 | <tr> | ||
| 3093 | <th>Key</th> | ||
| 3094 | <th>Command</th> | ||
| 3095 | </tr> | ||
| 3096 | </thead> | ||
| 3097 | <tbody> | ||
| 3098 | <tr> | ||
| 3099 | <td>CTRL+d</td> | ||
| 3100 | <td>preforms soft reboot</td> | ||
| 3101 | </tr> | ||
| 3102 | <tr> | ||
| 3103 | <td>CTRL+a x</td> | ||
| 3104 | <td>exits picocom</td> | ||
| 3105 | </tr> | ||
| 3106 | <tr> | ||
| 3107 | <td>CTRL+a \</td> | ||
| 3108 | <td>exits screen</td> | ||
| 3109 | </tr> | ||
| 3110 | </tbody> | ||
| 3111 | </table> | ||
| 3112 | <h2 id="install-better-tooling">Install better tooling</h2> | ||
| 3113 | <p>Now, to make our lives a little bit easier there are couple of additional tools | ||
| 3114 | that will make this whole experience a little more bearable.</p> | ||
| 3115 | <p>There are twq cool ways of uploading local files to SOC flash.</p> | ||
| 3116 | <ul> | ||
| 3117 | <li>ampy → <a href="https://github.com/scientifichackers/ampy">https://github.com/scientifichackers/ampy</a></li> | ||
| 3118 | <li>rshell → <a href="https://github.com/dhylands/rshell">https://github.com/dhylands/rshell</a></li> | ||
| 3119 | </ul> | ||
| 3120 | <h3 id="ampy">ampy</h3> | ||
| 3121 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># installing ampy</span> | ||
| 3122 | </span></span><span style="display:flex;"><span>sudo pip3 install adafruit-ampy | ||
| 3123 | </span></span></code></pre><p>Listed below are some common commands I used.</p> | ||
| 3124 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># uploads file to flash</span> | ||
| 3125 | </span></span><span style="display:flex;"><span>ampy --delay 2 --port /dev/ttyUSB0 put boot.py | ||
| 3126 | </span></span><span style="display:flex;"><span> | ||
| 3127 | </span></span><span style="display:flex;"><span><span style="color:#008000"># lists file on flash</span> | ||
| 3128 | </span></span><span style="display:flex;"><span>ampy --delay 2 --port /dev/ttyUSB0 ls | ||
| 3129 | </span></span><span style="display:flex;"><span> | ||
| 3130 | </span></span><span style="display:flex;"><span><span style="color:#008000"># outputs contents of file on flash</span> | ||
| 3131 | </span></span><span style="display:flex;"><span>ampy --delay 2 --port /dev/ttyUSB0 cat boot.py | ||
| 3132 | </span></span></code></pre><blockquote> | ||
| 3133 | <p>I added <code>delay</code> of 2 seconds because I had problems with executing commands.</p> | ||
| 3134 | </blockquote> | ||
| 3135 | <h3 id="rshell">rshell</h3> | ||
| 3136 | <p>Even though <code>ampy</code> is a cool tool I opted with <code>rshell</code> in the end since it's | ||
| 3137 | much more polished and feature rich.</p> | ||
| 3138 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># installing ampy</span> | ||
| 3139 | </span></span><span style="display:flex;"><span>sudo pip3 install rshell | ||
| 3140 | </span></span></code></pre><p>Now that <code>rshell</code> is installed we can connect to the board.</p> | ||
| 3141 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>rshell --buffer-size=30 -p /dev/ttyUSB0 -a | ||
| 3142 | </span></span></code></pre><p>This will open a shell inside bash and from here you can execute multiple | ||
| 3143 | commands. You can check what is supported with <code>help</code> once you are inside of a | ||
| 3144 | shell.</p> | ||
| 3145 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>m@turing ~/Junk/esp8266-test | ||
| 3146 | </span></span><span style="display:flex;"><span>$ rshell --buffer-size=30 -p /dev/ttyUSB0 -a | ||
| 3147 | </span></span><span style="display:flex;"><span> | ||
| 3148 | </span></span><span style="display:flex;"><span>Using buffer-size of 30 | ||
| 3149 | </span></span><span style="display:flex;"><span>Connecting to /dev/ttyUSB0 (buffer-size 30)... | ||
| 3150 | </span></span><span style="display:flex;"><span>Trying to connect to REPL connected | ||
| 3151 | </span></span><span style="display:flex;"><span>Testing <span style="color:#00f">if</span> ubinascii.unhexlify exists ... Y | ||
| 3152 | </span></span><span style="display:flex;"><span>Retrieving root directories ... /boot.py/ | ||
| 3153 | </span></span><span style="display:flex;"><span>Setting time ... Sep 06, 2020 23:54:28 | ||
| 3154 | </span></span><span style="display:flex;"><span>Evaluating board_name ... pyboard | ||
| 3155 | </span></span><span style="display:flex;"><span>Retrieving time epoch ... Jan 01, 2000 | ||
| 3156 | </span></span><span style="display:flex;"><span>Welcome to rshell. Use Control-D (or the exit command) to exit rshell. | ||
| 3157 | </span></span><span style="display:flex;"><span>/home/m/Junk/esp8266-test&gt; help | ||
| 3158 | </span></span><span style="display:flex;"><span> | ||
| 3159 | </span></span><span style="display:flex;"><span>Documented commands (type help &lt;topic&gt;): | ||
| 3160 | </span></span><span style="display:flex;"><span>======================================== | ||
| 3161 | </span></span><span style="display:flex;"><span>args cat connect date edit filesize help mkdir rm shell | ||
| 3162 | </span></span><span style="display:flex;"><span>boards cd cp echo exit filetype ls repl rsync | ||
| 3163 | </span></span><span style="display:flex;"><span> | ||
| 3164 | </span></span><span style="display:flex;"><span>Use Control-D (or the exit command) to exit rshell. | ||
| 3165 | </span></span></code></pre><blockquote> | ||
| 3166 | <p>Inside a shell <code>ls</code> will display list of files on your machine. To get list | ||
| 3167 | of files on flash folder <code>/pyboard</code> is remapped inside the shell. To list files | ||
| 3168 | on flash you must perform <code>ls /pyboard</code>.</p> | ||
| 3169 | </blockquote> | ||
| 3170 | <h4 id="moving-files-to-flash">Moving files to flash</h4> | ||
| 3171 | <p>To avoid copying files all the time I used <code>rsync</code> function from the inside of | ||
| 3172 | <code>rshell</code>.</p> | ||
| 3173 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>rsync . /pyboard | ||
| 3174 | </span></span></code></pre><h4 id="executing-scripts">Executing scripts</h4> | ||
| 3175 | <p>It is a pain to continuously reboot the device to trigger <code>/pyboard/boot.py</code> and | ||
| 3176 | there is a better way of testing local scripts on remote device.</p> | ||
| 3177 | <p>Lets assume we have <code>src/freq.py</code> file that displays CPU frequency of a remote | ||
| 3178 | device.</p> | ||
| 3179 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># src/freq.py</span> | ||
| 3180 | </span></span><span style="display:flex;"><span> | ||
| 3181 | </span></span><span style="display:flex;"><span><span style="color:#00f">import</span> machine | ||
| 3182 | </span></span><span style="display:flex;"><span>print(machine.freq()) | ||
| 3183 | </span></span></code></pre><p>Now lets upload this and execute it.</p> | ||
| 3184 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># syncs files to remove device</span> | ||
| 3185 | </span></span><span style="display:flex;"><span>rsync ./src /pyboard | ||
| 3186 | </span></span><span style="display:flex;"><span> | ||
| 3187 | </span></span><span style="display:flex;"><span><span style="color:#008000"># goes into REPL</span> | ||
| 3188 | </span></span><span style="display:flex;"><span>repl | ||
| 3189 | </span></span><span style="display:flex;"><span> | ||
| 3190 | </span></span><span style="display:flex;"><span><span style="color:#008000"># we import file by importing it without .py extension and this will run the script</span> | ||
| 3191 | </span></span><span style="display:flex;"><span>&gt; import freq | ||
| 3192 | </span></span><span style="display:flex;"><span> | ||
| 3193 | </span></span><span style="display:flex;"><span><span style="color:#008000"># CTRL+x will exit REPL</span> | ||
| 3194 | </span></span></code></pre><h2 id="additional-resources">Additional resources</h2> | ||
| 3195 | <ul> | ||
| 3196 | <li><a href="https://randomnerdtutorials.com/getting-started-micropython-esp32-esp8266/">https://randomnerdtutorials.com/getting-started-micropython-esp32-esp8266/</a></li> | ||
| 3197 | <li><a href="http://docs.micropython.org/en/latest/esp8266/quickref.html">http://docs.micropython.org/en/latest/esp8266/quickref.html</a></li> | ||
| 3198 | </ul> | ||
| 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 +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><p>I recently bought <a href="https://www.laptopmag.com/reviews/laptops/lenovo-thinkpad-x220">ThinkPad | ||
| 3211 | X220</a> just as a | ||
| 3212 | joke on eBay to test Linux distributions and play around with things and not | ||
| 3213 | destroy my main machine. Little to my knowledge I felt in love with it. Man, | ||
| 3214 | they really made awesome machines back then.</p> | ||
| 3215 | <p>After changing disk that came with it to SSD and installing Ubuntu to test if | ||
| 3216 | everything works I noticed that even after a single touch of my external mouse | ||
| 3217 | the system would wake up from sleep even though the lid was shut down.</p> | ||
| 3218 | <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 | ||
| 3219 | sleep indicator</a>. | ||
| 3220 | I already had a bad experience with Linux and it's power management. I had a | ||
| 3221 | <a href="https://www.pcmag.com/reviews/dell-inspiron-15-7537">Dell Inspiron 7537</a> laptop | ||
| 3222 | with a touchscreen and while traveling it decided to wake up and started cooking | ||
| 3223 | in my backpack to the point that the digitizer responsible for touch actually | ||
| 3224 | glue off and the whole screen got wrecked. So, I am a bit touchy about this.</p> | ||
| 3225 | <p>I went on solution hunting and to my surprise there is no easy way to disable | ||
| 3226 | specific devices to perform wake up. Why is this not under the power management | ||
| 3227 | tab in setting is really strange.</p> | ||
| 3228 | <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 | ||
| 3229 | solution</a> | ||
| 3230 | that worked for me. The only problem with this solution was that he added his | ||
| 3231 | solution to <code>.bashrc</code> and this triggers <code>sudo</code> that asks for a password each | ||
| 3232 | time new terminal is opened, which get annoying quickly since I open a lot of | ||
| 3233 | terminals all the time.</p> | ||
| 3234 | <p>I followed his instructions and got to solution <code>sudo sh -c &quot;echo 'disabled' &gt; /sys/bus/usb/devices/2-1.1/power/wakeup&quot;</code>.</p> | ||
| 3235 | <p>I created a system service file <code>sudo nano /etc/systemd/system/disable-mouse-wakeup.service</code> and removed <code>sudo</code> and | ||
| 3236 | replaced <code>sh</code> with <code>/usr/bin/sh</code> and pasted all that in <code>ExecStart</code>.</p> | ||
| 3237 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#00f">[Unit]</span> | ||
| 3238 | </span></span><span style="display:flex;"><span>Description=<span style="color:#a31515">Disables wakeup on mouse event</span> | ||
| 3239 | </span></span><span style="display:flex;"><span>After=<span style="color:#a31515">network.target</span> | ||
| 3240 | </span></span><span style="display:flex;"><span>StartLimitIntervalSec=<span style="color:#a31515">0</span> | ||
| 3241 | </span></span><span style="display:flex;"><span> | ||
| 3242 | </span></span><span style="display:flex;"><span><span style="color:#00f">[Service]</span> | ||
| 3243 | </span></span><span style="display:flex;"><span>Type=<span style="color:#a31515">simple</span> | ||
| 3244 | </span></span><span style="display:flex;"><span>Restart=<span style="color:#a31515">always</span> | ||
| 3245 | </span></span><span style="display:flex;"><span>RestartSec=<span style="color:#a31515">1</span> | ||
| 3246 | </span></span><span style="display:flex;"><span>User=<span style="color:#a31515">root</span> | ||
| 3247 | </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> | ||
| 3248 | </span></span><span style="display:flex;"><span> | ||
| 3249 | </span></span><span style="display:flex;"><span><span style="color:#00f">[Install]</span> | ||
| 3250 | </span></span><span style="display:flex;"><span>WantedBy=<span style="color:#a31515">multi-user.target</span> | ||
| 3251 | </span></span></code></pre><p>After that I enabled, started and checked status of service.</p> | ||
| 3252 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>sudo systemctl enable disable-mouse-wakeup.service | ||
| 3253 | </span></span><span style="display:flex;"><span>sudo systemctl start disable-mouse-wakeup.service | ||
| 3254 | </span></span><span style="display:flex;"><span>sudo systemctl status disable-mouse-wakeup.service | ||
| 3255 | </span></span></code></pre><p>This will permanently disable that device from wakeing up you computer on boot. | ||
| 3256 | If you have many devices you would like to surpress from waking up your machine | ||
| 3257 | I would create a shell script and call that instead of direclty doing it in | ||
| 3258 | service file.</p> | ||
| 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 +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><p>I have been working remotely for the past 5 years. I love it. Love the freedom | ||
| 3271 | and make your schedule thingy.</p> | ||
| 3272 | <h2 id="you-work-more-not-less">You work more not less</h2> | ||
| 3273 | <p>I've heard from people things like: &quot;Oh, you are so lucky, working from home, | ||
| 3274 | having all the free time you want&quot;. It was obvious they had no clue what means | ||
| 3275 | working remotely. They had this romantic idea of remote work. You can watch TV | ||
| 3276 | whenever you like, you can go outside for a picnic if you want and stuff like | ||
| 3277 | that.</p> | ||
| 3278 | <p>This may be true if you work a day or two in a week from home. But if you go | ||
| 3279 | completely remote all these changes completely. I take some time to acclimate | ||
| 3280 | but then you start feeling the consequences of going fully remote. And it's not | ||
| 3281 | all rainbows and unicorns. Rather the opposite.</p> | ||
| 3282 | <h2 id="feeling-lost">Feeling lost</h2> | ||
| 3283 | <p>At first, I remembered I felt lost. I was not used to this kind of environment. | ||
| 3284 | It felt disoriented and a part of you that is used to procrastinate turns on. | ||
| 3285 | You start thinking of a workday as a whole day. And soon this idea of &quot;I can do | ||
| 3286 | this later&quot; starts creeping in. Well, I have the whole day ahead of me. I can do | ||
| 3287 | this a bit later.</p> | ||
| 3288 | <h2 id="hyper-performance">Hyper-performance</h2> | ||
| 3289 | <p>As a direct result, you become more focused on your work since you don't have | ||
| 3290 | all the interruptions common in the workplace. And you can quickly get used to | ||
| 3291 | this hyper-performance. But this mode requires also a lot of peace and quiet.</p> | ||
| 3292 | <p>And here we come to the ugly parts of all this. <strong>People rarely have the | ||
| 3293 | self-control</strong> to not waste other people's time. It is paralyzing when people | ||
| 3294 | start calling you, sending you chat messages, etc. The thing is, that when I | ||
| 3295 | achieve this hyper-performance mode I am completely embroiled in the problem I | ||
| 3296 | am solving and this kind of interruptions mess with your head. I need an hour at | ||
| 3297 | least to get back in the zone. Sometimes not achieving the same focus the whole | ||
| 3298 | day.</p> | ||
| 3299 | <p>I know that life is not how you want it to be and takes its route but from what | ||
| 3300 | I've learned this kind of interruptions can be avoided in 90% of the case easily | ||
| 3301 | just by closing any chat programs and putting your phone in a drawer.</p> | ||
| 3302 | <h2 id="suggestion-to-all-the-new-remote-workers">Suggestion to all the new remote workers</h2> | ||
| 3303 | <ul> | ||
| 3304 | <li>Stop wasting other people's time. You don't bother people at their desks in | ||
| 3305 | the office either.</li> | ||
| 3306 | <li>Do not replace daily chats in the hallways with instant messaging software. | ||
| 3307 | It will only interrupt people. Nothing good will come of it.</li> | ||
| 3308 | <li>Set your working hours and try to not allow it to bleed outside these | ||
| 3309 | boundaries and maintain your routine.</li> | ||
| 3310 | <li>Be prepared that hours will be longer regardless of your good intentions and | ||
| 3311 | your well thought of routine.</li> | ||
| 3312 | <li>Try to be hyper-focused and do only one thing at the time. Multitasking is the | ||
| 3313 | enemy of progress.</li> | ||
| 3314 | <li>Avoid long meetings and if possible eliminate them. Rather take time to write | ||
| 3315 | them out and allow others to respond in their own time. Meetings are usually a | ||
| 3316 | large waste of time and most of the people attending them are there just | ||
| 3317 | because the manager said so.</li> | ||
| 3318 | <li>The software will not solve your problems. And throwing money at problems | ||
| 3319 | neither.</li> | ||
| 3320 | <li>If you are in a managerial position don't supervise any single minute of | ||
| 3321 | workers. They are probably giving you more hours anyways. Track progress | ||
| 3322 | weekly not daily. You hired them and give them the benefit of the doubt that | ||
| 3323 | they will deliver what you agreed upon.</li> | ||
| 3324 | </ul> | ||
| 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 +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><p>Previous project I was working on was being coded in | ||
| 3337 | <a href="https://golang.org/">Golang</a>. Also was my first project using it. And damn, | ||
| 3338 | that was an awesome experience. The whole thing is just superb. From how errors | ||
| 3339 | are handled. The C-like way you handle compiling. The way the language is | ||
| 3340 | structured making it incredibly versatile and easy to learn.</p> | ||
| 3341 | <p>It may cause some pain for somebody that is not used of using interfaces to map | ||
| 3342 | JSON and doing the recompilation all the time. But we have tools like | ||
| 3343 | <a href="http://eradman.com/entrproject/">entr</a> and | ||
| 3344 | <a href="https://www.gnu.org/software/make/">make</a> to fix that.</p> | ||
| 3345 | <p>But we are not here to talk about my undying love for <strong>Golang</strong>. Only in some | ||
| 3346 | way we probably should. It is an excellent example of how modern language should | ||
| 3347 | be designed. And because I have used it extensively in the last couple of years | ||
| 3348 | this probably taints my views of other languages. And is doing me a great | ||
| 3349 | disservice. Nevertheless, here we are.</p> | ||
| 3350 | <p>About two years ago I started flirting with <a href="https://nodejs.org/en/">Node.js</a> | ||
| 3351 | for a project I started working on. What I wanted was to have things written in | ||
| 3352 | a language that is widely used, and we could get additional developers for. As | ||
| 3353 | much as <strong>Golang</strong> is amazing it's really hard to get developers for it. Even | ||
| 3354 | now. And after playing around with it for a week I felt in love with the speed | ||
| 3355 | of iteration and massive package ecosystem. Do you want SSO? You got it! Do you | ||
| 3356 | want some esoteric library for something? There is a strong chance somebody | ||
| 3357 | wrote it. It is so extensive that you find yourself evaluating packages based on | ||
| 3358 | <strong>GitHub stars</strong> and number of contributors. You get swallowed by the vanity | ||
| 3359 | metrics and that potentially will become the downfall of Node.js.</p> | ||
| 3360 | <p>Because of the sheer amount of choice I often got anxiety when choosing | ||
| 3361 | libraries. Will I choose the correct one? Is this library something that will be | ||
| 3362 | supported for a foreseeable future or not? I am used of using libraries that are | ||
| 3363 | being in development for 10 years plus (Python, C) and that gave me some sort of | ||
| 3364 | comfort. And it is probably unfair to Node.js and community to expect same | ||
| 3365 | dedication.</p> | ||
| 3366 | <p>Moving forward ... Work started and things were great. <strong>Speed of iteration was | ||
| 3367 | insane</strong>. For some feature that I would need a day in Golang only took me hour | ||
| 3368 | or two. I became lazy! Using packages all over the place. Falling into the same | ||
| 3369 | trap as others. Packages on top of packages. And <a href="https://www.npmjs.com/">npm</a> | ||
| 3370 | didn't help at all. The way that the package manager works is just | ||
| 3371 | horrendous. And not allowing to have node_modules outside the project is also | ||
| 3372 | the stupidest idea ever.</p> | ||
| 3373 | <p>So at that point I started feeling the technical debt that comes with Node.js | ||
| 3374 | and the whole ecosystem. What nobody tells you is that <strong>structuring large | ||
| 3375 | Node.js apps</strong> is more problematic than one would think. And going microservice | ||
| 3376 | for every single thing is also a bad idea. The amount of networking you | ||
| 3377 | introduce with that approach always ends up being a pain in the ass. And I don't | ||
| 3378 | even want to go into system administration here. The overhead is | ||
| 3379 | insane. Package-lock.json made many days feel like living hell for me. And I | ||
| 3380 | would eat the cost of all this if it meant for better development | ||
| 3381 | experience. Well, it didn't.</p> | ||
| 3382 | <p>The <strong>lack of Typescript</strong> support in the interpreter is still mind boggling to | ||
| 3383 | me. Why haven't they added native support yet for this is beyond me?! That would | ||
| 3384 | have solved so many problems. Lack of type safety became a problem somewhere in | ||
| 3385 | the middle of the project where the codebase was sufficiently large enough to | ||
| 3386 | present problems. We started adding arguments to functions and there was <strong>no | ||
| 3387 | way to implicitly define argument types</strong>. And because at that point there were | ||
| 3388 | a lot of functions, it became impossible to know what each one accepts, | ||
| 3389 | development became more and more trial and error based.</p> | ||
| 3390 | <p>I tried <strong>implementing Typescript</strong>, but that would present a large refactor | ||
| 3391 | that we were not willing to do at that point. The benefits were not enough. I | ||
| 3392 | also tried <a href="https://flow.org/">Flow - static type checker</a> but implementation | ||
| 3393 | was also horrible. What Typescript and Flow forces you is to have src folder and | ||
| 3394 | then <strong>transpile</strong> your code into dist folder and run it with node. WTH is that | ||
| 3395 | all about. Why can't this be done in memory or some virtual file system? Why? I | ||
| 3396 | see no reason why this couldn't be done like this. But it is what it is. I | ||
| 3397 | abandoned all hope for static type checking.</p> | ||
| 3398 | <p>One of the problems that resulted from not having interfaces or types was | ||
| 3399 | inability to model out our data from <strong>Elasticsearch</strong>. I could have done a | ||
| 3400 | <strong>pedestrian implementation</strong> of it, but there must be a better way of doing | ||
| 3401 | this without resorting to some hack basically. Or maybe I haven't found a | ||
| 3402 | solution, which is also a possibility. I have looked, though. No juice!</p> | ||
| 3403 | <p><strong>Error handling?</strong> Is that a joke?</p> | ||
| 3404 | <p>Thank god for <strong>await/async</strong>. Without it, I would have probably just abandoned | ||
| 3405 | the whole thing and went with something else like Python. That's all I am going | ||
| 3406 | to say about this :)</p> | ||
| 3407 | <p>I started asking myself a question if Node.js is actually ready to be used in a | ||
| 3408 | <strong>large scale applications</strong>? And this was a totally wrong question. What I | ||
| 3409 | should have been asking myself was, how to use Node.js in large scale | ||
| 3410 | application. And you don't get this in <strong>marketing material</strong> for Express or Koa | ||
| 3411 | etc. They never tell you this. Making Node.js scale on infrastructure or in | ||
| 3412 | codebase is really <strong>more of an art than a science</strong>. And just like with the | ||
| 3413 | whole JavaScript ecosystem:</p> | ||
| 3414 | <ul> | ||
| 3415 | <li>impossible to master,</li> | ||
| 3416 | <li>half of your time you work on your tooling,</li> | ||
| 3417 | <li>just accept transpilers that convert one code into another (holly smokes),</li> | ||
| 3418 | <li>error handling is a joke,</li> | ||
| 3419 | <li>standards? What standards?</li> | ||
| 3420 | </ul> | ||
| 3421 | <p>But on the other hand. As I did, you will also learn to love it. Learn to use it | ||
| 3422 | quickly and do impossible things in crazy limited time.</p> | ||
| 3423 | <p>I hate to admit it. But I love Node.js. Dammit, I love it :)</p> | ||
| 3424 | <p><strong>2023 Update</strong>: I hate Node.js!</p> | ||
| 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 +0200</pubDate> | ||
| 3434 | <guid>https://mitjafelicijan.com/the-strange-case-of-elasticsearch-allocation-failure.html</guid> | ||
| 3435 | <description>I&#39;ve been using Elasticsearch in production for 5 years now and never had asingle problem with it.</description> | ||
| 3436 | <content:encoded><p>I've been using Elasticsearch in production for 5 years now and never had a | ||
| 3437 | single problem with it. Hell, never even known there could be a problem. Just | ||
| 3438 | worked. All this time. The first node that I deployed is still being used in | ||
| 3439 | production, never updated, upgraded, touched in anyway.</p> | ||
| 3440 | <p>All this bliss came to an abrupt end this Friday when I got notification that | ||
| 3441 | Elasticsearch cluster went warm. Well, warm is not that bad right? Wrong! | ||
| 3442 | Quickly after that I got another email which sent chills down my spine. Cluster | ||
| 3443 | is now red. RED! Now, shit really hit the fan!</p> | ||
| 3444 | <p>I tried googling what could be the problem and after executing allocation | ||
| 3445 | function noticed that some shards were unassigned and 5 attempts were already | ||
| 3446 | made (which is BTW to my luck the maximum) and that meant I am basically fucked. | ||
| 3447 | They also applied that one should wait for cluster to re-balance itself. So, I | ||
| 3448 | waited. One hour, two hours, several hours. Nothing, still RED.</p> | ||
| 3449 | <p>The strangest thing about it all was, that queries were still being fulfilled. | ||
| 3450 | Data was coming out. On the outside it looked like nothing was wrong but | ||
| 3451 | everybody that would look at the cluster would know immediately that something | ||
| 3452 | was very very wrong and we were living on borrowed time here.</p> | ||
| 3453 | <blockquote> | ||
| 3454 | <p><strong>Please, DO NOT do what I did.</strong> Seriously! Please ask someone on official | ||
| 3455 | forums or if you know an expert please consult him. There could be million of | ||
| 3456 | reasons and these solution fit my problem. Maybe in your case it would | ||
| 3457 | disastrous. I had all the data backed up and even if I would fail spectacularly | ||
| 3458 | I would be able to restore the data. It would be a huge pain and I would loose | ||
| 3459 | couple of days but I had a plan B.</p> | ||
| 3460 | </blockquote> | ||
| 3461 | <p>Executing allocation and told me what the problem was but no clear solution yet.</p> | ||
| 3462 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>GET /_cat/allocation?format=json | ||
| 3463 | </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 | ||
| 3464 | splendid! I must also say that our cluster is capable more than enough to handle | ||
| 3465 | the traffic. Also JVM memory pressure never was an issue. So what happened | ||
| 3466 | really then?</p> | ||
| 3467 | <p>I tried also re-routing failed ones with no success due to AWS restrictions on | ||
| 3468 | having managed Elasticsearch cluster (they lock some of the functions).</p> | ||
| 3469 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>POST /_cluster/reroute?retry_failed=true | ||
| 3470 | </span></span></code></pre><p>I got a message that significantly reduced my options.</p> | ||
| 3471 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>{ | ||
| 3472 | </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> | ||
| 3473 | </span></span><span style="display:flex;"><span>} | ||
| 3474 | </span></span></code></pre><p>After that I went on a hunt again. I won't bother you with all the details | ||
| 3475 | because hours/days went by until I was finally able to re-index the problematic | ||
| 3476 | index and hoped for the best. Until that moment even re-indexing was giving me | ||
| 3477 | errors.</p> | ||
| 3478 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>POST _reindex | ||
| 3479 | </span></span><span style="display:flex;"><span>{ | ||
| 3480 | </span></span><span style="display:flex;"><span> &#34;source&#34;: { | ||
| 3481 | </span></span><span style="display:flex;"><span> &#34;index&#34;: <span style="color:#a31515">&#34;myindex&#34;</span> | ||
| 3482 | </span></span><span style="display:flex;"><span> }, | ||
| 3483 | </span></span><span style="display:flex;"><span> &#34;dest&#34;: { | ||
| 3484 | </span></span><span style="display:flex;"><span> &#34;index&#34;: <span style="color:#a31515">&#34;myindex-new&#34;</span> | ||
| 3485 | </span></span><span style="display:flex;"><span> } | ||
| 3486 | </span></span><span style="display:flex;"><span>} | ||
| 3487 | </span></span></code></pre><p>I needed to do this multiple times to get all the documents re-indexed. Then I | ||
| 3488 | dropped the original one with the following command.</p> | ||
| 3489 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>DELETE /myindex | ||
| 3490 | </span></span></code></pre><p>And re-indexed again new one in the original one (well by name only).</p> | ||
| 3491 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>POST _reindex | ||
| 3492 | </span></span><span style="display:flex;"><span>{ | ||
| 3493 | </span></span><span style="display:flex;"><span> &#34;source&#34;: { | ||
| 3494 | </span></span><span style="display:flex;"><span> &#34;index&#34;: <span style="color:#a31515">&#34;myindex-new&#34;</span> | ||
| 3495 | </span></span><span style="display:flex;"><span> }, | ||
| 3496 | </span></span><span style="display:flex;"><span> &#34;dest&#34;: { | ||
| 3497 | </span></span><span style="display:flex;"><span> &#34;index&#34;: <span style="color:#a31515">&#34;myindex&#34;</span> | ||
| 3498 | </span></span><span style="display:flex;"><span> } | ||
| 3499 | </span></span><span style="display:flex;"><span>} | ||
| 3500 | </span></span></code></pre><p>On the surface it looks like all is working but I have a long road in front of | ||
| 3501 | me to get all the things working again. Cluster now shows that it is in Green | ||
| 3502 | mode but I am also getting a notification that the cluster has processing status | ||
| 3503 | which could mean million of things.</p> | ||
| 3504 | <p>Godspeed!</p> | ||
| 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 +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><p>I have been searching for a solution to pre-generate some placeholder images for | ||
| 3517 | image server I needed to develop that resizes images on S3. I though this would | ||
| 3518 | be a 15min job and quickly found out how very mistaken I was.</p> | ||
| 3519 | <p>Even though Node.js is not really the best way to do this kind of things (surely | ||
| 3520 | something written in C or Rust or even Golang would be the correct way to do | ||
| 3521 | this but we didn't need the speed in our case) I found an excellent library | ||
| 3522 | <a href="https://github.com/lovell/sharp">sharp - High performance Node.js image | ||
| 3523 | processing</a>.</p> | ||
| 3524 | <p>Getting things running was a breeze.</p> | ||
| 3525 | <h2 id="fetch-image-from-s3-and-save-resized">Fetch image from S3 and save resized</h2> | ||
| 3526 | <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>); | ||
| 3527 | </span></span><span style="display:flex;"><span><span style="color:#00f">const</span> aws = require(<span style="color:#a31515">&#39;aws-sdk&#39;</span>); | ||
| 3528 | </span></span><span style="display:flex;"><span> | ||
| 3529 | </span></span><span style="display:flex;"><span><span style="color:#00f">const</span> x,y = 100; | ||
| 3530 | </span></span><span style="display:flex;"><span><span style="color:#00f">const</span> s3 = <span style="color:#00f">new</span> aws.S3({}); | ||
| 3531 | </span></span><span style="display:flex;"><span> | ||
| 3532 | </span></span><span style="display:flex;"><span>aws.config.update({ | ||
| 3533 | </span></span><span style="display:flex;"><span> secretAccessKey: <span style="color:#a31515">&#39;secretAccessKey&#39;</span>, | ||
| 3534 | </span></span><span style="display:flex;"><span> accessKeyId: <span style="color:#a31515">&#39;accessKeyId&#39;</span>, | ||
| 3535 | </span></span><span style="display:flex;"><span> region: <span style="color:#a31515">&#39;region&#39;</span> | ||
| 3536 | </span></span><span style="display:flex;"><span>}); | ||
| 3537 | </span></span><span style="display:flex;"><span> | ||
| 3538 | </span></span><span style="display:flex;"><span><span style="color:#00f">const</span> originalImage = <span style="color:#00f">await</span> s3.getObject({ | ||
| 3539 | </span></span><span style="display:flex;"><span> Bucket: <span style="color:#a31515">&#39;some-bucket-name&#39;</span>, | ||
| 3540 | </span></span><span style="display:flex;"><span> Key: <span style="color:#a31515">&#39;image.jpg&#39;</span>, | ||
| 3541 | </span></span><span style="display:flex;"><span>}).promise(); | ||
| 3542 | </span></span><span style="display:flex;"><span> | ||
| 3543 | </span></span><span style="display:flex;"><span><span style="color:#00f">const</span> resizedImage = <span style="color:#00f">await</span> sharp(originalImage.Body) | ||
| 3544 | </span></span><span style="display:flex;"><span> .resize(x, y) | ||
| 3545 | </span></span><span style="display:flex;"><span> .jpeg({ progressive: <span style="color:#00f">true</span> }) | ||
| 3546 | </span></span><span style="display:flex;"><span> .toBuffer(); | ||
| 3547 | </span></span><span style="display:flex;"><span> | ||
| 3548 | </span></span><span style="display:flex;"><span>s3.putObject({ | ||
| 3549 | </span></span><span style="display:flex;"><span> Bucket: <span style="color:#a31515">&#39;some-bucket-name&#39;</span>, | ||
| 3550 | </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>, | ||
| 3551 | </span></span><span style="display:flex;"><span> Body: resizedImage, | ||
| 3552 | </span></span><span style="display:flex;"><span> ContentType: <span style="color:#a31515">&#39;image/jpeg&#39;</span>, | ||
| 3553 | </span></span><span style="display:flex;"><span> ACL: <span style="color:#a31515">&#39;public-read&#39;</span> | ||
| 3554 | </span></span><span style="display:flex;"><span>}).promise(); | ||
| 3555 | </span></span></code></pre><p>All this code was wrapped inside a web service with some additional security | ||
| 3556 | checks and defensive coding to detect if key is missing on S3.</p> | ||
| 3557 | <p>And at that point I needed to return placeholder images as a response in case | ||
| 3558 | key is missing or x,y are not allowed by the server etc. I could have created | ||
| 3559 | PNG in Gimp and just serve them but I wanted to respect aspect ratio and I | ||
| 3560 | didn't want to return some mangled images.</p> | ||
| 3561 | <blockquote> | ||
| 3562 | <p>Main problem with finding a clean solution I could copy and paste and change a | ||
| 3563 | bit was a task. API is changing constantly and there weren't clear examples or | ||
| 3564 | I was unable to find them.</p> | ||
| 3565 | </blockquote> | ||
| 3566 | <h2 id="generating-placeholder-images-using-svg">Generating placeholder images using SVG</h2> | ||
| 3567 | <p>What I ended up was using SVG to generate text and created image with sharp and | ||
| 3568 | used composition to combine both layers. Response returned by this function is a | ||
| 3569 | buffer you can use to either upload to S3 or save to local file.</p> | ||
| 3570 | <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; { | ||
| 3571 | </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; | ||
| 3572 | </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; | ||
| 3573 | </span></span></span><span style="display:flex;"><span><span style="color:#a31515"> &lt;/svg&gt;`</span>; | ||
| 3574 | </span></span><span style="display:flex;"><span> | ||
| 3575 | </span></span><span style="display:flex;"><span> <span style="color:#00f">return</span> <span style="color:#00f">await</span> sharp({ | ||
| 3576 | </span></span><span style="display:flex;"><span> create: { | ||
| 3577 | </span></span><span style="display:flex;"><span> width: width, | ||
| 3578 | </span></span><span style="display:flex;"><span> height: height, | ||
| 3579 | </span></span><span style="display:flex;"><span> channels: 4, | ||
| 3580 | </span></span><span style="display:flex;"><span> background: { r: 230, g: 230, b: 230, alpha: 1 } | ||
| 3581 | </span></span><span style="display:flex;"><span> } | ||
| 3582 | </span></span><span style="display:flex;"><span> }) | ||
| 3583 | </span></span><span style="display:flex;"><span> .composite([{ | ||
| 3584 | </span></span><span style="display:flex;"><span> input: Buffer.from(overlay), | ||
| 3585 | </span></span><span style="display:flex;"><span> gravity: <span style="color:#a31515">&#39;center&#39;</span>, | ||
| 3586 | </span></span><span style="display:flex;"><span> }]) | ||
| 3587 | </span></span><span style="display:flex;"><span> .jpeg() | ||
| 3588 | </span></span><span style="display:flex;"><span> .toBuffer(); | ||
| 3589 | </span></span><span style="display:flex;"><span>} | ||
| 3590 | </span></span></code></pre><p>That is about it. Nothing more to it. You can change the color of the image by | ||
| 3591 | changing <code>background</code> and if you want to change text styling you can adapt SVG | ||
| 3592 | to your needs.</p> | ||
| 3593 | <blockquote> | ||
| 3594 | <p>Also be careful about the length of the text. This function positions text at | ||
| 3595 | the center and adds <code>20px</code> padding on all sides. If text is longer than the | ||
| 3596 | image it will get cut.</p> | ||
| 3597 | </blockquote> | ||
| 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 +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><h2 id="before-we-continue-">Before we continue ...</h2> | ||
| 3610 | <p>Publisher Subscriber model is nothing new and there are many amazing solutions | ||
| 3611 | out there, so writing a new one would be a waste of time if other solutions | ||
| 3612 | wouldn't have quite complex install procedures and weren't so hard to maintain. | ||
| 3613 | But to be fair, comparing this simple server with something like | ||
| 3614 | <a href="https://kafka.apache.org/">Kafka</a> or <a href="https://www.rabbitmq.com/">RabbitMQ</a> is | ||
| 3615 | laughable at the least. Those solutions are enterprise grade and have many | ||
| 3616 | mechanisms there to ensure messages aren't lost and much more. Regardless of | ||
| 3617 | these drawbacks, this method has been tested on a large website and worked until | ||
| 3618 | now without any problems. So now, that we got that cleared up, let's continue.</p> | ||
| 3619 | <p><em><strong>Wiki definition:</strong> Publish/subscribe messaging, or pub/sub messaging, is a | ||
| 3620 | form of asynchronous service-to-service communication used in serverless and | ||
| 3621 | microservices architectures. In a pub/sub model, any message published to a | ||
| 3622 | topic is immediately received by all the subscribers to the topic.</em></p> | ||
| 3623 | <h2 id="general-goals">General goals</h2> | ||
| 3624 | <ul> | ||
| 3625 | <li>provide a simple server that relays messages to all the connected clients,</li> | ||
| 3626 | <li>messages can be posted on specific topics,</li> | ||
| 3627 | <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 | ||
| 3628 | Events</a> | ||
| 3629 | to all the subscribers.</li> | ||
| 3630 | </ul> | ||
| 3631 | <h2 id="how-exactly-does-the-pubsub-model-work">How exactly does the pub/sub model work?</h2> | ||
| 3632 | <p>The easiest way to explain this is with diagram bellow. Basic function is | ||
| 3633 | simple. We have subscribers that receive messages, and we have publishers that | ||
| 3634 | create and post messages. Similar model is also well know pattern that works on | ||
| 3635 | a premise of consumers and producers, and they take similar roles.</p> | ||
| 3636 | <figure> | ||
| 3637 | <img src="/posts/simple-pubsub-server/pubsub-overview.png" alt="How PubSub works" /> | ||
| 3638 | </figure> | ||
| 3639 | <p><strong>These are some naive characteristics we want to achieve:</strong></p> | ||
| 3640 | <ul> | ||
| 3641 | <li>producer is publishing messages to subscribe topic,</li> | ||
| 3642 | <li>consumer is receiving messages from subscribed topic,</li> | ||
| 3643 | <li>servers is also known as Broker,</li> | ||
| 3644 | <li>broker does not store messages or tracks success,</li> | ||
| 3645 | <li>broker uses | ||
| 3646 | <a href="https://en.wikipedia.org/wiki/FIFO_(computing_and_electronics)">FIFO</a> method | ||
| 3647 | for delivering messages,</li> | ||
| 3648 | <li>if consumer wants to receive messages from a topic, producer and consumer | ||
| 3649 | topics must match,</li> | ||
| 3650 | <li>consumer can subscribe to multiple topics,</li> | ||
| 3651 | <li>producer can publish to multiple topics,</li> | ||
| 3652 | <li>each message has a messageId.</li> | ||
| 3653 | </ul> | ||
| 3654 | <p><strong>Known drawbacks:</strong></p> | ||
| 3655 | <ul> | ||
| 3656 | <li>messages will not be stored in a persistent queue or unreceived messages like | ||
| 3657 | <a href="https://en.wikipedia.org/wiki/Dead_letter_queue">DeadLetterQueue</a> so old | ||
| 3658 | messages could be lost on server restart,</li> | ||
| 3659 | <li><a href="https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events">Server-Sent | ||
| 3660 | Events</a> | ||
| 3661 | opens a long-running connection between the client and the server so make sure | ||
| 3662 | if your setup is load balanced that the load balancer in this case can have | ||
| 3663 | long opened connection,</li> | ||
| 3664 | <li>no system moderation due to the dynamic nature of creating queues.</li> | ||
| 3665 | </ul> | ||
| 3666 | <h2 id="server-sent-events">Server-Sent Events</h2> | ||
| 3667 | <p>Read more about it on <a href="https://html.spec.whatwg.org/multipage/server-sent-events.html">official specification | ||
| 3668 | page</a>.</p> | ||
| 3669 | <h3 id="current-browser-support">Current browser support</h3> | ||
| 3670 | <figure> | ||
| 3671 | <img src="/posts/simple-pubsub-server/caniuse.png" alt="Browser support" /> | ||
| 3672 | </figure> | ||
| 3673 | <p>Check | ||
| 3674 | <a href="https://caniuse.com/#feat=eventsource">https://caniuse.com/#feat=eventsource</a> | ||
| 3675 | for latest information about browser support.</p> | ||
| 3676 | <h3 id="known-issues">Known issues</h3> | ||
| 3677 | <ul> | ||
| 3678 | <li>Firefox 52 and below do not support EventSource in web/shared workers</li> | ||
| 3679 | <li>In Firefox prior to version 36 server-sent events do not reconnect | ||
| 3680 | automatically in case of a connection interrupt (bug)</li> | ||
| 3681 | <li>Reportedly, CORS in EventSource is currently supported in Firefox 10+, Opera | ||
| 3682 | 12+, Chrome 26+, Safari 7.0+.</li> | ||
| 3683 | <li>Antivirus software may block the event streaming data chunks.</li> | ||
| 3684 | </ul> | ||
| 3685 | <p>Source: <a href="https://caniuse.com/#feat=eventsource">https://caniuse.com/#feat=eventsource</a></p> | ||
| 3686 | <h3 id="message-format">Message format</h3> | ||
| 3687 | <p>The simplest message that can be sent is only with data attribute:</p> | ||
| 3688 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>data: this is a simple message | ||
| 3689 | </span></span><span style="display:flex;"><span>&lt;blank line&gt; | ||
| 3690 | </span></span></code></pre><p>You can send message IDs to be used if the connection is dropped:</p> | ||
| 3691 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>id: 33 | ||
| 3692 | </span></span><span style="display:flex;"><span>data: this is line one | ||
| 3693 | </span></span><span style="display:flex;"><span>data: this is line two | ||
| 3694 | </span></span><span style="display:flex;"><span>&lt;blank line&gt; | ||
| 3695 | </span></span></code></pre><p>And you can specify your own event types (the above messages will all trigger | ||
| 3696 | the message event):</p> | ||
| 3697 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>id: 36 | ||
| 3698 | </span></span><span style="display:flex;"><span>event: price | ||
| 3699 | </span></span><span style="display:flex;"><span>data: 103.34 | ||
| 3700 | </span></span><span style="display:flex;"><span>&lt;blank line&gt; | ||
| 3701 | </span></span></code></pre><h3 id="server-requirements">Server requirements</h3> | ||
| 3702 | <p>The important thing is how you send headers and which headers are sent by the | ||
| 3703 | server that triggers browser to threat response as a EventStream.</p> | ||
| 3704 | <p>Headers responsible for this are:</p> | ||
| 3705 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>Content-Type: text/event-stream | ||
| 3706 | </span></span><span style="display:flex;"><span>Cache-Control: no-cache | ||
| 3707 | </span></span><span style="display:flex;"><span>Connection: keep-alive | ||
| 3708 | </span></span></code></pre><h3 id="debugging-with-google-chrome">Debugging with Google Chrome</h3> | ||
| 3709 | <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 | ||
| 3710 | Events</a> | ||
| 3711 | which is quite nice and available from Developer Tools under Network tab.</p> | ||
| 3712 | <blockquote> | ||
| 3713 | <p>You can debug only client side events that get received and not the server | ||
| 3714 | ones. For debugging server events add <code>console.log</code> to <code>server.js</code> code and | ||
| 3715 | print out events.</p> | ||
| 3716 | </blockquote> | ||
| 3717 | <figure> | ||
| 3718 | <img src="/posts/simple-pubsub-server/chrome-debugging.png" alt="Google Chrome Developer Tools EventStream" /> | ||
| 3719 | </figure> | ||
| 3720 | <h2 id="server-implementation">Server implementation</h2> | ||
| 3721 | <p>For the sake of this example we will use <a href="https://nodejs.org/en/">Node.js</a> with | ||
| 3722 | <a href="https://expressjs.com">Express</a> as our router since this is the easiest way to | ||
| 3723 | get started and we will use already written SSE library for node | ||
| 3724 | <a href="https://www.npmjs.com/package/sse-pubsub">sse-pubsub</a> so we don't reinvent the | ||
| 3725 | wheel.</p> | ||
| 3726 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>npm init --yes | ||
| 3727 | </span></span><span style="display:flex;"><span> | ||
| 3728 | </span></span><span style="display:flex;"><span>npm install express | ||
| 3729 | </span></span><span style="display:flex;"><span>npm install body-parser | ||
| 3730 | </span></span><span style="display:flex;"><span>npm install sse-pubsub | ||
| 3731 | </span></span></code></pre><p>Basic implementation of a server (<code>server.js</code>):</p> | ||
| 3732 | <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>); | ||
| 3733 | </span></span><span style="display:flex;"><span><span style="color:#00f">const</span> bodyParser = require(<span style="color:#a31515">&#39;body-parser&#39;</span>); | ||
| 3734 | </span></span><span style="display:flex;"><span><span style="color:#00f">const</span> SSETopic = require(<span style="color:#a31515">&#39;sse-pubsub&#39;</span>); | ||
| 3735 | </span></span><span style="display:flex;"><span> | ||
| 3736 | </span></span><span style="display:flex;"><span><span style="color:#00f">const</span> app = express(); | ||
| 3737 | </span></span><span style="display:flex;"><span><span style="color:#00f">const</span> port = process.env.PORT || 4000; | ||
| 3738 | </span></span><span style="display:flex;"><span> | ||
| 3739 | </span></span><span style="display:flex;"><span><span style="color:#008000">// topics container | ||
| 3740 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span><span style="color:#00f">const</span> sseTopics = {}; | ||
| 3741 | </span></span><span style="display:flex;"><span> | ||
| 3742 | </span></span><span style="display:flex;"><span>app.use(bodyParser.json()); | ||
| 3743 | </span></span><span style="display:flex;"><span> | ||
| 3744 | </span></span><span style="display:flex;"><span><span style="color:#008000">// open for all cors | ||
| 3745 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span>app.all(<span style="color:#a31515">&#39;*&#39;</span>, (req, res, next) =&gt; { | ||
| 3746 | </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>); | ||
| 3747 | </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>); | ||
| 3748 | </span></span><span style="display:flex;"><span> next(); | ||
| 3749 | </span></span><span style="display:flex;"><span>}); | ||
| 3750 | </span></span><span style="display:flex;"><span> | ||
| 3751 | </span></span><span style="display:flex;"><span><span style="color:#008000">// preflight request error fix | ||
| 3752 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span>app.options(<span style="color:#a31515">&#39;*&#39;</span>, <span style="color:#00f">async</span> (req, res) =&gt; { | ||
| 3753 | </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>); | ||
| 3754 | </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>); | ||
| 3755 | </span></span><span style="display:flex;"><span> res.send(<span style="color:#a31515">&#39;OK&#39;</span>); | ||
| 3756 | </span></span><span style="display:flex;"><span>}); | ||
| 3757 | </span></span><span style="display:flex;"><span> | ||
| 3758 | </span></span><span style="display:flex;"><span><span style="color:#008000">// serve the event streams | ||
| 3759 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span>app.get(<span style="color:#a31515">&#39;/stream/:topic&#39;</span>, <span style="color:#00f">async</span> (req, res, next) =&gt; { | ||
| 3760 | </span></span><span style="display:flex;"><span> <span style="color:#00f">const</span> topic = req.params.topic; | ||
| 3761 | </span></span><span style="display:flex;"><span> | ||
| 3762 | </span></span><span style="display:flex;"><span> <span style="color:#00f">if</span> (!(topic <span style="color:#00f">in</span> sseTopics)) { | ||
| 3763 | </span></span><span style="display:flex;"><span> sseTopics[topic] = <span style="color:#00f">new</span> SSETopic({ | ||
| 3764 | </span></span><span style="display:flex;"><span> pingInterval: 0, | ||
| 3765 | </span></span><span style="display:flex;"><span> maxStreamDuration: 15000, | ||
| 3766 | </span></span><span style="display:flex;"><span> }); | ||
| 3767 | </span></span><span style="display:flex;"><span> } | ||
| 3768 | </span></span><span style="display:flex;"><span> | ||
| 3769 | </span></span><span style="display:flex;"><span> <span style="color:#008000">// subscribing client to topic | ||
| 3770 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span> sseTopics[topic].subscribe(req, res); | ||
| 3771 | </span></span><span style="display:flex;"><span>}); | ||
| 3772 | </span></span><span style="display:flex;"><span> | ||
| 3773 | </span></span><span style="display:flex;"><span><span style="color:#008000">// accepts new messages into topic | ||
| 3774 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span>app.post(<span style="color:#a31515">&#39;/publish&#39;</span>, <span style="color:#00f">async</span> (req, res) =&gt; { | ||
| 3775 | </span></span><span style="display:flex;"><span> <span style="color:#00f">let</span> body = req.body; | ||
| 3776 | </span></span><span style="display:flex;"><span> <span style="color:#00f">let</span> status = 200; | ||
| 3777 | </span></span><span style="display:flex;"><span> | ||
| 3778 | </span></span><span style="display:flex;"><span> console.log(<span style="color:#a31515">&#39;Incoming message:&#39;</span>, req.body); | ||
| 3779 | </span></span><span style="display:flex;"><span> | ||
| 3780 | </span></span><span style="display:flex;"><span> <span style="color:#00f">if</span> ( | ||
| 3781 | </span></span><span style="display:flex;"><span> body.hasOwnProperty(<span style="color:#a31515">&#39;topic&#39;</span>) &amp;&amp; | ||
| 3782 | </span></span><span style="display:flex;"><span> body.hasOwnProperty(<span style="color:#a31515">&#39;event&#39;</span>) &amp;&amp; | ||
| 3783 | </span></span><span style="display:flex;"><span> body.hasOwnProperty(<span style="color:#a31515">&#39;message&#39;</span>) | ||
| 3784 | </span></span><span style="display:flex;"><span> ) { | ||
| 3785 | </span></span><span style="display:flex;"><span> <span style="color:#00f">const</span> topic = req.body.topic; | ||
| 3786 | </span></span><span style="display:flex;"><span> <span style="color:#00f">const</span> event = req.body.event; | ||
| 3787 | </span></span><span style="display:flex;"><span> <span style="color:#00f">const</span> message = req.body.message; | ||
| 3788 | </span></span><span style="display:flex;"><span> | ||
| 3789 | </span></span><span style="display:flex;"><span> <span style="color:#00f">if</span> (topic <span style="color:#00f">in</span> sseTopics) { | ||
| 3790 | </span></span><span style="display:flex;"><span> <span style="color:#008000">// sends message to all the subscribers | ||
| 3791 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span> sseTopics[topic].publish(message, event); | ||
| 3792 | </span></span><span style="display:flex;"><span> } | ||
| 3793 | </span></span><span style="display:flex;"><span> } <span style="color:#00f">else</span> { | ||
| 3794 | </span></span><span style="display:flex;"><span> status = 400; | ||
| 3795 | </span></span><span style="display:flex;"><span> } | ||
| 3796 | </span></span><span style="display:flex;"><span> | ||
| 3797 | </span></span><span style="display:flex;"><span> res.status(status).send({ | ||
| 3798 | </span></span><span style="display:flex;"><span> status, | ||
| 3799 | </span></span><span style="display:flex;"><span> }); | ||
| 3800 | </span></span><span style="display:flex;"><span>}); | ||
| 3801 | </span></span><span style="display:flex;"><span> | ||
| 3802 | </span></span><span style="display:flex;"><span><span style="color:#008000">// returns JSON object of all opened topics | ||
| 3803 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span>app.get(<span style="color:#a31515">&#39;/status&#39;</span>, <span style="color:#00f">async</span> (req, res) =&gt; { | ||
| 3804 | </span></span><span style="display:flex;"><span> res.send(sseTopics); | ||
| 3805 | </span></span><span style="display:flex;"><span>}); | ||
| 3806 | </span></span><span style="display:flex;"><span> | ||
| 3807 | </span></span><span style="display:flex;"><span><span style="color:#008000">// health-check endpoint | ||
| 3808 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span>app.get(<span style="color:#a31515">&#39;/&#39;</span>, <span style="color:#00f">async</span> (req, res) =&gt; { | ||
| 3809 | </span></span><span style="display:flex;"><span> res.send(<span style="color:#a31515">&#39;OK&#39;</span>); | ||
| 3810 | </span></span><span style="display:flex;"><span>}); | ||
| 3811 | </span></span><span style="display:flex;"><span> | ||
| 3812 | </span></span><span style="display:flex;"><span><span style="color:#008000">// return a 404 if no routes match | ||
| 3813 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span>app.use((req, res, next) =&gt; { | ||
| 3814 | </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>); | ||
| 3815 | </span></span><span style="display:flex;"><span> res.status(404).end(<span style="color:#a31515">&#39;Not found&#39;</span>); | ||
| 3816 | </span></span><span style="display:flex;"><span>}); | ||
| 3817 | </span></span><span style="display:flex;"><span> | ||
| 3818 | </span></span><span style="display:flex;"><span><span style="color:#008000">// starts the server | ||
| 3819 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span>app.listen(port, () =&gt; { | ||
| 3820 | </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>); | ||
| 3821 | </span></span><span style="display:flex;"><span>}); | ||
| 3822 | </span></span></code></pre><h3 id="our-custom-message-format">Our custom message format</h3> | ||
| 3823 | <p>Each message posted on a server must be in a specific format that out server | ||
| 3824 | accepts. Having structure like this allows us to have multiple separated type of | ||
| 3825 | events on each topic.</p> | ||
| 3826 | <p>With this we can separate streams and only receive events that belong to the | ||
| 3827 | topic.</p> | ||
| 3828 | <p>One example would be, that we have index page and we want to receive messages | ||
| 3829 | about new upvotes or new subscribers but we don't want to follow events for | ||
| 3830 | other pages. This reduces clutter and overall network. And structure is much | ||
| 3831 | nicer and maintanable.</p> | ||
| 3832 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>{ | ||
| 3833 | </span></span><span style="display:flex;"><span> &#34;topic&#34;: <span style="color:#a31515">&#34;sample-topic&#34;</span>, | ||
| 3834 | </span></span><span style="display:flex;"><span> &#34;event&#34;: <span style="color:#a31515">&#34;sample-event&#34;</span>, | ||
| 3835 | </span></span><span style="display:flex;"><span> &#34;message&#34;: { &#34;name&#34;: <span style="color:#a31515">&#34;John&#34;</span> } | ||
| 3836 | </span></span><span style="display:flex;"><span>} | ||
| 3837 | </span></span></code></pre><h2 id="publisher-and-subscriber-clients">Publisher and subscriber clients</h2> | ||
| 3838 | <h3 id="publisher-and-subscriber-in-action">Publisher and subscriber in action</h3> | ||
| 3839 | <p><video src="/posts/simple-pubsub-server/clients.m4v" controls></video></p> | ||
| 3840 | <p>You can download <a href="../simple-pubsub-server/sse-pubsub-server.zip">the code</a> and | ||
| 3841 | follow along.</p> | ||
| 3842 | <h3 id="publisher">Publisher</h3> | ||
| 3843 | <p>As talked about above publisher is the one that send messages to the | ||
| 3844 | broker/server. Message inside the payload can be whatever you want (string, | ||
| 3845 | object, array). I would however personally avoid send large chunks of data like | ||
| 3846 | blobs and such.</p> | ||
| 3847 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#00f">&lt;!DOCTYPE html&gt;</span> | ||
| 3848 | </span></span><span style="display:flex;"><span>&lt;html lang=<span style="color:#a31515">&#34;en&#34;</span>&gt; | ||
| 3849 | </span></span><span style="display:flex;"><span> | ||
| 3850 | </span></span><span style="display:flex;"><span> &lt;head&gt; | ||
| 3851 | </span></span><span style="display:flex;"><span> &lt;meta charset=<span style="color:#a31515">&#34;UTF-8&#34;</span>&gt; | ||
| 3852 | </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; | ||
| 3853 | </span></span><span style="display:flex;"><span> &lt;title&gt;Publisher&lt;/title&gt; | ||
| 3854 | </span></span><span style="display:flex;"><span> &lt;/head&gt; | ||
| 3855 | </span></span><span style="display:flex;"><span> | ||
| 3856 | </span></span><span style="display:flex;"><span> &lt;body&gt; | ||
| 3857 | </span></span><span style="display:flex;"><span> | ||
| 3858 | </span></span><span style="display:flex;"><span> &lt;h1&gt;Publisher&lt;/h1&gt; | ||
| 3859 | </span></span><span style="display:flex;"><span> | ||
| 3860 | </span></span><span style="display:flex;"><span> &lt;fieldset&gt; | ||
| 3861 | </span></span><span style="display:flex;"><span> &lt;p&gt; | ||
| 3862 | </span></span><span style="display:flex;"><span> &lt;label&gt;Server:&lt;/label&gt; | ||
| 3863 | </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; | ||
| 3864 | </span></span><span style="display:flex;"><span> &lt;/p&gt; | ||
| 3865 | </span></span><span style="display:flex;"><span> &lt;p&gt; | ||
| 3866 | </span></span><span style="display:flex;"><span> &lt;label&gt;Topic:&lt;/label&gt; | ||
| 3867 | </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; | ||
| 3868 | </span></span><span style="display:flex;"><span> &lt;/p&gt; | ||
| 3869 | </span></span><span style="display:flex;"><span> &lt;p&gt; | ||
| 3870 | </span></span><span style="display:flex;"><span> &lt;label&gt;Event:&lt;/label&gt; | ||
| 3871 | </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; | ||
| 3872 | </span></span><span style="display:flex;"><span> &lt;/p&gt; | ||
| 3873 | </span></span><span style="display:flex;"><span> &lt;p&gt; | ||
| 3874 | </span></span><span style="display:flex;"><span> &lt;label&gt;Message:&lt;/label&gt; | ||
| 3875 | </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; | ||
| 3876 | </span></span><span style="display:flex;"><span> &lt;/p&gt; | ||
| 3877 | </span></span><span style="display:flex;"><span> &lt;p&gt; | ||
| 3878 | </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; | ||
| 3879 | </span></span><span style="display:flex;"><span> &lt;/p&gt; | ||
| 3880 | </span></span><span style="display:flex;"><span> &lt;/fieldset&gt; | ||
| 3881 | </span></span><span style="display:flex;"><span> | ||
| 3882 | </span></span><span style="display:flex;"><span> &lt;script&gt; | ||
| 3883 | </span></span><span style="display:flex;"><span> | ||
| 3884 | </span></span><span style="display:flex;"><span> <span style="color:#00f">const</span> button = document.querySelector(<span style="color:#a31515">&#39;#button&#39;</span>); | ||
| 3885 | </span></span><span style="display:flex;"><span> <span style="color:#00f">const</span> server = document.querySelector(<span style="color:#a31515">&#39;#server&#39;</span>); | ||
| 3886 | </span></span><span style="display:flex;"><span> <span style="color:#00f">const</span> topic = document.querySelector(<span style="color:#a31515">&#39;#topic&#39;</span>); | ||
| 3887 | </span></span><span style="display:flex;"><span> <span style="color:#00f">const</span> event = document.querySelector(<span style="color:#a31515">&#39;#event&#39;</span>); | ||
| 3888 | </span></span><span style="display:flex;"><span> <span style="color:#00f">const</span> message = document.querySelector(<span style="color:#a31515">&#39;#message&#39;</span>); | ||
| 3889 | </span></span><span style="display:flex;"><span> | ||
| 3890 | </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; { | ||
| 3891 | </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>, { | ||
| 3892 | </span></span><span style="display:flex;"><span> method: <span style="color:#a31515">&#39;post&#39;</span>, | ||
| 3893 | </span></span><span style="display:flex;"><span> headers: { | ||
| 3894 | </span></span><span style="display:flex;"><span> <span style="color:#a31515">&#39;Accept&#39;</span>: <span style="color:#a31515">&#39;application/json&#39;</span>, | ||
| 3895 | </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>, | ||
| 3896 | </span></span><span style="display:flex;"><span> }, | ||
| 3897 | </span></span><span style="display:flex;"><span> body: JSON.stringify({ | ||
| 3898 | </span></span><span style="display:flex;"><span> topic: topic.value, | ||
| 3899 | </span></span><span style="display:flex;"><span> event: event.value, | ||
| 3900 | </span></span><span style="display:flex;"><span> message: JSON.parse(message.value), | ||
| 3901 | </span></span><span style="display:flex;"><span> }), | ||
| 3902 | </span></span><span style="display:flex;"><span> }); | ||
| 3903 | </span></span><span style="display:flex;"><span> | ||
| 3904 | </span></span><span style="display:flex;"><span> <span style="color:#00f">const</span> res = <span style="color:#00f">await</span> req.json(); | ||
| 3905 | </span></span><span style="display:flex;"><span> console.log(res); | ||
| 3906 | </span></span><span style="display:flex;"><span> }); | ||
| 3907 | </span></span><span style="display:flex;"><span> | ||
| 3908 | </span></span><span style="display:flex;"><span> &lt;/script&gt; | ||
| 3909 | </span></span><span style="display:flex;"><span> | ||
| 3910 | </span></span><span style="display:flex;"><span> &lt;/body&gt; | ||
| 3911 | </span></span><span style="display:flex;"><span> | ||
| 3912 | </span></span><span style="display:flex;"><span>&lt;/html&gt; | ||
| 3913 | </span></span></code></pre><h3 id="subscriber">Subscriber</h3> | ||
| 3914 | <p>Subscriber is responsible for receiving new messages that come from server via | ||
| 3915 | publisher. The code bellow is very rudimentary but works and follows the | ||
| 3916 | implementation guidelines for EventSource.</p> | ||
| 3917 | <p>You can use either Developer Tools Console to see incoming messages or you can | ||
| 3918 | defer to Debugging with Google Chrome section above to see all EventStream | ||
| 3919 | messages.</p> | ||
| 3920 | <blockquote> | ||
| 3921 | <p>Don't be alarmed if the subscriber gets disconnected from the server every so | ||
| 3922 | often. The code we have here resets connection every 15s but it automatically | ||
| 3923 | get reconnected and fetches all messages up to last received message id. This | ||
| 3924 | setting can be adjusted in <code>server.js</code> file; search for the | ||
| 3925 | <code>maxStreamDuration</code> variable.</p> | ||
| 3926 | </blockquote> | ||
| 3927 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#00f">&lt;!DOCTYPE html&gt;</span> | ||
| 3928 | </span></span><span style="display:flex;"><span>&lt;html lang=<span style="color:#a31515">&#34;en&#34;</span>&gt; | ||
| 3929 | </span></span><span style="display:flex;"><span> | ||
| 3930 | </span></span><span style="display:flex;"><span> &lt;head&gt; | ||
| 3931 | </span></span><span style="display:flex;"><span> &lt;meta charset=<span style="color:#a31515">&#34;UTF-8&#34;</span>&gt; | ||
| 3932 | </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; | ||
| 3933 | </span></span><span style="display:flex;"><span> &lt;title&gt;Subscriber&lt;/title&gt; | ||
| 3934 | </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; | ||
| 3935 | </span></span><span style="display:flex;"><span> &lt;/head&gt; | ||
| 3936 | </span></span><span style="display:flex;"><span> | ||
| 3937 | </span></span><span style="display:flex;"><span> &lt;body&gt; | ||
| 3938 | </span></span><span style="display:flex;"><span> | ||
| 3939 | </span></span><span style="display:flex;"><span> &lt;h1&gt;Subscriber&lt;/h1&gt; | ||
| 3940 | </span></span><span style="display:flex;"><span> | ||
| 3941 | </span></span><span style="display:flex;"><span> &lt;fieldset&gt; | ||
| 3942 | </span></span><span style="display:flex;"><span> &lt;p&gt; | ||
| 3943 | </span></span><span style="display:flex;"><span> &lt;label&gt;Server:&lt;/label&gt; | ||
| 3944 | </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; | ||
| 3945 | </span></span><span style="display:flex;"><span> &lt;/p&gt; | ||
| 3946 | </span></span><span style="display:flex;"><span> &lt;p&gt; | ||
| 3947 | </span></span><span style="display:flex;"><span> &lt;label&gt;Topic:&lt;/label&gt; | ||
| 3948 | </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; | ||
| 3949 | </span></span><span style="display:flex;"><span> &lt;/p&gt; | ||
| 3950 | </span></span><span style="display:flex;"><span> &lt;p&gt; | ||
| 3951 | </span></span><span style="display:flex;"><span> &lt;label&gt;Event:&lt;/label&gt; | ||
| 3952 | </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; | ||
| 3953 | </span></span><span style="display:flex;"><span> &lt;/p&gt; | ||
| 3954 | </span></span><span style="display:flex;"><span> &lt;p&gt; | ||
| 3955 | </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; | ||
| 3956 | </span></span><span style="display:flex;"><span> &lt;/p&gt; | ||
| 3957 | </span></span><span style="display:flex;"><span> &lt;/fieldset&gt; | ||
| 3958 | </span></span><span style="display:flex;"><span> | ||
| 3959 | </span></span><span style="display:flex;"><span> &lt;script&gt; | ||
| 3960 | </span></span><span style="display:flex;"><span> | ||
| 3961 | </span></span><span style="display:flex;"><span> <span style="color:#00f">const</span> button = document.querySelector(<span style="color:#a31515">&#39;#button&#39;</span>); | ||
| 3962 | </span></span><span style="display:flex;"><span> <span style="color:#00f">const</span> server = document.querySelector(<span style="color:#a31515">&#39;#server&#39;</span>); | ||
| 3963 | </span></span><span style="display:flex;"><span> <span style="color:#00f">const</span> topic = document.querySelector(<span style="color:#a31515">&#39;#topic&#39;</span>); | ||
| 3964 | </span></span><span style="display:flex;"><span> <span style="color:#00f">const</span> event = document.querySelector(<span style="color:#a31515">&#39;#event&#39;</span>); | ||
| 3965 | </span></span><span style="display:flex;"><span> | ||
| 3966 | </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; { | ||
| 3967 | </span></span><span style="display:flex;"><span> | ||
| 3968 | </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>); | ||
| 3969 | </span></span><span style="display:flex;"><span> | ||
| 3970 | </span></span><span style="display:flex;"><span> es.addEventListener(event.value, <span style="color:#00f">function</span> (evt) { | ||
| 3971 | </span></span><span style="display:flex;"><span> console.log(<span style="color:#a31515">`incoming message`</span>, JSON.parse(evt.data)); | ||
| 3972 | </span></span><span style="display:flex;"><span> }); | ||
| 3973 | </span></span><span style="display:flex;"><span> | ||
| 3974 | </span></span><span style="display:flex;"><span> es.addEventListener(<span style="color:#a31515">&#39;open&#39;</span>, <span style="color:#00f">function</span> (evt) { | ||
| 3975 | </span></span><span style="display:flex;"><span> console.log(<span style="color:#a31515">&#39;connected&#39;</span>, evt); | ||
| 3976 | </span></span><span style="display:flex;"><span> }); | ||
| 3977 | </span></span><span style="display:flex;"><span> | ||
| 3978 | </span></span><span style="display:flex;"><span> es.addEventListener(<span style="color:#a31515">&#39;error&#39;</span>, <span style="color:#00f">function</span> (evt) { | ||
| 3979 | </span></span><span style="display:flex;"><span> console.log(<span style="color:#a31515">&#39;error&#39;</span>, evt); | ||
| 3980 | </span></span><span style="display:flex;"><span> }); | ||
| 3981 | </span></span><span style="display:flex;"><span> | ||
| 3982 | </span></span><span style="display:flex;"><span> }); | ||
| 3983 | </span></span><span style="display:flex;"><span> | ||
| 3984 | </span></span><span style="display:flex;"><span> &lt;/script&gt; | ||
| 3985 | </span></span><span style="display:flex;"><span> | ||
| 3986 | </span></span><span style="display:flex;"><span> &lt;/body&gt; | ||
| 3987 | </span></span><span style="display:flex;"><span> | ||
| 3988 | </span></span><span style="display:flex;"><span>&lt;/html&gt; | ||
| 3989 | </span></span></code></pre><h2 id="reading-further">Reading further</h2> | ||
| 3990 | <ul> | ||
| 3991 | <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> | ||
| 3992 | <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> | ||
| 3993 | <li><a href="https://apifriends.com/api-streaming/server-sent-events/">What is Server-Sent Events?</a></li> | ||
| 3994 | <li><a href="https://tools.ietf.org/id/draft-xie-bidirectional-messaging-01.html">An HTTP/2 extension for bidirectional messaging communication</a></li> | ||
| 3995 | <li><a href="https://developers.google.com/web/fundamentals/performance/http2">Introduction to HTTP/2</a></li> | ||
| 3996 | <li><a href="https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API">The WebSocket API (WebSockets)</a></li> | ||
| 3997 | </ul> | ||
| 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 +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><h2 id="initial-thoughts">Initial thoughts</h2> | ||
| 4010 | <p>One of the things that interested me for a while now is if major well | ||
| 4011 | established news sites use click bait titles to drive additional traffic to | ||
| 4012 | their sites and generate additional impressions.</p> | ||
| 4013 | <p>Goal is to see how article titles and actual content of article differ from each | ||
| 4014 | other and see if titles are clickbaited.</p> | ||
| 4015 | <h2 id="preparing-and-cleaning-data">Preparing and cleaning data</h2> | ||
| 4016 | <p>For this example I opted to just use RSS feed from a new website and decided to | ||
| 4017 | go with <a href="https://www.theguardian.com">The Guardian</a> World news. While this gets | ||
| 4018 | us limited data (~40) articles and also description (actual content) is trimmed | ||
| 4019 | this really doesn't reflect the actual article contents.</p> | ||
| 4020 | <p>To get better content I could use web scraping and use RSS as link list and | ||
| 4021 | fetch contents directly from website, but for this simple example this will | ||
| 4022 | suffice.</p> | ||
| 4023 | <p>There are couple of requirements we need to install before we continue:</p> | ||
| 4024 | <ul> | ||
| 4025 | <li><code>pip3 install feedparser</code> (parses RSS feed from url)</li> | ||
| 4026 | <li><code>pip3 install vaderSentiment</code> (does sentiment polarity analysis)</li> | ||
| 4027 | <li><code>pip3 install matplotlib</code> (plots chart of results)</li> | ||
| 4028 | </ul> | ||
| 4029 | <p>So first we need to fetch RSS data and sanitize HTML content from description.</p> | ||
| 4030 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#00f">import</span> re | ||
| 4031 | </span></span><span style="display:flex;"><span><span style="color:#00f">import</span> feedparser | ||
| 4032 | </span></span><span style="display:flex;"><span> | ||
| 4033 | </span></span><span style="display:flex;"><span>feed_url = <span style="color:#a31515">&#34;https://www.theguardian.com/world/rss&#34;</span> | ||
| 4034 | </span></span><span style="display:flex;"><span>feed = feedparser.parse(feed_url) | ||
| 4035 | </span></span><span style="display:flex;"><span> | ||
| 4036 | </span></span><span style="display:flex;"><span><span style="color:#008000"># sanitize html</span> | ||
| 4037 | </span></span><span style="display:flex;"><span><span style="color:#00f">for</span> item <span style="color:#00f">in</span> feed.entries: | ||
| 4038 | </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) | ||
| 4039 | </span></span></code></pre><h2 id="perform-sentiment-analysis">Perform sentiment analysis</h2> | ||
| 4040 | <p>Since we now have cleaned up data in our <code>feed.entries</code> object we can start with | ||
| 4041 | performing sentiment analysis.</p> | ||
| 4042 | <p>There are many sentiment analysis libraries available that range from rule-based | ||
| 4043 | sentiment analysis up to machine learning supported analysis. To keep things | ||
| 4044 | simple I decided to use rule-based analysis library | ||
| 4045 | <a href="https://github.com/cjhutto/vaderSentiment">vaderSentiment</a> from | ||
| 4046 | <a href="https://github.com/cjhutto">C.J. Hutto</a>. Really nice library and quite easy to | ||
| 4047 | use.</p> | ||
| 4048 | <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 | ||
| 4049 | </span></span><span style="display:flex;"><span>analyser = SentimentIntensityAnalyzer() | ||
| 4050 | </span></span><span style="display:flex;"><span> | ||
| 4051 | </span></span><span style="display:flex;"><span>sentiment_results = [] | ||
| 4052 | </span></span><span style="display:flex;"><span><span style="color:#00f">for</span> item <span style="color:#00f">in</span> feed.entries: | ||
| 4053 | </span></span><span style="display:flex;"><span> sentiment_title = analyser.polarity_scores(item.title) | ||
| 4054 | </span></span><span style="display:flex;"><span> sentiment_description = analyser.polarity_scores(item.description) | ||
| 4055 | </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>]]) | ||
| 4056 | </span></span></code></pre><p>Now that we have this data in a shape that is compatible with matplotlib we can | ||
| 4057 | plot results to see the difference between title and description sentiment of an | ||
| 4058 | article.</p> | ||
| 4059 | <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 | ||
| 4060 | </span></span><span style="display:flex;"><span> | ||
| 4061 | </span></span><span style="display:flex;"><span>plt.rcParams[<span style="color:#a31515">&#39;figure.figsize&#39;</span>] = (15, 3) | ||
| 4062 | </span></span><span style="display:flex;"><span>plt.plot(sentiment_results, drawstyle=<span style="color:#a31515">&#39;steps&#39;</span>) | ||
| 4063 | </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>) | ||
| 4064 | </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>]) | ||
| 4065 | </span></span><span style="display:flex;"><span>plt.show() | ||
| 4066 | </span></span></code></pre><h2 id="results-and-assets">Results and assets</h2> | ||
| 4067 | <ol> | ||
| 4068 | <li>Because of the small sample size further conclusions are impossible to make.</li> | ||
| 4069 | <li>Rule-based approach may not be the best way of doing this. By using deep | ||
| 4070 | learning we would be able to get better insights.</li> | ||
| 4071 | <li><strong>Next step would be to</strong> periodically fetch RSS items and store them over a | ||
| 4072 | longer period of time and then perform analysis again and use either machine | ||
| 4073 | learning or deep learning on top of it.</li> | ||
| 4074 | </ol> | ||
| 4075 | <figure> | ||
| 4076 | <img src="/posts/sentiment-analysis/guardian-sa-title-desc-relationship.png" alt="Relationship between title and description" /> | ||
| 4077 | </figure> | ||
| 4078 | <p>Figure above displays difference between title and description sentiment for | ||
| 4079 | specific RSS feed item. 1 means positive and -1 means negative sentiment.</p> | ||
| 4080 | <p><a href="/posts/sentiment-analysis/sentiment-analysis.ipynb">» Download Jupyter Notebook</a></p> | ||
| 4081 | <h2 id="going-further">Going further</h2> | ||
| 4082 | <ul> | ||
| 4083 | <li><a href="https://github.com/bswiss/news_mood">Twitter Sentiment Analysis by Bryan Schwierzke</a></li> | ||
| 4084 | <li><a href="https://github.com/thisandagain/sentiment">AFINN-based sentiment analysis for Node.js by Andrew Sliwinski</a></li> | ||
| 4085 | <li><a href="https://github.com/adeshpande3/LSTM-Sentiment-Analysis">Sentiment Analysis with LSTMs in Tensorflow by Adit Deshpande</a></li> | ||
| 4086 | <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></li> | ||
| 4087 | </ul> | ||
| 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 +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><p>I recently moved my main working machine back from Hachintosh to Linux. Well the | ||
| 4100 | experiment was interesting and I have done some great work on macOS but it was | ||
| 4101 | time to move back.</p> | ||
| 4102 | <p>I actually really missed Linux. The simplicity of <code>apt-get</code> or just the amount | ||
| 4103 | of software that exists for Linux should be a no-brainer. I spent most of my | ||
| 4104 | time on macOS finding solutions to make things work. Using | ||
| 4105 | <a href="https://brew.sh/">Brew</a> was just a horrible experience and far from package | ||
| 4106 | managers of Linux. At least they managed to get that <code>sudo</code> debacle sorted.</p> | ||
| 4107 | <p>Not all was bad. macOS in general was a perfectly good environment. Things like | ||
| 4108 | Docker and tooling like this worked without any hiccups. My normal tools like | ||
| 4109 | coding IDE worked flawlessly and the whole look and feel is just superb. I have | ||
| 4110 | been using MacBook Air for couple of years so I was used to the system but never | ||
| 4111 | as a daily driver.</p> | ||
| 4112 | <p>One of the things I did after I installed Linux back on my machine was cleaning | ||
| 4113 | up my Dropbox folder. I have everything on Dropbox. Even projects folder. I | ||
| 4114 | write code for living so my whole life revolves around couple of megs of code | ||
| 4115 | (with assets). So it's not like I have huge files on my machine. I don't have | ||
| 4116 | movies or music or pictures on my PC. All of that stuff is in cloud. I use | ||
| 4117 | Google music and I have Netflix account which is more than enough for me.</p> | ||
| 4118 | <p>I also went and deleted some of the repositories on my Github account. I have | ||
| 4119 | deleted more code than deployed. People find this strange but for me deleting | ||
| 4120 | something feels so cathartic and also forces me to write better code next time | ||
| 4121 | around when I am faced with similar problem. That was a huge relief if I am | ||
| 4122 | being totally honest.</p> | ||
| 4123 | <p>Next step was to do something with my webpage. I have been using some scripts I | ||
| 4124 | wrote a while ago to generate static pages from markdown source posts. I kept on | ||
| 4125 | adding and adding stuff on top of it and it became a source of a | ||
| 4126 | frustration. And this is just a simple blog and I was using gulp and npm. | ||
| 4127 | Anyways after couple of hours of searching and testing static generators I found | ||
| 4128 | an interesting one | ||
| 4129 | <a href="https://github.com/piranha/gostatic">https://github.com/piranha/gostatic</a> and I | ||
| 4130 | just decided to use this one. It was the only one that had a simple templating | ||
| 4131 | engine, not that I really need one. But others had this convoluted way of trying | ||
| 4132 | to solve everything and at the end just required quite bigger learning curve I | ||
| 4133 | was ready to go with. So I deleted couple of old posts, simplified HTML, trashed | ||
| 4134 | most of the CSS and went with | ||
| 4135 | <a href="https://motherfuckingwebsite.com/">https://motherfuckingwebsite.com/</a> | ||
| 4136 | aesthetics. Yeah, the previous site was more visually stimulating but all I | ||
| 4137 | really care is the content at this point. And Times New Roman font is kind of | ||
| 4138 | awesome.</p> | ||
| 4139 | <p>I stopped working on most of the projects in the past couple of months because | ||
| 4140 | the overhead was just too insane. There comes a point when you stretch yourself | ||
| 4141 | too much and then you stop progressing and with that comes dissatisfaction.</p> | ||
| 4142 | <p>So that's about it. Moving forward minimal style.</p> | ||
| 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 +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><h2 id="initial-thoughts">Initial thoughts</h2> | ||
| 4155 | <p>Imagine a world where you could go outside and take a leaf from a tree and put | ||
| 4156 | it through your personal DNA sequencer and get data like music, videos or | ||
| 4157 | computer programs from it. Well, this is all possible now. It was not done on a | ||
| 4158 | large scale because it is quite expensive to create DNA strands but it's | ||
| 4159 | possible.</p> | ||
| 4160 | <p>Encoding data into DNA sequence is relatively simple process once you understand | ||
| 4161 | the relationship between binary data and nucleotides and scientists have been | ||
| 4162 | making large leaps in this field in order to provide viable long-term storage | ||
| 4163 | solution for our data that would potentially survive our specie if case of | ||
| 4164 | global disaster. We could imprint all the world's knowledge into plants and | ||
| 4165 | ensure the survival of our knowledge.</p> | ||
| 4166 | <p>More optimistic usage for this technology would be easier storage of ever | ||
| 4167 | growing data we produce every day. Once machines for sequencing DNA become fast | ||
| 4168 | enough and cheaper this could mean the next evolution of storing data and | ||
| 4169 | abandoning classical hard and solid state drives in data warehouses.</p> | ||
| 4170 | <p>As we currently stand this is still not viable but it is quite an amazing and | ||
| 4171 | cool technology.</p> | ||
| 4172 | <p>My interests in this field are purely in encoding processes and experimental | ||
| 4173 | testing mainly because I don't have the access to this expensive machines. My | ||
| 4174 | initial goal was to create a toolkit that can be used by everybody to encode | ||
| 4175 | their data into a proper DNA sequence.</p> | ||
| 4176 | <h2 id="glossary">Glossary</h2> | ||
| 4177 | <p><strong>deoxyribose</strong> A five-carbon sugar molecule with a hydrogen atom rather than a | ||
| 4178 | hydroxyl group in the 2′ position; the sugar component of DNA nucleotides.</p> | ||
| 4179 | <p><strong>double helix</strong> The molecular shape of DNA in which two strands of nucleotides | ||
| 4180 | wind around each other in a spiral shape.</p> | ||
| 4181 | <p><strong>nitrogenous base</strong> A nitrogen-containing molecule that acts as a base; often | ||
| 4182 | referring to one of the purine or pyrimidine components of nucleic acids.</p> | ||
| 4183 | <p><strong>phosphate group</strong> A molecular group consisting of a central phosphorus atom | ||
| 4184 | bound to four oxygen atoms.</p> | ||
| 4185 | <p><strong>RGB</strong> The RGB color model is an additive color model in which red, green and | ||
| 4186 | blue light are added together in various ways to reproduce a broad array of | ||
| 4187 | colors.</p> | ||
| 4188 | <p><strong>GCC</strong> The GNU Compiler Collection is a compiler system produced by the GNU | ||
| 4189 | Project supporting various programming languages.</p> | ||
| 4190 | <h2 id="data-encoding">Data encoding</h2> | ||
| 4191 | <p><strong>TL;DR:</strong> Encoding involves the use of a code to change original data into a | ||
| 4192 | form that can be used by an external process.</p> | ||
| 4193 | <p>Encoding is the process of converting data into a format required for a number | ||
| 4194 | of information processing needs, including:</p> | ||
| 4195 | <ul> | ||
| 4196 | <li>Program compiling and execution</li> | ||
| 4197 | <li>Data transmission, storage and compression/decompression</li> | ||
| 4198 | <li>Application data processing, such as file conversion</li> | ||
| 4199 | </ul> | ||
| 4200 | <p>Encoding can have two meanings:</p> | ||
| 4201 | <ul> | ||
| 4202 | <li>In computer technology, encoding is the process of applying a specific code, | ||
| 4203 | such as letters, symbols and numbers, to data for conversion into an | ||
| 4204 | equivalent cipher.</li> | ||
| 4205 | <li>In electronics, encoding refers to analog to digital conversion.</li> | ||
| 4206 | </ul> | ||
| 4207 | <h2 id="quick-history-of-dna">Quick history of DNA</h2> | ||
| 4208 | <ul> | ||
| 4209 | <li><strong>1869</strong> - Friedrich Miescher identifies &quot;nuclein&quot;.</li> | ||
| 4210 | <li><strong>1900s</strong> - The Eugenics Movement.</li> | ||
| 4211 | <li><strong>1900</strong> – Mendel's theories are rediscovered by researchers.</li> | ||
| 4212 | <li><strong>1944</strong> - Oswald Avery identifies DNA as the 'transforming principle'.</li> | ||
| 4213 | <li><strong>1952</strong> - Rosalind Franklin photographs crystallized DNA fibres.</li> | ||
| 4214 | <li><strong>1953</strong> - James Watson and Francis Crick discover the double helix structure of DNA.</li> | ||
| 4215 | <li><strong>1965</strong> - Marshall Nirenberg is the first person to sequence the bases in each codon.</li> | ||
| 4216 | <li><strong>1983</strong> - Huntington's disease is the first mapped genetic disease.</li> | ||
| 4217 | <li><strong>1990</strong> - The Human Genome Project begins.</li> | ||
| 4218 | <li><strong>1995</strong> - Haemophilus Influenzae is the first bacterium genome sequenced.</li> | ||
| 4219 | <li><strong>1996</strong> - Dolly the sheep is cloned.</li> | ||
| 4220 | <li><strong>1999</strong> - First human chromosome is decoded.</li> | ||
| 4221 | <li><strong>2000</strong> – Genetic code of the fruit fly is decoded.</li> | ||
| 4222 | <li><strong>2002</strong> – Mouse is the first mammal to have its genome decoded.</li> | ||
| 4223 | <li><strong>2003</strong> – The Human Genome Project is completed.</li> | ||
| 4224 | <li><strong>2013</strong> – DNA Worldwide and Eurofins Forensic discover identical twins have differences in their genetic makeup.</li> | ||
| 4225 | </ul> | ||
| 4226 | <h2 id="what-is-dna">What is DNA?</h2> | ||
| 4227 | <p>Deoxyribonucleic acid, a self-replicating material which is <strong>present in nearly | ||
| 4228 | all living organisms</strong> as the main constituent of chromosomes. It is the | ||
| 4229 | <strong>carrier of genetic information</strong>.</p> | ||
| 4230 | <blockquote> | ||
| 4231 | <p>The nitrogen in our DNA, the calcium in our teeth, the iron in our blood, | ||
| 4232 | the carbon in our apple pies were made in the interiors of collapsing stars. | ||
| 4233 | We are made of starstuff. | ||
| 4234 | <strong>-- Carl Sagan, Cosmos</strong></p> | ||
| 4235 | </blockquote> | ||
| 4236 | <p>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. | ||
| 4238 | Cytosine and thymine are pyrimidine bases, while adenine and guanine are purine | ||
| 4239 | bases. The sugar and the base together are called a nucleoside.</p> | ||
| 4240 | <figure> | ||
| 4241 | <img src="/posts/dna-sequence/dna-basics.jpg" alt="DNA" /> | ||
| 4242 | <figcaption><p><em>DNA (a) forms a double stranded helix, and (b) adenine pairs with thymine and | ||
| 4243 | cytosine pairs with guanine. (credit a: modification of work by Jerome Walker, | ||
| 4244 | Dennis Myts)</em></p></figcaption> | ||
| 4245 | </figure> | ||
| 4246 | <h2 id="encode-binary-data-into-dna-sequence">Encode binary data into DNA sequence</h2> | ||
| 4247 | <p>As an input file you can use any file you want:</p> | ||
| 4248 | <ul> | ||
| 4249 | <li>ASCII files,</li> | ||
| 4250 | <li>Compiled programs,</li> | ||
| 4251 | <li>Multimedia files (MP3, MP4, MVK, etc),</li> | ||
| 4252 | <li>Images,</li> | ||
| 4253 | <li>Database files,</li> | ||
| 4254 | <li>etc.</li> | ||
| 4255 | </ul> | ||
| 4256 | <p>Note: If you would copy all the bytes from RAM to file or pipe data to file you | ||
| 4257 | could encode also this data as long as you provide file pointer to the encoder.</p> | ||
| 4258 | <h3 id="basic-encoding">Basic Encoding</h3> | ||
| 4259 | <p>As already mentioned, the Basic Encoding is based on a simple mapping. Since DNA | ||
| 4260 | is composed of 4 nucleotides (Adenine, Cytosine, Guanine, Thymine; usually | ||
| 4261 | referred using the first letter). Using this technique we can encode</p> | ||
| 4262 | <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> | ||
| 4263 | <p>using a single nucleotide. In this way, we are able to use the 4 bases that | ||
| 4264 | compose the DNA strand to encode each byte of data.</p> | ||
| 4265 | <table> | ||
| 4266 | <thead> | ||
| 4267 | <tr> | ||
| 4268 | <th>Two bits</th> | ||
| 4269 | <th>Nucleotides</th> | ||
| 4270 | </tr> | ||
| 4271 | </thead> | ||
| 4272 | <tbody> | ||
| 4273 | <tr> | ||
| 4274 | <td>00</td> | ||
| 4275 | <td><strong>A</strong> (Adenine)</td> | ||
| 4276 | </tr> | ||
| 4277 | <tr> | ||
| 4278 | <td>10</td> | ||
| 4279 | <td><strong>G</strong> (Guanine)</td> | ||
| 4280 | </tr> | ||
| 4281 | <tr> | ||
| 4282 | <td>01</td> | ||
| 4283 | <td><strong>C</strong> (Cytosine)</td> | ||
| 4284 | </tr> | ||
| 4285 | <tr> | ||
| 4286 | <td>11</td> | ||
| 4287 | <td><strong>T</strong> (Thymine)</td> | ||
| 4288 | </tr> | ||
| 4289 | </tbody> | ||
| 4290 | </table> | ||
| 4291 | <p>With this in mind we can simply encode any data by using two-bit to Nucleotides | ||
| 4292 | conversion.</p> | ||
| 4293 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>{ Algorithm 1: Naive byte array to DNA encode } | ||
| 4294 | </span></span><span style="display:flex;"><span>procedure EncodeToDNASequence(f) string | ||
| 4295 | </span></span><span style="display:flex;"><span>begin | ||
| 4296 | </span></span><span style="display:flex;"><span> enc string | ||
| 4297 | </span></span><span style="display:flex;"><span> <span style="color:#00f">while</span> <span style="color:#00f">not</span> eof(f) do | ||
| 4298 | </span></span><span style="display:flex;"><span> c byte := buffer[0] { Read 1 byte <span style="color:#00f">from</span> buffer } | ||
| 4299 | </span></span><span style="display:flex;"><span> bin integer := sprintf(<span style="color:#a31515">&#39;08b&#39;</span>, c) { Convert to string binary } | ||
| 4300 | </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 | ||
| 4301 | </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) } | ||
| 4302 | </span></span><span style="display:flex;"><span> enc += <span style="color:#a31515">&#39;A&#39;</span> | ||
| 4303 | </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) } | ||
| 4304 | </span></span><span style="display:flex;"><span> enc += <span style="color:#a31515">&#39;G&#39;</span> | ||
| 4305 | </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) } | ||
| 4306 | </span></span><span style="display:flex;"><span> enc += <span style="color:#a31515">&#39;C&#39;</span> | ||
| 4307 | </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) } | ||
| 4308 | </span></span><span style="display:flex;"><span> enc += <span style="color:#a31515">&#39;T&#39;</span> | ||
| 4309 | </span></span><span style="display:flex;"><span> <span style="color:#00f">return</span> enc { Return DNA sequence } | ||
| 4310 | </span></span><span style="display:flex;"><span>end | ||
| 4311 | </span></span></code></pre><p>Another encoding would be <strong>Goldman encoding</strong>. Using this encoding helps with | ||
| 4312 | Nonsense mutation (amino acids replaced by a stop codon) that occurs and is the | ||
| 4313 | most problematic during translation because it leads to truncated amino acid | ||
| 4314 | sequences, which in turn results in truncated proteins.</p> | ||
| 4315 | <p><a href="https://www.youtube.com/watch?v=a4PiGWNsIEU">Where to store big data? In DNA: Nick Goldman at TEDxPrague</a></p> | ||
| 4316 | <h3 id="fasta-file-format">FASTA file format</h3> | ||
| 4317 | <p>In bioinformatics, FASTA format is a text-based format for representing either | ||
| 4318 | nucleotide sequences or peptide sequences, in which nucleotides or amino acids | ||
| 4319 | are represented using single-letter codes. The format also allows for sequence | ||
| 4320 | names and comments to precede the sequences. The format originates from the | ||
| 4321 | FASTA software package, but has now become a standard in the field of | ||
| 4322 | bioinformatics.</p> | ||
| 4323 | <p>The first line in a FASTA file started either with a &quot;&gt;&quot; (greater-than) symbol | ||
| 4324 | or, less frequently, a &quot;;&quot; (semicolon) was taken as a comment. Subsequent lines | ||
| 4325 | starting with a semicolon would be ignored by software. Since the only comment | ||
| 4326 | used was the first, it quickly became used to hold a summary description of the | ||
| 4327 | sequence, often starting with a unique library accession number, and with time | ||
| 4328 | it has become commonplace to always use &quot;&gt;&quot; for the first line and to not use | ||
| 4329 | &quot;;&quot; comments (which would otherwise be ignored).</p> | ||
| 4330 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>;LCBO - Prolactin precursor - Bovine | ||
| 4331 | </span></span><span style="display:flex;"><span>; a sample sequence in FASTA format | ||
| 4332 | </span></span><span style="display:flex;"><span>MDSKGSSQKGSRLLLLLVVSNLLLCQGVVSTPVCPNGPGNCQVSLRDLFDRAVMVSHYIHDLSS | ||
| 4333 | </span></span><span style="display:flex;"><span>EMFNEFDKRYAQGKGFITMALNSCHTSSLPTPEDKEQAQQTHHEVLMSLILGLLRSWNDPLYHL | ||
| 4334 | </span></span><span style="display:flex;"><span>VTEVRGMKGAPDAILSRAIEIEEENKRLLEGMEMIFGQVIPGAKETEPYPVWSGLPSLQTKDED | ||
| 4335 | </span></span><span style="display:flex;"><span>ARYSAFYNLLHCLRRDSSKIDTYLKLLNCRIIYNNNC* | ||
| 4336 | </span></span><span style="display:flex;"><span> | ||
| 4337 | </span></span><span style="display:flex;"><span>&gt;MCHU - Calmodulin - Human, rabbit, bovine, rat, and chicken | ||
| 4338 | </span></span><span style="display:flex;"><span>ADQLTEEQIAEFKEAFSLFDKDGDGTITTKELGTVMRSLGQNPTEAELQDMINEVDADGNGTID | ||
| 4339 | </span></span><span style="display:flex;"><span>FPEFLTMMARKMKDTDSEEEIREAFRVFDKDGNGYISAAELRHVMTNLGEKLTDEEVDEMIREA | ||
| 4340 | </span></span><span style="display:flex;"><span>DIDGDGQVNYEEFVQMMTAK* | ||
| 4341 | </span></span><span style="display:flex;"><span> | ||
| 4342 | </span></span><span style="display:flex;"><span>&gt;gi|5524211|gb|AAD44166.1| cytochrome b [Elephas maximus maximus] | ||
| 4343 | </span></span><span style="display:flex;"><span>LCLYTHIGRNIYYGSYLYSETWNTGIMLLLITMATAFMGYVLPWGQMSFWGATVITNLFSAIPYIGTNLV | ||
| 4344 | </span></span><span style="display:flex;"><span>EWIWGGFSVDKATLNRFFAFHFILPFTMVALAGVHLTFLHETGSNNPLGLTSDSDKIPFHPYYTIKDFLG | ||
| 4345 | </span></span><span style="display:flex;"><span>LLILILLLLLLALLSPDMLGDPDNHMPADPLNTPLHIKPEWYFLFAYAILRSVPNKLGGVLALFLSIVIL | ||
| 4346 | </span></span><span style="display:flex;"><span>GLMPFLHTSKHRSMMLRPLSQALFWTLTMDLLTLTWIGSQPVEYPYTIIGQMASILYFSIILAFLPIAGX | ||
| 4347 | </span></span><span style="display:flex;"><span>IENY | ||
| 4348 | </span></span></code></pre><p>FASTA format was extended by <a href="https://en.wikipedia.org/wiki/FASTQ_format">FASTQ</a> | ||
| 4349 | format from the <a href="https://www.sanger.ac.uk/">Sanger Centre</a> in Cambridge.</p> | ||
| 4350 | <h3 id="png-encoded-dna-sequence">PNG encoded DNA sequence</h3> | ||
| 4351 | <table> | ||
| 4352 | <thead> | ||
| 4353 | <tr> | ||
| 4354 | <th>Nucleotides</th> | ||
| 4355 | <th>RGB</th> | ||
| 4356 | <th>Color name</th> | ||
| 4357 | </tr> | ||
| 4358 | </thead> | ||
| 4359 | <tbody> | ||
| 4360 | <tr> | ||
| 4361 | <td>A ➞ Adenine</td> | ||
| 4362 | <td>(0,0,255)</td> | ||
| 4363 | <td>Blue</td> | ||
| 4364 | </tr> | ||
| 4365 | <tr> | ||
| 4366 | <td>G ➞ Guanine</td> | ||
| 4367 | <td>(0,100,0)</td> | ||
| 4368 | <td>Green</td> | ||
| 4369 | </tr> | ||
| 4370 | <tr> | ||
| 4371 | <td>C ➞ Cytosine</td> | ||
| 4372 | <td>(255,0,0)</td> | ||
| 4373 | <td>Red</td> | ||
| 4374 | </tr> | ||
| 4375 | <tr> | ||
| 4376 | <td>T ➞ Thymine</td> | ||
| 4377 | <td>(255,255,0)</td> | ||
| 4378 | <td>Yellow</td> | ||
| 4379 | </tr> | ||
| 4380 | </tbody> | ||
| 4381 | </table> | ||
| 4382 | <p>With this in mind we can create a simple algorithm to create PNG representation | ||
| 4383 | of a DNA sequence.</p> | ||
| 4384 | <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 } | ||
| 4385 | </span></span><span style="display:flex;"><span>procedure EncodeDNASequenceToPNG(f) | ||
| 4386 | </span></span><span style="display:flex;"><span>begin | ||
| 4387 | </span></span><span style="display:flex;"><span> i image | ||
| 4388 | </span></span><span style="display:flex;"><span> <span style="color:#00f">while</span> <span style="color:#00f">not</span> eof(f) do | ||
| 4389 | </span></span><span style="display:flex;"><span> c char := buffer[0] { Read 1 char <span style="color:#00f">from</span> buffer } | ||
| 4390 | </span></span><span style="display:flex;"><span> case c of | ||
| 4391 | </span></span><span style="display:flex;"><span> <span style="color:#a31515">&#39;A&#39;</span>: color := RGB(0, 0, 255) { Blue } | ||
| 4392 | </span></span><span style="display:flex;"><span> <span style="color:#a31515">&#39;G&#39;</span>: color := RGB(0, 100, 0) { Green } | ||
| 4393 | </span></span><span style="display:flex;"><span> <span style="color:#a31515">&#39;C&#39;</span>: color := RGB(255, 0, 0) { Red } | ||
| 4394 | </span></span><span style="display:flex;"><span> <span style="color:#a31515">&#39;T&#39;</span>: color := RGB(255, 255, 0) { Yellow } | ||
| 4395 | </span></span><span style="display:flex;"><span> drawRect(i, [x, y], color) | ||
| 4396 | </span></span><span style="display:flex;"><span> save(i) { Save PNG image } | ||
| 4397 | </span></span><span style="display:flex;"><span>end | ||
| 4398 | </span></span></code></pre><h2 id="encoding-text-file-in-practice">Encoding text file in practice</h2> | ||
| 4399 | <p>In this example we will take a simple text file as our input stream for | ||
| 4400 | encoding. This file will have a quote from Niels Bohr and saved as txt file.</p> | ||
| 4401 | <blockquote> | ||
| 4402 | <p>How wonderful that we have met with a paradox. Now we have some hope of | ||
| 4403 | making progress. | ||
| 4404 | ― Niels Bohr</p> | ||
| 4405 | </blockquote> | ||
| 4406 | <p>First we encode text file into FASTA file.</p> | ||
| 4407 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>./dnae-encode -i quote.txt -o quote.fa | ||
| 4408 | </span></span><span style="display:flex;"><span>2019/01/10 00:38:29 Gathering input file stats | ||
| 4409 | </span></span><span style="display:flex;"><span>2019/01/10 00:38:29 Starting encoding ... | ||
| 4410 | </span></span><span style="display:flex;"><span> 106 B / 106 B [==================================] 100.00% 0s | ||
| 4411 | </span></span><span style="display:flex;"><span>2019/01/10 00:38:29 Saving to FASTA file ... | ||
| 4412 | </span></span><span style="display:flex;"><span>2019/01/10 00:38:29 Output FASTA file length is 438 B | ||
| 4413 | </span></span><span style="display:flex;"><span>2019/01/10 00:38:29 Process took 987.263µs | ||
| 4414 | </span></span><span style="display:flex;"><span>2019/01/10 00:38:29 Done ... | ||
| 4415 | </span></span></code></pre><p>Output of <code>quote.fa</code> file contains the encoded DNA sequence in ASCII format.</p> | ||
| 4416 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>&gt;SEQ1 | ||
| 4417 | </span></span><span style="display:flex;"><span>GACAGCTTGTGTACAAGTGTGCTTGCTCGCGAGCGGGTACGCGCGTGGGCTAACAAGTGA | ||
| 4418 | </span></span><span style="display:flex;"><span>GCCAGCAGGTGAACAAGTGTGCGGACAAGCCAGCAGGTGCGCGGACAAGCTGGCGGGTGA | ||
| 4419 | </span></span><span style="display:flex;"><span>ACAAGTGTGCCGGTGAGCCAACAAGCAGACAAGTAAGCAGGTACGCAGGCGAGCTTGTCA | ||
| 4420 | </span></span><span style="display:flex;"><span>ACTCACAAGATCGCTTGTGTACAAGTGTGCGGACAAGCCAGCAGGTGCGCGGACAAGTAT | ||
| 4421 | </span></span><span style="display:flex;"><span>GCTTGCTGGCGGACAAGCCAGCTTGTAAGCGGACAAGCTTGCGCACAAGCTGGCAGGCCT | ||
| 4422 | </span></span><span style="display:flex;"><span>GCCGGCTCGCGTACAAATTCACAAGTAAGTACGCTTGCGTGTACGCGGGTATGTATACTC | ||
| 4423 | </span></span><span style="display:flex;"><span>AACCTCACCAAACGGGACAAGATCGCCGGCGGGCTAGTATACAAGAACGCTTGCCAGTAC | ||
| 4424 | </span></span><span style="display:flex;"><span>AACC | ||
| 4425 | </span></span></code></pre><p>Then we encode FASTA file from previous operation to encode this data into PNG.</p> | ||
| 4426 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>./dnae-png -i quote.fa -o quote.png | ||
| 4427 | </span></span><span style="display:flex;"><span>2019/01/10 00:40:09 Gathering input file stats ... | ||
| 4428 | </span></span><span style="display:flex;"><span>2019/01/10 00:40:09 Deconstructing FASTA file ... | ||
| 4429 | </span></span><span style="display:flex;"><span>2019/01/10 00:40:09 Compositing image file ... | ||
| 4430 | </span></span><span style="display:flex;"><span> 424 / 424 [==================================] 100.00% 0s | ||
| 4431 | </span></span><span style="display:flex;"><span>2019/01/10 00:40:09 Saving output file ... | ||
| 4432 | </span></span><span style="display:flex;"><span>2019/01/10 00:40:09 Output image file length is 1.1 kB | ||
| 4433 | </span></span><span style="display:flex;"><span>2019/01/10 00:40:09 Process took 19.036117ms | ||
| 4434 | </span></span><span style="display:flex;"><span>2019/01/10 00:40:09 Done ... | ||
| 4435 | </span></span></code></pre><p>After encoding into PNG format this file looks like this.</p> | ||
| 4436 | <figure> | ||
| 4437 | <img src="/posts/dna-sequence/quote.png" alt="Encoded Quote in PNG format" /> | ||
| 4438 | <figcaption><p>The larger the input stream is the larger the PNG file would be.</p></figcaption> | ||
| 4439 | </figure> | ||
| 4440 | <p>Compiled basic Hello World C program with | ||
| 4441 | <a href="https://www.gnu.org/software/gcc/">GCC</a> would <a href="/posts/dna-sequence/sample.png">look | ||
| 4442 | like</a>.</p> | ||
| 4443 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000">// gcc -O3 -o sample sample.c | ||
| 4444 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span><span style="color:#00f">#include</span> <span style="color:#00f">&lt;stdio.h&gt;</span><span style="color:#00f"> | ||
| 4445 | </span></span></span><span style="display:flex;"><span><span style="color:#00f"></span> | ||
| 4446 | </span></span><span style="display:flex;"><span>main() { | ||
| 4447 | </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>); | ||
| 4448 | </span></span><span style="display:flex;"><span> <span style="color:#00f">return</span> 0; | ||
| 4449 | </span></span><span style="display:flex;"><span>} | ||
| 4450 | </span></span></code></pre><h2 id="toolkit-for-encoding-data">Toolkit for encoding data</h2> | ||
| 4451 | <p>I have created a toolkit with two main programs:</p> | ||
| 4452 | <ul> | ||
| 4453 | <li>dnae-encode (encodes file into FASTA file)</li> | ||
| 4454 | <li>dnae-png (encodes FASTA file into PNG)</li> | ||
| 4455 | </ul> | ||
| 4456 | <p>Toolkit with full source code is available on | ||
| 4457 | <a href="https://github.com/mitjafelicijan/dna-encoding">github.com/mitjafelicijan/dna-encoding</a>.</p> | ||
| 4458 | <h3 id="dnae-encode">dnae-encode</h3> | ||
| 4459 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>&gt; ./dnae-encode --help | ||
| 4460 | </span></span><span style="display:flex;"><span>usage: dnae-encode --input=INPUT [&lt;flags&gt;] | ||
| 4461 | </span></span><span style="display:flex;"><span> | ||
| 4462 | </span></span><span style="display:flex;"><span>A command-line application that encodes file into DNA sequence. | ||
| 4463 | </span></span><span style="display:flex;"><span> | ||
| 4464 | </span></span><span style="display:flex;"><span>Flags: | ||
| 4465 | </span></span><span style="display:flex;"><span> --help Show context-sensitive help (also try --help-long and --help-man). | ||
| 4466 | </span></span><span style="display:flex;"><span> -i, --input=INPUT Input file (ASCII or binary) which will be encoded into DNA sequence. | ||
| 4467 | </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. | ||
| 4468 | </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. | ||
| 4469 | </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. | ||
| 4470 | </span></span><span style="display:flex;"><span> --version Show application version. | ||
| 4471 | </span></span></code></pre><h3 id="dnae-png">dnae-png</h3> | ||
| 4472 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>&gt; ./dnae-png --help | ||
| 4473 | </span></span><span style="display:flex;"><span>usage: dnae-png --input=INPUT [&lt;flags&gt;] | ||
| 4474 | </span></span><span style="display:flex;"><span> | ||
| 4475 | </span></span><span style="display:flex;"><span>A command-line application that encodes FASTA file into PNG image. | ||
| 4476 | </span></span><span style="display:flex;"><span> | ||
| 4477 | </span></span><span style="display:flex;"><span>Flags: | ||
| 4478 | </span></span><span style="display:flex;"><span> --help Show context-sensitive help (also try --help-long and --help-man). | ||
| 4479 | </span></span><span style="display:flex;"><span> -i, --input=INPUT Input FASTA file which will be encoded into PNG image. | ||
| 4480 | </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. | ||
| 4481 | </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). | ||
| 4482 | </span></span><span style="display:flex;"><span> --version Show application version. | ||
| 4483 | </span></span></code></pre><h2 id="benchmarks">Benchmarks</h2> | ||
| 4484 | <p>First we generate some binary sample data with dd.</p> | ||
| 4485 | <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 | ||
| 4486 | </span></span></code></pre><figure> | ||
| 4487 | <img src="/posts/dna-sequence/sample-binary-file.png" alt="Sample binary file 1KB" /> | ||
| 4488 | <figcaption><p>Our freshly generated 1KB file looks something like this (its full of | ||
| 4489 | garbage data as intended).</p></figcaption> | ||
| 4490 | </figure> | ||
| 4491 | <p>We create following binary files:</p> | ||
| 4492 | <ul> | ||
| 4493 | <li>1KB.bin</li> | ||
| 4494 | <li>10KB.bin</li> | ||
| 4495 | <li>100KB.bin</li> | ||
| 4496 | <li>1MB.bin</li> | ||
| 4497 | <li>10MB.bin</li> | ||
| 4498 | <li>100MB.bin</li> | ||
| 4499 | </ul> | ||
| 4500 | <p>After this we create FASTA files for all the binary files by encoding them | ||
| 4501 | into DNA sequence.</p> | ||
| 4502 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>./dnae-encode -i 100MB.bin -o 100MB.fa | ||
| 4503 | </span></span></code></pre><p>Then we GZIP all the FASTA files to see how much the can be compressed.</p> | ||
| 4504 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>gzip -9 &lt; 10MB.fa &gt; 10MB.fa.gz | ||
| 4505 | </span></span></code></pre><figure> | ||
| 4506 | <img src="/posts/dna-sequence/chart-speed.svg" alt="Encode to FASTA" /> | ||
| 4507 | <figcaption><p>The speed increase that occurs when encoding to FASTA format.</p></figcaption> | ||
| 4508 | </figure> | ||
| 4509 | <figure> | ||
| 4510 | <img src="/posts/dna-sequence/chart-size.svg" alt="File sizes" /> | ||
| 4511 | <figcaption><p>Size of the out file after encoding.</p></figcaption> | ||
| 4512 | </figure> | ||
| 4513 | <p><a href="/posts/dna-sequence/benchmarks.csv">Download CSV file with benchmarks</a>.</p> | ||
| 4514 | <h2 id="references">References</h2> | ||
| 4515 | <ul> | ||
| 4516 | <li><a href="https://www.techopedia.com/definition/948/encoding">https://www.techopedia.com/definition/948/encoding</a></li> | ||
| 4517 | <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> | ||
| 4518 | <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> | ||
| 4519 | <li><a href="https://arxiv.org/abs/1801.04774">https://arxiv.org/abs/1801.04774</a></li> | ||
| 4520 | <li><a href="https://en.wikipedia.org/wiki/FASTA_format">https://en.wikipedia.org/wiki/FASTA_format</a></li> | ||
| 4521 | </ul> | ||
| 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 +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&#39;s S3.</description> | ||
| 4533 | <content:encoded><p>Couple of months ago <a href="https://www.digitalocean.com">DigitalOcean</a> introduced new | ||
| 4534 | product called | ||
| 4535 | <a href="https://blog.digitalocean.com/introducing-spaces-object-storage/">Spaces</a> which | ||
| 4536 | is Object Storage very similar to Amazon's S3. This really peaked my interest, | ||
| 4537 | because this was something I was missing and even the thought of going over the | ||
| 4538 | internet for such functionality was in no interest to me. Also in fashion with | ||
| 4539 | their previous pricing this also is very cheap and pricing page is a no-brainer | ||
| 4540 | compared to AWS or GCE. <a href="https://www.digitalocean.com/pricing/">Prices are clearly and precisely defined and | ||
| 4541 | outlined</a>. You must love them for that | ||
| 4542 | :)</p> | ||
| 4543 | <h2 id="initial-requirements">Initial requirements</h2> | ||
| 4544 | <ul> | ||
| 4545 | <li>Is it possible to use them as a mounted drive with FUSE? (tl;dr YES)</li> | ||
| 4546 | <li>Will the performance degrade over time and over different sizes of objects? | ||
| 4547 | (tl;dr NO&amp;YES)</li> | ||
| 4548 | <li>Can storage be mounted on multiple machines at the same time and be writable? | ||
| 4549 | (tl;dr YES)</li> | ||
| 4550 | </ul> | ||
| 4551 | <blockquote> | ||
| 4552 | <p>Let me be clear. This scripts I use are made just for benchmarking and are not | ||
| 4553 | intended to be used in real-life situations. Besides that, I am looking into | ||
| 4554 | using this approaches but adding caching service in front of it and then | ||
| 4555 | dumping everything as an object to storage. This could potentially be some | ||
| 4556 | interesting post of itself. But in case you would need real-time data without | ||
| 4557 | eventual consistency please take this scripts as they are: not usable in such | ||
| 4558 | situations.</p> | ||
| 4559 | </blockquote> | ||
| 4560 | <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> | ||
| 4561 | <p>Well, actually they can be used in such manor. Because they are similar to <a href="https://aws.amazon.com/s3/">AWS | ||
| 4562 | S3</a> many tools are available and you can find many | ||
| 4563 | articles and <a href="https://stackoverflow.com/search?q=s3+fuse">Stackoverflow items</a>.</p> | ||
| 4564 | <p>To make this work you will need DigitalOcean account. If you don't have one you | ||
| 4565 | will not be able to test this code. But if you have an account then you go and | ||
| 4566 | <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 | ||
| 4567 | Droplet</a>. | ||
| 4568 | If you click on this link you will already have preselected Debian 9 with | ||
| 4569 | smallest VM option.</p> | ||
| 4570 | <ul> | ||
| 4571 | <li>Please be sure to add you SSH key, because we will login to this machine | ||
| 4572 | remotely.</li> | ||
| 4573 | <li>If you change your region please remember which one you choose because we will | ||
| 4574 | need this information when we try to mount space to our machine.</li> | ||
| 4575 | </ul> | ||
| 4576 | <p>Instuctions on how to use SSH keys and how to setup them are available in | ||
| 4577 | article <a href="https://www.digitalocean.com/community/tutorials/how-to-use-ssh-keys-with-digitalocean-droplets">How To Use SSH Keys with DigitalOcean | ||
| 4578 | Droplets</a>.</p> | ||
| 4579 | <figure> | ||
| 4580 | <img src="/posts/do-fuse/fuse-droplets.png" alt="DigitalOcean Droplets" /> | ||
| 4581 | </figure> | ||
| 4582 | <p>After we created Droplet it's time to create new Space. This is done by clicking | ||
| 4583 | on a button <a href="https://cloud.digitalocean.com/spaces/new">Create</a> (right top | ||
| 4584 | corner) and selecting Spaces. Choose pronounceable <code>Unique name</code> because we | ||
| 4585 | will use it in examples below. You can either choose Private or Public, it | ||
| 4586 | doesn't matter in our case. And you can always change that in the future.</p> | ||
| 4587 | <p>When you have created new Space we should <a href="https://cloud.digitalocean.com/settings/api/tokens">generate Access | ||
| 4588 | key</a>. This link will guide | ||
| 4589 | to the page when you can generate this key. After you create new one, please | ||
| 4590 | save provided Key and Secret because Secret will not be shown again.</p> | ||
| 4591 | <figure> | ||
| 4592 | <img src="/posts/do-fuse/fuse-spaces.png" alt="DigitalOcean Spaces" /> | ||
| 4593 | </figure> | ||
| 4594 | <p>Now that we have new Space and Access key we should SSH into our machine.</p> | ||
| 4595 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># replace IP with the ip of your newly created droplet</span> | ||
| 4596 | </span></span><span style="display:flex;"><span>ssh root@IP | ||
| 4597 | </span></span><span style="display:flex;"><span> | ||
| 4598 | </span></span><span style="display:flex;"><span><span style="color:#008000"># this will install utilities for mounting storage objects as FUSE</span> | ||
| 4599 | </span></span><span style="display:flex;"><span>apt install s3fs | ||
| 4600 | </span></span><span style="display:flex;"><span> | ||
| 4601 | </span></span><span style="display:flex;"><span><span style="color:#008000"># we now need to provide credentials (access key we created earlier)</span> | ||
| 4602 | </span></span><span style="display:flex;"><span><span style="color:#008000"># replace KEY and SECRET with your own credentials but leave the colon between them</span> | ||
| 4603 | </span></span><span style="display:flex;"><span><span style="color:#008000"># we also need to set proper permissions</span> | ||
| 4604 | </span></span><span style="display:flex;"><span>echo <span style="color:#a31515">&#34;KEY:SECRET&#34;</span> &gt; .passwd-s3fs | ||
| 4605 | </span></span><span style="display:flex;"><span>chmod 600 .passwd-s3fs | ||
| 4606 | </span></span><span style="display:flex;"><span> | ||
| 4607 | </span></span><span style="display:flex;"><span><span style="color:#008000"># now we mount space to our machine</span> | ||
| 4608 | </span></span><span style="display:flex;"><span><span style="color:#008000"># replace UNIQUE-NAME with the name you choose earlier</span> | ||
| 4609 | </span></span><span style="display:flex;"><span><span style="color:#008000"># if you choose different region for your space be careful about -ourl option (ams3)</span> | ||
| 4610 | </span></span><span style="display:flex;"><span>s3fs UNIQUE-NAME /mnt/ -ourl=https://ams3.digitaloceanspaces.com -ouse_cache=/tmp | ||
| 4611 | </span></span><span style="display:flex;"><span> | ||
| 4612 | </span></span><span style="display:flex;"><span><span style="color:#008000"># now we try to create a file</span> | ||
| 4613 | </span></span><span style="display:flex;"><span><span style="color:#008000"># once you mount it may take a couple of seconds to retrieve data</span> | ||
| 4614 | </span></span><span style="display:flex;"><span>echo <span style="color:#a31515">&#34;Hello cruel world&#34;</span> &gt; /mnt/hello.txt | ||
| 4615 | </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 | ||
| 4616 | Spaces</a> and click on your created | ||
| 4617 | space. If file hello.txt is present you have successfully mounted space to your | ||
| 4618 | machine and wrote data to it.</p> | ||
| 4619 | <p>I choose the same region for my Droplet and my Space but you don't have to. You | ||
| 4620 | can have different regions. What this actually does to performance I don't know.</p> | ||
| 4621 | <p>Additional information on FUSE:</p> | ||
| 4622 | <ul> | ||
| 4623 | <li><a href="https://github.com/s3fs-fuse/s3fs-fuse">Github project page for s3fs</a></li> | ||
| 4624 | <li><a href="https://en.wikipedia.org/wiki/Filesystem_in_Userspace">FUSE - Filesystem in Userspace</a></li> | ||
| 4625 | </ul> | ||
| 4626 | <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> | ||
| 4627 | <p>For this task I didn't want to just read and write text files or uploading | ||
| 4628 | images. I actually wanted to figure out if using something like SQlite is viable | ||
| 4629 | in this case.</p> | ||
| 4630 | <h3 id="measurement-experiment-1-file-copy">Measurement experiment 1: File copy</h3> | ||
| 4631 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># first we create some dummy files at different sizes</span> | ||
| 4632 | </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:#008000">#10KB</span> | ||
| 4633 | </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:#008000">#100KB</span> | ||
| 4634 | </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:#008000">#1MB</span> | ||
| 4635 | </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:#008000">#10MB</span> | ||
| 4636 | </span></span><span style="display:flex;"><span> | ||
| 4637 | </span></span><span style="display:flex;"><span><span style="color:#008000"># now we set time command to only return real</span> | ||
| 4638 | </span></span><span style="display:flex;"><span>TIMEFORMAT=%R | ||
| 4639 | </span></span><span style="display:flex;"><span> | ||
| 4640 | </span></span><span style="display:flex;"><span><span style="color:#008000"># now lets test it</span> | ||
| 4641 | </span></span><span style="display:flex;"><span>(time cp 10KB.dat /mnt/) |&amp; tee -a 10KB.results.txt | ||
| 4642 | </span></span><span style="display:flex;"><span> | ||
| 4643 | </span></span><span style="display:flex;"><span><span style="color:#008000"># and now we automate</span> | ||
| 4644 | </span></span><span style="display:flex;"><span><span style="color:#008000"># this will perform the same operation 100 times</span> | ||
| 4645 | </span></span><span style="display:flex;"><span><span style="color:#008000"># this will output results into separated files based on objecty size</span> | ||
| 4646 | </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> | ||
| 4647 | </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> | ||
| 4648 | </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> | ||
| 4649 | </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> | ||
| 4650 | </span></span></code></pre><p>Files of size 100MB were not successfully transferred and ended up displaying | ||
| 4651 | error (cp: failed to close '/mnt/100MB.1.dat': Operation not permitted).</p> | ||
| 4652 | <p>As I suspected, object size is not really that important. Sadly I don't have the | ||
| 4653 | time to test performance over periods of time. But if some of you would do it | ||
| 4654 | please send me your data. I would be interested in seeing results.</p> | ||
| 4655 | <p><strong>Here are plotted results</strong></p> | ||
| 4656 | <p>You can download <a href="/posts/do-fuse/copy-benchmarks.tsv">raw result here</a>. | ||
| 4657 | Measurements are in seconds.</p> | ||
| 4658 | <script src="//cdn.plot.ly/plotly-latest.min.js"></script> | ||
| 4659 | <div id="copy-benchmarks"></div> | ||
| 4660 | <script> | ||
| 4661 | (function(){ | ||
| 4662 | var request = new XMLHttpRequest(); | ||
| 4663 | request.open("GET", "/posts/do-fuse/copy-benchmarks.tsv", true); | ||
| 4664 | request.onload = function() { | ||
| 4665 | if (request.status >= 200 && request.status < 400) { | ||
| 4666 | var payload = request.responseText.trim(); | ||
| 4667 | var tsv = payload.split("\n"); | ||
| 4668 | for (var i=0; i<tsv.length; i++) { tsv[i] = tsv[i].split("\t"); } | ||
| 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<tsv.length; j++) { | ||
| 4676 | x.push(j); | ||
| 4677 | y.push(parseFloat(tsv[j][idx].replace(",", "."))); | ||
| 4678 | } | ||
| 4679 | traces.push({ x: x, y: y, type: "scatter", name: el, line: { width: 1, shape: "spline" } }); | ||
| 4680 | }); | ||
| 4681 | 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 } } }); | ||
| 4682 | } else { } | ||
| 4683 | }; | ||
| 4684 | request.onerror = function() { }; | ||
| 4685 | request.send(null); | ||
| 4686 | })(); | ||
| 4687 | </script> | ||
| 4688 | <p>As far as these tests show, performance is quite stable and can be predicted | ||
| 4689 | which is fantastic. But this is a small test and spans only over couple of | ||
| 4690 | hours. So you should not completely trust them.</p> | ||
| 4691 | <h3 id="measurement-experiment-2-sqlite-performanse">Measurement experiment 2: SQLite performanse</h3> | ||
| 4692 | <p>I was unable to use database file directly from mounted drive so this is a no-go | ||
| 4693 | as I suspected. So I executed code below on a local disk just to get some | ||
| 4694 | benchmarks. I inserted 1000 records with DROPTABLE, CREATETABLE, INSERTMANY, | ||
| 4695 | FETCHALL, COMMIT for 1000 times to generate statistics. As you can see | ||
| 4696 | performance of SQLite is quite amazing. You could then potentially just copy | ||
| 4697 | file to mounted drive and be done with it.</p> | ||
| 4698 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#00f">import</span> time | ||
| 4699 | </span></span><span style="display:flex;"><span><span style="color:#00f">import</span> sqlite3 | ||
| 4700 | </span></span><span style="display:flex;"><span><span style="color:#00f">import</span> sys | ||
| 4701 | </span></span><span style="display:flex;"><span> | ||
| 4702 | </span></span><span style="display:flex;"><span><span style="color:#00f">if</span> len(sys.argv) &lt; 3: | ||
| 4703 | </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>) | ||
| 4704 | </span></span><span style="display:flex;"><span> exit() | ||
| 4705 | </span></span><span style="display:flex;"><span> | ||
| 4706 | </span></span><span style="display:flex;"><span><span style="color:#00f">def</span> data_iter(x): | ||
| 4707 | </span></span><span style="display:flex;"><span> <span style="color:#00f">for</span> i <span style="color:#00f">in</span> range(x): | ||
| 4708 | </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) | ||
| 4709 | </span></span><span style="display:flex;"><span> | ||
| 4710 | </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>) | ||
| 4711 | </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: | ||
| 4712 | </span></span><span style="display:flex;"><span> fp.write(header_line) | ||
| 4713 | </span></span><span style="display:flex;"><span> | ||
| 4714 | </span></span><span style="display:flex;"><span>start_time = time.time() | ||
| 4715 | </span></span><span style="display:flex;"><span>conn = sqlite3.connect(sys.argv[1]) | ||
| 4716 | </span></span><span style="display:flex;"><span>c = conn.cursor() | ||
| 4717 | </span></span><span style="display:flex;"><span>end_time = time.time() | ||
| 4718 | </span></span><span style="display:flex;"><span>result_time = CONNECT = end_time - start_time | ||
| 4719 | </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)) | ||
| 4720 | </span></span><span style="display:flex;"><span> | ||
| 4721 | </span></span><span style="display:flex;"><span>start_time = time.time() | ||
| 4722 | </span></span><span style="display:flex;"><span>c.execute(<span style="color:#a31515">&#34;PRAGMA journal_mode=WAL&#34;</span>) | ||
| 4723 | </span></span><span style="display:flex;"><span>c.execute(<span style="color:#a31515">&#34;PRAGMA temp_store=MEMORY&#34;</span>) | ||
| 4724 | </span></span><span style="display:flex;"><span>c.execute(<span style="color:#a31515">&#34;PRAGMA synchronous=OFF&#34;</span>) | ||
| 4725 | </span></span><span style="display:flex;"><span>result_time = PRAGMA = end_time - start_time | ||
| 4726 | </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)) | ||
| 4727 | </span></span><span style="display:flex;"><span> | ||
| 4728 | </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])): | ||
| 4729 | </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)) | ||
| 4730 | </span></span><span style="display:flex;"><span> | ||
| 4731 | </span></span><span style="display:flex;"><span> start_time = time.time() | ||
| 4732 | </span></span><span style="display:flex;"><span> c.execute(<span style="color:#a31515">&#34;drop table if exists test&#34;</span>) | ||
| 4733 | </span></span><span style="display:flex;"><span> end_time = time.time() | ||
| 4734 | </span></span><span style="display:flex;"><span> result_time = DROPTABLE = end_time - start_time | ||
| 4735 | </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)) | ||
| 4736 | </span></span><span style="display:flex;"><span> | ||
| 4737 | </span></span><span style="display:flex;"><span> start_time = time.time() | ||
| 4738 | </span></span><span style="display:flex;"><span> c.execute(<span style="color:#a31515">&#34;create table if not exists test(a,b)&#34;</span>) | ||
| 4739 | </span></span><span style="display:flex;"><span> end_time = time.time() | ||
| 4740 | </span></span><span style="display:flex;"><span> result_time = CREATETABLE = end_time - start_time | ||
| 4741 | </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)) | ||
| 4742 | </span></span><span style="display:flex;"><span> | ||
| 4743 | </span></span><span style="display:flex;"><span> start_time = time.time() | ||
| 4744 | </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]))) | ||
| 4745 | </span></span><span style="display:flex;"><span> end_time = time.time() | ||
| 4746 | </span></span><span style="display:flex;"><span> result_time = INSERTMANY = end_time - start_time | ||
| 4747 | </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)) | ||
| 4748 | </span></span><span style="display:flex;"><span> | ||
| 4749 | </span></span><span style="display:flex;"><span> start_time = time.time() | ||
| 4750 | </span></span><span style="display:flex;"><span> c.execute(<span style="color:#a31515">&#34;select count(*) from test&#34;</span>) | ||
| 4751 | </span></span><span style="display:flex;"><span> res = c.fetchall() | ||
| 4752 | </span></span><span style="display:flex;"><span> end_time = time.time() | ||
| 4753 | </span></span><span style="display:flex;"><span> result_time = FETCHALL = end_time - start_time | ||
| 4754 | </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)) | ||
| 4755 | </span></span><span style="display:flex;"><span> | ||
| 4756 | </span></span><span style="display:flex;"><span> start_time = time.time() | ||
| 4757 | </span></span><span style="display:flex;"><span> conn.commit() | ||
| 4758 | </span></span><span style="display:flex;"><span> end_time = time.time() | ||
| 4759 | </span></span><span style="display:flex;"><span> result_time = COMMIT = end_time - start_time | ||
| 4760 | </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)) | ||
| 4761 | </span></span><span style="display:flex;"><span> | ||
| 4762 | </span></span><span style="display:flex;"><span> print | ||
| 4763 | </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) | ||
| 4764 | </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: | ||
| 4765 | </span></span><span style="display:flex;"><span> fp.write(log_line) | ||
| 4766 | </span></span><span style="display:flex;"><span> | ||
| 4767 | </span></span><span style="display:flex;"><span>start_time = time.time() | ||
| 4768 | </span></span><span style="display:flex;"><span>conn.close() | ||
| 4769 | </span></span><span style="display:flex;"><span>end_time = time.time() | ||
| 4770 | </span></span><span style="display:flex;"><span>result_time = CLOSE = end_time - start_time | ||
| 4771 | </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)) | ||
| 4772 | </span></span></code></pre><p>You can download <a href="/posts/do-fuse/sqlite-benchmarks.tsv">raw result here</a>. And | ||
| 4773 | again, these results are done on a local block storage and do not represent | ||
| 4774 | capabilities of object storage. With my current approach and state of the test | ||
| 4775 | code these can not be done. I would need to make Python code much more robust | ||
| 4776 | and check locking etc.</p> | ||
| 4777 | <div id="sqlite-benchmarks"></div> | ||
| 4778 | <script> | ||
| 4779 | (function(){ | ||
| 4780 | var request = new XMLHttpRequest(); | ||
| 4781 | request.open("GET", "/posts/do-fuse/sqlite-benchmarks.tsv", true); | ||
| 4782 | request.onload = function() { | ||
| 4783 | if (request.status >= 200 && request.status < 400) { | ||
| 4784 | var payload = request.responseText.trim(); | ||
| 4785 | var tsv = payload.split("\n"); | ||
| 4786 | for (var i=0; i<tsv.length; i++) { tsv[i] = tsv[i].split("\t"); } | ||
| 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<tsv.length; j++) { | ||
| 4794 | x.push(j); | ||
| 4795 | y.push(parseFloat(tsv[j][idx].replace(",", "."))); | ||
| 4796 | } | ||
| 4797 | traces.push({ x: x, y: y, type: "scatter", name: el, line: { width: 1, shape: "spline" } }); | ||
| 4798 | }); | ||
| 4799 | 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 } } }); | ||
| 4800 | } else { } | ||
| 4801 | }; | ||
| 4802 | request.onerror = function() { }; | ||
| 4803 | request.send(null); | ||
| 4804 | })(); | ||
| 4805 | </script> | ||
| 4806 | <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> | ||
| 4807 | <p>Well, this one didn't take long to test. And the answer is <strong>YES</strong>. I mounted | ||
| 4808 | space on both machines and measured same performance on both machines. But | ||
| 4809 | because file is downloaded before write and then uploaded on complete there | ||
| 4810 | could potentially be problems is another process is trying to access the same | ||
| 4811 | file.</p> | ||
| 4812 | <h2 id="observations-and-conslusion">Observations and conslusion</h2> | ||
| 4813 | <p>Using Spaces in this way makes it easier to access and manage files. But besides | ||
| 4814 | that you would need to write additional code to make this one play nice with you | ||
| 4815 | applications.</p> | ||
| 4816 | <p>Nevertheless, this was extremely simple to setup and use and this is just | ||
| 4817 | another excellent product in DigitalOcean product line. I found this exercise | ||
| 4818 | very valuable and am thinking about implementing some sort of mechanism for | ||
| 4819 | SQLite, so data can be stored on Spaces and accessed by many VM's. For a project | ||
| 4820 | where data doesn't need to be accessible in real-time and can have couple of | ||
| 4821 | minutes old data this would be very interesting. If any of you find this | ||
| 4822 | proposal interesting please write in a comment box below or shoot me an email | ||
| 4823 | and I will keep you posted.</p> | ||
| 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 +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><h2 id="initial-thoughts">Initial thoughts</h2> | ||
| 4836 | <p>I have been developing these kind of application for the better part of my last | ||
| 4837 | 5 years and people keep asking me how to approach developing such application | ||
| 4838 | and I will give a try explaining it here.</p> | ||
| 4839 | <p>IOT applications are really no different than any other kind of applications. | ||
| 4840 | We have data that needs to be collected and visualized in some form of tables or | ||
| 4841 | charts. The main difference here is that most of the times these data is | ||
| 4842 | collected by some kind of device foreign to developer that mainly operates in | ||
| 4843 | web domain. But fear not, it's not that different than writing some JavaScript.</p> | ||
| 4844 | <p>There are many devices able to transmit data via wireless or wired network by | ||
| 4845 | default but for the sake of example we will be using commonly known Arduino with | ||
| 4846 | wireless module already on the board → <a href="https://store.arduino.cc/arduino-mkr1000">Arduino | ||
| 4847 | MKR1000</a>.</p> | ||
| 4848 | <p>In order to make this little project as accessible to others as possible I will | ||
| 4849 | try to make it as inexpensive as possible. And by this I mean that I will avoid | ||
| 4850 | using hosted virtual servers and will be using my own laptop as a server. But | ||
| 4851 | you must buy Arduino MKR1000 to follow steps below. But if you would want to | ||
| 4852 | deploy this software I would suggest using | ||
| 4853 | <a href="https://www.digitalocean.com">DigitalOcean</a> → smallest VPS is only per month | ||
| 4854 | making this one of the most affordable option out there. Please notice that this | ||
| 4855 | software will not run on stock web hosting that only supports LAMP (Linux, | ||
| 4856 | Apache, MySQL, and PHP).</p> | ||
| 4857 | <p>But before we begin please take notice that this is strictly experimental code | ||
| 4858 | and not well optimized and there are much better ways in handling some aspects | ||
| 4859 | of the application but that requires much deeper knowledge of technology that is | ||
| 4860 | not needed for an example like this.</p> | ||
| 4861 | <p><strong>Development steps</strong></p> | ||
| 4862 | <ol> | ||
| 4863 | <li>Simple Python API that will receive and store incoming data.</li> | ||
| 4864 | <li>Prototype C++ code that will read &quot;sensor data&quot; and transmit it to API.</li> | ||
| 4865 | <li>Data visualization with charts → extends Python web application.</li> | ||
| 4866 | </ol> | ||
| 4867 | <p>Step 1. and 3. will share the same web application. One route will be dedicated | ||
| 4868 | to API and another to serving HTML with chart.</p> | ||
| 4869 | <p>Schema below represents what we will try to achieve and how different parts | ||
| 4870 | correlates to each other.</p> | ||
| 4871 | <figure> | ||
| 4872 | <img src="/posts/iot-application/simple-iot-application-overview.svg" alt="Overview" /> | ||
| 4873 | </figure> | ||
| 4874 | <h2 id="simple-python-api">Simple Python API</h2> | ||
| 4875 | <p>I have always been a fan of simplicity so we will be using <a href="https://bottlepy.org/docs/dev/">Bottle: Python Web | ||
| 4876 | Framework</a>. It is a single file web framework | ||
| 4877 | that seriously simplifies working with routes, templating and has built-in web | ||
| 4878 | server that satisfies our need in this case.</p> | ||
| 4879 | <p>First we need to install bottle package. This can be done by downloading | ||
| 4880 | <code>bottle.py</code> and placing it in the root of your application or by using pip | ||
| 4881 | software <code>pip install bottle --user</code>.</p> | ||
| 4882 | <p>If you are using Linux or MacOS then Python is already installed. If you will | ||
| 4883 | try to test this on Windows please install <a href="https://www.python.org/downloads/windows/">Python for | ||
| 4884 | Windows</a>. There may be some problems | ||
| 4885 | with path when you will try to launch <code>python webapp.py</code> so please take care | ||
| 4886 | of this before you continue.</p> | ||
| 4887 | <h3 id="basic-web-application">Basic web application</h3> | ||
| 4888 | <p>Most basic bottle application is quite simple. Paste code below in | ||
| 4889 | <code>webapp.py</code> file and save.</p> | ||
| 4890 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># -*- coding: utf-8 -*-</span> | ||
| 4891 | </span></span><span style="display:flex;"><span> | ||
| 4892 | </span></span><span style="display:flex;"><span><span style="color:#00f">import</span> bottle | ||
| 4893 | </span></span><span style="display:flex;"><span> | ||
| 4894 | </span></span><span style="display:flex;"><span><span style="color:#008000"># initializing bottle app</span> | ||
| 4895 | </span></span><span style="display:flex;"><span>app = bottle.Bottle() | ||
| 4896 | </span></span><span style="display:flex;"><span> | ||
| 4897 | </span></span><span style="display:flex;"><span><span style="color:#008000"># triggered when / is accessed from browser</span> | ||
| 4898 | </span></span><span style="display:flex;"><span><span style="color:#008000"># only accepts GET → no POST allowed</span> | ||
| 4899 | </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>]) | ||
| 4900 | </span></span><span style="display:flex;"><span><span style="color:#00f">def</span> route_default(): | ||
| 4901 | </span></span><span style="display:flex;"><span> <span style="color:#00f">return</span> <span style="color:#a31515">&#34;howdy from python&#34;</span> | ||
| 4902 | </span></span><span style="display:flex;"><span> | ||
| 4903 | </span></span><span style="display:flex;"><span><span style="color:#008000"># starting server on http://0.0.0.0:5000</span> | ||
| 4904 | </span></span><span style="display:flex;"><span><span style="color:#00f">if</span> __name__ == <span style="color:#a31515">&#34;__main__&#34;</span>: | ||
| 4905 | </span></span><span style="display:flex;"><span> bottle.run( | ||
| 4906 | </span></span><span style="display:flex;"><span> app = app, | ||
| 4907 | </span></span><span style="display:flex;"><span> host = <span style="color:#a31515">&#34;0.0.0.0&#34;</span>, | ||
| 4908 | </span></span><span style="display:flex;"><span> port = 5000, | ||
| 4909 | </span></span><span style="display:flex;"><span> debug = <span style="color:#00f">True</span>, | ||
| 4910 | </span></span><span style="display:flex;"><span> reloader = <span style="color:#00f">True</span>, | ||
| 4911 | </span></span><span style="display:flex;"><span> catchall = <span style="color:#00f">True</span>, | ||
| 4912 | </span></span><span style="display:flex;"><span> ) | ||
| 4913 | </span></span></code></pre><p>To run this simple application you should open command prompt or terminal on | ||
| 4914 | your 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 | ||
| 4915 | <code>http://0.0.0.0:5000</code>.</p> | ||
| 4916 | <p>If you would like change the port of your application (like port 80) and not use | ||
| 4917 | root to run your app this will present a problem. The TCP/IP port numbers below | ||
| 4918 | 1024 are privileged ports → this is a security feature. So in order of | ||
| 4919 | simplicity and security use a port number above 1024 like I have used port 5000.</p> | ||
| 4920 | <p>If this fails at any time please fix it before you continue, because nothing | ||
| 4921 | below will work otherwise.</p> | ||
| 4922 | <p>We use 0.0.0.0 as default host so that this app is available over your local | ||
| 4923 | network. If you find your local ip <code>ifconfig</code> and try accessing this site | ||
| 4924 | with your phone (if on same network/router as your machine) this should work as | ||
| 4925 | well (example of such ip <code>http://192.168.1.15:5000</code>). This is a must have | ||
| 4926 | because Arduino will be accessing this application to send it's data.</p> | ||
| 4927 | <h3 id="web-application-security">Web application security</h3> | ||
| 4928 | <p>There is a lot to be said about security and is a topic of many books. Of course | ||
| 4929 | all this can not be written here but to just establish some basic security → you | ||
| 4930 | should always use SSL with your application. Some fantastic free certificates | ||
| 4931 | are available by <a href="https://letsencrypt.org">Let's Encrypt - Free SSL/TLS | ||
| 4932 | Certificates</a>. With SSL certificate installed you | ||
| 4933 | should then make use of HTTP headers and send your &quot;API key&quot; via a header. If | ||
| 4934 | your key is send via header then this key is encrypted by SSL and send encrypted | ||
| 4935 | over the network. Never send your api keys by GET parameter like | ||
| 4936 | <code>http://example.com/?api_key=somekeyvalue</code>. The problem that this kind of | ||
| 4937 | sending presents is that this key is visible in logs and by network sniffers.</p> | ||
| 4938 | <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 | ||
| 4939 | Application Security Best | ||
| 4940 | Practices</a>. Please | ||
| 4941 | check it out.</p> | ||
| 4942 | <h3 id="simple-api-for-writing-data-points">Simple API for writing data-points</h3> | ||
| 4943 | <p>We will now be using boilerplate code from example above and extend it to be | ||
| 4944 | SQLite3 because it plays well with Python and can store quite large amount of | ||
| 4945 | able to write data received by API to local storage. For example use I will use | ||
| 4946 | data. I have been using it to collect gigabytes of data in a single database | ||
| 4947 | without any corruption or problems → your experience may vary.</p> | ||
| 4948 | <p>To avoid learning SQLite I will be using <a href="https://dataset.readthedocs.io/en/latest/index.html">Dataset: databases for lazy | ||
| 4949 | people</a>. This package | ||
| 4950 | abstracts SQL and simplifies writing and reading data from database. You should | ||
| 4951 | install this package with pip software <code>pip install dataset --user</code>.</p> | ||
| 4952 | <p>Because API will use POST method I will be testing if code works correctly by | ||
| 4953 | using <a href="https://chrome.google.com/webstore/detail/restlet-client-rest-api-t/aejoelaoggembcahagimdiliamlcdmfm">Restlet Client for Google | ||
| 4954 | Chrome</a>. | ||
| 4955 | This software also allows you to set headers → for basic security with API_KEY.</p> | ||
| 4956 | <p>To quickly generate passwords or API keys I usually use this nifty website | ||
| 4957 | <a href="https://randomkeygen.com/">RandomKeygen</a>.</p> | ||
| 4958 | <p>Copy and paste code below over your previous code in file <code>webapp.py</code>.</p> | ||
| 4959 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># -*- coding: utf-8 -*-</span> | ||
| 4960 | </span></span><span style="display:flex;"><span> | ||
| 4961 | </span></span><span style="display:flex;"><span><span style="color:#00f">import</span> time | ||
| 4962 | </span></span><span style="display:flex;"><span><span style="color:#00f">import</span> bottle | ||
| 4963 | </span></span><span style="display:flex;"><span><span style="color:#00f">import</span> random | ||
| 4964 | </span></span><span style="display:flex;"><span><span style="color:#00f">import</span> dataset | ||
| 4965 | </span></span><span style="display:flex;"><span> | ||
| 4966 | </span></span><span style="display:flex;"><span><span style="color:#008000"># initializing bottle app</span> | ||
| 4967 | </span></span><span style="display:flex;"><span>app = bottle.Bottle() | ||
| 4968 | </span></span><span style="display:flex;"><span> | ||
| 4969 | </span></span><span style="display:flex;"><span><span style="color:#008000"># connects to sqlite database</span> | ||
| 4970 | </span></span><span style="display:flex;"><span><span style="color:#008000"># check_same_thread=False allows using it in multi-threaded mode</span> | ||
| 4971 | </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>) | ||
| 4972 | </span></span><span style="display:flex;"><span> | ||
| 4973 | </span></span><span style="display:flex;"><span><span style="color:#008000"># api key that will be used in Arduino code</span> | ||
| 4974 | </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> | ||
| 4975 | </span></span><span style="display:flex;"><span> | ||
| 4976 | </span></span><span style="display:flex;"><span><span style="color:#008000"># triggered when /api is accessed from browser</span> | ||
| 4977 | </span></span><span style="display:flex;"><span><span style="color:#008000"># only accepts POST → no GET allowed</span> | ||
| 4978 | </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>]) | ||
| 4979 | </span></span><span style="display:flex;"><span><span style="color:#00f">def</span> route_default(): | ||
| 4980 | </span></span><span style="display:flex;"><span> status = 400 | ||
| 4981 | </span></span><span style="display:flex;"><span> ts = int(time.time()) <span style="color:#008000"># current timestamp</span> | ||
| 4982 | </span></span><span style="display:flex;"><span> value = bottle.request.body.read() <span style="color:#008000"># data from device</span> | ||
| 4983 | </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:#008000"># api key from header</span> | ||
| 4984 | </span></span><span style="display:flex;"><span> | ||
| 4985 | </span></span><span style="display:flex;"><span> <span style="color:#008000"># outputs to console received data for debug reason</span> | ||
| 4986 | </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) | ||
| 4987 | </span></span><span style="display:flex;"><span> | ||
| 4988 | </span></span><span style="display:flex;"><span> <span style="color:#008000"># if api_key is correct and value is present</span> | ||
| 4989 | </span></span><span style="display:flex;"><span> <span style="color:#008000"># then writes attribute to point table</span> | ||
| 4990 | </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: | ||
| 4991 | </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)) | ||
| 4992 | </span></span><span style="display:flex;"><span> status = 200 | ||
| 4993 | </span></span><span style="display:flex;"><span> | ||
| 4994 | </span></span><span style="display:flex;"><span> <span style="color:#008000"># we only need to return status</span> | ||
| 4995 | </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>) | ||
| 4996 | </span></span><span style="display:flex;"><span> | ||
| 4997 | </span></span><span style="display:flex;"><span><span style="color:#008000"># starting server on http://0.0.0.0:5000</span> | ||
| 4998 | </span></span><span style="display:flex;"><span><span style="color:#00f">if</span> __name__ == <span style="color:#a31515">&#34;__main__&#34;</span>: | ||
| 4999 | </span></span><span style="display:flex;"><span> bottle.run( | ||
| 5000 | </span></span><span style="display:flex;"><span> app = app, | ||
| 5001 | </span></span><span style="display:flex;"><span> host = <span style="color:#a31515">&#34;0.0.0.0&#34;</span>, | ||
| 5002 | </span></span><span style="display:flex;"><span> port = 5000, | ||
| 5003 | </span></span><span style="display:flex;"><span> debug = <span style="color:#00f">True</span>, | ||
| 5004 | </span></span><span style="display:flex;"><span> reloader = <span style="color:#00f">True</span>, | ||
| 5005 | </span></span><span style="display:flex;"><span> catchall = <span style="color:#00f">True</span>, | ||
| 5006 | </span></span><span style="display:flex;"><span> ) | ||
| 5007 | </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 | ||
| 5008 | available via POST method on /api route.</p> | ||
| 5009 | <p>After testing the service with Restlet Client you should be able to view your | ||
| 5010 | data in a database file <code>data.db</code>.</p> | ||
| 5011 | <figure> | ||
| 5012 | <img src="/posts/iot-application/iot-rest-example.png" alt="REST settings example" /> | ||
| 5013 | </figure> | ||
| 5014 | <p>You can also check the contents of new database file by using desktop client | ||
| 5015 | for SQLite → <a href="http://sqlitebrowser.org/">DB Browser for SQLite</a>.</p> | ||
| 5016 | <figure> | ||
| 5017 | <img src="/posts/iot-application/iot-sqlite-db.png" alt="SQLite database example" /> | ||
| 5018 | </figure> | ||
| 5019 | <p>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 | ||
| 5021 | would happen to have atomic clock on Arduino it would be then better to generate | ||
| 5022 | and send timestamp with the value. This would be particularity useful if we | ||
| 5023 | would be collecting sensor data at a higher frequency and then sending this data | ||
| 5024 | in bulk to API.</p> | ||
| 5025 | <p>If you will deploy this app with uWSGI and multi-threaded, use DSN (Data Source | ||
| 5026 | Name) url with <code>?check_same_thread=False</code>.</p> | ||
| 5027 | <p>Ok, now that we have some sort of a working API with some basic security so | ||
| 5028 | unwanted people can not post data to your database can we proceed further and | ||
| 5029 | try to program Arduino to send data to API.</p> | ||
| 5030 | <h2 id="sending-data-to-api-with-arduino-mkr1000">Sending data to API with Arduino MKR1000</h2> | ||
| 5031 | <p>First of all you should have MKR1000 module and microUSB cable to proceed. If | ||
| 5032 | you have ever done any work with Arduino you should know that you also need | ||
| 5033 | <a href="https://www.arduino.cc/en/Main/Software">Arduino IDE</a>. On provided link you | ||
| 5034 | should be able to download and install IDE. Once that task is completed and you | ||
| 5035 | have successfully run blink example you should proceed to the next step.</p> | ||
| 5036 | <p>In order to use wireless capabilities of MKR1000 you need to first install | ||
| 5037 | <a href="https://www.arduino.cc/en/Reference/WiFi101">WiFi101 library</a> in Arduino IDE. | ||
| 5038 | Please check before you install, you may already have it installed.</p> | ||
| 5039 | <p>Code below is a working example that sends data to API. Before you try to test | ||
| 5040 | your code make sure you have run Python web application. Then change settings | ||
| 5041 | for wifi, api endpoint and api_key. If by some reason code bellow doesn't work | ||
| 5042 | for you please leave a comment and I'll try to help.</p> | ||
| 5043 | <p>Once you have opened IDE and copied this code try to compile and upload it. | ||
| 5044 | Then open &quot;Serial monitor&quot; to see if any output is presented by Arduino.</p> | ||
| 5045 | <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"> | ||
| 5046 | </span></span></span><span style="display:flex;"><span><span style="color:#00f"></span> | ||
| 5047 | </span></span><span style="display:flex;"><span><span style="color:#008000">// wifi settings | ||
| 5048 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span><span style="color:#2b91af">char</span> ssid[] = <span style="color:#a31515">&#34;ssid-name&#34;</span>; | ||
| 5049 | </span></span><span style="display:flex;"><span><span style="color:#2b91af">char</span> pass[] = <span style="color:#a31515">&#34;ssid-password&#34;</span>; | ||
| 5050 | </span></span><span style="display:flex;"><span> | ||
| 5051 | </span></span><span style="display:flex;"><span><span style="color:#008000">// api server enpoint | ||
| 5052 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span><span style="color:#2b91af">char</span> server[] = <span style="color:#a31515">&#34;192.168.6.22&#34;</span>; | ||
| 5053 | </span></span><span style="display:flex;"><span><span style="color:#2b91af">int</span> port = 5000; | ||
| 5054 | </span></span><span style="display:flex;"><span> | ||
| 5055 | </span></span><span style="display:flex;"><span><span style="color:#008000">// api key that must be the same as the one in Python code | ||
| 5056 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span>String api_key = <span style="color:#a31515">&#34;JtF2aUE5SGHfVJBCG5SH&#34;</span>; | ||
| 5057 | </span></span><span style="display:flex;"><span> | ||
| 5058 | </span></span><span style="display:flex;"><span><span style="color:#008000">// frequency data is sent in ms - every 5 seconds | ||
| 5059 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span><span style="color:#2b91af">int</span> timeout = 1000 * 5; | ||
| 5060 | </span></span><span style="display:flex;"><span> | ||
| 5061 | </span></span><span style="display:flex;"><span><span style="color:#2b91af">int</span> status = WL_IDLE_STATUS; | ||
| 5062 | </span></span><span style="display:flex;"><span> | ||
| 5063 | </span></span><span style="display:flex;"><span><span style="color:#2b91af">void</span> setup() { | ||
| 5064 | </span></span><span style="display:flex;"><span> | ||
| 5065 | </span></span><span style="display:flex;"><span> <span style="color:#008000">// initialize serial and wait for port to open: | ||
| 5066 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span> Serial.begin(9600); | ||
| 5067 | </span></span><span style="display:flex;"><span> delay(1000); | ||
| 5068 | </span></span><span style="display:flex;"><span> | ||
| 5069 | </span></span><span style="display:flex;"><span> <span style="color:#008000">// check for the presence of the shield | ||
| 5070 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span> <span style="color:#00f">if</span> (WiFi.status() == WL_NO_SHIELD) { | ||
| 5071 | </span></span><span style="display:flex;"><span> Serial.println(<span style="color:#a31515">&#34;WiFi shield not present&#34;</span>); | ||
| 5072 | </span></span><span style="display:flex;"><span> <span style="color:#00f">while</span> (true); | ||
| 5073 | </span></span><span style="display:flex;"><span> } | ||
| 5074 | </span></span><span style="display:flex;"><span> | ||
| 5075 | </span></span><span style="display:flex;"><span> <span style="color:#008000">// attempt to connect to wifi network | ||
| 5076 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span> <span style="color:#00f">while</span> (status != WL_CONNECTED) { | ||
| 5077 | </span></span><span style="display:flex;"><span> Serial.print(<span style="color:#a31515">&#34;Attempting to connect to SSID: &#34;</span>); | ||
| 5078 | </span></span><span style="display:flex;"><span> Serial.println(ssid); | ||
| 5079 | </span></span><span style="display:flex;"><span> status = WiFi.begin(ssid, pass); | ||
| 5080 | </span></span><span style="display:flex;"><span> <span style="color:#008000">// wait 10 seconds for connection | ||
| 5081 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span> delay(10000); | ||
| 5082 | </span></span><span style="display:flex;"><span> } | ||
| 5083 | </span></span><span style="display:flex;"><span> | ||
| 5084 | </span></span><span style="display:flex;"><span> <span style="color:#008000">// output wifi status to serial monitor | ||
| 5085 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span> Serial.print(<span style="color:#a31515">&#34;SSID: &#34;</span>); | ||
| 5086 | </span></span><span style="display:flex;"><span> Serial.println(WiFi.SSID()); | ||
| 5087 | </span></span><span style="display:flex;"><span> | ||
| 5088 | </span></span><span style="display:flex;"><span> IPAddress ip = WiFi.localIP(); | ||
| 5089 | </span></span><span style="display:flex;"><span> Serial.print(<span style="color:#a31515">&#34;IP Address: &#34;</span>); | ||
| 5090 | </span></span><span style="display:flex;"><span> Serial.println(ip); | ||
| 5091 | </span></span><span style="display:flex;"><span> | ||
| 5092 | </span></span><span style="display:flex;"><span> <span style="color:#2b91af">long</span> rssi = WiFi.RSSI(); | ||
| 5093 | </span></span><span style="display:flex;"><span> Serial.print(<span style="color:#a31515">&#34;signal strength (RSSI):&#34;</span>); | ||
| 5094 | </span></span><span style="display:flex;"><span> Serial.print(rssi); | ||
| 5095 | </span></span><span style="display:flex;"><span> Serial.println(<span style="color:#a31515">&#34; dBm&#34;</span>); | ||
| 5096 | </span></span><span style="display:flex;"><span>} | ||
| 5097 | </span></span><span style="display:flex;"><span> | ||
| 5098 | </span></span><span style="display:flex;"><span><span style="color:#2b91af">void</span> loop() { | ||
| 5099 | </span></span><span style="display:flex;"><span> WiFiClient client; | ||
| 5100 | </span></span><span style="display:flex;"><span> | ||
| 5101 | </span></span><span style="display:flex;"><span> <span style="color:#00f">if</span> (client.connect(server, port)) { | ||
| 5102 | </span></span><span style="display:flex;"><span> | ||
| 5103 | </span></span><span style="display:flex;"><span> <span style="color:#008000">// I use random number generator for this example | ||
| 5104 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span> <span style="color:#008000">// but you can use analog or digital inputs from arduino | ||
| 5105 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span> String content = String(random(1000)); | ||
| 5106 | </span></span><span style="display:flex;"><span> | ||
| 5107 | </span></span><span style="display:flex;"><span> client.println(<span style="color:#a31515">&#34;POST /api HTTP/1.1&#34;</span>); | ||
| 5108 | </span></span><span style="display:flex;"><span> client.println(<span style="color:#a31515">&#34;Connection: close&#34;</span>); | ||
| 5109 | </span></span><span style="display:flex;"><span> client.println(<span style="color:#a31515">&#34;Api-Key: &#34;</span> + api_key); | ||
| 5110 | </span></span><span style="display:flex;"><span> client.println(<span style="color:#a31515">&#34;Content-Length: &#34;</span> + String(content.length())); | ||
| 5111 | </span></span><span style="display:flex;"><span> client.println(); | ||
| 5112 | </span></span><span style="display:flex;"><span> client.println(content); | ||
| 5113 | </span></span><span style="display:flex;"><span> | ||
| 5114 | </span></span><span style="display:flex;"><span> delay(100); | ||
| 5115 | </span></span><span style="display:flex;"><span> client.stop(); | ||
| 5116 | </span></span><span style="display:flex;"><span> Serial.println(<span style="color:#a31515">&#34;Data sent successfully ...&#34;</span>); | ||
| 5117 | </span></span><span style="display:flex;"><span> | ||
| 5118 | </span></span><span style="display:flex;"><span> } <span style="color:#00f">else</span> { | ||
| 5119 | </span></span><span style="display:flex;"><span> Serial.println(<span style="color:#a31515">&#34;Problem sending data ...&#34;</span>); | ||
| 5120 | </span></span><span style="display:flex;"><span> } | ||
| 5121 | </span></span><span style="display:flex;"><span> | ||
| 5122 | </span></span><span style="display:flex;"><span> <span style="color:#008000">// waits for x seconds and continue looping | ||
| 5123 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span> delay(timeout); | ||
| 5124 | </span></span><span style="display:flex;"><span>} | ||
| 5125 | </span></span></code></pre><p>As seen from example you can notice that Arduino is generating random integer | ||
| 5126 | between [ 0 .. 1000 ]. You can easily replace this with a temperature sensor or | ||
| 5127 | any other kind of sensor.</p> | ||
| 5128 | <p>Now that we have API under the hood and Arduino is sending demo data we can now | ||
| 5129 | focus on data visualization.</p> | ||
| 5130 | <h2 id="data-visualization">Data visualization</h2> | ||
| 5131 | <p>Before we continue we should examine our project folder structure. Currently we | ||
| 5132 | only have two files in our project:</p> | ||
| 5133 | <p><em>simple-iot-app/</em></p> | ||
| 5134 | <ul> | ||
| 5135 | <li><em>webapp.py</em></li> | ||
| 5136 | <li><em>data.db</em></li> | ||
| 5137 | </ul> | ||
| 5138 | <p>We will now add HTML template that will contain CSS and JavaScript code inline | ||
| 5139 | for the simplicity reason. And for the bottle framework to be able to scan root | ||
| 5140 | application folder for templates we will add <code>bottle.TEMPLATE_PATH.insert(0, &quot;./&quot;)</code> in <code>webapp.py</code>. By default bottle framework uses <code>views/</code> | ||
| 5141 | subfolder to store templates. This is not the ideal situation and if you will | ||
| 5142 | use bottle to develop web applications you should use native behavior and store | ||
| 5143 | templates in it's predefined folder. But for the sake of example we will | ||
| 5144 | over-ride this. Be careful to fully replace your code with new code that is | ||
| 5145 | provided below. Avoid partially replacing code in file :) Also new code for | ||
| 5146 | reading data-points is provided in Python example below.</p> | ||
| 5147 | <p>First we add new route to our web application. It should be trigger when browser | ||
| 5148 | hits root of application <code>http://0.0.0.0:5000/</code>. This route will do nothing | ||
| 5149 | more than render <code>frontend.html</code> template. This is done by <code>return bottle.template(&quot;frontend.html&quot;)</code>. Check code below to further examine how | ||
| 5150 | exactly this is done.</p> | ||
| 5151 | <p>Now we will expand <code>/api</code> route and use different methods to write or read | ||
| 5152 | data-points. For writing data-point we will use POST method and for reading | ||
| 5153 | points we will use GET method. GET method will return JSON object with latest | ||
| 5154 | readings and historical data.</p> | ||
| 5155 | <p>There is a fantastic JavaScript library for plotting time-series charts called | ||
| 5156 | <a href="https://www.metricsgraphicsjs.org">MetricsGraphics.js</a> that is based on | ||
| 5157 | <a href="https://d3js.org/">D3.js</a> library for visualizing data.</p> | ||
| 5158 | <p>Data schema required by MetricsGraphics.js → to achieve this we need to | ||
| 5159 | transform data from database into this format:</p> | ||
| 5160 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>[ | ||
| 5161 | </span></span><span style="display:flex;"><span> { | ||
| 5162 | </span></span><span style="display:flex;"><span> &#34;date&#34;: <span style="color:#a31515">&#34;2017-08-11 01:07:20&#34;</span>, | ||
| 5163 | </span></span><span style="display:flex;"><span> &#34;value&#34;: 933 | ||
| 5164 | </span></span><span style="display:flex;"><span> }, | ||
| 5165 | </span></span><span style="display:flex;"><span> { | ||
| 5166 | </span></span><span style="display:flex;"><span> &#34;date&#34;: <span style="color:#a31515">&#34;2017-08-11 01:07:30&#34;</span>, | ||
| 5167 | </span></span><span style="display:flex;"><span> &#34;value&#34;: 743 | ||
| 5168 | </span></span><span style="display:flex;"><span> } | ||
| 5169 | </span></span><span style="display:flex;"><span>] | ||
| 5170 | </span></span></code></pre><p>Web application is now complete and we only need <code>frontend.html</code> that we | ||
| 5171 | will develop now. If you would try to start web app now and go to root app this | ||
| 5172 | will return error because we don't have frontend.html yet.</p> | ||
| 5173 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># -*- coding: utf-8 -*-</span> | ||
| 5174 | </span></span><span style="display:flex;"><span> | ||
| 5175 | </span></span><span style="display:flex;"><span><span style="color:#00f">import</span> time | ||
| 5176 | </span></span><span style="display:flex;"><span><span style="color:#00f">import</span> bottle | ||
| 5177 | </span></span><span style="display:flex;"><span><span style="color:#00f">import</span> json | ||
| 5178 | </span></span><span style="display:flex;"><span><span style="color:#00f">import</span> datetime | ||
| 5179 | </span></span><span style="display:flex;"><span><span style="color:#00f">import</span> random | ||
| 5180 | </span></span><span style="display:flex;"><span><span style="color:#00f">import</span> dataset | ||
| 5181 | </span></span><span style="display:flex;"><span> | ||
| 5182 | </span></span><span style="display:flex;"><span><span style="color:#008000"># initializing bottle app</span> | ||
| 5183 | </span></span><span style="display:flex;"><span>app = bottle.Bottle() | ||
| 5184 | </span></span><span style="display:flex;"><span> | ||
| 5185 | </span></span><span style="display:flex;"><span><span style="color:#008000"># adds root directory as template folder</span> | ||
| 5186 | </span></span><span style="display:flex;"><span>bottle.TEMPLATE_PATH.insert(0, <span style="color:#a31515">&#34;./&#34;</span>) | ||
| 5187 | </span></span><span style="display:flex;"><span> | ||
| 5188 | </span></span><span style="display:flex;"><span><span style="color:#008000"># connects to sqlite database</span> | ||
| 5189 | </span></span><span style="display:flex;"><span><span style="color:#008000"># check_same_thread=False allows using it in multi-threaded mode</span> | ||
| 5190 | </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>) | ||
| 5191 | </span></span><span style="display:flex;"><span> | ||
| 5192 | </span></span><span style="display:flex;"><span><span style="color:#008000"># api key that will be used in Arduino code</span> | ||
| 5193 | </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> | ||
| 5194 | </span></span><span style="display:flex;"><span> | ||
| 5195 | </span></span><span style="display:flex;"><span><span style="color:#008000"># triggered when / is accessed from browser</span> | ||
| 5196 | </span></span><span style="display:flex;"><span><span style="color:#008000"># only accepts GET → no POST allowed</span> | ||
| 5197 | </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>]) | ||
| 5198 | </span></span><span style="display:flex;"><span><span style="color:#00f">def</span> route_default(): | ||
| 5199 | </span></span><span style="display:flex;"><span> <span style="color:#00f">return</span> bottle.template(<span style="color:#a31515">&#34;frontend.html&#34;</span>) | ||
| 5200 | </span></span><span style="display:flex;"><span> | ||
| 5201 | </span></span><span style="display:flex;"><span><span style="color:#008000"># triggered when /api is accessed from browser</span> | ||
| 5202 | </span></span><span style="display:flex;"><span><span style="color:#008000"># accepts POST and GET</span> | ||
| 5203 | </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>]) | ||
| 5204 | </span></span><span style="display:flex;"><span><span style="color:#00f">def</span> route_default(): | ||
| 5205 | </span></span><span style="display:flex;"><span> | ||
| 5206 | </span></span><span style="display:flex;"><span> <span style="color:#008000"># if method is POST then we write datapoint</span> | ||
| 5207 | </span></span><span style="display:flex;"><span> <span style="color:#00f">if</span> bottle.request.method == <span style="color:#a31515">&#34;POST&#34;</span>: | ||
| 5208 | </span></span><span style="display:flex;"><span> status = 400 | ||
| 5209 | </span></span><span style="display:flex;"><span> ts = int(time.time()) <span style="color:#008000"># current timestamp</span> | ||
| 5210 | </span></span><span style="display:flex;"><span> value = bottle.request.body.read() <span style="color:#008000"># data from device</span> | ||
| 5211 | </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:#008000"># api key from header</span> | ||
| 5212 | </span></span><span style="display:flex;"><span> | ||
| 5213 | </span></span><span style="display:flex;"><span> <span style="color:#008000"># outputs to console recieved data for debug reason</span> | ||
| 5214 | </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) | ||
| 5215 | </span></span><span style="display:flex;"><span> | ||
| 5216 | </span></span><span style="display:flex;"><span> <span style="color:#008000"># if api_key is correct and value is present</span> | ||
| 5217 | </span></span><span style="display:flex;"><span> <span style="color:#008000"># then writes attribute to point table</span> | ||
| 5218 | </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: | ||
| 5219 | </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)) | ||
| 5220 | </span></span><span style="display:flex;"><span> status = 200 | ||
| 5221 | </span></span><span style="display:flex;"><span> | ||
| 5222 | </span></span><span style="display:flex;"><span> <span style="color:#008000"># we only need to return status</span> | ||
| 5223 | </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>) | ||
| 5224 | </span></span><span style="display:flex;"><span> | ||
| 5225 | </span></span><span style="display:flex;"><span> <span style="color:#008000"># if method is GET then we read datapoint</span> | ||
| 5226 | </span></span><span style="display:flex;"><span> <span style="color:#00f">else</span>: | ||
| 5227 | </span></span><span style="display:flex;"><span> response = [] | ||
| 5228 | </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() | ||
| 5229 | </span></span><span style="display:flex;"><span> | ||
| 5230 | </span></span><span style="display:flex;"><span> <span style="color:#00f">for</span> point <span style="color:#00f">in</span> datapoints: | ||
| 5231 | </span></span><span style="display:flex;"><span> response.append({ | ||
| 5232 | </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>), | ||
| 5233 | </span></span><span style="display:flex;"><span> <span style="color:#a31515">&#34;value&#34;</span>: point[<span style="color:#a31515">&#34;value&#34;</span>] | ||
| 5234 | </span></span><span style="display:flex;"><span> }) | ||
| 5235 | </span></span><span style="display:flex;"><span> | ||
| 5236 | </span></span><span style="display:flex;"><span> bottle.response.content_type = <span style="color:#a31515">&#34;application/json&#34;</span> | ||
| 5237 | </span></span><span style="display:flex;"><span> <span style="color:#00f">return</span> json.dumps(response) | ||
| 5238 | </span></span><span style="display:flex;"><span> | ||
| 5239 | </span></span><span style="display:flex;"><span><span style="color:#008000"># starting server on http://0.0.0.0:5000</span> | ||
| 5240 | </span></span><span style="display:flex;"><span><span style="color:#00f">if</span> __name__ == <span style="color:#a31515">&#34;__main__&#34;</span>: | ||
| 5241 | </span></span><span style="display:flex;"><span> bottle.run( | ||
| 5242 | </span></span><span style="display:flex;"><span> app = app, | ||
| 5243 | </span></span><span style="display:flex;"><span> host = <span style="color:#a31515">&#34;0.0.0.0&#34;</span>, | ||
| 5244 | </span></span><span style="display:flex;"><span> port = 5000, | ||
| 5245 | </span></span><span style="display:flex;"><span> debug = <span style="color:#00f">True</span>, | ||
| 5246 | </span></span><span style="display:flex;"><span> reloader = <span style="color:#00f">True</span>, | ||
| 5247 | </span></span><span style="display:flex;"><span> catchall = <span style="color:#00f">True</span>, | ||
| 5248 | </span></span><span style="display:flex;"><span> ) | ||
| 5249 | </span></span></code></pre><p>And now finally we can implement <code>frontend.html</code>. Create file with this name | ||
| 5250 | and copy code below. When you are done you can start web application. Steps for | ||
| 5251 | this part are listed below the code.</p> | ||
| 5252 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#00f">&lt;!DOCTYPE html&gt;</span> | ||
| 5253 | </span></span><span style="display:flex;"><span>&lt;html&gt; | ||
| 5254 | </span></span><span style="display:flex;"><span> | ||
| 5255 | </span></span><span style="display:flex;"><span> &lt;head&gt; | ||
| 5256 | </span></span><span style="display:flex;"><span> &lt;meta charset=<span style="color:#a31515">&#34;utf-8&#34;</span>&gt; | ||
| 5257 | </span></span><span style="display:flex;"><span> &lt;title&gt;Simple IOT application&lt;/title&gt; | ||
| 5258 | </span></span><span style="display:flex;"><span> &lt;/head&gt; | ||
| 5259 | </span></span><span style="display:flex;"><span> | ||
| 5260 | </span></span><span style="display:flex;"><span> &lt;body&gt; | ||
| 5261 | </span></span><span style="display:flex;"><span> | ||
| 5262 | </span></span><span style="display:flex;"><span> &lt;h1&gt;Simple IOT application&lt;/h1&gt; | ||
| 5263 | </span></span><span style="display:flex;"><span> | ||
| 5264 | </span></span><span style="display:flex;"><span> &lt;div class=<span style="color:#a31515">&#34;chart-placeholder&#34;</span>&gt; | ||
| 5265 | </span></span><span style="display:flex;"><span> &lt;div id=<span style="color:#a31515">&#34;chart&#34;</span>&gt;&lt;/div&gt; | ||
| 5266 | </span></span><span style="display:flex;"><span> &lt;/div&gt; | ||
| 5267 | </span></span><span style="display:flex;"><span> | ||
| 5268 | </span></span><span style="display:flex;"><span> <span style="color:#008000">&lt;!-- application main script --&gt;</span> | ||
| 5269 | </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; | ||
| 5270 | </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; | ||
| 5271 | </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; | ||
| 5272 | </span></span><span style="display:flex;"><span> &lt;script&gt; | ||
| 5273 | </span></span><span style="display:flex;"><span> <span style="color:#00f">function</span> fetch_and_render() { | ||
| 5274 | </span></span><span style="display:flex;"><span> d3.json(<span style="color:#a31515">&#34;/api&#34;</span>, <span style="color:#00f">function</span>(data) { | ||
| 5275 | </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>); | ||
| 5276 | </span></span><span style="display:flex;"><span> MG.data_graphic({ | ||
| 5277 | </span></span><span style="display:flex;"><span> data: data, | ||
| 5278 | </span></span><span style="display:flex;"><span> chart_type: <span style="color:#a31515">&#34;line&#34;</span>, | ||
| 5279 | </span></span><span style="display:flex;"><span> full_width: <span style="color:#00f">true</span>, | ||
| 5280 | </span></span><span style="display:flex;"><span> height: 270, | ||
| 5281 | </span></span><span style="display:flex;"><span> target: document.getElementById(<span style="color:#a31515">&#34;chart&#34;</span>), | ||
| 5282 | </span></span><span style="display:flex;"><span> x_accessor: <span style="color:#a31515">&#34;date&#34;</span>, | ||
| 5283 | </span></span><span style="display:flex;"><span> y_accessor: <span style="color:#a31515">&#34;value&#34;</span> | ||
| 5284 | </span></span><span style="display:flex;"><span> }); | ||
| 5285 | </span></span><span style="display:flex;"><span> }); | ||
| 5286 | </span></span><span style="display:flex;"><span> } | ||
| 5287 | </span></span><span style="display:flex;"><span> window.onload = <span style="color:#00f">function</span>() { | ||
| 5288 | </span></span><span style="display:flex;"><span> <span style="color:#008000">// initial call for rendering | ||
| 5289 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span> fetch_and_render(); | ||
| 5290 | </span></span><span style="display:flex;"><span> | ||
| 5291 | </span></span><span style="display:flex;"><span> <span style="color:#008000">// updates chart every 5 seconds | ||
| 5292 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span> setInterval(<span style="color:#00f">function</span>() { | ||
| 5293 | </span></span><span style="display:flex;"><span> fetch_and_render(); | ||
| 5294 | </span></span><span style="display:flex;"><span> }, 5000); | ||
| 5295 | </span></span><span style="display:flex;"><span> } | ||
| 5296 | </span></span><span style="display:flex;"><span> &lt;/script&gt; | ||
| 5297 | </span></span><span style="display:flex;"><span> | ||
| 5298 | </span></span><span style="display:flex;"><span> <span style="color:#008000">&lt;!-- application styles --&gt;</span> | ||
| 5299 | </span></span><span style="display:flex;"><span> &lt;style&gt; | ||
| 5300 | </span></span><span style="display:flex;"><span> body { | ||
| 5301 | </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>; | ||
| 5302 | </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>; | ||
| 5303 | </span></span><span style="display:flex;"><span> } | ||
| 5304 | </span></span><span style="display:flex;"><span> .<span style="color:#2b91af">chart-placeholder</span> { | ||
| 5305 | </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; | ||
| 5306 | </span></span><span style="display:flex;"><span> <span style="color:#00f">width</span>: 100<span style="color:#2b91af">%</span>; | ||
| 5307 | </span></span><span style="display:flex;"><span> <span style="color:#00f">user-select</span>: <span style="color:#00f">none</span>; | ||
| 5308 | </span></span><span style="display:flex;"><span> } | ||
| 5309 | </span></span><span style="display:flex;"><span> <span style="color:#008000">/* chart styles */</span> | ||
| 5310 | </span></span><span style="display:flex;"><span> .<span style="color:#2b91af">mg-line1-color</span> { | ||
| 5311 | </span></span><span style="display:flex;"><span> stroke: <span style="color:#00f">red</span>; | ||
| 5312 | </span></span><span style="display:flex;"><span> stroke-width: 2; | ||
| 5313 | </span></span><span style="display:flex;"><span> } | ||
| 5314 | </span></span><span style="display:flex;"><span> .<span style="color:#2b91af">mg-main-area</span>, .<span style="color:#2b91af">mg-main-line</span> { | ||
| 5315 | </span></span><span style="display:flex;"><span> fill: #fff; | ||
| 5316 | </span></span><span style="display:flex;"><span> } | ||
| 5317 | </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 { | ||
| 5318 | </span></span><span style="display:flex;"><span> stroke: #b3b2b2; | ||
| 5319 | </span></span><span style="display:flex;"><span> stroke-width: 1<span style="color:#2b91af">px</span>; | ||
| 5320 | </span></span><span style="display:flex;"><span> } | ||
| 5321 | </span></span><span style="display:flex;"><span> &lt;/style&gt; | ||
| 5322 | </span></span><span style="display:flex;"><span> | ||
| 5323 | </span></span><span style="display:flex;"><span> &lt;/body&gt; | ||
| 5324 | </span></span><span style="display:flex;"><span> | ||
| 5325 | </span></span><span style="display:flex;"><span>&lt;/html&gt; | ||
| 5326 | </span></span></code></pre><p>Now the folder structure should look like:</p> | ||
| 5327 | <p><em>simple-iot-app/</em></p> | ||
| 5328 | <ul> | ||
| 5329 | <li><em>webapp.py</em></li> | ||
| 5330 | <li><em>data.db</em></li> | ||
| 5331 | <li><em>frontend.html</em></li> | ||
| 5332 | </ul> | ||
| 5333 | <p>Ok, lets now start application and start feeding it data.</p> | ||
| 5334 | <ol> | ||
| 5335 | <li><code>python webapp.py</code></li> | ||
| 5336 | <li>connect Arduino MKR1000 to power source</li> | ||
| 5337 | <li>open browser and go to <code>http://0.0.0.0:5000</code></li> | ||
| 5338 | </ol> | ||
| 5339 | <p>If everything goes well you should be seeing new data-points rendered on chart | ||
| 5340 | every 5 seconds.</p> | ||
| 5341 | <p>If you navigate to <code>http://0.0.0.0:5000</code> you should see rendered chart as | ||
| 5342 | shown on picture below.</p> | ||
| 5343 | <figure> | ||
| 5344 | <img src="/posts/iot-application/iot-app-output.png" alt="Application output" /> | ||
| 5345 | </figure> | ||
| 5346 | <p>Complete application with all the code is available for | ||
| 5347 | <a href="/posts/iot-application/simple-iot-application.zip">download</a>.</p> | ||
| 5348 | <h2 id="conclusion">Conclusion</h2> | ||
| 5349 | <p>I hope this clarifies some aspects of IOT application development. Of course | ||
| 5350 | this is a minimal example and is far from what can be done in real life with | ||
| 5351 | some further dive into other technologies.</p> | ||
| 5352 | <p>If you would like to continue exploring IOT world here are some interesting | ||
| 5353 | resources for you to examine:</p> | ||
| 5354 | <ul> | ||
| 5355 | <li><a href="https://www.allaboutcircuits.com/projects/reading-sensors-with-an-arduino/">Reading Sensors with an Arduino</a></li> | ||
| 5356 | <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> | ||
| 5357 | <li><a href="https://www.html5rocks.com/en/tutorials/eventsource/basics/">Stream Updates with Server-Sent Events</a></li> | ||
| 5358 | <li><a href="http://www.tutorialspoint.com/internet_of_things/">Internet of Things (IoT) Tutorials</a></li> | ||
| 5359 | </ul> | ||
| 5360 | <p>Any comment or additional ideas are welcomed in comments below.</p> | ||
| 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 +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&#39;s or other web services.</description> | ||
| 5372 | <content:encoded><p>I have been profiling my software with KCachegrind for a long time now and I was | ||
| 5373 | missing this option when I am developing API's or other web services. I always | ||
| 5374 | knew that this is possible but never really took the time and dive into it.</p> | ||
| 5375 | <p>Before we begin there are some requirements. We will need to:</p> | ||
| 5376 | <ul> | ||
| 5377 | <li>implement <a href="https://docs.python.org/2/library/profile.html#module-cProfile">cProfile</a> into our web app,</li> | ||
| 5378 | <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> | ||
| 5379 | <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>.</li> | ||
| 5380 | </ul> | ||
| 5381 | <p>If you are using MacOS you should check out <a href="http://www.profilingviewer.com/">Profiling | ||
| 5382 | Viewer</a> or | ||
| 5383 | <a href="http://www.maccallgrind.com/">MacCallGrind</a>.</p> | ||
| 5384 | <figure> | ||
| 5385 | <img src="/posts/python-profiling/kcachegrind.png" alt="KCachegrind" /> | ||
| 5386 | </figure> | ||
| 5387 | <p>We will be dividing this post into two main categories:</p> | ||
| 5388 | <ul> | ||
| 5389 | <li>writing simple web-service,</li> | ||
| 5390 | <li>visualize profile of this web-service.</li> | ||
| 5391 | </ul> | ||
| 5392 | <h2 id="simple-web-service">Simple web-service</h2> | ||
| 5393 | <p>Let's use virtualenv so we won't pollute our base system. If you don't have | ||
| 5394 | virtualenv installed on your system you can install it with pip command.</p> | ||
| 5395 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># let&#39;s install virtualenv globally</span> | ||
| 5396 | </span></span><span style="display:flex;"><span>$ sudo pip install virtualenv | ||
| 5397 | </span></span><span style="display:flex;"><span> | ||
| 5398 | </span></span><span style="display:flex;"><span><span style="color:#008000"># let&#39;s also install pyprof2calltree globally</span> | ||
| 5399 | </span></span><span style="display:flex;"><span>$ sudo pip install pyprof2calltree | ||
| 5400 | </span></span><span style="display:flex;"><span> | ||
| 5401 | </span></span><span style="display:flex;"><span><span style="color:#008000"># now we create project</span> | ||
| 5402 | </span></span><span style="display:flex;"><span>$ mkdir demo-project | ||
| 5403 | </span></span><span style="display:flex;"><span>$ cd demo-project/ | ||
| 5404 | </span></span><span style="display:flex;"><span> | ||
| 5405 | </span></span><span style="display:flex;"><span><span style="color:#008000"># now let&#39;s create folder where we will store profiles</span> | ||
| 5406 | </span></span><span style="display:flex;"><span>$ mkdir prof | ||
| 5407 | </span></span><span style="display:flex;"><span> | ||
| 5408 | </span></span><span style="display:flex;"><span><span style="color:#008000"># now we create empty virtualenv in venv/ folder</span> | ||
| 5409 | </span></span><span style="display:flex;"><span>$ virtualenv --no-site-packages venv | ||
| 5410 | </span></span><span style="display:flex;"><span> | ||
| 5411 | </span></span><span style="display:flex;"><span><span style="color:#008000"># we now need to activate virtualenv</span> | ||
| 5412 | </span></span><span style="display:flex;"><span>$ source venv/bin/activate | ||
| 5413 | </span></span><span style="display:flex;"><span> | ||
| 5414 | </span></span><span style="display:flex;"><span><span style="color:#008000"># you can check if virtualenv was correctly initialized by</span> | ||
| 5415 | </span></span><span style="display:flex;"><span><span style="color:#008000"># checking where your python interpreter is located</span> | ||
| 5416 | </span></span><span style="display:flex;"><span><span style="color:#008000"># if command bellow points to your created directory and not some</span> | ||
| 5417 | </span></span><span style="display:flex;"><span><span style="color:#008000"># system dir like /usr/bin/python then everything is fine</span> | ||
| 5418 | </span></span><span style="display:flex;"><span>$ which python | ||
| 5419 | </span></span><span style="display:flex;"><span> | ||
| 5420 | </span></span><span style="display:flex;"><span><span style="color:#008000"># we can check now if all is good ➜ if ok couple of</span> | ||
| 5421 | </span></span><span style="display:flex;"><span><span style="color:#008000"># lines will be displayed</span> | ||
| 5422 | </span></span><span style="display:flex;"><span>$ pip freeze | ||
| 5423 | </span></span><span style="display:flex;"><span><span style="color:#008000"># appdirs==1.4.3</span> | ||
| 5424 | </span></span><span style="display:flex;"><span><span style="color:#008000"># packaging==16.8</span> | ||
| 5425 | </span></span><span style="display:flex;"><span><span style="color:#008000"># pyparsing==2.2.0</span> | ||
| 5426 | </span></span><span style="display:flex;"><span><span style="color:#008000"># six==1.10.0</span> | ||
| 5427 | </span></span><span style="display:flex;"><span> | ||
| 5428 | </span></span><span style="display:flex;"><span><span style="color:#008000"># now we are ready to install bottlepy ➜ web micro-framework</span> | ||
| 5429 | </span></span><span style="display:flex;"><span>$ pip install bottle | ||
| 5430 | </span></span><span style="display:flex;"><span> | ||
| 5431 | </span></span><span style="display:flex;"><span><span style="color:#008000"># you can deactivate virtualenv but you will then go</span> | ||
| 5432 | </span></span><span style="display:flex;"><span><span style="color:#008000"># under system domain ➜ for now don&#39;t deactivate</span> | ||
| 5433 | </span></span><span style="display:flex;"><span>$ deactivate | ||
| 5434 | </span></span></code></pre><p>We are now ready to write simple web service. Let's create file app.py and paste | ||
| 5435 | code bellow in this newly created file.</p> | ||
| 5436 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># -*- coding: utf-8 -*-</span> | ||
| 5437 | </span></span><span style="display:flex;"><span> | ||
| 5438 | </span></span><span style="display:flex;"><span><span style="color:#00f">import</span> bottle | ||
| 5439 | </span></span><span style="display:flex;"><span><span style="color:#00f">import</span> random | ||
| 5440 | </span></span><span style="display:flex;"><span><span style="color:#00f">import</span> cProfile | ||
| 5441 | </span></span><span style="display:flex;"><span> | ||
| 5442 | </span></span><span style="display:flex;"><span>app = bottle.Bottle() | ||
| 5443 | </span></span><span style="display:flex;"><span> | ||
| 5444 | </span></span><span style="display:flex;"><span><span style="color:#008000"># this function is a decorator and encapsulates function</span> | ||
| 5445 | </span></span><span style="display:flex;"><span><span style="color:#008000"># and performs profiling and then saves it to subfolder</span> | ||
| 5446 | </span></span><span style="display:flex;"><span><span style="color:#008000"># prof/function-name.prof</span> | ||
| 5447 | </span></span><span style="display:flex;"><span><span style="color:#008000"># in our example only awesome_random_number function will</span> | ||
| 5448 | </span></span><span style="display:flex;"><span><span style="color:#008000"># be profiled because it has do_cprofile defined</span> | ||
| 5449 | </span></span><span style="display:flex;"><span><span style="color:#00f">def</span> do_cprofile(func): | ||
| 5450 | </span></span><span style="display:flex;"><span> <span style="color:#00f">def</span> profiled_func(*args, **kwargs): | ||
| 5451 | </span></span><span style="display:flex;"><span> profile = cProfile.Profile() | ||
| 5452 | </span></span><span style="display:flex;"><span> <span style="color:#00f">try</span>: | ||
| 5453 | </span></span><span style="display:flex;"><span> profile.enable() | ||
| 5454 | </span></span><span style="display:flex;"><span> result = func(*args, **kwargs) | ||
| 5455 | </span></span><span style="display:flex;"><span> profile.disable() | ||
| 5456 | </span></span><span style="display:flex;"><span> <span style="color:#00f">return</span> result | ||
| 5457 | </span></span><span style="display:flex;"><span> <span style="color:#00f">finally</span>: | ||
| 5458 | </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>) | ||
| 5459 | </span></span><span style="display:flex;"><span> <span style="color:#00f">return</span> profiled_func | ||
| 5460 | </span></span><span style="display:flex;"><span> | ||
| 5461 | </span></span><span style="display:flex;"><span> | ||
| 5462 | </span></span><span style="display:flex;"><span><span style="color:#008000"># we use profiling over specific function with including</span> | ||
| 5463 | </span></span><span style="display:flex;"><span><span style="color:#008000"># @do_cprofile above function declaration</span> | ||
| 5464 | </span></span><span style="display:flex;"><span>@app.route(<span style="color:#a31515">&#34;/&#34;</span>) | ||
| 5465 | </span></span><span style="display:flex;"><span>@do_cprofile | ||
| 5466 | </span></span><span style="display:flex;"><span><span style="color:#00f">def</span> awesome_random_number(): | ||
| 5467 | </span></span><span style="display:flex;"><span> awesome_random_number = random.randint(0, 100) | ||
| 5468 | </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) | ||
| 5469 | </span></span><span style="display:flex;"><span> | ||
| 5470 | </span></span><span style="display:flex;"><span>@app.route(<span style="color:#a31515">&#34;/test&#34;</span>) | ||
| 5471 | </span></span><span style="display:flex;"><span><span style="color:#00f">def</span> test(): | ||
| 5472 | </span></span><span style="display:flex;"><span> <span style="color:#00f">return</span> <span style="color:#a31515">&#34;dummy test&#34;</span> | ||
| 5473 | </span></span><span style="display:flex;"><span> | ||
| 5474 | </span></span><span style="display:flex;"><span><span style="color:#00f">if</span> __name__ == <span style="color:#a31515">&#39;__main__&#39;</span>: | ||
| 5475 | </span></span><span style="display:flex;"><span> bottle.run( | ||
| 5476 | </span></span><span style="display:flex;"><span> app = app, | ||
| 5477 | </span></span><span style="display:flex;"><span> host = <span style="color:#a31515">&#34;0.0.0.0&#34;</span>, | ||
| 5478 | </span></span><span style="display:flex;"><span> port = 4000 | ||
| 5479 | </span></span><span style="display:flex;"><span> ) | ||
| 5480 | </span></span><span style="display:flex;"><span> | ||
| 5481 | </span></span><span style="display:flex;"><span><span style="color:#008000"># run with &#39;python app.py&#39;</span> | ||
| 5482 | </span></span><span style="display:flex;"><span><span style="color:#008000"># open browser &#39;http://0.0.0.0:4000&#39;</span> | ||
| 5483 | </span></span></code></pre><p>When browser hits awesome_random_number() function profile is created in prof/ | ||
| 5484 | subfolder.</p> | ||
| 5485 | <h2 id="visualize-profile">Visualize profile</h2> | ||
| 5486 | <p>Now let's create callgrind format from this cProfile output.</p> | ||
| 5487 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>$ cd prof/ | ||
| 5488 | </span></span><span style="display:flex;"><span>$ pyprof2calltree -i awesome_random_number.prof | ||
| 5489 | </span></span><span style="display:flex;"><span><span style="color:#008000"># this creates &#39;awesome_random_number.prof.log&#39; file in the same folder</span> | ||
| 5490 | </span></span></code></pre><p>This file can be opened with visualizing tools listed above. In this case we | ||
| 5491 | will be using Profilling Viewer under MacOS. You can open image in new tab. As | ||
| 5492 | you can see from this example there is hierarchy of execution order of your | ||
| 5493 | code.</p> | ||
| 5494 | <figure> | ||
| 5495 | <img src="/posts/python-profiling/profiling-viewer.png" alt="Profilling Viewer" /> | ||
| 5496 | </figure> | ||
| 5497 | <blockquote> | ||
| 5498 | <p>Make sure you convert output of the cProfile output every time you want to | ||
| 5499 | refresh and take a look at your possible optimizations because cProfile updates | ||
| 5500 | .prof file every time browser hits the function.</p> | ||
| 5501 | </blockquote> | ||
| 5502 | <p>This is just a simple example but when you are developing real-life applications | ||
| 5503 | this can be very illuminating, especially to see which parts of your code are | ||
| 5504 | bottlenecks and need to be optimized.</p> | ||
| 5505 | <h2 id="update-2017-04-22">Update 2017-04-22</h2> | ||
| 5506 | <p>Reddit user <a href="https://www.reddit.com/user/mvt">mvt</a> also recommended this awesome | ||
| 5507 | web based profile visualizer <a href="https://jiffyclub.github.io/snakeviz/">SnakeViz</a> | ||
| 5508 | that directly takes output from | ||
| 5509 | <a href="https://docs.python.org/2/library/profile.html#module-cProfile">cProfile</a> | ||
| 5510 | module.</p> | ||
| 5511 | <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> | ||
| 5512 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># let&#39;s install it globally as well</span> | ||
| 5513 | </span></span><span style="display:flex;"><span>$ sudo pip install snakeviz | ||
| 5514 | </span></span><span style="display:flex;"><span> | ||
| 5515 | </span></span><span style="display:flex;"><span><span style="color:#008000"># now let&#39;s visualize</span> | ||
| 5516 | </span></span><span style="display:flex;"><span>$ cd prof/ | ||
| 5517 | </span></span><span style="display:flex;"><span>$ snakeviz awesome_random_number.prof | ||
| 5518 | </span></span><span style="display:flex;"><span><span style="color:#008000"># this automatically opens browser window and</span> | ||
| 5519 | </span></span><span style="display:flex;"><span><span style="color:#008000"># shows visualized profile</span> | ||
| 5520 | </span></span></code></pre><figure> | ||
| 5521 | <img src="/posts/python-profiling/snakeviz.png" alt="SnakeViz" /> | ||
| 5522 | </figure> | ||
| 5523 | <p>Reddit user <a href="https://www.reddit.com/user/ccharles">ccharles</a> suggested a better | ||
| 5524 | way for installing pip software by targeting user level instead of using sudo.</p> | ||
| 5525 | <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> | ||
| 5526 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># now we need to add this path to our $PATH variable</span> | ||
| 5527 | </span></span><span style="display:flex;"><span><span style="color:#008000"># we do this my adding this line at the end of your</span> | ||
| 5528 | </span></span><span style="display:flex;"><span><span style="color:#008000"># ~/.bashrc file</span> | ||
| 5529 | </span></span><span style="display:flex;"><span>PATH=$PATH:$HOME/.local/bin/ | ||
| 5530 | </span></span><span style="display:flex;"><span> | ||
| 5531 | </span></span><span style="display:flex;"><span><span style="color:#008000"># in order to use this new configuration you can close</span> | ||
| 5532 | </span></span><span style="display:flex;"><span><span style="color:#008000"># and reopen terminal or reload .bashrc file</span> | ||
| 5533 | </span></span><span style="display:flex;"><span>$ source ~/.bashrc | ||
| 5534 | </span></span><span style="display:flex;"><span> | ||
| 5535 | </span></span><span style="display:flex;"><span><span style="color:#008000"># now let&#39;s test if new directory is present in $PATH</span> | ||
| 5536 | </span></span><span style="display:flex;"><span>$ echo $PATH | ||
| 5537 | </span></span><span style="display:flex;"><span> | ||
| 5538 | </span></span><span style="display:flex;"><span><span style="color:#008000"># now we can install on user level by adding --user</span> | ||
| 5539 | </span></span><span style="display:flex;"><span><span style="color:#008000"># without use of sudo</span> | ||
| 5540 | </span></span><span style="display:flex;"><span>$ pip install snakeviz --user | ||
| 5541 | </span></span></code></pre><p>Or as suggested by <a href="https://www.reddit.com/user/mvt">mvt</a> you can | ||
| 5542 | use <a href="https://github.com/mitsuhiko/pipsi">pipsi</a>.</p> | ||
| 5543 | </content:encoded> | ||
| 5544 | </item> | ||
| 5545 | |||
| 5546 | |||
| 5547 | |||
| 5548 | <item> | ||
| 5549 | <title>What I'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 +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><p>For the past year and half I have been developing native advertising server that | ||
| 5555 | contextually matches ads and displays them in different template forms on | ||
| 5556 | variety of websites. This project grew from serving thousands of ads per day to | ||
| 5557 | millions.</p> | ||
| 5558 | <p>The system is made from couple of core components:</p> | ||
| 5559 | <ul> | ||
| 5560 | <li>API for serving ads,</li> | ||
| 5561 | <li>Utils - cronjobs and queue management tools,</li> | ||
| 5562 | <li>Dashboard UI.</li> | ||
| 5563 | </ul> | ||
| 5564 | <p>Initial release was using <a href="https://www.mongodb.com/">MongoDB</a> for full-text | ||
| 5565 | search but was later replaced by <a href="https://www.elastic.co/">Elasticsearch</a> for | ||
| 5566 | better CPU utilization and better search performance. This provided us with many | ||
| 5567 | amazing functionalities of <a href="https://www.elastic.co/">Elasticsearch</a>. You should | ||
| 5568 | check it out if you do any search related operations.</p> | ||
| 5569 | <p>Because the premise of the server is to provide native ad experience, they are | ||
| 5570 | rendered on the client side via simple templating engine. This ensures that ads | ||
| 5571 | can be displayed number of different ways based on the visual style of the | ||
| 5572 | page. And this makes JavaScript client library quite complex.</p> | ||
| 5573 | <p>So now that you know basic information about the product lets get into the | ||
| 5574 | lessons we learned.</p> | ||
| 5575 | <h2 id="aggregate-everything">Aggregate everything</h2> | ||
| 5576 | <p>After beta version was released everything (impressions, clicks, etc) was | ||
| 5577 | written in nanosecond resolution in the database. At that time we were using | ||
| 5578 | <a href="https://www.postgresql.org/">PostgreSQL</a> and database quickly grew way above | ||
| 5579 | 200GB in disk space. And that was problematic. Statistics took disturbingly long | ||
| 5580 | time to aggregate. Also using indexes on stats table in database was no help | ||
| 5581 | after we reached 500 million datapoints.</p> | ||
| 5582 | <blockquote> | ||
| 5583 | <p>There is a marketing product information and there is real life experience. | ||
| 5584 | And the tend to be quite the opposite.</p> | ||
| 5585 | </blockquote> | ||
| 5586 | <p>This was the reason that now everything is aggregated on daily basis and this | ||
| 5587 | data is then fed to Elastic in form of daily summary. With this we achieved we | ||
| 5588 | can now track many more dimensions such as zone, channel and platform | ||
| 5589 | information. And with this information we can now adapt occurrences of ads on | ||
| 5590 | specific places more precisely.</p> | ||
| 5591 | <p>We have also adapted <a href="https://redis.io/">Redis</a> as a full-time citizen in our | ||
| 5592 | stack. Because Redis also stores information on a local disk we have some sort | ||
| 5593 | of backup if server would accidentally suffer some failure.</p> | ||
| 5594 | <p>All the real-time statistics for ad serving and redirecting is presented as | ||
| 5595 | counters in Redis instance and daily extracted and pushed to Elastic.</p> | ||
| 5596 | <h2 id="measure-everything">Measure everything</h2> | ||
| 5597 | <p>The thing about software is that we really don't know how well it is performing | ||
| 5598 | under load until such load is presented. When testing locally everything is fine | ||
| 5599 | but when on production things tend to fall apart.</p> | ||
| 5600 | <p>As a solution for this we are measuring everything we can. Function execution | ||
| 5601 | time (by encapsulating functions with timers), server performance (cpu, memory, | ||
| 5602 | disk, etc), Nginx and <a href="https://uwsgi-docs.readthedocs.io/">uWSGI</a> performance. | ||
| 5603 | We sacrifice a bit of performance for the sake of this information. And we store | ||
| 5604 | all this information for later analysis.</p> | ||
| 5605 | <p><strong>Example of function execution time</strong></p> | ||
| 5606 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>{ | ||
| 5607 | </span></span><span style="display:flex;"><span> &#34;get_final_filtered_ads&#34;: { | ||
| 5608 | </span></span><span style="display:flex;"><span> &#34;counter&#34;: 1931250, | ||
| 5609 | </span></span><span style="display:flex;"><span> &#34;avg&#34;: 0.0066143431, | ||
| 5610 | </span></span><span style="display:flex;"><span> &#34;elapsed&#34;: 12773.9500310003 | ||
| 5611 | </span></span><span style="display:flex;"><span> }, | ||
| 5612 | </span></span><span style="display:flex;"><span> &#34;store_keywords_statistics&#34;: { | ||
| 5613 | </span></span><span style="display:flex;"><span> &#34;counter&#34;: 1931011, | ||
| 5614 | </span></span><span style="display:flex;"><span> &#34;avg&#34;: 0.0004605267, | ||
| 5615 | </span></span><span style="display:flex;"><span> &#34;elapsed&#34;: 889.2821669996 | ||
| 5616 | </span></span><span style="display:flex;"><span> }, | ||
| 5617 | </span></span><span style="display:flex;"><span> &#34;match_by_context&#34;: { | ||
| 5618 | </span></span><span style="display:flex;"><span> &#34;counter&#34;: 1931011, | ||
| 5619 | </span></span><span style="display:flex;"><span> &#34;avg&#34;: 0.0055960716, | ||
| 5620 | </span></span><span style="display:flex;"><span> &#34;elapsed&#34;: 10806.0758889999 | ||
| 5621 | </span></span><span style="display:flex;"><span> }, | ||
| 5622 | </span></span><span style="display:flex;"><span> &#34;match_by_high_performance&#34;: { | ||
| 5623 | </span></span><span style="display:flex;"><span> &#34;counter&#34;: 262, | ||
| 5624 | </span></span><span style="display:flex;"><span> &#34;avg&#34;: 0.0152770229, | ||
| 5625 | </span></span><span style="display:flex;"><span> &#34;elapsed&#34;: 4.00258 | ||
| 5626 | </span></span><span style="display:flex;"><span> }, | ||
| 5627 | </span></span><span style="display:flex;"><span> &#34;store_impression_stats&#34;: { | ||
| 5628 | </span></span><span style="display:flex;"><span> &#34;counter&#34;: 1931250, | ||
| 5629 | </span></span><span style="display:flex;"><span> &#34;avg&#34;: 0.0006189991, | ||
| 5630 | </span></span><span style="display:flex;"><span> &#34;elapsed&#34;: 1195.4419869999 | ||
| 5631 | </span></span><span style="display:flex;"><span> } | ||
| 5632 | </span></span><span style="display:flex;"><span>} | ||
| 5633 | </span></span></code></pre><p>We have also started profiling with <a href="https://pymotw.com/2/profile/">cProfile</a> | ||
| 5634 | and then visualizing with <a href="http://kcachegrind.sourceforge.net/">KCachegrind</a>. | ||
| 5635 | This provides much more detailed look into code execution.</p> | ||
| 5636 | <h2 id="cache-control-is-your-friend">Cache control is your friend</h2> | ||
| 5637 | <p>Because we use Javascript library for rendering ads we rely on this script | ||
| 5638 | extensively and when in need we need to be able to change behavior of the script | ||
| 5639 | quickly.</p> | ||
| 5640 | <p>In our case we can not simply replace javascript url in html code. It usually | ||
| 5641 | takes 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 | ||
| 5643 | and time consuming. There is a limitation of how much you can test locally.</p> | ||
| 5644 | <p>We are now in the process of integrating <a href="https://www.google.com/analytics/tag-manager/">Google Tag | ||
| 5645 | Manager</a> but couple of websites | ||
| 5646 | are developed on ASP.net platform that have some problems with tag manager. With | ||
| 5647 | a solution below we are certain that we are serving latest version of the | ||
| 5648 | script.</p> | ||
| 5649 | <p>And it only takes one mistake and users have the script cached and in case of | ||
| 5650 | caching it for 1 year you probably know where the problem is.</p> | ||
| 5651 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># nginx ➜ /etc/nginx/sites-available/default | ||
| 5652 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span><span style="color:#00f">location</span> <span style="color:#a31515">/static/</span> { | ||
| 5653 | </span></span><span style="display:flex;"><span> <span style="color:#00f">alias</span> <span style="color:#a31515">/path-to-static-content/</span>; | ||
| 5654 | </span></span><span style="display:flex;"><span> <span style="color:#00f">autoindex</span> off; | ||
| 5655 | </span></span><span style="display:flex;"><span> <span style="color:#00f">charset</span> <span style="color:#a31515">utf-8</span>; | ||
| 5656 | </span></span><span style="display:flex;"><span> <span style="color:#00f">gzip</span> on; | ||
| 5657 | </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>; | ||
| 5658 | </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>$ { | ||
| 5659 | </span></span><span style="display:flex;"><span> <span style="color:#00f">expires</span> <span style="color:#a31515">1y</span>; | ||
| 5660 | </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>; | ||
| 5661 | </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>; | ||
| 5662 | </span></span><span style="display:flex;"><span> } | ||
| 5663 | </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>$ { | ||
| 5664 | </span></span><span style="display:flex;"><span> <span style="color:#00f">expires</span> <span style="color:#a31515">3600s</span>; | ||
| 5665 | </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>; | ||
| 5666 | </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>; | ||
| 5667 | </span></span><span style="display:flex;"><span> } | ||
| 5668 | </span></span><span style="display:flex;"><span>} | ||
| 5669 | </span></span></code></pre><p>Also be careful when redirecting to url in your python code. We noticed that if | ||
| 5670 | we didn't precisely setup cache control and expire headers in response we didn't | ||
| 5671 | get the request on the server and therefore couldn't measure clicks. So when | ||
| 5672 | redirecting do as follows and there will be no problems.</p> | ||
| 5673 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># python ➜ bottlepy web micro-framework</span> | ||
| 5674 | </span></span><span style="display:flex;"><span>response = bottle.HTTPResponse(status=302) | ||
| 5675 | </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>) | ||
| 5676 | </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>) | ||
| 5677 | </span></span><span style="display:flex;"><span>response.set_header(<span style="color:#a31515">&#34;Location&#34;</span>, url) | ||
| 5678 | </span></span><span style="display:flex;"><span><span style="color:#00f">return</span> response | ||
| 5679 | </span></span></code></pre><blockquote> | ||
| 5680 | <p>Cache control in browsers is quite aggressive and you need to be precise to | ||
| 5681 | avoid future problems. We learned that lesson the hard way.</p> | ||
| 5682 | </blockquote> | ||
| 5683 | <h2 id="learn-nginx">Learn NGINX</h2> | ||
| 5684 | <p>When deciding on a web server we went with Nginx as a reverse proxy for our | ||
| 5685 | applications. We adapted micro-service oriented architecture early in the | ||
| 5686 | project to ensure when we scale we can easily add additional servers to our | ||
| 5687 | cluster. And Nginx was crucial to perform load balancing and static content | ||
| 5688 | delivery.</p> | ||
| 5689 | <p>At first our config file was quite simple and later grew larger. After patching | ||
| 5690 | and adding new settings I sat down and learned more about the guts of Nginx. | ||
| 5691 | This proved to be very useful and we were able to squeeze much more out of our | ||
| 5692 | setup. So I advise you to take your time and read through the | ||
| 5693 | <a href="https://nginx.org/en/docs/">documentation</a>. This saved us a lot of headache. | ||
| 5694 | Googling for solutions only goes so far.</p> | ||
| 5695 | <h2 id="use-redismemcached">Use Redis/Memcached</h2> | ||
| 5696 | <p>As explained above we are using caching basically for everything. It is the | ||
| 5697 | corner stone of our services. At first we were very careful about the quantity | ||
| 5698 | of things we stored in <a href="https://redis.io/">Redis</a>. But we later found out that | ||
| 5699 | the memory footprint is very low even when storing large amount of data in it.</p> | ||
| 5700 | <p>So we gradually increased our usage to caching whole HTML outputs of dashboard. | ||
| 5701 | This improved our performance in order of magnitude. And by using native TTL | ||
| 5702 | support this goes hand in hand with our needs.</p> | ||
| 5703 | <p>The reason why we choose <a href="https://redis.io/">Redis</a> over | ||
| 5704 | <a href="https://memcached.org/">Memcached</a> was the nature of scalability of Redis out | ||
| 5705 | of the box. But all this can be achieved with Memcached.</p> | ||
| 5706 | <h2 id="conclusion">Conclusion</h2> | ||
| 5707 | <p>There are a lot more details that could have been written and every single topic | ||
| 5708 | in here deserves it's own post but you probably got the idea about the problems | ||
| 5709 | we faced.</p> | ||
| 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 +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><p>Many posts have been written regarding profiling in Golang and I haven’t found | ||
| 5722 | proper tutorial regarding this. Almost all of them are missing some part of | ||
| 5723 | important information and it gets pretty frustrating when you have a deadline | ||
| 5724 | and are not finding simple distilled solution.</p> | ||
| 5725 | <p>Nevertheless, after searching and experimenting I have found a solution that | ||
| 5726 | works for me and probably should also for you.</p> | ||
| 5727 | <h2 id="where-are-my-pprof-files">Where are my pprof files?</h2> | ||
| 5728 | <p>By default pprof files are generated in /tmp/ folder. You can override folder | ||
| 5729 | where this files are generated programmatically in your golang code as we will | ||
| 5730 | see below in example.</p> | ||
| 5731 | <h2 id="why-is-my-cpu-profile-empty">Why is my CPU profile empty?</h2> | ||
| 5732 | <p>I have found out that sometimes CPU profile is empty because program was not | ||
| 5733 | executing long enough. Programs, that execute too quickly don’t produce pprof | ||
| 5734 | file in my cases. Well, file is generated but only contains 4KB of information.</p> | ||
| 5735 | <h2 id="profiling">Profiling</h2> | ||
| 5736 | <p>As you can see from examples we are executing dummy_benchmark functions to | ||
| 5737 | ensure some sort of execution. Memory profiling can be done without such a | ||
| 5738 | “complex” function. But CPU profiling needs it.</p> | ||
| 5739 | <p>Both memory and CPU profiling examples are almost the same. Only parameters in | ||
| 5740 | main function when calling profile.Start are different. When we set | ||
| 5741 | profile.ProfilePath(“.”) we tell profiler to store pprof files in the same | ||
| 5742 | folder as our program.</p> | ||
| 5743 | <h3 id="memory-profiling">Memory profiling</h3> | ||
| 5744 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#00f">package</span> main | ||
| 5745 | </span></span><span style="display:flex;"><span> | ||
| 5746 | </span></span><span style="display:flex;"><span><span style="color:#00f">import</span> ( | ||
| 5747 | </span></span><span style="display:flex;"><span> <span style="color:#a31515">&#34;fmt&#34;</span> | ||
| 5748 | </span></span><span style="display:flex;"><span> <span style="color:#a31515">&#34;time&#34;</span> | ||
| 5749 | </span></span><span style="display:flex;"><span> <span style="color:#a31515">&#34;github.com/pkg/profile&#34;</span> | ||
| 5750 | </span></span><span style="display:flex;"><span>) | ||
| 5751 | </span></span><span style="display:flex;"><span> | ||
| 5752 | </span></span><span style="display:flex;"><span><span style="color:#00f">func</span> dummy_benchmark() { | ||
| 5753 | </span></span><span style="display:flex;"><span> | ||
| 5754 | </span></span><span style="display:flex;"><span> fmt.Println(<span style="color:#a31515">&#34;first set ...&#34;</span>) | ||
| 5755 | </span></span><span style="display:flex;"><span> <span style="color:#00f">for</span> i := 0; i &lt; 918231333; i++ { | ||
| 5756 | </span></span><span style="display:flex;"><span> i *= 2 | ||
| 5757 | </span></span><span style="display:flex;"><span> i /= 2 | ||
| 5758 | </span></span><span style="display:flex;"><span> } | ||
| 5759 | </span></span><span style="display:flex;"><span> | ||
| 5760 | </span></span><span style="display:flex;"><span> &lt;-time.After(time.Second*3) | ||
| 5761 | </span></span><span style="display:flex;"><span> | ||
| 5762 | </span></span><span style="display:flex;"><span> fmt.Println(<span style="color:#a31515">&#34;sencond set ...&#34;</span>) | ||
| 5763 | </span></span><span style="display:flex;"><span> <span style="color:#00f">for</span> i := 0; i &lt; 9182312232; i++ { | ||
| 5764 | </span></span><span style="display:flex;"><span> i *= 2 | ||
| 5765 | </span></span><span style="display:flex;"><span> i /= 2 | ||
| 5766 | </span></span><span style="display:flex;"><span> } | ||
| 5767 | </span></span><span style="display:flex;"><span>} | ||
| 5768 | </span></span><span style="display:flex;"><span> | ||
| 5769 | </span></span><span style="display:flex;"><span><span style="color:#00f">func</span> main() { | ||
| 5770 | </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() | ||
| 5771 | </span></span><span style="display:flex;"><span> dummy_benchmark() | ||
| 5772 | </span></span><span style="display:flex;"><span>} | ||
| 5773 | </span></span></code></pre><h3 id="cpu-profiling">CPU profiling</h3> | ||
| 5774 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#00f">package</span> main | ||
| 5775 | </span></span><span style="display:flex;"><span> | ||
| 5776 | </span></span><span style="display:flex;"><span><span style="color:#00f">import</span> ( | ||
| 5777 | </span></span><span style="display:flex;"><span> <span style="color:#a31515">&#34;fmt&#34;</span> | ||
| 5778 | </span></span><span style="display:flex;"><span> <span style="color:#a31515">&#34;time&#34;</span> | ||
| 5779 | </span></span><span style="display:flex;"><span> <span style="color:#a31515">&#34;github.com/pkg/profile&#34;</span> | ||
| 5780 | </span></span><span style="display:flex;"><span>) | ||
| 5781 | </span></span><span style="display:flex;"><span> | ||
| 5782 | </span></span><span style="display:flex;"><span><span style="color:#00f">func</span> dummy_benchmark() { | ||
| 5783 | </span></span><span style="display:flex;"><span> | ||
| 5784 | </span></span><span style="display:flex;"><span> fmt.Println(<span style="color:#a31515">&#34;first set ...&#34;</span>) | ||
| 5785 | </span></span><span style="display:flex;"><span> <span style="color:#00f">for</span> i := 0; i &lt; 918231333; i++ { | ||
| 5786 | </span></span><span style="display:flex;"><span> i *= 2 | ||
| 5787 | </span></span><span style="display:flex;"><span> i /= 2 | ||
| 5788 | </span></span><span style="display:flex;"><span> } | ||
| 5789 | </span></span><span style="display:flex;"><span> | ||
| 5790 | </span></span><span style="display:flex;"><span> &lt;-time.After(time.Second*3) | ||
| 5791 | </span></span><span style="display:flex;"><span> | ||
| 5792 | </span></span><span style="display:flex;"><span> fmt.Println(<span style="color:#a31515">&#34;sencond set ...&#34;</span>) | ||
| 5793 | </span></span><span style="display:flex;"><span> <span style="color:#00f">for</span> i := 0; i &lt; 9182312232; i++ { | ||
| 5794 | </span></span><span style="display:flex;"><span> i *= 2 | ||
| 5795 | </span></span><span style="display:flex;"><span> i /= 2 | ||
| 5796 | </span></span><span style="display:flex;"><span> } | ||
| 5797 | </span></span><span style="display:flex;"><span>} | ||
| 5798 | </span></span><span style="display:flex;"><span> | ||
| 5799 | </span></span><span style="display:flex;"><span><span style="color:#00f">func</span> main() { | ||
| 5800 | </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() | ||
| 5801 | </span></span><span style="display:flex;"><span> dummy_benchmark() | ||
| 5802 | </span></span><span style="display:flex;"><span>} | ||
| 5803 | </span></span></code></pre><h3 id="generating-profiling-reports">Generating profiling reports</h3> | ||
| 5804 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># memory profiling</span> | ||
| 5805 | </span></span><span style="display:flex;"><span>go build mem.go | ||
| 5806 | </span></span><span style="display:flex;"><span>./mem | ||
| 5807 | </span></span><span style="display:flex;"><span>go tool pprof -pdf ./mem mem.pprof &gt; mem.pdf | ||
| 5808 | </span></span><span style="display:flex;"><span> | ||
| 5809 | </span></span><span style="display:flex;"><span><span style="color:#008000"># cpu profiling</span> | ||
| 5810 | </span></span><span style="display:flex;"><span>go build cpu.go | ||
| 5811 | </span></span><span style="display:flex;"><span>./cpu | ||
| 5812 | </span></span><span style="display:flex;"><span>go tool pprof -pdf ./cpu cpu.pprof &gt; cpu.pdf | ||
| 5813 | </span></span></code></pre><p>This will generate PDF document with visualized profile.</p> | ||
| 5814 | <ul> | ||
| 5815 | <li><a href="/posts/go-profiling/golang-profiling-mem.pdf">Memory PDF profile example</a></li> | ||
| 5816 | <li><a href="/posts/go-profiling/golang-profiling-cpu.pdf">CPU PDF profile example</a></li> | ||
| 5817 | </ul> | ||
| 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 +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><p>Over the years I had the privilege to work on some very excited projects both in | ||
| 5830 | software development field and also in electronics field and every experience | ||
| 5831 | taught me some invaluable lessons about how NOT TO approach development. And | ||
| 5832 | through this post I will try to point out some absurd, outdated techniques I | ||
| 5833 | find the most annoying and damaging during a development cycle. There will be | ||
| 5834 | swearing because this topic really gets on my nerves and I never coherently | ||
| 5835 | tried to explain them in writing. So if I get heated up, please bear with me.</p> | ||
| 5836 | <p>As new methods of project management are emerging, underlying processes still | ||
| 5837 | stay old and outdated. This is mainly because we as people are unable to | ||
| 5838 | completely shift away from these approaches.</p> | ||
| 5839 | <p>I was always struggling with communication, and many times that cost me a | ||
| 5840 | relationship or two because I was not on the ball all the time. Through every | ||
| 5841 | experience, I became more convinced that I am the problem and never ever doubted | ||
| 5842 | that the problem may be that communication never evolved a single step from | ||
| 5843 | emails. And if you think for a second, not many things have changed around this | ||
| 5844 | topic. We just have different representations of email (message boards, chats, | ||
| 5845 | project management tools). And I believe this is the real issue we are facing | ||
| 5846 | now.</p> | ||
| 5847 | <p>There are many articles written about hyper connectivity and the effects that | ||
| 5848 | are a direct result of it. But mainstream does nothing towards it. We are just | ||
| 5849 | putting out fires, and we do nothing to prevent it. I am certain this will be a | ||
| 5850 | major source of grief in coming years. And what we all can do to avoid this is | ||
| 5851 | to change our mindset and experiment on our communication skills, development | ||
| 5852 | approaches. We need to maximize possible output that a person can give. And to | ||
| 5853 | achieve this we need to listen to them, encourage them. I know that not | ||
| 5854 | everybody is a naturally born leader, but with enough practice and encouragement | ||
| 5855 | they also can become active participants in leadership.</p> | ||
| 5856 | <p>There are many talks now about methodologies such as Scrum, Kanban, Cleanroom | ||
| 5857 | and they all fucking piss me of :). These are all boxes that imprison people and | ||
| 5858 | take away their freedom of thought. This is a straightforward mindfuck / | ||
| 5859 | amputation of creativity.</p> | ||
| 5860 | <p>Let me list a couple of things that I find really destructive and bad for a | ||
| 5861 | project and in a long run company.</p> | ||
| 5862 | <h2 id="ping-emails">Ping emails</h2> | ||
| 5863 | <p>Ping emails are emails you have to write as soon as you receive an email. Its | ||
| 5864 | sole purpose is to inform the sender that you received their email, and you are | ||
| 5865 | working on it. Its result is only to calm down the sender that their task is | ||
| 5866 | being dealt with. It’s intent basically is, I did my job by sending you this | ||
| 5867 | email, so I am on clear grounds. I categorize this email as fuck you email. | ||
| 5868 | This is one of the most irritating types of emails I need to write. This is the | ||
| 5869 | ultimate control freak show you can experience, and it gives the sender a false | ||
| 5870 | feeling of control. Newsflash: We do not live in 1982 where there was a | ||
| 5871 | possibility that email never reached the destination. I really hate this from | ||
| 5872 | the bottom of my heart.</p> | ||
| 5873 | <p>They should be like: “Yes, I am fucking alive, and I am at your service my | ||
| 5874 | leash!”. I guess if I would reply like this, I wouldn’t have to write any more | ||
| 5875 | of this kind of messages.</p> | ||
| 5876 | <h2 id="everybody-is-a-project-manager">Everybody is a project manager</h2> | ||
| 5877 | <p>Well, this is a tough one. I noticed that as soon as you let people to give | ||
| 5878 | their suggestions, you are basically screwed. There is a truth in the saying: | ||
| 5879 | “Give low expectations and deliver little more than you promised.”.</p> | ||
| 5880 | <p>People tend to take a role of a manager as soon as they are presented with an | ||
| 5881 | opportunity. And by getting angry at them, you only provoke yourself. They are | ||
| 5882 | not at fault. You just need to tell them they are only giving suggestions and | ||
| 5883 | not tasks at the beginning and everything will be alright. But if you give them | ||
| 5884 | a feeling that they are in control, you will have immense problems explaining | ||
| 5885 | why their features are not in current release.</p> | ||
| 5886 | <p>Project mission must be always leading project requirements and any deviation | ||
| 5887 | from it will result in major project butchering. And by this, I mean that the | ||
| 5888 | project will get its own path, and you will be left with half done software that | ||
| 5889 | helps nobody. Clear mission goals and clean execution will allow you to develop | ||
| 5890 | software will clear intent.</p> | ||
| 5891 | <h2 id="we-are-never-wrong">We are never wrong</h2> | ||
| 5892 | <p>I find this type of arrogance the worst. We must always conduct ourselves that | ||
| 5893 | we are infallible and cannot make mistakes. As soon as a procedure or process is | ||
| 5894 | established, there is no room for changes or improvements. This is the most | ||
| 5895 | idiotic thing someone can say of think. I think that processes need to involve | ||
| 5896 | and change over time. This is imperative and need to have in your organization | ||
| 5897 | if you want to improve and develop company. We all need to grow balls and change | ||
| 5898 | everything in order to adapt to current situations. Being a prisoner of | ||
| 5899 | predefined processes kills creativity.</p> | ||
| 5900 | <p>I am constantly trying new software for project managing and communication. I | ||
| 5901 | believe every team has its own dynamic, and it needs to be discovered | ||
| 5902 | organically and naturally through many experiments. By putting the team in a | ||
| 5903 | box, you are amputating their creativity and therefore minimizing their | ||
| 5904 | potential. But if you talk to an executive, you will mainly find archetypical | ||
| 5905 | thinking and a strong need to compartmentalize everything from business | ||
| 5906 | processes to resource management. And this type of management that often | ||
| 5907 | displays micromanagement techniques only works for short periods (couple of | ||
| 5908 | years) and then employees either leave the company or become basically retarded | ||
| 5909 | drones on autopilot.</p> | ||
| 5910 | <h2 id="micromanaging">Micromanaging</h2> | ||
| 5911 | <p>This basically implies that everybody on the team is an idiot who needs to have | ||
| 5912 | a to-do list that they cannot write themselves. How about spoon-feeding the team | ||
| 5913 | at launch because besides the team leader, everybody must be a retarded idiot at | ||
| 5914 | best?</p> | ||
| 5915 | <p>I prefer milestones as they give developers much more freedom and creativity in | ||
| 5916 | developing and not waste their time checking some bizarre to-do list that was | ||
| 5917 | not even thought through. Projects constantly change throughout the development | ||
| 5918 | cycle, and all you are left at the end is a list of unchecked tasks and the | ||
| 5919 | wrath of management why they are not completed. Best WTF moment!</p> | ||
| 5920 | <h2 id="human-contact--no-need-for-it">Human contact — no need for it!</h2> | ||
| 5921 | <p>We are vigorously trying to eliminate physical contact by replacing short | ||
| 5922 | meetings with software, with no regards that we are not machines. Many times a | ||
| 5923 | simple 5-min meeting at morning can solve most of the problems. In rapid | ||
| 5924 | development, short bursts of man to man communication is possibly the best way | ||
| 5925 | to go.</p> | ||
| 5926 | <p>We now have all this software available, and all what we get out of it is a | ||
| 5927 | giant clusterfuck. An obstacle and not a solution. So, why we still use them?</p> | ||
| 5928 | <h2 id="mvp-is-killing-innovation">MVP is killing innovation</h2> | ||
| 5929 | <p>Many will disagree with me on this one, but I stand strong by this statement. | ||
| 5930 | What I noticed in my experience that all this buzz words around us only mislead | ||
| 5931 | and capture us in a circle of solving issues that already have a solution, but | ||
| 5932 | we are unable to see it without using some fancy word for it.</p> | ||
| 5933 | <p>The toughest thing to do for a developer is to minimize requirements. Well, this | ||
| 5934 | is though only for bad developers. Yes, I said it. There are many types of | ||
| 5935 | developers out there. And those unable to minimize feature scope are the ones | ||
| 5936 | you don’t need on your team. Their only goal is to solve problems that exist | ||
| 5937 | only in their heads. And then you have to argue with them, and waste energy on | ||
| 5938 | them, instead of developing your awesome product. They are a cancer and I | ||
| 5939 | suggest you cut them off.</p> | ||
| 5940 | <p>MVP as an idea is great, but sadly people don’t understand underlying | ||
| 5941 | philosophy, and they spent too much time focusing and fixating on something that | ||
| 5942 | every sane person with normal IQ will understand without some made up | ||
| 5943 | acronym. And the result is a lot of talking and barely no execution.</p> | ||
| 5944 | <p>Well, MVP is not directly killing innovation, but stupid people do when they try | ||
| 5945 | to understand it.</p> | ||
| 5946 | <h2 id="pressure-wasteland">Pressure wasteland</h2> | ||
| 5947 | <p>You must never allow to be pressured into confirming a deadline if you are not | ||
| 5948 | confident. We often feel a need that we are in service of others, which is true | ||
| 5949 | to some extent. But it is also true that others are in service to us to some | ||
| 5950 | extent. And we forget this all the time. We are all pressured all the time to | ||
| 5951 | make decisions just to calm other people down. And when they leave your office | ||
| 5952 | you experience WTF moment :) How the hell did they manage to fuck me up again?</p> | ||
| 5953 | <p>People need to realize that the more pressure you put on somebody, the less they | ||
| 5954 | will be able to do. So 5-min update email requests will only resolve in mental | ||
| 5955 | breakdown and inability to work that day. Constant poking is probably the only | ||
| 5956 | thing I lose my mind instantly. For all you that are doing this: “Stop bothering | ||
| 5957 | us with your insecurities and let us do our job. We will do it quicker and | ||
| 5958 | better without you breathing down our necks.”</p> | ||
| 5959 | <p>If this happens to me, I end up with no energy at the end. Don’t you get it? | ||
| 5960 | You will get much more from and out of me if you ask me like a human person and | ||
| 5961 | not your personal butler. On a long run, you are destroying your relationships | ||
| 5962 | and nobody would want to work with you. Your schizophrenic approach will damage | ||
| 5963 | only you in a long run. Nobody is anybody’s property.</p> | ||
| 5964 | <h2 id="conclusion">Conclusion</h2> | ||
| 5965 | <p>I am guilty of many things described in this post. And I find it hard sometimes | ||
| 5966 | to acknowledge this. And I lie to myself and try vigorously to find some | ||
| 5967 | explanation why I do these things. There is always space for growth. And maybe | ||
| 5968 | you will also find some of yourself in this post and realize what needs to | ||
| 5969 | change for you to evolve.</p> | ||
| 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 +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><p>Zigbee networks have this wonderful capability to self-heal, which means they | ||
| 5982 | can reorder connections between them if one of them is inoperable. This works | ||
| 5983 | our of the box when you deploy them. But you have to have in mind that achieving | ||
| 5984 | this is not as easy as you would think. None of it is plug&amp;play. So to make | ||
| 5985 | your life a bit easier, here are some pointers which, I hope, will help you.</p> | ||
| 5986 | <ul> | ||
| 5987 | <li>Be careful when you are ordering your equipment abroad. There are many rules | ||
| 5988 | and regulations you need to comply before you get your Xbee radios. What they | ||
| 5989 | do is they wait until you prove that you won’t use the technology for some | ||
| 5990 | kind of evil take over control of the world project :). For this, they have | ||
| 5991 | EAR (Export Administration Regulations) which basically means “This product | ||
| 5992 | may require a license to export from the United States.”.</li> | ||
| 5993 | <li>I don’t know if this applies for every country, but when we purchased our Xbee | ||
| 5994 | radios from Mouser, this was mandatory! What we needed to do was to print out | ||
| 5995 | a form and write information about our company and send them a copy via | ||
| 5996 | email. With this document, we proved that we are a legitimate company.</li> | ||
| 5997 | <li>When you complete your purchase and send all the documentation, you are not | ||
| 5998 | clear yet. Then customs will take it from there :). There will be some | ||
| 5999 | additional costs. Before purchasing, make sure you have as much information | ||
| 6000 | about costs as possible. Because it can get costly in the end.</li> | ||
| 6001 | <li>I suggest you use companies from your country. You can seriously cut your | ||
| 6002 | costs. Here in Slovenia, the best option so far as I know is Farnell. And | ||
| 6003 | based on my personal experience, they rock! All I need to say!</li> | ||
| 6004 | <li>Make plans when ordering larger quantities. Do not, I say, do not make your | ||
| 6005 | orders in December! :) Believe me! You will have problems with stock they can | ||
| 6006 | provide for you. So, we were forced to buy some things from Mouser, which was | ||
| 6007 | extremely painful because of all the regulations you need to obey when | ||
| 6008 | importing goods from the USA.</li> | ||
| 6009 | <li>Make sure that firmware version on your Xbee radios is exactly the same! Do | ||
| 6010 | not get creative!!! I propose using templates. You can get template by | ||
| 6011 | exporting 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.</li> | ||
| 6013 | <li>And again: make plans! Plan everything! In months advanced! You will thank me | ||
| 6014 | later :)</li> | ||
| 6015 | <li>Test, test, test. Wireless networks can be tricky.</li> | ||
| 6016 | </ul> | ||
| 6017 | <p>If you are serious, I suggest you buy this book, Building Wireless Sensor | ||
| 6018 | Networks. You will get a glimpse of how networks work in lumens terms. It is a | ||
| 6019 | good starting point for everybody who wants to build wireless networks.</p> | ||
| 6020 | <p><strong>Additional resources:</strong></p> | ||
| 6021 | <ul> | ||
| 6022 | <li><a href="http://www.digi.com/aboutus/export/generalexportinfo">http://www.digi.com/aboutus/export/generalexportinfo</a></li> | ||
| 6023 | <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> | ||
| 6024 | <li><a href="http://www.bis.doc.gov/licensing/exportingbasics.htm">http://www.bis.doc.gov/licensing/exportingbasics.htm</a></li> | ||
| 6025 | </ul> | ||
| 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 +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><p>There is a lot of talk about LED technology. It is beginning to infiltrate | ||
| 6038 | industry at a fast rate, and it’s a challenge for designers and also engineers. | ||
| 6039 | I wondered when a weakness will be revealed. Then I stomped on an article | ||
| 6040 | talking about harm in using LED technology. It looks like this magical | ||
| 6041 | technology is not so magical and eco-friendly.</p> | ||
| 6042 | <p>A new study from the University of California indicates that LED lights contain | ||
| 6043 | toxic metals, and should be produced, used and disposed of carefully. Besides | ||
| 6044 | the lead and nickel, the bulbs and their associated parts were also found to | ||
| 6045 | contain arsenic, copper, and other metals that have been linked to different | ||
| 6046 | cancers, neurological damage, kidney disease, hypertension, skin rashes and | ||
| 6047 | other illnesses in humans, and to ecological damage in waterways.</p> | ||
| 6048 | <p>Since then, I haven’t yet found any regulation for disposal of LED lights or any | ||
| 6049 | other regulation or standard. This might be a problem in the future. And it is a | ||
| 6050 | massive drawback. This might have quite an impact on consumer market.</p> | ||
| 6051 | <p>Nevertheless, there is a potential, and I am sure the market will adapt. I also | ||
| 6052 | hope I will be reading documents regarding solution for this concern soon.</p> | ||
| 6053 | <p><strong>Additional resources:</strong></p> | ||
| 6054 | <ul> | ||
| 6055 | <li><a href="http://ezinearticles.com/?Recycling-and-Disposal-of-Light-Bulbs&amp;id=1091304">Recycling and Disposal of Light Bulbs</a></li> | ||
| 6056 | <li><a href="http://www.ehow.com/how_7483442_dispose-lowenergy-light-bulb.html">How to Dispose of a Low-Energy Light Bulb</a></li> | ||
| 6057 | </ul> | ||
| 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 +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><p>The year of 2010 was definitely the year of Geo-location. The market responded | ||
| 6070 | beautifully and lots of very cool services were launched. We all have to thank | ||
| 6071 | the mobile market for such extensive adoption. With new generations of mobile | ||
| 6072 | phones that are not only buffed with high-tech hardware but are also affordable. | ||
| 6073 | We can now manage tasks that were not so long time ago, almost Star Trek’ish. | ||
| 6074 | And all this had and has great influence on the destination to which we are | ||
| 6075 | going now.</p> | ||
| 6076 | <p>Reading all this articles about new innovation about new thriving technologies | ||
| 6077 | makes me wonder what’s the next step. The future is the mesh, like Lisa Gansky | ||
| 6078 | said in her book The Mesh.</p> | ||
| 6079 | <p>Many still have conservative views on distributed systems. The problems with | ||
| 6080 | security of information. Fear of not controlling every aspect of information | ||
| 6081 | flow. I am very opened to distributed systems and heterogeneous applications, | ||
| 6082 | and I think this is the correct and best way to proceed.</p> | ||
| 6083 | <p>This year will definitely be about communication platforms. Mobile to mobile. | ||
| 6084 | Machine to mobile and vice versa. All the tech is available and ready to put | ||
| 6085 | into action. Wireless is today’s new mantra. And the concept of semantic web is | ||
| 6086 | now ready for industry.</p> | ||
| 6087 | <p>Applications and developers now can gain access to new layers of systems and can | ||
| 6088 | prepare and build solutions to meet the high quality needs of market. The speed | ||
| 6089 | is everything now.</p> | ||
| 6090 | <p>My vote goes to “Machine to Machine” and “Embedded Systems”!</p> | ||
| 6091 | <ul> | ||
| 6092 | <li><a href="http://en.wikipedia.org/wiki/Machine-to-Machine">Machine-to-Machine</a></li> | ||
| 6093 | <li><a href="http://www.bitxml.org/">The ultimate M2M communication protocol</a></li> | ||
| 6094 | <li><a href="http://www.coosproject.org/maven-site/1.0.0/project-info.html">COOS Project (connectivity initiative)</a></li> | ||
| 6095 | <li><a href="http://m2m.com/index.jspa">Community for machine-to-machine</a></li> | ||
| 6096 | <li><a href="http://en.wikipedia.org/wiki/Embedded_system">Embedded system</a></li> | ||
| 6097 | </ul> | ||
| 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 | ||
| 11 | programs 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 | ||
| 17 | a lock on a Linux NFS server, which turned | ||
| 18 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 19 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 20 | owns 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 | ||
| 21 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 22 | list where the're doing | ||
| 23 | bad computer history and insisting that a guy Larry Rosen | ||
| 24 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 25 | somethin…<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: | ||
| 26 | i2c, plan9 | ||
| 27 | Another month, another file system. | ||
| 28 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 29 | you, bme680, we’re not | ||
| 30 | done yet). The show must go on, as they say, and I would like my | ||
| 31 | experiments to go on. | ||
| 32 | So a “new” addition to the environmental sensor family connected to | ||
| 33 | the 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 | ||
| 34 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 35 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 36 | unique 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. | ||
| 37 | My 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 | ||
| 38 | 1.0 has been released: | ||
| 39 | wifi_da-1.0.sit | ||
| 40 | (StuffIt 3 archive) | ||
| 41 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 42 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 43 | classic 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. | ||
| 44 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 45 | Design Goals | ||
| 46 | I 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 | ||
| 47 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 48 | catch 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 | ||
| 49 | specified 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 | ||
| 10 | industry at a fast rate, and it’s a challenge for designers and also engineers. | ||
| 11 | I wondered when a weakness will be revealed. Then I stomped on an article | ||
| 12 | talking about harm in using LED technology. It looks like this magical | ||
| 13 | technology is not so magical and eco-friendly.<p>A new study from the University of California indicates that LED lights contain | ||
| 14 | toxic metals, and should be produced, used and disposed of carefully. Besides | ||
| 15 | the lead and nickel, the bulbs and their associated parts were also found to | ||
| 16 | contain arsenic, copper, and other metals that have been linked to different | ||
| 17 | cancers, neurological damage, kidney disease, hypertension, skin rashes and | ||
| 18 | other 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 | ||
| 19 | other regulation or standard. This might be a problem in the future. And it is a | ||
| 20 | massive 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 | ||
| 21 | hope 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&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 | ||
| 22 | a lock on a Linux NFS server, which turned | ||
| 23 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 24 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 25 | owns 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 | ||
| 26 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 27 | list where the're doing | ||
| 28 | bad computer history and insisting that a guy Larry Rosen | ||
| 29 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 30 | somethin…<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: | ||
| 31 | i2c, plan9 | ||
| 32 | Another month, another file system. | ||
| 33 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 34 | you, bme680, we’re not | ||
| 35 | done yet). The show must go on, as they say, and I would like my | ||
| 36 | experiments to go on. | ||
| 37 | So a “new” addition to the environmental sensor family connected to | ||
| 38 | the 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 | ||
| 39 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 40 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 41 | unique 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. | ||
| 42 | My 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 | ||
| 43 | 1.0 has been released: | ||
| 44 | wifi_da-1.0.sit | ||
| 45 | (StuffIt 3 archive) | ||
| 46 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 47 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 48 | classic 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. | ||
| 49 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 50 | Design Goals | ||
| 51 | I 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 | ||
| 52 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 53 | catch 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 | ||
| 54 | specified 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 &#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>"your_email@example.com"</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>"your_email@example.com"</span> | ||
| 13 | </span></span></code></pre><p>Note: By default SSH keys get stored to <code>/home/<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 <user>@<host> | ||
| 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 <port> <user>@<host> | ||
| 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>"ls /root"</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>"cd /root;touch file.txt"</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 <username> | ||
| 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 <path/to/directory> | ||
| 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* > /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* > /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 <x> 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 <x> 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'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>"index"</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 <pid> | ||
| 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 <user> | ||
| 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 | ||
| 110 | a lock on a Linux NFS server, which turned | ||
| 111 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 112 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 113 | owns 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 | ||
| 114 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 115 | list where the're doing | ||
| 116 | bad computer history and insisting that a guy Larry Rosen | ||
| 117 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 118 | somethin…<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: | ||
| 119 | i2c, plan9 | ||
| 120 | Another month, another file system. | ||
| 121 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 122 | you, bme680, we’re not | ||
| 123 | done yet). The show must go on, as they say, and I would like my | ||
| 124 | experiments to go on. | ||
| 125 | So a “new” addition to the environmental sensor family connected to | ||
| 126 | the 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 | ||
| 127 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 128 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 129 | unique 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. | ||
| 130 | My 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 | ||
| 131 | 1.0 has been released: | ||
| 132 | wifi_da-1.0.sit | ||
| 133 | (StuffIt 3 archive) | ||
| 134 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 135 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 136 | classic 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. | ||
| 137 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 138 | Design Goals | ||
| 139 | I 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 | ||
| 140 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 141 | catch 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 | ||
| 142 | specified 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>. | ||
| 22 | This 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>"data.csv"</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>"Connect median NLB vs ALB"</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>"Epoch"</span>], df[<span style=color:#a31515>"Connect (ALB)"</span>], label = <span style=color:#a31515>"ALB"</span>, color=<span style=color:#a31515>"black"</span>, linestyle=<span style=color:#a31515>"-"</span>) | ||
| 39 | </span></span><span style=display:flex><span>plt.plot(df[<span style=color:#a31515>"Epoch"</span>], df[<span style=color:#a31515>"Connect (NLB)"</span>], label = <span style=color:#a31515>"NLB"</span>, color=<span style=color:#a31515>"black"</span>, linestyle=<span style=color:#a31515>"--"</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>"Epoch"</span>, fontstyle=<span style=color:#a31515>"italic"</span>) | ||
| 43 | </span></span><span style=display:flex><span>plt.ylabel(<span style=color:#a31515>"Median value (ms)"</span>, fontstyle=<span style=color:#a31515>"italic"</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>"plot.svg"</span>, format=<span style=color:#a31515>"svg"</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 | ||
| 52 | a lock on a Linux NFS server, which turned | ||
| 53 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 54 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 55 | owns 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 | ||
| 56 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 57 | list where the're doing | ||
| 58 | bad computer history and insisting that a guy Larry Rosen | ||
| 59 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 60 | somethin…<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: | ||
| 61 | i2c, plan9 | ||
| 62 | Another month, another file system. | ||
| 63 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 64 | you, bme680, we’re not | ||
| 65 | done yet). The show must go on, as they say, and I would like my | ||
| 66 | experiments to go on. | ||
| 67 | So a “new” addition to the environmental sensor family connected to | ||
| 68 | the 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 | ||
| 69 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 70 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 71 | unique 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. | ||
| 72 | My 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 | ||
| 73 | 1.0 has been released: | ||
| 74 | wifi_da-1.0.sit | ||
| 75 | (StuffIt 3 archive) | ||
| 76 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 77 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 78 | classic 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. | ||
| 79 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 80 | Design Goals | ||
| 81 | I 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 | ||
| 82 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 83 | catch 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 | ||
| 84 | specified 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> | ||
| 10 | set up and I use GitHub just as a mirror. By default the cgit theme looks a bit | ||
| 11 | dated 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 | ||
| 194 | a lock on a Linux NFS server, which turned | ||
| 195 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 196 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 197 | owns 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 | ||
| 198 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 199 | list where the're doing | ||
| 200 | bad computer history and insisting that a guy Larry Rosen | ||
| 201 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 202 | somethin…<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: | ||
| 203 | i2c, plan9 | ||
| 204 | Another month, another file system. | ||
| 205 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 206 | you, bme680, we’re not | ||
| 207 | done yet). The show must go on, as they say, and I would like my | ||
| 208 | experiments to go on. | ||
| 209 | So a “new” addition to the environmental sensor family connected to | ||
| 210 | the 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 | ||
| 211 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 212 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 213 | unique 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. | ||
| 214 | My 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 | ||
| 215 | 1.0 has been released: | ||
| 216 | wifi_da-1.0.sit | ||
| 217 | (StuffIt 3 archive) | ||
| 218 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 219 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 220 | classic 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. | ||
| 221 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 222 | Design Goals | ||
| 223 | I 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 | ||
| 224 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 225 | catch 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 | ||
| 226 | specified 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 | ||
| 10 | files 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>"*.xml"</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 | ||
| 12 | a lock on a Linux NFS server, which turned | ||
| 13 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 14 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 15 | owns 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 | ||
| 16 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 17 | list where the're doing | ||
| 18 | bad computer history and insisting that a guy Larry Rosen | ||
| 19 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 20 | somethin…<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: | ||
| 21 | i2c, plan9 | ||
| 22 | Another month, another file system. | ||
| 23 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 24 | you, bme680, we’re not | ||
| 25 | done yet). The show must go on, as they say, and I would like my | ||
| 26 | experiments to go on. | ||
| 27 | So a “new” addition to the environmental sensor family connected to | ||
| 28 | the 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 | ||
| 29 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 30 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 31 | unique 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. | ||
| 32 | My 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 | ||
| 33 | 1.0 has been released: | ||
| 34 | wifi_da-1.0.sit | ||
| 35 | (StuffIt 3 archive) | ||
| 36 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 37 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 38 | classic 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. | ||
| 39 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 40 | Design Goals | ||
| 41 | I 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 | ||
| 42 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 43 | catch 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 | ||
| 44 | specified 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 | ||
| 10 | beautifully and lots of very cool services were launched. We all have to thank | ||
| 11 | the mobile market for such extensive adoption. With new generations of mobile | ||
| 12 | phones that are not only buffed with high-tech hardware but are also affordable. | ||
| 13 | We can now manage tasks that were not so long time ago, almost Star Trek’ish. | ||
| 14 | And all this had and has great influence on the destination to which we are | ||
| 15 | going now.<p>Reading all this articles about new innovation about new thriving technologies | ||
| 16 | makes me wonder what’s the next step. The future is the mesh, like Lisa Gansky | ||
| 17 | said in her book The Mesh.<p>Many still have conservative views on distributed systems. The problems with | ||
| 18 | security of information. Fear of not controlling every aspect of information | ||
| 19 | flow. I am very opened to distributed systems and heterogeneous applications, | ||
| 20 | and I think this is the correct and best way to proceed.<p>This year will definitely be about communication platforms. Mobile to mobile. | ||
| 21 | Machine to mobile and vice versa. All the tech is available and ready to put | ||
| 22 | into action. Wireless is today’s new mantra. And the concept of semantic web is | ||
| 23 | now ready for industry.<p>Applications and developers now can gain access to new layers of systems and can | ||
| 24 | prepare and build solutions to meet the high quality needs of market. The speed | ||
| 25 | is 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 | ||
| 26 | a lock on a Linux NFS server, which turned | ||
| 27 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 28 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 29 | owns 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 | ||
| 30 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 31 | list where the're doing | ||
| 32 | bad computer history and insisting that a guy Larry Rosen | ||
| 33 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 34 | somethin…<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: | ||
| 35 | i2c, plan9 | ||
| 36 | Another month, another file system. | ||
| 37 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 38 | you, bme680, we’re not | ||
| 39 | done yet). The show must go on, as they say, and I would like my | ||
| 40 | experiments to go on. | ||
| 41 | So a “new” addition to the environmental sensor family connected to | ||
| 42 | the 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 | ||
| 43 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 44 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 45 | unique 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. | ||
| 46 | My 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 | ||
| 47 | 1.0 has been released: | ||
| 48 | wifi_da-1.0.sit | ||
| 49 | (StuffIt 3 archive) | ||
| 50 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 51 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 52 | classic 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. | ||
| 53 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 54 | Design Goals | ||
| 55 | I 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 | ||
| 56 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 57 | catch 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 | ||
| 58 | specified 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 | ||
| 17 | a lock on a Linux NFS server, which turned | ||
| 18 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 19 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 20 | owns 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 | ||
| 21 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 22 | list where the're doing | ||
| 23 | bad computer history and insisting that a guy Larry Rosen | ||
| 24 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 25 | somethin…<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: | ||
| 26 | i2c, plan9 | ||
| 27 | Another month, another file system. | ||
| 28 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 29 | you, bme680, we’re not | ||
| 30 | done yet). The show must go on, as they say, and I would like my | ||
| 31 | experiments to go on. | ||
| 32 | So a “new” addition to the environmental sensor family connected to | ||
| 33 | the 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 | ||
| 34 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 35 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 36 | unique 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. | ||
| 37 | My 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 | ||
| 38 | 1.0 has been released: | ||
| 39 | wifi_da-1.0.sit | ||
| 40 | (StuffIt 3 archive) | ||
| 41 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 42 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 43 | classic 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. | ||
| 44 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 45 | Design Goals | ||
| 46 | I 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 | ||
| 47 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 48 | catch 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 | ||
| 49 | specified 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, | ||
| 11 | that was an awesome experience. The whole thing is just superb. From how errors | ||
| 12 | are handled. The C-like way you handle compiling. The way the language is | ||
| 13 | structured 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 | ||
| 14 | JSON 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 | ||
| 17 | way we probably should. It is an excellent example of how modern language should | ||
| 18 | be designed. And because I have used it extensively in the last couple of years | ||
| 19 | this probably taints my views of other languages. And is doing me a great | ||
| 20 | disservice. Nevertheless, here we are.<p>About two years ago I started flirting with <a href=https://nodejs.org/en/>Node.js</a> | ||
| 21 | for a project I started working on. What I wanted was to have things written in | ||
| 22 | a language that is widely used, and we could get additional developers for. As | ||
| 23 | much as <strong>Golang</strong> is amazing it's really hard to get developers for it. Even | ||
| 24 | now. And after playing around with it for a week I felt in love with the speed | ||
| 25 | of iteration and massive package ecosystem. Do you want SSO? You got it! Do you | ||
| 26 | want some esoteric library for something? There is a strong chance somebody | ||
| 27 | wrote 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 | ||
| 29 | metrics and that potentially will become the downfall of Node.js.<p>Because of the sheer amount of choice I often got anxiety when choosing | ||
| 30 | libraries. Will I choose the correct one? Is this library something that will be | ||
| 31 | supported for a foreseeable future or not? I am used of using libraries that are | ||
| 32 | being in development for 10 years plus (Python, C) and that gave me some sort of | ||
| 33 | comfort. And it is probably unfair to Node.js and community to expect same | ||
| 34 | dedication.<p>Moving forward ... Work started and things were great. <strong>Speed of iteration was | ||
| 35 | insane</strong>. For some feature that I would need a day in Golang only took me hour | ||
| 36 | or two. I became lazy! Using packages all over the place. Falling into the same | ||
| 37 | trap as others. Packages on top of packages. And <a href=https://www.npmjs.com/>npm</a> | ||
| 38 | didn't help at all. The way that the package manager works is just | ||
| 39 | horrendous. And not allowing to have node_modules outside the project is also | ||
| 40 | the stupidest idea ever.<p>So at that point I started feeling the technical debt that comes with Node.js | ||
| 41 | and the whole ecosystem. What nobody tells you is that <strong>structuring large | ||
| 42 | Node.js apps</strong> is more problematic than one would think. And going microservice | ||
| 43 | for every single thing is also a bad idea. The amount of networking you | ||
| 44 | introduce with that approach always ends up being a pain in the ass. And I don't | ||
| 45 | even want to go into system administration here. The overhead is | ||
| 46 | insane. Package-lock.json made many days feel like living hell for me. And I | ||
| 47 | would eat the cost of all this if it meant for better development | ||
| 48 | experience. Well, it didn't.<p>The <strong>lack of Typescript</strong> support in the interpreter is still mind boggling to | ||
| 49 | me. Why haven't they added native support yet for this is beyond me?! That would | ||
| 50 | have solved so many problems. Lack of type safety became a problem somewhere in | ||
| 51 | the middle of the project where the codebase was sufficiently large enough to | ||
| 52 | present problems. We started adding arguments to functions and there was <strong>no | ||
| 53 | way to implicitly define argument types</strong>. And because at that point there were | ||
| 54 | a lot of functions, it became impossible to know what each one accepts, | ||
| 55 | development became more and more trial and error based.<p>I tried <strong>implementing Typescript</strong>, but that would present a large refactor | ||
| 56 | that we were not willing to do at that point. The benefits were not enough. I | ||
| 57 | also tried <a href=https://flow.org/>Flow - static type checker</a> but implementation | ||
| 58 | was also horrible. What Typescript and Flow forces you is to have src folder and | ||
| 59 | then <strong>transpile</strong> your code into dist folder and run it with node. WTH is that | ||
| 60 | all about. Why can't this be done in memory or some virtual file system? Why? I | ||
| 61 | see no reason why this couldn't be done like this. But it is what it is. I | ||
| 62 | abandoned all hope for static type checking.<p>One of the problems that resulted from not having interfaces or types was | ||
| 63 | inability 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 | ||
| 65 | this without resorting to some hack basically. Or maybe I haven't found a | ||
| 66 | solution, 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 | ||
| 67 | the whole thing and went with something else like Python. That's all I am going | ||
| 68 | to 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 | ||
| 70 | should have been asking myself was, how to use Node.js in large scale | ||
| 71 | application. And you don't get this in <strong>marketing material</strong> for Express or Koa | ||
| 72 | etc. They never tell you this. Making Node.js scale on infrastructure or in | ||
| 73 | codebase is really <strong>more of an art than a science</strong>. And just like with the | ||
| 74 | whole 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 | ||
| 75 | quickly 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 | ||
| 76 | a lock on a Linux NFS server, which turned | ||
| 77 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 78 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 79 | owns 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 | ||
| 80 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 81 | list where the're doing | ||
| 82 | bad computer history and insisting that a guy Larry Rosen | ||
| 83 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 84 | somethin…<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: | ||
| 85 | i2c, plan9 | ||
| 86 | Another month, another file system. | ||
| 87 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 88 | you, bme680, we’re not | ||
| 89 | done yet). The show must go on, as they say, and I would like my | ||
| 90 | experiments to go on. | ||
| 91 | So a “new” addition to the environmental sensor family connected to | ||
| 92 | the 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 | ||
| 93 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 94 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 95 | unique 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. | ||
| 96 | My 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 | ||
| 97 | 1.0 has been released: | ||
| 98 | wifi_da-1.0.sit | ||
| 99 | (StuffIt 3 archive) | ||
| 100 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 101 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 102 | classic 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. | ||
| 103 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 104 | Design Goals | ||
| 105 | I 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 | ||
| 106 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 107 | catch 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 | ||
| 108 | specified 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(() => | ||
| 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>"cmd"</span>, <span style=color:#a31515>"/c dir"</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 | ||
| 30 | in 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 | ||
| 35 | a lock on a Linux NFS server, which turned | ||
| 36 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 37 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 38 | owns 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 | ||
| 39 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 40 | list where the're doing | ||
| 41 | bad computer history and insisting that a guy Larry Rosen | ||
| 42 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 43 | somethin…<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: | ||
| 44 | i2c, plan9 | ||
| 45 | Another month, another file system. | ||
| 46 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 47 | you, bme680, we’re not | ||
| 48 | done yet). The show must go on, as they say, and I would like my | ||
| 49 | experiments to go on. | ||
| 50 | So a “new” addition to the environmental sensor family connected to | ||
| 51 | the 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 | ||
| 52 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 53 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 54 | unique 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. | ||
| 55 | My 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 | ||
| 56 | 1.0 has been released: | ||
| 57 | wifi_da-1.0.sit | ||
| 58 | (StuffIt 3 archive) | ||
| 59 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 60 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 61 | classic 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. | ||
| 62 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 63 | Design Goals | ||
| 64 | I 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 | ||
| 65 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 66 | catch 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 | ||
| 67 | specified 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 +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><p>First install two dependencies:</p> | ||
| 17 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>sudo dnf install libX11-devel libXt-devel | ||
| 18 | </span></span></code></pre><p>Clone the repo and compile it:</p> | ||
| 19 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>git clone git://git.9front.org/plan9front/drawterm | ||
| 20 | </span></span><span style="display:flex;"><span>cd drawterm | ||
| 21 | </span></span><span style="display:flex;"><span>CONF=unix make | ||
| 22 | </span></span></code></pre><p>That should produce <code>drawterm</code> binary.</p> | ||
| 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 +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><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> | ||
| 35 | on my machine.</p> | ||
| 36 | <p>I tried installing it with <code>pip install awsebcli --upgrade --user</code> and it failed.</p> | ||
| 37 | <p>The error was the following.</p> | ||
| 38 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>Collecting PyYAML&lt;6.1,&gt;=5.3.1 (from awsebcli) | ||
| 39 | </span></span><span style="display:flex;"><span> Using cached PyYAML-5.4.1.tar.gz (175 kB) | ||
| 40 | </span></span><span style="display:flex;"><span> Installing build dependencies ... done | ||
| 41 | </span></span><span style="display:flex;"><span> Getting requirements to build wheel ... error | ||
| 42 | </span></span><span style="display:flex;"><span> error: subprocess-exited-with-error | ||
| 43 | </span></span><span style="display:flex;"><span> | ||
| 44 | </span></span><span style="display:flex;"><span> × Getting requirements to build wheel did not run successfully. | ||
| 45 | </span></span><span style="display:flex;"><span> │ exit code: 1 | ||
| 46 | </span></span><span style="display:flex;"><span> ╰─&gt; [68 lines of output] | ||
| 47 | </span></span></code></pre><p>To fix this issue with PyYAML you must install PyYAML separately.</p> | ||
| 48 | <p>Do the following and try installing <code>eb</code> again after.</p> | ||
| 49 | <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 | ||
| 50 | </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> | ||
| 51 | </span></span></code></pre></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 +0200</pubDate> | ||
| 60 | <guid>https://mitjafelicijan.com/floods-in-slovenia.html</guid> | ||
| 61 | <description></description> | ||
| 62 | <content:encoded><p><video src="/notes/floods/IMG_1471.mp4" controls></video></p> | ||
| 63 | <p><video src="/notes/floods/IMG_1474.mp4" controls></video></p> | ||
| 64 | <figure> | ||
| 65 | <img src="/notes/floods/IMG_1469.webp" alt="" /> | ||
| 66 | </figure> | ||
| 67 | <figure> | ||
| 68 | <img src="/notes/floods/IMG_1470.webp" alt="" /> | ||
| 69 | </figure> | ||
| 70 | <p><video src="/notes/floods/IMG_1461.mp4" controls></video></p> | ||
| 71 | <p><video src="/notes/floods/IMG_1466.mp4" controls></video></p> | ||
| 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 +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><p>Install pip requirements.</p> | ||
| 84 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>pip install matplotlib | ||
| 85 | </span></span><span style="display:flex;"><span>pip install pandas | ||
| 86 | </span></span></code></pre><p>Example of data being used.</p> | ||
| 87 | <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) | ||
| 88 | </span></span><span style="display:flex;"><span>1,57.7,315.7,309.4,321.6,9,104.4,98.3,105.7 | ||
| 89 | </span></span><span style="display:flex;"><span>2,121.9,114.4,100.3,176.9,5.8,99.1,97.1,101.1 | ||
| 90 | </span></span><span style="display:flex;"><span>3,5.3,229.4,231.2,231.4,14.2,83,69.4,87.9 | ||
| 91 | </span></span><span style="display:flex;"><span>4,4.2,134.5,112.2,135.3,5.3,132.4,105.5,134.1 | ||
| 92 | </span></span><span style="display:flex;"><span>5,5.8,247.4,246.8,248.1,6,74.3,70.2,75.5 | ||
| 93 | </span></span><span style="display:flex;"><span>6,9.9,122.9,100.6,122.7,7.5,241.1,79.3,242.3 | ||
| 94 | </span></span><span style="display:flex;"><span>7,6.1,170.2,106.4,170.5,7.2,382.4,375.1,383.8 | ||
| 95 | </span></span><span style="display:flex;"><span>8,6.6,194.3,201.4,195.5,7.1,130.9,104.8,132.6 | ||
| 96 | </span></span><span style="display:flex;"><span>9,6.4,146.1,122.3,147.7,9.4,95.6,74,96.4 | ||
| 97 | </span></span></code></pre><p>In the code you can use <code>df</code> as dataframes and use the headers like <code>df[&quot;Epoch&quot;]</code>. | ||
| 98 | This is how you get a column data with pandas.</p> | ||
| 99 | <p>The Python code responsible for generating a chart:</p> | ||
| 100 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#00f">import</span> csv | ||
| 101 | </span></span><span style="display:flex;"><span><span style="color:#00f">import</span> sys | ||
| 102 | </span></span><span style="display:flex;"><span> | ||
| 103 | </span></span><span style="display:flex;"><span><span style="color:#00f">import</span> matplotlib.pyplot <span style="color:#00f">as</span> plt | ||
| 104 | </span></span><span style="display:flex;"><span><span style="color:#00f">import</span> pandas <span style="color:#00f">as</span> pd | ||
| 105 | </span></span><span style="display:flex;"><span> | ||
| 106 | </span></span><span style="display:flex;"><span><span style="color:#008000"># Read the data</span> | ||
| 107 | </span></span><span style="display:flex;"><span>df = pd.read_csv(<span style="color:#a31515">&#34;data.csv&#34;</span>) | ||
| 108 | </span></span><span style="display:flex;"><span> | ||
| 109 | </span></span><span style="display:flex;"><span><span style="color:#008000"># Settings</span> | ||
| 110 | </span></span><span style="display:flex;"><span>plt.title(<span style="color:#a31515">&#34;Connect median NLB vs ALB&#34;</span>) | ||
| 111 | </span></span><span style="display:flex;"><span>plt.tight_layout(pad=2) | ||
| 112 | </span></span><span style="display:flex;"><span>fig = plt.gcf() | ||
| 113 | </span></span><span style="display:flex;"><span>fig.set_size_inches(10, 4) | ||
| 114 | </span></span><span style="display:flex;"><span> | ||
| 115 | </span></span><span style="display:flex;"><span><span style="color:#008000"># Plotting</span> | ||
| 116 | </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>) | ||
| 117 | </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>) | ||
| 118 | </span></span><span style="display:flex;"><span> | ||
| 119 | </span></span><span style="display:flex;"><span><span style="color:#008000"># Adding x and y axis labels</span> | ||
| 120 | </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>) | ||
| 121 | </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>) | ||
| 122 | </span></span><span style="display:flex;"><span> | ||
| 123 | </span></span><span style="display:flex;"><span><span style="color:#008000"># Legend</span> | ||
| 124 | </span></span><span style="display:flex;"><span>legend = plt.legend() | ||
| 125 | </span></span><span style="display:flex;"><span>legend.get_frame().set_linewidth(0) | ||
| 126 | </span></span><span style="display:flex;"><span> | ||
| 127 | </span></span><span style="display:flex;"><span><span style="color:#008000"># Export as SVG</span> | ||
| 128 | </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>) | ||
| 129 | </span></span></code></pre><figure> | ||
| 130 | <img src="/notes/plot.svg" alt="SVG Chart" /> | ||
| 131 | </figure> | ||
| 132 | <p>The image above is SVG and you can zoom in and out and check that the image is vector.</p> | ||
| 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 +0200</pubDate> | ||
| 142 | <guid>https://mitjafelicijan.com/set-color-temperature-of-displays-on-i3.html</guid> | ||
| 143 | <description>I have been using Gnome&#39;s night shift for a while now and I have been missingthis feature under i3wm.</description> | ||
| 144 | <content:encoded><p>I have been using Gnome's night shift for a while now and I have been missing | ||
| 145 | this feature under i3wm. This can be done with | ||
| 146 | <a href="https://linux.die.net/man/1/redshift">redshift</a>.</p> | ||
| 147 | <ul> | ||
| 148 | <li>On Debian install with <code>sudo apt install redshift</code></li> | ||
| 149 | <li>And then manually set it with <code>redshift -O 3000</code></li> | ||
| 150 | <li>Reset the current settings with <code>redshift -x</code></li> | ||
| 151 | </ul> | ||
| 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 +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><p>I have been experiencing some issues with Intel® Integrated HD Graphics 3000 | ||
| 164 | under Debian 12 with Xorg and i3. Using <code>picom</code> compositor didn't help. To fix | ||
| 165 | this issue create new file <code>/etc/X11/xorg.conf.d/20-intel.conf</code> as root and put | ||
| 166 | the following in the file.</p> | ||
| 167 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>Section &#34;Device&#34; | ||
| 168 | </span></span><span style="display:flex;"><span> Identifier &#34;Intel Graphics&#34; | ||
| 169 | </span></span><span style="display:flex;"><span> Driver &#34;intel&#34; | ||
| 170 | </span></span><span style="display:flex;"><span> Option &#34;TearFree&#34; &#34;true&#34; | ||
| 171 | </span></span><span style="display:flex;"><span>EndSection | ||
| 172 | </span></span></code></pre><p>Reboot the system and that should be it.</p> | ||
| 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 +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><p>Recently I have been using my Thinkpad x220 more and there are some constraints | ||
| 185 | I have faced with it. CPU is not as powerful as on my main machine and I really | ||
| 186 | want to listen to some music while using the machine. Browsers really are bloat.</p> | ||
| 187 | <p>Check out this site <a href="https://streamurl.link/">https://streamurl.link/</a> and copy the stream url and then do | ||
| 188 | <code>mpv streamlink</code>.</p> | ||
| 189 | </content:encoded> | ||
| 190 | </item> | ||
| 191 | |||
| 192 | |||
| 193 | |||
| 194 | |||
| 195 | |||
| 196 | |||
| 197 | |||
| 198 | <item> | ||
| 199 | <title>60'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 +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><p>Likely aired during an hour-long program during the 1960s, long commercials such | ||
| 205 | as this typically aired during hour-long programs. They would <em>not</em> have aired | ||
| 206 | during a half-hour program.</p> | ||
| 207 | <p><video | ||
| 208 | poster="/notes/60s-ibm-computers-commercial.jpg" | ||
| 209 | src="/notes/60s-ibm-computers-commercial.mp4" | ||
| 210 | controls></video></p> | ||
| 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 +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><p>Message from 10/GUI team (page 10gui.com does not exist anymore):</p> | ||
| 223 | <p><em>Over a quarter-century ago, Xerox introduced the modern graphical user | ||
| 224 | interface paradigm we today take for granted.</em></p> | ||
| 225 | <p><em>That it has endured is a testament to the genius of its design. But the | ||
| 226 | industry is now at a crossroads: New technologies promise higher-bandwidth | ||
| 227 | interaction, but have yet to find a truly viable implementation.</em></p> | ||
| 228 | <p><em>10/GUI aims to bridge this gap by rethinking the desktop to leverage technology | ||
| 229 | in an intuitive and powerful way.</em></p> | ||
| 230 | <p><video | ||
| 231 | poster="/notes/10gui-10-finger-multitouch-user-interface.jpg" | ||
| 232 | src="/notes/10gui-10-finger-multitouch-user-interface.mp4" | ||
| 233 | controls></video></p> | ||
| 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 +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><p>Alacritty by default makes all links in the terminal output clickable and this | ||
| 246 | gets annoying rather quickly. I liked the default behavior of Gnome terminal | ||
| 247 | where you needed to hold Control key and then you could click and open links.</p> | ||
| 248 | <p>To achieve this in Alacritty you need to provide a <code>hint</code> in the configuration | ||
| 249 | file. Config file is located at <code>~/.config/alacritty/alacritty.yml</code>.</p> | ||
| 250 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>hints: | ||
| 251 | </span></span><span style="display:flex;"><span> enabled: | ||
| 252 | </span></span><span style="display:flex;"><span> - regex: <span style="color:#a31515">&#34;(mailto:|gemini:|gopher:|https:|http:|news:|file:|git:|ssh:|ftp:)\ | ||
| 253 | </span></span></span><span style="display:flex;"><span><span style="color:#a31515"> [^\u0000-\u001F\u007F-\u009F&lt;&gt;\&#34;\\s{-}\\^⟨⟩`]+&#34;</span> | ||
| 254 | </span></span><span style="display:flex;"><span> command: xdg-open | ||
| 255 | </span></span><span style="display:flex;"><span> post_processing: <span style="color:#00f">true</span> | ||
| 256 | </span></span><span style="display:flex;"><span> mouse: | ||
| 257 | </span></span><span style="display:flex;"><span> enabled: <span style="color:#00f">true</span> | ||
| 258 | </span></span><span style="display:flex;"><span> mods: Control | ||
| 259 | </span></span></code></pre><p>The following should work under any Linux system. For macOS, you will need to | ||
| 260 | change <code>command: xdg-open</code> to something else.</p> | ||
| 261 | <p>Now the links will be visible and clickable only when Control key is being | ||
| 262 | pressed.</p> | ||
| 263 | <p>Source: <a href="https://github.com/alacritty/alacritty/issues/5246">https://github.com/alacritty/alacritty/issues/5246</a></p> | ||
| 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 +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><p>Nix is amazing for making reproducible cross OS development environment.</p> | ||
| 276 | <p>First you need to <a href="https://nixos.org/download.html">install Nix package | ||
| 277 | manager</a>.</p> | ||
| 278 | <ul> | ||
| 279 | <li>Create a file <code>shell.nix</code> in your project folder.</li> | ||
| 280 | <li>In the section that has <code>python3</code> etc add programs you want to use. These can | ||
| 281 | be CLI or GUI applications. It doesn't matter to Nix.</li> | ||
| 282 | </ul> | ||
| 283 | <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> {} }: | ||
| 284 | </span></span><span style="display:flex;"><span> pkgs.mkShell { | ||
| 285 | </span></span><span style="display:flex;"><span> nativeBuildInputs = <span style="color:#00f">with</span> pkgs.buildPackages; [ | ||
| 286 | </span></span><span style="display:flex;"><span> python3 | ||
| 287 | </span></span><span style="display:flex;"><span> tinycc | ||
| 288 | </span></span><span style="display:flex;"><span> ]; | ||
| 289 | </span></span><span style="display:flex;"><span>} | ||
| 290 | </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 | ||
| 291 | you want to specify a different file use <code>nix-shell file.nix</code>. That is about it.</p> | ||
| 292 | <p>When the shell is spawned it could happen that your <code>PS1</code> prompt will be | ||
| 293 | overwritten and your prompt will look differently. In that case you need to | ||
| 294 | either do <code>NIX_SHELL_PRESERVE_PROMPT=1 nix shell</code> or add | ||
| 295 | <code>NIX_SHELL_PRESERVE_PROMPT</code> variable to your <code>bashrc</code> or <code>zshrc</code> file and set it | ||
| 296 | to <code>1</code>.</p> | ||
| 297 | <p>I also have a modified <code>PS1</code> prompt for Bash that I use and it also catches the | ||
| 298 | usage of Nix shell.</p> | ||
| 299 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>NIX_SHELL_PRESERVE_PROMPT=1 | ||
| 300 | </span></span><span style="display:flex;"><span> | ||
| 301 | </span></span><span style="display:flex;"><span>parse_git_branch() { | ||
| 302 | </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> | ||
| 303 | </span></span><span style="display:flex;"><span>} | ||
| 304 | </span></span><span style="display:flex;"><span> | ||
| 305 | </span></span><span style="display:flex;"><span>is_inside_nix_shell() { | ||
| 306 | </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> | ||
| 307 | </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> | ||
| 308 | </span></span><span style="display:flex;"><span> echo <span style="color:#a31515">&#34; \e[0;36m(nix-shell)\e[0m&#34;</span> | ||
| 309 | </span></span><span style="display:flex;"><span> <span style="color:#00f">fi</span> | ||
| 310 | </span></span><span style="display:flex;"><span>} | ||
| 311 | </span></span><span style="display:flex;"><span> | ||
| 312 | </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> | ||
| 313 | </span></span></code></pre><p>And this is what it looks like when you are in a Nix shell. Otherwise that part | ||
| 314 | of prompt is omitted</p> | ||
| 315 | <figure> | ||
| 316 | <img src="/notes/ps1-prompt.png" alt="PS1 Prompt" /> | ||
| 317 | </figure> | ||
| 318 | <p>More resources:</p> | ||
| 319 | <ul> | ||
| 320 | <li><a href="https://nixos.wiki/wiki/Development_environment_with_nix-shell">https://nixos.wiki/wiki/Development_environment_with_nix-shell</a></li> | ||
| 321 | <li><a href="https://nixos.wiki/wiki/Main_Page">https://nixos.wiki/wiki/Main_Page</a></li> | ||
| 322 | <li><a href="https://itsfoss.com/why-use-nixos/">https://itsfoss.com/why-use-nixos/</a></li> | ||
| 323 | <li><a href="https://mynixos.com/">https://mynixos.com/</a></li> | ||
| 324 | </ul> | ||
| 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 +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><p>For personal use I have a <a href="https://git.mitjafelicijan.com">private Git server</a> | ||
| 337 | set up and I use GitHub just as a mirror. By default the cgit theme looks a bit | ||
| 338 | dated so I made the flowing theme.</p> | ||
| 339 | <ul> | ||
| 340 | <li><code>/etc/cgitrc</code></li> | ||
| 341 | </ul> | ||
| 342 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>css=<span style="color:#a31515">/cgit.css</span> | ||
| 343 | </span></span><span style="display:flex;"><span>logo=<span style="color:#a31515">/startrek.gif</span> | ||
| 344 | </span></span><span style="display:flex;"><span>favicon=<span style="color:#a31515">/favicon.png</span> | ||
| 345 | </span></span><span style="display:flex;"><span>source-filter=<span style="color:#a31515">/usr/lib/cgit/filters/syntax-highlighting-edited.sh</span> | ||
| 346 | </span></span><span style="display:flex;"><span>about-filter=<span style="color:#a31515">/usr/lib/cgit/filters/about-formatting.sh</span> | ||
| 347 | </span></span><span style="display:flex;"><span> | ||
| 348 | </span></span><span style="display:flex;"><span>local-time=<span style="color:#a31515">1</span> | ||
| 349 | </span></span><span style="display:flex;"><span>snapshots=<span style="color:#a31515">tar.gz</span> | ||
| 350 | </span></span><span style="display:flex;"><span>repository-sort=<span style="color:#a31515">age</span> | ||
| 351 | </span></span><span style="display:flex;"><span>cache-size=<span style="color:#a31515">1000</span> | ||
| 352 | </span></span><span style="display:flex;"><span>branch-sort=<span style="color:#a31515">age</span> | ||
| 353 | </span></span><span style="display:flex;"><span>summary-log=<span style="color:#a31515">200</span> | ||
| 354 | </span></span><span style="display:flex;"><span>max-atom-items=<span style="color:#a31515">50</span> | ||
| 355 | </span></span><span style="display:flex;"><span>max-repo-count=<span style="color:#a31515">100</span> | ||
| 356 | </span></span><span style="display:flex;"><span> | ||
| 357 | </span></span><span style="display:flex;"><span>enable-index-owner=<span style="color:#a31515">0</span> | ||
| 358 | </span></span><span style="display:flex;"><span>enable-follow-links=<span style="color:#a31515">1</span> | ||
| 359 | </span></span><span style="display:flex;"><span>enable-log-filecount=<span style="color:#a31515">1</span> | ||
| 360 | </span></span><span style="display:flex;"><span>enable-log-linecount=<span style="color:#a31515">1</span> | ||
| 361 | </span></span><span style="display:flex;"><span> | ||
| 362 | </span></span><span style="display:flex;"><span>root-title=<span style="color:#a31515">Place for code, experiments and other bullshit!</span> | ||
| 363 | </span></span><span style="display:flex;"><span>root-desc= | ||
| 364 | </span></span><span style="display:flex;"><span>clone-url=<span style="color:#a31515">git@git.mitjafelicijan.com:/home/git/$CGIT_REPO_URL</span> | ||
| 365 | </span></span><span style="display:flex;"><span> | ||
| 366 | </span></span><span style="display:flex;"><span>mimetype.gif=<span style="color:#a31515">image/gif</span> | ||
| 367 | </span></span><span style="display:flex;"><span>mimetype.html=<span style="color:#a31515">text/html</span> | ||
| 368 | </span></span><span style="display:flex;"><span>mimetype.jpg=<span style="color:#a31515">image/jpeg</span> | ||
| 369 | </span></span><span style="display:flex;"><span>mimetype.jpeg=<span style="color:#a31515">image/jpeg</span> | ||
| 370 | </span></span><span style="display:flex;"><span>mimetype.pdf=<span style="color:#a31515">application/pdf</span> | ||
| 371 | </span></span><span style="display:flex;"><span>mimetype.png=<span style="color:#a31515">image/png</span> | ||
| 372 | </span></span><span style="display:flex;"><span>mimetype.svg=<span style="color:#a31515">image/svg+xml</span> | ||
| 373 | </span></span><span style="display:flex;"><span> | ||
| 374 | </span></span><span style="display:flex;"><span>readme=<span style="color:#a31515">:README.md</span> | ||
| 375 | </span></span><span style="display:flex;"><span>readme=<span style="color:#a31515">:readme.md</span> | ||
| 376 | </span></span><span style="display:flex;"><span> | ||
| 377 | </span></span><span style="display:flex;"><span><span style="color:#008000"># Must be at the end!</span> | ||
| 378 | </span></span><span style="display:flex;"><span>virtual-root=<span style="color:#a31515">/</span> | ||
| 379 | </span></span><span style="display:flex;"><span>scan-path=<span style="color:#a31515">/home/git/</span> | ||
| 380 | </span></span></code></pre><p>For <code>syntax-highlighting-edited.sh</code> follow instructions on | ||
| 381 | <a href="https://wiki.archlinux.org/title/Cgit#Using_highlight">https://wiki.archlinux.org/title/Cgit</a>.</p> | ||
| 382 | <ul> | ||
| 383 | <li><code>/usr/share/cgit/cgit.css</code></li> | ||
| 384 | </ul> | ||
| 385 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>* { | ||
| 386 | </span></span><span style="display:flex;"><span> <span style="color:#00f">font-size</span>: 11<span style="color:#2b91af">pt</span>; | ||
| 387 | </span></span><span style="display:flex;"><span>} | ||
| 388 | </span></span><span style="display:flex;"><span> | ||
| 389 | </span></span><span style="display:flex;"><span>body { | ||
| 390 | </span></span><span style="display:flex;"><span> <span style="color:#00f">font-family</span>: <span style="color:#00f">monospace</span>; | ||
| 391 | </span></span><span style="display:flex;"><span> <span style="color:#00f">background</span>: <span style="color:#00f">white</span>; | ||
| 392 | </span></span><span style="display:flex;"><span> <span style="color:#00f">padding</span>: 1<span style="color:#2b91af">em</span>; | ||
| 393 | </span></span><span style="display:flex;"><span>} | ||
| 394 | </span></span><span style="display:flex;"><span> | ||
| 395 | </span></span><span style="display:flex;"><span>th, td { | ||
| 396 | </span></span><span style="display:flex;"><span> <span style="color:#00f">text-align</span>: <span style="color:#00f">left</span>; | ||
| 397 | </span></span><span style="display:flex;"><span>} | ||
| 398 | </span></span><span style="display:flex;"><span> | ||
| 399 | </span></span><span style="display:flex;"><span><span style="color:#008000">/* HEADER */</span> | ||
| 400 | </span></span><span style="display:flex;"><span> | ||
| 401 | </span></span><span style="display:flex;"><span>#header { | ||
| 402 | </span></span><span style="display:flex;"><span> <span style="color:#00f">margin-bottom</span>: 1<span style="color:#2b91af">em</span>; | ||
| 403 | </span></span><span style="display:flex;"><span>} | ||
| 404 | </span></span><span style="display:flex;"><span> | ||
| 405 | </span></span><span style="display:flex;"><span>#header .<span style="color:#2b91af">logo</span> img { | ||
| 406 | </span></span><span style="display:flex;"><span> <span style="color:#00f">display</span>: <span style="color:#00f">block</span>; | ||
| 407 | </span></span><span style="display:flex;"><span> <span style="color:#00f">height</span>: 3<span style="color:#2b91af">em</span>; | ||
| 408 | </span></span><span style="display:flex;"><span> <span style="color:#00f">margin-right</span>: 10<span style="color:#2b91af">px</span>; | ||
| 409 | </span></span><span style="display:flex;"><span>} | ||
| 410 | </span></span><span style="display:flex;"><span> | ||
| 411 | </span></span><span style="display:flex;"><span>#header .<span style="color:#2b91af">sub</span>.<span style="color:#2b91af">right</span> { | ||
| 412 | </span></span><span style="display:flex;"><span> <span style="color:#00f">display</span>: <span style="color:#00f">none</span>; | ||
| 413 | </span></span><span style="display:flex;"><span>} | ||
| 414 | </span></span><span style="display:flex;"><span> | ||
| 415 | </span></span><span style="display:flex;"><span><span style="color:#008000">/* FOOTER */</span> | ||
| 416 | </span></span><span style="display:flex;"><span> | ||
| 417 | </span></span><span style="display:flex;"><span>.<span style="color:#2b91af">footer</span> { | ||
| 418 | </span></span><span style="display:flex;"><span> <span style="color:#00f">margin-top</span>: 2<span style="color:#2b91af">em</span>; | ||
| 419 | </span></span><span style="display:flex;"><span> <span style="color:#00f">font-style</span>: <span style="color:#00f">italic</span>; | ||
| 420 | </span></span><span style="display:flex;"><span>} | ||
| 421 | </span></span><span style="display:flex;"><span> | ||
| 422 | </span></span><span style="display:flex;"><span>.<span style="color:#2b91af">footer</span>, .<span style="color:#2b91af">footer</span> a { | ||
| 423 | </span></span><span style="display:flex;"><span> <span style="color:#00f">color</span>: <span style="color:#00f">gray</span>; | ||
| 424 | </span></span><span style="display:flex;"><span>} | ||
| 425 | </span></span><span style="display:flex;"><span> | ||
| 426 | </span></span><span style="display:flex;"><span><span style="color:#008000">/* TABS */</span> | ||
| 427 | </span></span><span style="display:flex;"><span> | ||
| 428 | </span></span><span style="display:flex;"><span>.<span style="color:#2b91af">tabs</span> a { | ||
| 429 | </span></span><span style="display:flex;"><span> <span style="color:#00f">margin-bottom</span>: 2<span style="color:#2b91af">em</span>; | ||
| 430 | </span></span><span style="display:flex;"><span> <span style="color:#00f">display</span>: <span style="color:#00f">inline-block</span>; | ||
| 431 | </span></span><span style="display:flex;"><span> <span style="color:#00f">margin-right</span>: 1<span style="color:#2b91af">em</span>; | ||
| 432 | </span></span><span style="display:flex;"><span>} | ||
| 433 | </span></span><span style="display:flex;"><span> | ||
| 434 | </span></span><span style="display:flex;"><span>.<span style="color:#2b91af">tabs</span> td a:only-child { | ||
| 435 | </span></span><span style="display:flex;"><span> <span style="color:#00f">display</span>: <span style="color:#00f">none</span>; | ||
| 436 | </span></span><span style="display:flex;"><span>} | ||
| 437 | </span></span><span style="display:flex;"><span> | ||
| 438 | </span></span><span style="display:flex;"><span><span style="color:#008000">/* HIDING ELEMENTS */</span> | ||
| 439 | </span></span><span style="display:flex;"><span> | ||
| 440 | </span></span><span style="display:flex;"><span>.<span style="color:#2b91af">cgit-panel</span>, .<span style="color:#2b91af">form</span> { | ||
| 441 | </span></span><span style="display:flex;"><span> <span style="color:#00f">display</span>: <span style="color:#00f">none</span>; | ||
| 442 | </span></span><span style="display:flex;"><span>} | ||
| 443 | </span></span><span style="display:flex;"><span> | ||
| 444 | </span></span><span style="display:flex;"><span><span style="color:#008000">/* LISTS */</span> | ||
| 445 | </span></span><span style="display:flex;"><span> | ||
| 446 | </span></span><span style="display:flex;"><span>.<span style="color:#2b91af">list</span> td, .<span style="color:#2b91af">list</span> th { | ||
| 447 | </span></span><span style="display:flex;"><span> <span style="color:#00f">padding-right</span>: 2<span style="color:#2b91af">em</span>; | ||
| 448 | </span></span><span style="display:flex;"><span>} | ||
| 449 | </span></span><span style="display:flex;"><span> | ||
| 450 | </span></span><span style="display:flex;"><span>.<span style="color:#2b91af">list</span> .<span style="color:#2b91af">nohover</span> a { | ||
| 451 | </span></span><span style="display:flex;"><span> <span style="color:#00f">color</span>: <span style="color:#00f">black</span>; | ||
| 452 | </span></span><span style="display:flex;"><span>} | ||
| 453 | </span></span><span style="display:flex;"><span> | ||
| 454 | </span></span><span style="display:flex;"><span>.<span style="color:#2b91af">list</span> .<span style="color:#2b91af">button</span> { | ||
| 455 | </span></span><span style="display:flex;"><span> <span style="color:#00f">padding-right</span>: 0.5<span style="color:#2b91af">em</span>; | ||
| 456 | </span></span><span style="display:flex;"><span>} | ||
| 457 | </span></span><span style="display:flex;"><span> | ||
| 458 | </span></span><span style="display:flex;"><span><span style="color:#008000">/* COMMIT */</span> | ||
| 459 | </span></span><span style="display:flex;"><span> | ||
| 460 | </span></span><span style="display:flex;"><span>.<span style="color:#2b91af">commit-subject</span> { | ||
| 461 | </span></span><span style="display:flex;"><span> <span style="color:#00f">padding</span>: 1<span style="color:#2b91af">em</span> 0; | ||
| 462 | </span></span><span style="display:flex;"><span>} | ||
| 463 | </span></span><span style="display:flex;"><span> | ||
| 464 | </span></span><span style="display:flex;"><span>.<span style="color:#2b91af">decoration</span> a { | ||
| 465 | </span></span><span style="display:flex;"><span> <span style="color:#00f">padding-left</span>: 0.5<span style="color:#2b91af">em</span>; | ||
| 466 | </span></span><span style="display:flex;"><span>} | ||
| 467 | </span></span><span style="display:flex;"><span> | ||
| 468 | </span></span><span style="display:flex;"><span>.<span style="color:#2b91af">commit-info</span> th { | ||
| 469 | </span></span><span style="display:flex;"><span> <span style="color:#00f">padding-right</span>: 1<span style="color:#2b91af">em</span>; | ||
| 470 | </span></span><span style="display:flex;"><span>} | ||
| 471 | </span></span><span style="display:flex;"><span> | ||
| 472 | </span></span><span style="display:flex;"><span>.<span style="color:#2b91af">commit-subject</span> { | ||
| 473 | </span></span><span style="display:flex;"><span> <span style="color:#00f">padding</span>: 2<span style="color:#2b91af">em</span> 0; | ||
| 474 | </span></span><span style="display:flex;"><span>} | ||
| 475 | </span></span><span style="display:flex;"><span> | ||
| 476 | </span></span><span style="display:flex;"><span>table.<span style="color:#2b91af">diff</span> div.<span style="color:#2b91af">head</span> { | ||
| 477 | </span></span><span style="display:flex;"><span> <span style="color:#00f">padding-top</span>: 2<span style="color:#2b91af">em</span>; | ||
| 478 | </span></span><span style="display:flex;"><span>} | ||
| 479 | </span></span><span style="display:flex;"><span> | ||
| 480 | </span></span><span style="display:flex;"><span>table.<span style="color:#2b91af">diffstat</span> td { | ||
| 481 | </span></span><span style="display:flex;"><span> <span style="color:#00f">padding-right</span>: 1<span style="color:#2b91af">em</span>; | ||
| 482 | </span></span><span style="display:flex;"><span>} | ||
| 483 | </span></span><span style="display:flex;"><span> | ||
| 484 | </span></span><span style="display:flex;"><span><span style="color:#008000">/* CONTENT */</span> | ||
| 485 | </span></span><span style="display:flex;"><span> | ||
| 486 | </span></span><span style="display:flex;"><span>.<span style="color:#2b91af">linenumbers</span> { | ||
| 487 | </span></span><span style="display:flex;"><span> <span style="color:#00f">padding-right</span>: 0.5<span style="color:#2b91af">em</span>; | ||
| 488 | </span></span><span style="display:flex;"><span>} | ||
| 489 | </span></span><span style="display:flex;"><span> | ||
| 490 | </span></span><span style="display:flex;"><span>.<span style="color:#2b91af">linenumbers</span> a { | ||
| 491 | </span></span><span style="display:flex;"><span> <span style="color:#00f">color</span>: <span style="color:#00f">gray</span>; | ||
| 492 | </span></span><span style="display:flex;"><span>} | ||
| 493 | </span></span><span style="display:flex;"><span> | ||
| 494 | </span></span><span style="display:flex;"><span>.<span style="color:#2b91af">pager</span> { | ||
| 495 | </span></span><span style="display:flex;"><span> <span style="color:#00f">display</span>: <span style="color:#00f">flex</span>; | ||
| 496 | </span></span><span style="display:flex;"><span> <span style="color:#00f">list-style-type</span>: <span style="color:#00f">none</span>; | ||
| 497 | </span></span><span style="display:flex;"><span> <span style="color:#00f">padding</span>: 0; | ||
| 498 | </span></span><span style="display:flex;"><span> gap: 0.5<span style="color:#2b91af">em</span>; | ||
| 499 | </span></span><span style="display:flex;"><span>} | ||
| 500 | </span></span><span style="display:flex;"><span> | ||
| 501 | </span></span><span style="display:flex;"><span><span style="color:#008000">/* DIFF COLORS */</span> | ||
| 502 | </span></span><span style="display:flex;"><span> | ||
| 503 | </span></span><span style="display:flex;"><span>table.<span style="color:#2b91af">diff</span> { | ||
| 504 | </span></span><span style="display:flex;"><span> <span style="color:#00f">width</span>: 100<span style="color:#2b91af">%</span>; | ||
| 505 | </span></span><span style="display:flex;"><span>} | ||
| 506 | </span></span><span style="display:flex;"><span> | ||
| 507 | </span></span><span style="display:flex;"><span>table.<span style="color:#2b91af">diff</span> td { | ||
| 508 | </span></span><span style="display:flex;"><span> <span style="color:#00f">white-space</span>: <span style="color:#00f">pre</span>; | ||
| 509 | </span></span><span style="display:flex;"><span>} | ||
| 510 | </span></span><span style="display:flex;"><span> | ||
| 511 | </span></span><span style="display:flex;"><span>table.<span style="color:#2b91af">diff</span> td div.<span style="color:#2b91af">head</span> { | ||
| 512 | </span></span><span style="display:flex;"><span> <span style="color:#00f">font-weight</span>: <span style="color:#00f">bold</span>; | ||
| 513 | </span></span><span style="display:flex;"><span> <span style="color:#00f">margin-top</span>: 1<span style="color:#2b91af">em</span>; | ||
| 514 | </span></span><span style="display:flex;"><span> <span style="color:#00f">color</span>: <span style="color:#00f">black</span>; | ||
| 515 | </span></span><span style="display:flex;"><span>} | ||
| 516 | </span></span><span style="display:flex;"><span> | ||
| 517 | </span></span><span style="display:flex;"><span>table.<span style="color:#2b91af">diff</span> td div.<span style="color:#2b91af">hunk</span> { | ||
| 518 | </span></span><span style="display:flex;"><span> <span style="color:#00f">color</span>: #009; | ||
| 519 | </span></span><span style="display:flex;"><span>} | ||
| 520 | </span></span><span style="display:flex;"><span> | ||
| 521 | </span></span><span style="display:flex;"><span>table.<span style="color:#2b91af">diff</span> td div.<span style="color:#2b91af">add</span> { | ||
| 522 | </span></span><span style="display:flex;"><span> <span style="color:#00f">color</span>: <span style="color:#00f">green</span>; | ||
| 523 | </span></span><span style="display:flex;"><span>} | ||
| 524 | </span></span><span style="display:flex;"><span> | ||
| 525 | </span></span><span style="display:flex;"><span>table.<span style="color:#2b91af">diff</span> td div.<span style="color:#2b91af">del</span> { | ||
| 526 | </span></span><span style="display:flex;"><span> <span style="color:#00f">color</span>: <span style="color:#00f">red</span>; | ||
| 527 | </span></span><span style="display:flex;"><span>} | ||
| 528 | </span></span></code></pre></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 +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><p>A simple way to make presentations without using desktop apps or using online | ||
| 540 | services is <a href="https://github.com/remarkjs/remark">https://github.com/remarkjs/remark</a>.</p> | ||
| 541 | <p>First create <code>index.html</code> and be sure you make changes to <code>config</code> variable.</p> | ||
| 542 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#00f">&lt;!DOCTYPE html&gt;</span> | ||
| 543 | </span></span><span style="display:flex;"><span>&lt;html&gt; | ||
| 544 | </span></span><span style="display:flex;"><span> | ||
| 545 | </span></span><span style="display:flex;"><span>&lt;head&gt; | ||
| 546 | </span></span><span style="display:flex;"><span> &lt;title&gt;&lt;/title&gt; | ||
| 547 | </span></span><span style="display:flex;"><span> &lt;meta charset=<span style="color:#a31515">&#34;utf-8&#34;</span>&gt; | ||
| 548 | </span></span><span style="display:flex;"><span> &lt;style&gt; | ||
| 549 | </span></span><span style="display:flex;"><span> body { | ||
| 550 | </span></span><span style="display:flex;"><span> <span style="color:#00f">font-family</span>: <span style="color:#a31515">&#39;SF Pro Display&#39;</span>; | ||
| 551 | </span></span><span style="display:flex;"><span> } | ||
| 552 | </span></span><span style="display:flex;"><span> | ||
| 553 | </span></span><span style="display:flex;"><span> .<span style="color:#2b91af">remark-code</span>, | ||
| 554 | </span></span><span style="display:flex;"><span> .<span style="color:#2b91af">remark-inline-code</span> { | ||
| 555 | </span></span><span style="display:flex;"><span> <span style="color:#00f">font-family</span>: <span style="color:#a31515">&#39;SF Mono&#39;</span>; | ||
| 556 | </span></span><span style="display:flex;"><span> <span style="color:#00f">font-size</span>: <span style="color:#00f">medium</span>; | ||
| 557 | </span></span><span style="display:flex;"><span> <span style="color:#00f">background-color</span>: <span style="color:#00f">gainsboro</span>; | ||
| 558 | </span></span><span style="display:flex;"><span> <span style="color:#00f">border-radius</span>: 5<span style="color:#2b91af">px</span>; | ||
| 559 | </span></span><span style="display:flex;"><span> <span style="color:#00f">padding</span>: 0 5<span style="color:#2b91af">px</span>; | ||
| 560 | </span></span><span style="display:flex;"><span> } | ||
| 561 | </span></span><span style="display:flex;"><span> &lt;/style&gt; | ||
| 562 | </span></span><span style="display:flex;"><span>&lt;/head&gt; | ||
| 563 | </span></span><span style="display:flex;"><span> | ||
| 564 | </span></span><span style="display:flex;"><span>&lt;body&gt; | ||
| 565 | </span></span><span style="display:flex;"><span> &lt;textarea id=<span style="color:#a31515">&#34;source&#34;</span>&gt;&lt;/textarea&gt; | ||
| 566 | </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; | ||
| 567 | </span></span><span style="display:flex;"><span> &lt;script&gt; | ||
| 568 | </span></span><span style="display:flex;"><span> <span style="color:#00f">const</span> config = { | ||
| 569 | </span></span><span style="display:flex;"><span> title: <span style="color:#a31515">&#39;My presentation&#39;</span>, | ||
| 570 | </span></span><span style="display:flex;"><span> file: <span style="color:#a31515">&#39;presentation.md&#39;</span>, | ||
| 571 | </span></span><span style="display:flex;"><span> }; | ||
| 572 | </span></span><span style="display:flex;"><span> | ||
| 573 | </span></span><span style="display:flex;"><span> document.title = config.title; | ||
| 574 | </span></span><span style="display:flex;"><span> remark.create({ sourceUrl: config.file }); | ||
| 575 | </span></span><span style="display:flex;"><span> &lt;/script&gt; | ||
| 576 | </span></span><span style="display:flex;"><span>&lt;/body&gt; | ||
| 577 | </span></span><span style="display:flex;"><span> | ||
| 578 | </span></span><span style="display:flex;"><span>&lt;/html&gt; | ||
| 579 | </span></span></code></pre><p>Now the markdown file <code>presentation.md</code> with presenetation. <code>---</code> is used to | ||
| 580 | separate slides. Other stuff is just pure markdown.</p> | ||
| 581 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>class: center, middle | ||
| 582 | </span></span><span style="display:flex;"><span> | ||
| 583 | </span></span><span style="display:flex;"><span><span style="font-weight:bold"># Main title of the presentation | ||
| 584 | </span></span></span><span style="display:flex;"><span><span style="font-weight:bold"></span> | ||
| 585 | </span></span><span style="display:flex;"><span>--- | ||
| 586 | </span></span><span style="display:flex;"><span> | ||
| 587 | </span></span><span style="display:flex;"><span><span style="font-weight:bold"># Fist slide | ||
| 588 | </span></span></span><span style="display:flex;"><span><span style="font-weight:bold"></span> | ||
| 589 | </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. | ||
| 590 | </span></span><span style="display:flex;"><span> | ||
| 591 | </span></span><span style="display:flex;"><span><span style="color:#00f">-</span> Lorem ipsum dolor sit amet, consectetur adipiscing elit. | ||
| 592 | </span></span><span style="display:flex;"><span><span style="color:#00f">-</span> Integer aliquet mauris a felis fringilla, ut congue massa finibus. | ||
| 593 | </span></span><span style="display:flex;"><span> | ||
| 594 | </span></span><span style="display:flex;"><span>--- | ||
| 595 | </span></span><span style="display:flex;"><span> | ||
| 596 | </span></span><span style="display:flex;"><span><span style="font-weight:bold"># Slide two | ||
| 597 | </span></span></span><span style="display:flex;"><span><span style="font-weight:bold"></span> | ||
| 598 | </span></span><span style="display:flex;"><span><span style="color:#00f">-</span> Lorem ipsum dolor sit amet, consectetur adipiscing elit. | ||
| 599 | </span></span><span style="display:flex;"><span><span style="color:#00f">-</span> Vestibulum eget leo ac dolor venenatis pulvinar. | ||
| 600 | </span></span></code></pre></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 +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><p>Make bulk thumbnails of JPGs with ImageMagick.</p> | ||
| 612 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#00f">#!/bin/bash | ||
| 613 | </span></span></span><span style="display:flex;"><span><span style="color:#00f"></span> | ||
| 614 | </span></span><span style="display:flex;"><span>directory=<span style="color:#a31515">&#34;./images/&#34;</span> | ||
| 615 | </span></span><span style="display:flex;"><span>dimensions=<span style="color:#a31515">&#34;360x360&#34;</span> | ||
| 616 | </span></span><span style="display:flex;"><span> | ||
| 617 | </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> | ||
| 618 | </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> | ||
| 619 | </span></span><span style="display:flex;"><span><span style="color:#00f">done</span> | ||
| 620 | </span></span></code></pre></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 +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><p>I love reading the original manuscripts of Edsger W. Dijkstra. They are | ||
| 632 | available online at the University of Texas at Austin website, but I also found | ||
| 633 | MOBI version. I converted it into ePub as well.</p> | ||
| 634 | <p>Downloads:</p> | ||
| 635 | <ul> | ||
| 636 | <li><a href="https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/ewd-manuscripts.mobi">MOBI version of all Manuscripts</a></li> | ||
| 637 | <li><a href="https://mitjafelicijan.fra1.digitaloceanspaces.com/haphazard/ewd-manuscripts.epub">ePub version of all Manuscripts</a></li> | ||
| 638 | </ul> | ||
| 639 | <p>Sources and credits:</p> | ||
| 640 | <ul> | ||
| 641 | <li><a href="https://www.cs.utexas.edu/users/EWD/index00xx.html">Original manuscripts from University of Texas at Austin</a></li> | ||
| 642 | <li><a href="https://github.com/evmn/The-Manuscripts-of-Edsger-W.-Dijkstra">Original repository of MOBI version</a></li> | ||
| 643 | </ul> | ||
| 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 +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><p><a href="https://craigbarnes.gitlab.io/dte/"><code>dte</code></a> is an interesting editor I started | ||
| 658 | using lately more and more. Since it is using | ||
| 659 | <a href="https://linux.die.net/man/3/execvp"><code>execvp()</code></a> it can be easily extended. I | ||
| 660 | needed comment/uncomment feature so I created a small utility that does this for | ||
| 661 | me. Code lives on repository <a href="https://git.mitjafelicijan.com/dte-extensions.git/about/">dte | ||
| 662 | extensions</a> but this | ||
| 663 | utilities can be used for whatever you want. Make sure you have version 1.11 or | ||
| 664 | above.</p> | ||
| 665 | <p>Next one will be invoking formatter based on the type of a file.</p> | ||
| 666 | <p>My config that works for me.</p> | ||
| 667 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>set show-line-numbers true; | ||
| 668 | </span></span><span style="display:flex;"><span>set tab-width 4; | ||
| 669 | </span></span><span style="display:flex;"><span>set <span style="color:#00f">case</span>-sensitive-search false; | ||
| 670 | </span></span><span style="display:flex;"><span> | ||
| 671 | </span></span><span style="display:flex;"><span><span style="color:#008000"># Special aliases</span> | ||
| 672 | </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> | ||
| 673 | </span></span><span style="display:flex;"><span>alias m_format <span style="color:#a31515">&#39;save; exec go fmt .; reload&#39;</span> | ||
| 674 | </span></span><span style="display:flex;"><span>alias m_duplicate <span style="color:#a31515">&#39;copy;paste&#39;</span>; | ||
| 675 | </span></span><span style="display:flex;"><span> | ||
| 676 | </span></span><span style="display:flex;"><span><span style="color:#008000"># Useful aliases.</span> | ||
| 677 | </span></span><span style="display:flex;"><span>alias m_force_close <span style="color:#a31515">&#39;quit -f&#39;</span>; | ||
| 678 | </span></span><span style="display:flex;"><span>alias m_reload <span style="color:#a31515">&#39;close; open $FILE&#39;</span> | ||
| 679 | </span></span><span style="display:flex;"><span> | ||
| 680 | </span></span><span style="display:flex;"><span><span style="color:#008000"># Key bindings.</span> | ||
| 681 | </span></span><span style="display:flex;"><span>bind M-s save; | ||
| 682 | </span></span><span style="display:flex;"><span>bind M-q m_force_close; | ||
| 683 | </span></span><span style="display:flex;"><span>bind M-z refresh; | ||
| 684 | </span></span><span style="display:flex;"><span>bind C-down blkdown; | ||
| 685 | </span></span><span style="display:flex;"><span>bind C-up blkup; | ||
| 686 | </span></span><span style="display:flex;"><span>bind C-_ m_comment; | ||
| 687 | </span></span><span style="display:flex;"><span>bind M-. m_format; | ||
| 688 | </span></span><span style="display:flex;"><span>bind C-d m_duplicate; | ||
| 689 | </span></span><span style="display:flex;"><span> | ||
| 690 | </span></span><span style="display:flex;"><span><span style="color:#008000"># Syntax highlighting.</span> | ||
| 691 | </span></span><span style="display:flex;"><span>hi preproc magenta; | ||
| 692 | </span></span><span style="display:flex;"><span>hi keyword red; | ||
| 693 | </span></span><span style="display:flex;"><span>hi linenumber blue; | ||
| 694 | </span></span><span style="display:flex;"><span>hi comment cyan; | ||
| 695 | </span></span></code></pre></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 +0200</pubDate> | ||
| 704 | <guid>https://mitjafelicijan.com/grep-to-less-maintain-colors.html</guid> | ||
| 705 | <description>I often use grep to search for todo&#39;s in my code and other people&#39;s code andthen pipe them in less and I missed having colors that grep outputs in less.</description> | ||
| 706 | <content:encoded><p>I often use <code>grep</code> to search for todo's in my code and other people's code and | ||
| 707 | then pipe them in <code>less</code> and I missed having colors that grep outputs in <code>less</code>.</p> | ||
| 708 | <ul> | ||
| 709 | <li>Grep's <code>--color=always</code> use markers to highlight the matching strings.</li> | ||
| 710 | <li>Less's <code>-R</code> option outputs &quot;raw&quot; control characters.</li> | ||
| 711 | </ul> | ||
| 712 | <p>You could use <code>alias grep='grep --color=always'</code> and <code>alias less='less -R'</code> or | ||
| 713 | create todo function in your <code>.bashrc</code> that accepts first argument as search | ||
| 714 | string.</p> | ||
| 715 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># This is where the magic happens.</span> | ||
| 716 | </span></span><span style="display:flex;"><span>grep --color=always -rni <span style="color:#a31515">&#34;TODO:&#34;</span> | less -R | ||
| 717 | </span></span></code></pre><figure> | ||
| 718 | <img src="/notes/grep-less.png" alt="Less and grep" /> | ||
| 719 | </figure> | ||
| 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 +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><p>In Bash, the <code>$SECONDS</code> variable is a special variable that automatically keeps | ||
| 732 | track of the number of seconds since the current shell or script started | ||
| 733 | executing. It starts counting from the moment the script begins running.</p> | ||
| 734 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#00f">#!/bin/bash | ||
| 735 | </span></span></span><span style="display:flex;"><span><span style="color:#00f"></span> | ||
| 736 | </span></span><span style="display:flex;"><span><span style="color:#008000"># Reset the timer to zero.</span> | ||
| 737 | </span></span><span style="display:flex;"><span>SECONDS=0 | ||
| 738 | </span></span><span style="display:flex;"><span> | ||
| 739 | </span></span><span style="display:flex;"><span><span style="color:#008000"># Do something.</span> | ||
| 740 | </span></span><span style="display:flex;"><span>sleep 5 | ||
| 741 | </span></span><span style="display:flex;"><span> | ||
| 742 | </span></span><span style="display:flex;"><span><span style="color:#008000"># Print the time elapsed.</span> | ||
| 743 | </span></span><span style="display:flex;"><span>echo <span style="color:#a31515">&#34;Time taken: </span>$SECONDS<span style="color:#a31515"> seconds&#34;</span> | ||
| 744 | </span></span></code></pre></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 +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><p>Dungeon Crawl Stone Soup has a a very small font by default. On a 4k display, it | ||
| 756 | is barely readable. This is how I made it playable.</p> | ||
| 757 | <p>Make a file <code>~/.crawlrc</code> with the following content:</p> | ||
| 758 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># Adjust the sizes to your liking.</span> | ||
| 759 | </span></span><span style="display:flex;"><span> | ||
| 760 | </span></span><span style="display:flex;"><span>tile_font_crt_size = <span style="color:#a31515">32</span> | ||
| 761 | </span></span><span style="display:flex;"><span>tile_font_stat_size = <span style="color:#a31515">32</span> | ||
| 762 | </span></span><span style="display:flex;"><span>tile_font_msg_size = <span style="color:#a31515">32</span> | ||
| 763 | </span></span><span style="display:flex;"><span>tile_font_tip_size = <span style="color:#a31515">32</span> | ||
| 764 | </span></span><span style="display:flex;"><span>tile_font_lbl_size = <span style="color:#a31515">32</span> | ||
| 765 | </span></span><span style="display:flex;"><span>tile_sidebar_pixels = <span style="color:#a31515">64</span> | ||
| 766 | </span></span></code></pre><p>To zoom in and out in viewport, press <code>Ctrl+</code> and <code>Ctrl-</code> respectively.</p> | ||
| 767 | <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 | ||
| 768 | Guide</a> | ||
| 769 | file.</p> | ||
| 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 +0200</pubDate> | ||
| 779 | <guid>https://mitjafelicijan.com/drawing-pixels-in-plan9.html</guid> | ||
| 780 | <description>I have started exploring Plan9&#39;s graphics capabilities.</description> | ||
| 781 | <content:encoded><p>I have started exploring Plan9's graphics capabilities. This is a hello world | ||
| 782 | alternative for drawing that draws a yellow square on a blue background.</p> | ||
| 783 | <p>More information:</p> | ||
| 784 | <ul> | ||
| 785 | <li><a href="https://github.com/0intro/plan9/blob/main/sys/include/draw.h">draw.h header file</a> | ||
| 786 | contains all the drawing functions</li> | ||
| 787 | <li><a href="https://9fans.github.io/plan9port/man/man3/draw.html">draw man page</a> | ||
| 788 | has a bit more digestable descriptions of the draw functions</li> | ||
| 789 | <li><a href="https://9fans.github.io/plan9port/man/man3/graphics.html">graphics man page</a> | ||
| 790 | has a bit more digestable descriptions of the graphics functions</li> | ||
| 791 | <li><a href="https://9fans.github.io/plan9port/man/man3/">all man pages</a> | ||
| 792 | can be a valuable resource for learning about the system</li> | ||
| 793 | </ul> | ||
| 794 | <figure> | ||
| 795 | <img src="/notes/plan9-pixels.png" alt="Plan9 Howdy World!" /> | ||
| 796 | </figure> | ||
| 797 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000">// main.c | ||
| 798 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span><span style="color:#00f">#include</span> <span style="color:#00f">&lt;u.h&gt;</span><span style="color:#00f"> | ||
| 799 | </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"> | ||
| 800 | </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"> | ||
| 801 | </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"> | ||
| 802 | </span></span></span><span style="display:flex;"><span><span style="color:#00f"></span> | ||
| 803 | </span></span><span style="display:flex;"><span><span style="color:#2b91af">void</span> | ||
| 804 | </span></span><span style="display:flex;"><span>main() | ||
| 805 | </span></span><span style="display:flex;"><span>{ | ||
| 806 | </span></span><span style="display:flex;"><span> ulong co; | ||
| 807 | </span></span><span style="display:flex;"><span> Image *im, *bg; | ||
| 808 | </span></span><span style="display:flex;"><span> co = 0x0000FFFF; | ||
| 809 | </span></span><span style="display:flex;"><span> | ||
| 810 | </span></span><span style="display:flex;"><span> <span style="color:#00f">if</span> (initdraw(nil, nil, argv0) &lt; 0) | ||
| 811 | </span></span><span style="display:flex;"><span> { | ||
| 812 | </span></span><span style="display:flex;"><span> sysfatal(<span style="color:#a31515">&#34;%s: %r&#34;</span>, argv0); | ||
| 813 | </span></span><span style="display:flex;"><span> } | ||
| 814 | </span></span><span style="display:flex;"><span> | ||
| 815 | </span></span><span style="display:flex;"><span> im = allocimage(display, Rect(0, 0, 300, 300), RGB24, 0, DYellow); | ||
| 816 | </span></span><span style="display:flex;"><span> bg = allocimage(display, Rect(0, 0, 1, 1), RGB24, 1, co); | ||
| 817 | </span></span><span style="display:flex;"><span> | ||
| 818 | </span></span><span style="display:flex;"><span> <span style="color:#00f">if</span> (im == nil || bg == nil) | ||
| 819 | </span></span><span style="display:flex;"><span> { | ||
| 820 | </span></span><span style="display:flex;"><span> sysfatal(<span style="color:#a31515">&#34;not enough memory&#34;</span>); | ||
| 821 | </span></span><span style="display:flex;"><span> } | ||
| 822 | </span></span><span style="display:flex;"><span> | ||
| 823 | </span></span><span style="display:flex;"><span> draw(screen, screen-&gt;r, bg, nil, ZP); | ||
| 824 | </span></span><span style="display:flex;"><span> draw(screen, screen-&gt;r, im, nil, Pt(-40, -40)); | ||
| 825 | </span></span><span style="display:flex;"><span> | ||
| 826 | </span></span><span style="display:flex;"><span> flushimage(display, Refnone); | ||
| 827 | </span></span><span style="display:flex;"><span> | ||
| 828 | </span></span><span style="display:flex;"><span> <span style="color:#008000">// Wait 10 seconds before exiting. | ||
| 829 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span> sleep(10000); | ||
| 830 | </span></span><span style="display:flex;"><span> | ||
| 831 | </span></span><span style="display:flex;"><span> exits(nil); | ||
| 832 | </span></span><span style="display:flex;"><span>} | ||
| 833 | </span></span></code></pre><p>And then compile with <code>mk</code> (mkfile below):</p> | ||
| 834 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># mkfile | ||
| 835 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></span><span style="">&lt;/$objtype/mkfile</span> | ||
| 836 | </span></span><span style="display:flex;"><span> | ||
| 837 | </span></span><span style="display:flex;"><span>RC=/rc/bin | ||
| 838 | </span></span><span style="display:flex;"><span>BIN=/$objtype/bin | ||
| 839 | </span></span><span style="display:flex;"><span>MAN=/sys/man | ||
| 840 | </span></span><span style="display:flex;"><span> | ||
| 841 | </span></span><span style="display:flex;"><span>main: | ||
| 842 | </span></span><span style="display:flex;"><span> $CC $CFLAGS main.c | ||
| 843 | </span></span><span style="display:flex;"><span> $LD $LDFLAGS -o main main.$O | ||
| 844 | </span></span></code></pre><p>And run with <code>./main</code>. To exit the program, press <code>Delete key</code> (strange but this | ||
| 845 | is the alternative for Ctrl+C).</p> | ||
| 846 | <p><em>This is <strong>very cool</strong> indeed!</em></p> | ||
| 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 +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><p>In the root of your repository create a folder <code>.github/workflows</code> and in that | ||
| 859 | folder create a file a file <code>cron.yaml</code>. This file can be named whatever you | ||
| 860 | wish. But it has to be a <code>yaml</code> file.</p> | ||
| 861 | <p>File below (<code>.github/workflows/cron.yaml</code>) describes an action that will trigger | ||
| 862 | every six hours and it will curl example.com.</p> | ||
| 863 | <p>However. Be sure that you have enough credits. Free account is not that generous | ||
| 864 | with the minutes they give you for free. Check more about GitHub Actions usage | ||
| 865 | on their website <a href="https://docs.github.com/en/actions">https://docs.github.com/en/actions</a>.</p> | ||
| 866 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># .github/workflows/cron.yaml</span> | ||
| 867 | </span></span><span style="display:flex;"><span>name: Do a curl every 6 hours | ||
| 868 | </span></span><span style="display:flex;"><span>on: | ||
| 869 | </span></span><span style="display:flex;"><span> schedule: | ||
| 870 | </span></span><span style="display:flex;"><span> - cron: <span style="color:#a31515">&#39;0 */6 * * *&#39;</span> | ||
| 871 | </span></span><span style="display:flex;"><span>jobs: | ||
| 872 | </span></span><span style="display:flex;"><span> cron: | ||
| 873 | </span></span><span style="display:flex;"><span> runs-on: ubuntu-latest | ||
| 874 | </span></span><span style="display:flex;"><span> steps: | ||
| 875 | </span></span><span style="display:flex;"><span> - name: Call some url | ||
| 876 | </span></span><span style="display:flex;"><span> run: curl &#39;https://example.com&#39; | ||
| 877 | </span></span></code></pre></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 +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><p>An amazing game deserves an amazing guide. All this material can be find in some | ||
| 889 | form on another on <a href="https://github.com/crawl/crawl">craw's</a> official repository.</p> | ||
| 890 | <ul> | ||
| 891 | <li><a href="/notes/dcss-quickstart.pdf">DCSS Quickstart</a> - Very short introduction to the | ||
| 892 | game</li> | ||
| 893 | <li><a href="/notes/dcss_manual.pdf">DCSS Manual</a> - Extensive manual about the game</li> | ||
| 894 | </ul> | ||
| 895 | <figure> | ||
| 896 | <img src="/notes/dcss.jpg" alt="Dungeon Crawl Stone Soup" /> | ||
| 897 | </figure> | ||
| 898 | <p><strong>Movement and Exploration</strong></p> | ||
| 899 | <ul> | ||
| 900 | <li>You can move around with the numpad (try numlock on and off), vi-keys, or | ||
| 901 | clicking with the mouse. Arrow keys work, though you can't move diagonally | ||
| 902 | with them. Pressing Shift and a direction will move until you see/hit | ||
| 903 | something.</li> | ||
| 904 | <li>Pressing <code>&gt;</code> will take you down a staircase, and <code>&lt;</code> to go up a staircase.</li> | ||
| 905 | <li>You can open doors by walking into them, and close them with <code>C</code>.</li> | ||
| 906 | <li>You can autoexplore by pressing <code>o</code>.</li> | ||
| 907 | <li>You can re-view recent messages with <code>Ctrl-p</code>.</li> | ||
| 908 | </ul> | ||
| 909 | <p><strong>Monsters and Combat</strong></p> | ||
| 910 | <ul> | ||
| 911 | <li>You can pick up items with <code>,</code> or <code>g</code>.</li> | ||
| 912 | <li>Wield weapons with <code>w</code>. Weapons have different stats. | ||
| 913 | <ul> | ||
| 914 | <li>(You may also engage in Unarmed Combat, though it isn't very effective when | ||
| 915 | untrained).</li> | ||
| 916 | </ul> | ||
| 917 | </li> | ||
| 918 | <li>Attack monsters in melee by walking in their direction (or with | ||
| 919 | Ctrl-direction).</li> | ||
| 920 | <li>You can wait with <code>.</code> or <code>s</code>, passing your turn - such as to get monsters into | ||
| 921 | a corridor with you.</li> | ||
| 922 | <li>You can rest with <code>5</code>, waiting until you are fully healed, or something | ||
| 923 | noteworthy happens.</li> | ||
| 924 | <li>Either mouseover and rightclick, or use <code>x</code> then <code>v</code> on the monster to examine | ||
| 925 | monsters. Monsters with a red border are 'dangerous' relative to your current | ||
| 926 | XP level (XL).</li> | ||
| 927 | <li>Quiver (often ranged) actions for further use with <code>Q</code>.</li> | ||
| 928 | <li>You can fire ranged weapons manually with <code>f</code>, or auto-target your quiver with | ||
| 929 | <code>p</code> or <code>Shift-Tab</code>. Throwing weapons can be thrown immediately, while | ||
| 930 | launchers (like bows) need to be wielded first.</li> | ||
| 931 | </ul> | ||
| 932 | <p><strong>Items and Inventory</strong></p> | ||
| 933 | <ul> | ||
| 934 | <li>View your inventory by pressing <code>i</code>. Most item related commands can also be | ||
| 935 | done with this menu.</li> | ||
| 936 | <li>You can wear amour with <code>W;</code> amour gives <code>AC</code>, while heavier body armour | ||
| 937 | reduces <code>EV</code>.</li> | ||
| 938 | <li>Autoexplore will automatically pick up useful items, such as potions and | ||
| 939 | scrolls, if you aren't in danger.</li> | ||
| 940 | <li>You can read scrolls with <code>r</code> and drink (&quot;quaff&quot;) potions with <code>q</code>.</li> | ||
| 941 | <li>Equipment items may have brands, with special properties. Branded equipment is | ||
| 942 | blue when unidentified.</li> | ||
| 943 | <li>Equipment items may be artifacts, often with unique properties, and are | ||
| 944 | unmodifiable. They are written in white.</li> | ||
| 945 | <li>You can evoke wands with <code>V</code>.</li> | ||
| 946 | <li>You can put on jewelry with <code>P</code>, and remove it with <code>R</code>.</li> | ||
| 947 | <li>Gold is used in shops, which can be interacted with by either <code>&gt;</code> or <code>&lt;</code>.</li> | ||
| 948 | </ul> | ||
| 949 | <p><strong>Magic and Spellcasting</strong></p> | ||
| 950 | <ul> | ||
| 951 | <li>Once you find a spellbook, you can memorize spells with <code>M</code>.</li> | ||
| 952 | <li>You need to be the same XL as the spell's spell level in order to learn it, in | ||
| 953 | addition to training magical skill (to lower failure rate).</li> | ||
| 954 | <li>Cast spells by pressing <code>z</code>, then the letter assigned to the spell. You may | ||
| 955 | also Quiver a spell and then use it like a ranged weapon (with Shift-Tab).</li> | ||
| 956 | <li>You can view your memorized spells by pressing <code>I</code> (capital-i) or <code>z</code>.</li> | ||
| 957 | <li>Like HP, you can recover MP by resting (with 5).</li> | ||
| 958 | <li>Many spells can be positioned more effectively, or combined with other spells, | ||
| 959 | in order to get (more effective) use out of them.</li> | ||
| 960 | <li>Heavier body amour and shields hamper spellcasting.</li> | ||
| 961 | </ul> | ||
| 962 | <p><strong>Gods and Divine Abilities</strong></p> | ||
| 963 | <ul> | ||
| 964 | <li>You may look at a god's overview by praying at their altar (with <code>&gt;</code> or <code>&lt;</code>). | ||
| 965 | After praying, you can worship the god by pressing Enter afterwards.</li> | ||
| 966 | <li>Gods all have unique features about them. Trog, the god of the tutorial, is | ||
| 967 | also the god of rage and bloodshed, and so despises spellcasting.</li> | ||
| 968 | <li>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.</li> | ||
| 971 | <li>You should learn to use and even rely on divine abilities often, as they are | ||
| 972 | usually very strong. Trog's Berserk gives you 1.5x health, 1.5x speed (to all | ||
| 973 | valid actions), and a big damage boost. Note that Berserk prevents most | ||
| 974 | actions other than move and melee attack, and runs out very quickly if you | ||
| 975 | aren't attacking. And after berserk ends, you are slowed down and can't | ||
| 976 | berserk again for a short time.</li> | ||
| 977 | <li>In addition, the vast majority of abilities consume piety in the process. | ||
| 978 | Regardless, this ability is very cheap, and the benefits are incredible, so | ||
| 979 | don't hold back!</li> | ||
| 980 | <li>Pressing <code>^</code> will let you view your current god, abilities, and piety.</li> | ||
| 981 | </ul> | ||
| 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 +0200</pubDate> | ||
| 991 | <guid>https://mitjafelicijan.com/xterm-color-palette.html</guid> | ||
| 992 | <description>bash xterm-palette.</description> | ||
| 993 | <content:encoded><ul> | ||
| 994 | <li><code>bash xterm-palette.sh</code> - will show you number of max colors available</li> | ||
| 995 | <li><code>bash xterm-palette.sh -v</code> - will create a list of all colors with codes</li> | ||
| 996 | </ul> | ||
| 997 | <figure> | ||
| 998 | <img src="/notes/xterm-palette.png" alt="xterm color palette" /> | ||
| 999 | </figure> | ||
| 1000 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#00f">#!/usr/bin/env bash | ||
| 1001 | </span></span></span><span style="display:flex;"><span><span style="color:#00f"></span><span style="color:#008000"># xterm-palette.sh</span> | ||
| 1002 | </span></span><span style="display:flex;"><span> | ||
| 1003 | </span></span><span style="display:flex;"><span>trap <span style="color:#a31515">&#39;tput sgr0&#39;</span> exit <span style="color:#008000"># Clean up even if user hits ^C</span> | ||
| 1004 | </span></span><span style="display:flex;"><span> | ||
| 1005 | </span></span><span style="display:flex;"><span><span style="color:#00f">function</span> setfg () { | ||
| 1006 | </span></span><span style="display:flex;"><span> printf <span style="color:#a31515">&#39;\e[38;5;%dm&#39;</span> $1 | ||
| 1007 | </span></span><span style="display:flex;"><span>} | ||
| 1008 | </span></span><span style="display:flex;"><span> | ||
| 1009 | </span></span><span style="display:flex;"><span><span style="color:#00f">function</span> setbg () { | ||
| 1010 | </span></span><span style="display:flex;"><span> printf <span style="color:#a31515">&#39;\e[48;5;%dm&#39;</span> $1 | ||
| 1011 | </span></span><span style="display:flex;"><span>} | ||
| 1012 | </span></span><span style="display:flex;"><span> | ||
| 1013 | </span></span><span style="display:flex;"><span><span style="color:#00f">function</span> showcolors() { | ||
| 1014 | </span></span><span style="display:flex;"><span> <span style="color:#008000"># Given an integer, display that many colors</span> | ||
| 1015 | </span></span><span style="display:flex;"><span> <span style="color:#00f">for</span> ((i=0; i&lt;$1; i++)) | ||
| 1016 | </span></span><span style="display:flex;"><span> <span style="color:#00f">do</span> | ||
| 1017 | </span></span><span style="display:flex;"><span> printf <span style="color:#a31515">&#39;%4d &#39;</span> $i | ||
| 1018 | </span></span><span style="display:flex;"><span> setbg $i | ||
| 1019 | </span></span><span style="display:flex;"><span> tput el | ||
| 1020 | </span></span><span style="display:flex;"><span> tput sgr0 | ||
| 1021 | </span></span><span style="display:flex;"><span> echo | ||
| 1022 | </span></span><span style="display:flex;"><span> <span style="color:#00f">done</span> | ||
| 1023 | </span></span><span style="display:flex;"><span> tput sgr0 el | ||
| 1024 | </span></span><span style="display:flex;"><span>} | ||
| 1025 | </span></span><span style="display:flex;"><span> | ||
| 1026 | </span></span><span style="display:flex;"><span><span style="color:#008000"># First, test if terminal supports OSC 4 at all.</span> | ||
| 1027 | </span></span><span style="display:flex;"><span>printf <span style="color:#a31515">&#39;\e]4;%d;?\a&#39;</span> 0 | ||
| 1028 | </span></span><span style="display:flex;"><span>read -d <span style="color:#a31515">$&#39;\a&#39;</span> -s -t 0.1 &lt;/dev/tty | ||
| 1029 | </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> ] | ||
| 1030 | </span></span><span style="display:flex;"><span><span style="color:#00f">then</span> | ||
| 1031 | </span></span><span style="display:flex;"><span> <span style="color:#008000"># OSC 4 not supported, so we&#39;ll fall back to terminfo</span> | ||
| 1032 | </span></span><span style="display:flex;"><span> max=<span style="color:#00f">$(</span>tput colors<span style="color:#00f">)</span> | ||
| 1033 | </span></span><span style="display:flex;"><span><span style="color:#00f">else</span> | ||
| 1034 | </span></span><span style="display:flex;"><span> <span style="color:#008000"># OSC 4 is supported, so use it for a binary search</span> | ||
| 1035 | </span></span><span style="display:flex;"><span> min=0 | ||
| 1036 | </span></span><span style="display:flex;"><span> max=256 | ||
| 1037 | </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 ]] | ||
| 1038 | </span></span><span style="display:flex;"><span> <span style="color:#00f">do</span> | ||
| 1039 | </span></span><span style="display:flex;"><span> i=<span style="color:#00f">$((</span> (min+max)/2 <span style="color:#00f">))</span> | ||
| 1040 | </span></span><span style="display:flex;"><span> printf <span style="color:#a31515">&#39;\e]4;%d;?\a&#39;</span> $i | ||
| 1041 | </span></span><span style="display:flex;"><span> read -d <span style="color:#a31515">$&#39;\a&#39;</span> -s -t 0.1 &lt;/dev/tty | ||
| 1042 | </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> ] | ||
| 1043 | </span></span><span style="display:flex;"><span> <span style="color:#00f">then</span> | ||
| 1044 | </span></span><span style="display:flex;"><span> max=$i | ||
| 1045 | </span></span><span style="display:flex;"><span> <span style="color:#00f">else</span> | ||
| 1046 | </span></span><span style="display:flex;"><span> min=$i | ||
| 1047 | </span></span><span style="display:flex;"><span> <span style="color:#00f">fi</span> | ||
| 1048 | </span></span><span style="display:flex;"><span> <span style="color:#00f">done</span> | ||
| 1049 | </span></span><span style="display:flex;"><span><span style="color:#00f">fi</span> | ||
| 1050 | </span></span><span style="display:flex;"><span> | ||
| 1051 | </span></span><span style="display:flex;"><span> | ||
| 1052 | </span></span><span style="display:flex;"><span><span style="color:#008000"># If -v is given, show all the colors</span> | ||
| 1053 | </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 | ||
| 1054 | </span></span><span style="display:flex;"><span> none) | ||
| 1055 | </span></span><span style="display:flex;"><span> echo $max | ||
| 1056 | </span></span><span style="display:flex;"><span> ;; | ||
| 1057 | </span></span><span style="display:flex;"><span> -v) | ||
| 1058 | </span></span><span style="display:flex;"><span> showcolors $max | ||
| 1059 | </span></span><span style="display:flex;"><span> ;; | ||
| 1060 | </span></span><span style="display:flex;"><span> *) | ||
| 1061 | </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> | ||
| 1062 | </span></span><span style="display:flex;"><span> showcolors $1 | ||
| 1063 | </span></span><span style="display:flex;"><span> <span style="color:#00f">else</span> | ||
| 1064 | </span></span><span style="display:flex;"><span> echo $max | ||
| 1065 | </span></span><span style="display:flex;"><span> <span style="color:#00f">fi</span> | ||
| 1066 | </span></span><span style="display:flex;"><span> ;; | ||
| 1067 | </span></span><span style="display:flex;"><span><span style="color:#00f">esac</span> | less --raw-control-chars --QUIT-AT-EOF --no-init | ||
| 1068 | </span></span></code></pre></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 +0200</pubDate> | ||
| 1077 | <guid>https://mitjafelicijan.com/tmux-sane-defaults.html</guid> | ||
| 1078 | <description># Remap prefix from &#39;C-b&#39; to &#39;M-a&#39;.</description> | ||
| 1079 | <content:encoded><pre><code class="language-conf"># Remap prefix from 'C-b' to 'M-a'. | ||
| 1080 | unbind C-b | ||
| 1081 | set-option -g prefix M-a | ||
| 1082 | bind-key M-a send-prefix | ||
| 1083 | |||
| 1084 | # Split panes using | and -. | ||
| 1085 | bind | split-window -h | ||
| 1086 | bind - split-window -v | ||
| 1087 | unbind '&quot;' | ||
| 1088 | unbind % | ||
| 1089 | |||
| 1090 | # Start counting windows with 1. | ||
| 1091 | set-option -g allow-rename on | ||
| 1092 | set -g base-index 1 | ||
| 1093 | setw -g pane-base-index 1 | ||
| 1094 | |||
| 1095 | # Statusbar: purple bg and white fg. | ||
| 1096 | set -g status-bg '#480b8e' | ||
| 1097 | set -g status-fg '#ffffff' | ||
| 1098 | |||
| 1099 | # Active window: black bg and white fg. | ||
| 1100 | set -g window-status-current-format &quot;#[fg=#ffffff]#[bg=#111111]#[fg=#ffffff]#[bg=#111111] #I:#W #[fg=#ffffff]#[bg=#111111]&quot; | ||
| 1101 | |||
| 1102 | # Disable mouse mode (tmux 2.1 and above). | ||
| 1103 | set -g mouse off | ||
| 1104 | </code></pre> | ||
| 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 +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><p>I have been experimenting with Plan9/9front for a week now. Noice! This is how | ||
| 1117 | my desktop looks like.</p> | ||
| 1118 | <figure> | ||
| 1119 | <img src="/notes/9front-desktop.png" alt="9front desktop" /> | ||
| 1120 | </figure> | ||
| 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 +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><p>Example of parsing RSS feeds with Lua. Before running the script install:</p> | ||
| 1135 | <ul> | ||
| 1136 | <li>feedparser with <code>luarocks install feedparser</code></li> | ||
| 1137 | <li>luasocket with <code>luarocks install luasocket</code></li> | ||
| 1138 | </ul> | ||
| 1139 | <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>) | ||
| 1140 | </span></span><span style="display:flex;"><span><span style="color:#00f">local</span> feedparser = require(<span style="color:#a31515">&#34;feedparser&#34;</span>) | ||
| 1141 | </span></span><span style="display:flex;"><span> | ||
| 1142 | </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> | ||
| 1143 | </span></span><span style="display:flex;"><span> | ||
| 1144 | </span></span><span style="display:flex;"><span><span style="color:#00f">local</span> response, status, _ = http.request(feed_url) | ||
| 1145 | </span></span><span style="display:flex;"><span><span style="color:#00f">if</span> status == 200 <span style="color:#00f">then</span> | ||
| 1146 | </span></span><span style="display:flex;"><span> <span style="color:#00f">local</span> parsed = feedparser.parse(response) | ||
| 1147 | </span></span><span style="display:flex;"><span> | ||
| 1148 | </span></span><span style="display:flex;"><span> <span style="color:#008000">-- Print out feed details.</span> | ||
| 1149 | </span></span><span style="display:flex;"><span> print(<span style="color:#a31515">&#34;&gt; Title &#34;</span>, parsed.feed.title) | ||
| 1150 | </span></span><span style="display:flex;"><span> print(<span style="color:#a31515">&#34;&gt; Author &#34;</span>, parsed.feed.author) | ||
| 1151 | </span></span><span style="display:flex;"><span> print(<span style="color:#a31515">&#34;&gt; ID &#34;</span>, parsed.feed.id) | ||
| 1152 | </span></span><span style="display:flex;"><span> print(<span style="color:#a31515">&#34;&gt; Entries &#34;</span>, #parsed.entries) | ||
| 1153 | </span></span><span style="display:flex;"><span> | ||
| 1154 | </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> | ||
| 1155 | </span></span><span style="display:flex;"><span> print(<span style="color:#a31515">&#34;GUID &#34;</span>, item.guid) | ||
| 1156 | </span></span><span style="display:flex;"><span> print(<span style="color:#a31515">&#34;Title &#34;</span>, item.title) | ||
| 1157 | </span></span><span style="display:flex;"><span> print(<span style="color:#a31515">&#34;Link &#34;</span>, item.link) | ||
| 1158 | </span></span><span style="display:flex;"><span> print(<span style="color:#a31515">&#34;Summary &#34;</span>, item.summary) | ||
| 1159 | </span></span><span style="display:flex;"><span> <span style="color:#00f">end</span> | ||
| 1160 | </span></span><span style="display:flex;"><span><span style="color:#00f">else</span> | ||
| 1161 | </span></span><span style="display:flex;"><span> print(<span style="color:#a31515">&#34;! Request failed. Status:&#34;</span>, status) | ||
| 1162 | </span></span><span style="display:flex;"><span><span style="color:#00f">end</span> | ||
| 1163 | </span></span></code></pre></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 +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><p>Here is a boilerplate for extending Lua with custom C functions. This requires | ||
| 1175 | Clang and Lua 5.1 to be installed. GCC can be used instead of Clang, but the | ||
| 1176 | Makefile will need to be modified.</p> | ||
| 1177 | <ul> | ||
| 1178 | <li> | ||
| 1179 | <p>nativefunc.c</p> | ||
| 1180 | <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"> | ||
| 1181 | </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"> | ||
| 1182 | </span></span></span><span style="display:flex;"><span><span style="color:#00f"></span> | ||
| 1183 | </span></span><span style="display:flex;"><span><span style="color:#00f">static</span> <span style="color:#2b91af">int</span> l_mult50(lua_State *L) { | ||
| 1184 | </span></span><span style="display:flex;"><span> <span style="color:#2b91af">double</span> number = luaL_checknumber(L, 1); | ||
| 1185 | </span></span><span style="display:flex;"><span> lua_pushnumber(L, number * 50); | ||
| 1186 | </span></span><span style="display:flex;"><span> <span style="color:#00f">return</span> 1; | ||
| 1187 | </span></span><span style="display:flex;"><span>} | ||
| 1188 | </span></span><span style="display:flex;"><span> | ||
| 1189 | </span></span><span style="display:flex;"><span><span style="color:#2b91af">int</span> luaopen_nativefunc(lua_State *L) { | ||
| 1190 | </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}}; | ||
| 1191 | </span></span><span style="display:flex;"><span> | ||
| 1192 | </span></span><span style="display:flex;"><span> luaL_register(L, <span style="color:#a31515">&#34;nativelib&#34;</span>, nativeFuncLib); | ||
| 1193 | </span></span><span style="display:flex;"><span> <span style="color:#00f">return</span> 1; | ||
| 1194 | </span></span><span style="display:flex;"><span>} | ||
| 1195 | </span></span></code></pre></li> | ||
| 1196 | <li> | ||
| 1197 | <p>main.lua</p> | ||
| 1198 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>require <span style="color:#a31515">&#34;nativefunc&#34;</span> | ||
| 1199 | </span></span><span style="display:flex;"><span>print(nativelib.mult50(50)) | ||
| 1200 | </span></span></code></pre></li> | ||
| 1201 | <li> | ||
| 1202 | <p>Makefile</p> | ||
| 1203 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span>CC = clang | ||
| 1204 | </span></span><span style="display:flex;"><span>CFLAGS = | ||
| 1205 | </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> | ||
| 1206 | </span></span><span style="display:flex;"><span> | ||
| 1207 | </span></span><span style="display:flex;"><span>all: | ||
| 1208 | </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> | ||
| 1209 | </span></span><span style="display:flex;"><span> | ||
| 1210 | </span></span><span style="display:flex;"><span>clean: | ||
| 1211 | </span></span><span style="display:flex;"><span> rm *.so | ||
| 1212 | </span></span></code></pre></li> | ||
| 1213 | </ul> | ||
| 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 +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><p>Execute a shell command in async in C# while not blocking the UI thread.</p> | ||
| 1226 | <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() | ||
| 1227 | </span></span><span style="display:flex;"><span>{ | ||
| 1228 | </span></span><span style="display:flex;"><span> <span style="color:#00f">await</span> Task.Run(() =&gt; | ||
| 1229 | </span></span><span style="display:flex;"><span> { | ||
| 1230 | </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>) | ||
| 1231 | </span></span><span style="display:flex;"><span> { | ||
| 1232 | </span></span><span style="display:flex;"><span> RedirectStandardOutput = <span style="color:#00f">true</span>, | ||
| 1233 | </span></span><span style="display:flex;"><span> UseShellExecute = <span style="color:#00f">false</span>, | ||
| 1234 | </span></span><span style="display:flex;"><span> CreateNoWindow = <span style="color:#00f">true</span> | ||
| 1235 | </span></span><span style="display:flex;"><span> }; | ||
| 1236 | </span></span><span style="display:flex;"><span> | ||
| 1237 | </span></span><span style="display:flex;"><span> <span style="color:#2b91af">var</span> process = <span style="color:#00f">new</span> Process | ||
| 1238 | </span></span><span style="display:flex;"><span> { | ||
| 1239 | </span></span><span style="display:flex;"><span> StartInfo = processStartInfo | ||
| 1240 | </span></span><span style="display:flex;"><span> }; | ||
| 1241 | </span></span><span style="display:flex;"><span> | ||
| 1242 | </span></span><span style="display:flex;"><span> process.Start(); | ||
| 1243 | </span></span><span style="display:flex;"><span> process.WaitForExit(); | ||
| 1244 | </span></span><span style="display:flex;"><span> }); | ||
| 1245 | </span></span><span style="display:flex;"><span>} | ||
| 1246 | </span></span></code></pre><p>Make sure that <code>async</code> is present in the function definition and <code>await</code> is used | ||
| 1247 | in the method that calls <code>executeCopyCommand()</code>.</p> | ||
| 1248 | <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) | ||
| 1249 | </span></span><span style="display:flex;"><span>{ | ||
| 1250 | </span></span><span style="display:flex;"><span> <span style="color:#00f">await</span> executeCopyCommand(); | ||
| 1251 | </span></span><span style="display:flex;"><span>} | ||
| 1252 | </span></span></code></pre></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 +0200</pubDate> | ||
| 1261 | <guid>https://mitjafelicijan.com/mass-set-permission.html</guid> | ||
| 1262 | <description>Replace *.</description> | ||
| 1263 | <content:encoded><p>Replace <code>*.xml</code> with your pattern. This will remove executable bit from all | ||
| 1264 | files matching the pattern. Change <code>+</code> to <code>-</code> to add executable bit.</p> | ||
| 1265 | <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 {} + | ||
| 1266 | </span></span></code></pre></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 +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><p>Troff is used to write man pages and it is difficult to read it so this will | ||
| 1280 | preview how it will look like when it is rendered.</p> | ||
| 1281 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># On Linux system.</span> | ||
| 1282 | </span></span><span style="display:flex;"><span>groff -man -Tascii filename | ||
| 1283 | </span></span><span style="display:flex;"><span> | ||
| 1284 | </span></span><span style="display:flex;"><span><span style="color:#008000"># On Plan9 system.</span> | ||
| 1285 | </span></span><span style="display:flex;"><span>man 1 filename | ||
| 1286 | </span></span></code></pre></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 +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><p>You will need <code>ffmpeg</code> installed on your system. This will convert all MKV files | ||
| 1298 | into WebM format.</p> | ||
| 1299 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># Convert all MKV files into WebM format.</span> | ||
| 1300 | </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> | ||
| 1301 | </span></span></code></pre><pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># Convert all MKV files into MP4 format.</span> | ||
| 1302 | </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> | ||
| 1303 | </span></span></code></pre></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 +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&#39;t want to download theactual YouTube list (which yt-dlp supports), you can use the following method.</description> | ||
| 1314 | <content:encoded><p>If you need to download a list of YouTube videos and don't want to download the | ||
| 1315 | actual YouTube list (which <code>yt-dlp</code> supports), you can use the following method.</p> | ||
| 1316 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000">// Used to get list of raw URL&#39;s from YouTube&#39;s video tab&#39;. | ||
| 1317 | </span></span></span><span style="display:flex;"><span><span style="color:#008000">// Copy them into videos.txt. | ||
| 1318 | </span></span></span><span style="display:flex;"><span><span style="color:#008000"></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)) | ||
| 1319 | </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>.</p> | ||
| 1320 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># This will download all videos in videos.txt.</span> | ||
| 1321 | </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 | ||
| 1322 | </span></span></code></pre></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 +0200</pubDate> | ||
| 1331 | <guid>https://mitjafelicijan.com/install-plan9port-linux.html</guid> | ||
| 1332 | <description>Install Plan9port on Linux.</description> | ||
| 1333 | <content:encoded><p>Install Plan9port on Linux. This applies to | ||
| 1334 | <a href="https://9fans.github.io/plan9port/">Plan9port</a>. This is a port of many Plan 9 | ||
| 1335 | programs to Unix-like operating systems. Useful for programs like <code>9term</code> and | ||
| 1336 | <code>rc</code>.</p> | ||
| 1337 | <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 | ||
| 1338 | </span></span><span style="display:flex;"><span>git clone https://github.com/9fans/plan9port $HOME/plan9 | ||
| 1339 | </span></span><span style="display:flex;"><span>cd $HOME/plan9/plan9port | ||
| 1340 | </span></span><span style="display:flex;"><span>./INSTALL -r $HOME/plan9 | ||
| 1341 | </span></span></code></pre></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 +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><p>If the bootloader is not being written to a disk when installing 9front on real | ||
| 1353 | harware try clearing first sector of the disk with the following command.</p> | ||
| 1354 | <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 | ||
| 1355 | </span></span><span style="display:flex;"><span> | ||
| 1356 | </span></span><span style="display:flex;"><span><span style="color:#008000"># If command above doesn&#39;t work try this one, wait couple of seconds and</span> | ||
| 1357 | </span></span><span style="display:flex;"><span><span style="color:#008000"># press delete key to stop the command.</span> | ||
| 1358 | </span></span><span style="display:flex;"><span>cat &lt;/dev/zero &gt;/dev/sd*/data | ||
| 1359 | </span></span></code></pre></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 +0200</pubDate> | ||
| 1368 | <guid>https://mitjafelicijan.com/plan9-screenshot.html</guid> | ||
| 1369 | <description>Take a screenshot in Plan9.</description> | ||
| 1370 | <content:encoded><p>Take a screenshot in Plan9. This applies to <a href="https://9p.io/plan9/">Plan9</a> and | ||
| 1371 | <a href="https://9front.org/">9front</a>. This will take a screenshot of the screen and | ||
| 1372 | output it to <code>/dev/screen</code>. You can then use <code>topng</code> to convert it to a png | ||
| 1373 | image.</p> | ||
| 1374 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># Instant screenshot.</span> | ||
| 1375 | </span></span><span style="display:flex;"><span>cat /dev/screen | topng &gt; screen.png | ||
| 1376 | </span></span><span style="display:flex;"><span> | ||
| 1377 | </span></span><span style="display:flex;"><span><span style="color:#008000"># Delayed screenshot (5 seconds).</span> | ||
| 1378 | </span></span><span style="display:flex;"><span>sleep 5; cat /dev/screen | topng &gt; screen.png | ||
| 1379 | </span></span></code></pre></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 +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><p>Set up weechat to connect to #cat-v on oftc. This applies to | ||
| 1391 | <a href="https://weechat.org/">weechat</a> but should be similar for other irc clients.</p> | ||
| 1392 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># Install weechat and launch it and execute the following commands.</span> | ||
| 1393 | </span></span><span style="display:flex;"><span> | ||
| 1394 | </span></span><span style="display:flex;"><span>/server add oftc irc.oftc.net -tls | ||
| 1395 | </span></span><span style="display:flex;"><span>/set irc.server.oftc.autoconnect on | ||
| 1396 | </span></span><span style="display:flex;"><span>/set irc.server.oftc.autojoin <span style="color:#a31515">&#34;#cat-v&#34;</span> | ||
| 1397 | </span></span><span style="display:flex;"><span>/set irc.server.oftc.nicks <span style="color:#a31515">&#34;nick1,nick2,nick3&#34;</span> | ||
| 1398 | </span></span></code></pre></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 +0200</pubDate> | ||
| 1407 | <guid>https://mitjafelicijan.com/write-iso-usb.html</guid> | ||
| 1408 | <description>Write ISO to USB key.</description> | ||
| 1409 | <content:encoded><p>Write ISO to USB key. Nothing fancy here.</p> | ||
| 1410 | <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 | ||
| 1411 | </span></span></code></pre></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 +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><ul> | ||
| 1423 | <li>First install libfuse with sudo apt install libfuse-dev.</li> | ||
| 1424 | <li>Then clone <a href="https://github.com/ftrvxmtrx/9pfs">https://github.com/ftrvxmtrx/9pfs</a> and compile it with make.</li> | ||
| 1425 | <li>Copy 9pfs to your path.</li> | ||
| 1426 | </ul> | ||
| 1427 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># On Plan9 side</span> | ||
| 1428 | </span></span><span style="display:flex;"><span>ip/ipconfig <span style="color:#008000"># enables network</span> | ||
| 1429 | </span></span><span style="display:flex;"><span>aux/listen1 -tv tcp!*!9999 /bin/exportfs -r tmp <span style="color:#008000"># export tmp folder</span> | ||
| 1430 | </span></span><span style="display:flex;"><span> | ||
| 1431 | </span></span><span style="display:flex;"><span><span style="color:#008000"># On Linux side</span> | ||
| 1432 | </span></span><span style="display:flex;"><span>9pfs 172.18.0.1 -p 9999 local_folder <span style="color:#008000"># mount</span> | ||
| 1433 | </span></span><span style="display:flex;"><span>umount local_folder <span style="color:#008000"># unmount</span> | ||
| 1434 | </span></span></code></pre></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 +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><p>Sometimes you want to push to multiple origins at once. This is useful if you | ||
| 1446 | have a mirror of your repository on another server. You can do this by adding | ||
| 1447 | multiple push urls to your git config. This is a shorthand for command above.</p> | ||
| 1448 | <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> | ||
| 1449 | </span></span></code></pre></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 +0200</pubDate> | ||
| 1458 | <guid>https://mitjafelicijan.com/run-9front-in-qemu.html</guid> | ||
| 1459 | <description>Run 9front in Qemu.</description> | ||
| 1460 | <content:encoded><p>Run 9front in Qemu. This applies to <a href="https://9p.io/plan9/">Plan9</a> and | ||
| 1461 | <a href="https://9front.org/">9front</a>.</p> | ||
| 1462 | <p>Download from here <a href="http://9front.org/iso/">http://9front.org/iso/</a>.</p> | ||
| 1463 | <pre tabindex="0" style="background-color:#fff;"><code><span style="display:flex;"><span><span style="color:#008000"># Create a qcow2 image.</span> | ||
| 1464 | </span></span><span style="display:flex;"><span>qemu-img create -f qcow2 $HOME/VM/9front.qcow2.img 30G | ||
| 1465 | </span></span><span style="display:flex;"><span> | ||
| 1466 | </span></span><span style="display:flex;"><span><span style="color:#008000"># Run the VM.</span> | ||
| 1467 | </span></span><span style="display:flex;"><span>qemu-system-x86_64 -cpu host -enable-kvm -m 1024 <span style="color:#a31515">\ | ||
| 1468 | </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">\ | ||
| 1469 | </span></span></span><span style="display:flex;"><span><span style="color:#a31515"></span> -device virtio-scsi-pci,id=scsi <span style="color:#a31515">\ | ||
| 1470 | </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">\ | ||
| 1471 | </span></span></span><span style="display:flex;"><span><span style="color:#a31515"></span> -device scsi-hd,drive=vd0 <span style="color:#a31515">\ | ||
| 1472 | </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">\ | ||
| 1473 | </span></span></span><span style="display:flex;"><span><span style="color:#a31515"></span> -device scsi-cd,drive=vd1,bootindex=0 | ||
| 1474 | </span></span></code></pre></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 +0200</pubDate> | ||
| 1483 | <guid>https://mitjafelicijan.com/cachebusting-in-hugo.html</guid> | ||
| 1484 | <description>{{ $cachebuster := delimit (shuffle (split (md5 &#34;6fab11c6669976d759d2992eff1dd5be&#34;) &#34;&#34; )) &#34;&#34; }}&lt;link rel=&#34;stylesheet&#34; href=&#34;/style.</description> | ||
| 1485 | <content:encoded><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; }} | ||
| 1486 | </span></span><span style="display:flex;"><span> | ||
| 1487 | </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; | ||
| 1488 | </span></span></code></pre><p>This <code>6fab11c6669976d759d2992eff1dd5be</code> can be random string you generate use. | ||
| 1489 | You can use whatever you want.</p> | ||
| 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 | ||
| 10 | I have faced with it. CPU is not as powerful as on my main machine and I really | ||
| 11 | want 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 | ||
| 13 | a lock on a Linux NFS server, which turned | ||
| 14 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 15 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 16 | owns 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 | ||
| 17 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 18 | list where the're doing | ||
| 19 | bad computer history and insisting that a guy Larry Rosen | ||
| 20 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 21 | somethin…<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: | ||
| 22 | i2c, plan9 | ||
| 23 | Another month, another file system. | ||
| 24 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 25 | you, bme680, we’re not | ||
| 26 | done yet). The show must go on, as they say, and I would like my | ||
| 27 | experiments to go on. | ||
| 28 | So a “new” addition to the environmental sensor family connected to | ||
| 29 | the 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 | ||
| 30 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 31 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 32 | unique 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. | ||
| 33 | My 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 | ||
| 34 | 1.0 has been released: | ||
| 35 | wifi_da-1.0.sit | ||
| 36 | (StuffIt 3 archive) | ||
| 37 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 38 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 39 | classic 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. | ||
| 40 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 41 | Design Goals | ||
| 42 | I 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 | ||
| 43 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 44 | catch 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 | ||
| 45 | specified 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>"socket.http"</span>) | ||
| 10 | </span></span><span style=display:flex><span><span style=color:#00f>local</span> feedparser = require(<span style=color:#a31515>"feedparser"</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>"https://mitjafelicijan.com/index.xml"</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>"> Title "</span>, parsed.feed.title) | ||
| 20 | </span></span><span style=display:flex><span> print(<span style=color:#a31515>"> Author "</span>, parsed.feed.author) | ||
| 21 | </span></span><span style=display:flex><span> print(<span style=color:#a31515>"> ID "</span>, parsed.feed.id) | ||
| 22 | </span></span><span style=display:flex><span> print(<span style=color:#a31515>"> Entries "</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>"GUID "</span>, item.guid) | ||
| 26 | </span></span><span style=display:flex><span> print(<span style=color:#a31515>"Title "</span>, item.title) | ||
| 27 | </span></span><span style=display:flex><span> print(<span style=color:#a31515>"Link "</span>, item.link) | ||
| 28 | </span></span><span style=display:flex><span> print(<span style=color:#a31515>"Summary "</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>"! Request failed. Status:"</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 | ||
| 34 | a lock on a Linux NFS server, which turned | ||
| 35 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 36 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 37 | owns 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 | ||
| 38 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 39 | list where the're doing | ||
| 40 | bad computer history and insisting that a guy Larry Rosen | ||
| 41 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 42 | somethin…<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: | ||
| 43 | i2c, plan9 | ||
| 44 | Another month, another file system. | ||
| 45 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 46 | you, bme680, we’re not | ||
| 47 | done yet). The show must go on, as they say, and I would like my | ||
| 48 | experiments to go on. | ||
| 49 | So a “new” addition to the environmental sensor family connected to | ||
| 50 | the 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 | ||
| 51 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 52 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 53 | unique 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. | ||
| 54 | My 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 | ||
| 55 | 1.0 has been released: | ||
| 56 | wifi_da-1.0.sit | ||
| 57 | (StuffIt 3 archive) | ||
| 58 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 59 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 60 | classic 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. | ||
| 61 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 62 | Design Goals | ||
| 63 | I 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 | ||
| 64 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 65 | catch 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 | ||
| 66 | specified 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 | ||
| 11 | output it to <code>/dev/screen</code>. You can then use <code>topng</code> to convert it to a png | ||
| 12 | image.<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 > 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 > 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 | ||
| 18 | a lock on a Linux NFS server, which turned | ||
| 19 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 20 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 21 | owns 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 | ||
| 22 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 23 | list where the're doing | ||
| 24 | bad computer history and insisting that a guy Larry Rosen | ||
| 25 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 26 | somethin…<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: | ||
| 27 | i2c, plan9 | ||
| 28 | Another month, another file system. | ||
| 29 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 30 | you, bme680, we’re not | ||
| 31 | done yet). The show must go on, as they say, and I would like my | ||
| 32 | experiments to go on. | ||
| 33 | So a “new” addition to the environmental sensor family connected to | ||
| 34 | the 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 | ||
| 35 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 36 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 37 | unique 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. | ||
| 38 | My 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 | ||
| 39 | 1.0 has been released: | ||
| 40 | wifi_da-1.0.sit | ||
| 41 | (StuffIt 3 archive) | ||
| 42 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 43 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 44 | classic 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. | ||
| 45 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 46 | Design Goals | ||
| 47 | I 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 | ||
| 48 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 49 | catch 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 | ||
| 50 | specified 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 | ||
| 10 | services 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><!DOCTYPE html></span> | ||
| 11 | </span></span><span style=display:flex><span><html> | ||
| 12 | </span></span><span style=display:flex><span> | ||
| 13 | </span></span><span style=display:flex><span><head> | ||
| 14 | </span></span><span style=display:flex><span> <title></title> | ||
| 15 | </span></span><span style=display:flex><span> <meta charset=<span style=color:#a31515>"utf-8"</span>> | ||
| 16 | </span></span><span style=display:flex><span> <style> | ||
| 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>'SF Pro Display'</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>'SF Mono'</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> </style> | ||
| 30 | </span></span><span style=display:flex><span></head> | ||
| 31 | </span></span><span style=display:flex><span> | ||
| 32 | </span></span><span style=display:flex><span><body> | ||
| 33 | </span></span><span style=display:flex><span> <textarea id=<span style=color:#a31515>"source"</span>></textarea> | ||
| 34 | </span></span><span style=display:flex><span> <script src=<span style=color:#a31515>"https://remarkjs.com/downloads/remark-latest.min.js"</span>></script> | ||
| 35 | </span></span><span style=display:flex><span> <script> | ||
| 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>'My presentation'</span>, | ||
| 38 | </span></span><span style=display:flex><span> file: <span style=color:#a31515>'presentation.md'</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> </script> | ||
| 44 | </span></span><span style=display:flex><span></body> | ||
| 45 | </span></span><span style=display:flex><span> | ||
| 46 | </span></span><span style=display:flex><span></html> | ||
| 47 | </span></span></code></pre><p>Now the markdown file <code>presentation.md</code> with presenetation. <code>---</code> is used to | ||
| 48 | separate 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 | ||
| 68 | a lock on a Linux NFS server, which turned | ||
| 69 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 70 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 71 | owns 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 | ||
| 72 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 73 | list where the're doing | ||
| 74 | bad computer history and insisting that a guy Larry Rosen | ||
| 75 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 76 | somethin…<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: | ||
| 77 | i2c, plan9 | ||
| 78 | Another month, another file system. | ||
| 79 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 80 | you, bme680, we’re not | ||
| 81 | done yet). The show must go on, as they say, and I would like my | ||
| 82 | experiments to go on. | ||
| 83 | So a “new” addition to the environmental sensor family connected to | ||
| 84 | the 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 | ||
| 85 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 86 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 87 | unique 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. | ||
| 88 | My 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 | ||
| 89 | 1.0 has been released: | ||
| 90 | wifi_da-1.0.sit | ||
| 91 | (StuffIt 3 archive) | ||
| 92 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 93 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 94 | classic 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. | ||
| 95 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 96 | Design Goals | ||
| 97 | I 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 | ||
| 98 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 99 | catch 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 | ||
| 100 | specified 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 | ||
| 10 | preview 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 | ||
| 16 | a lock on a Linux NFS server, which turned | ||
| 17 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 18 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 19 | owns 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 | ||
| 20 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 21 | list where the're doing | ||
| 22 | bad computer history and insisting that a guy Larry Rosen | ||
| 23 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 24 | somethin…<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: | ||
| 25 | i2c, plan9 | ||
| 26 | Another month, another file system. | ||
| 27 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 28 | you, bme680, we’re not | ||
| 29 | done yet). The show must go on, as they say, and I would like my | ||
| 30 | experiments to go on. | ||
| 31 | So a “new” addition to the environmental sensor family connected to | ||
| 32 | the 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 | ||
| 33 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 34 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 35 | unique 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. | ||
| 36 | My 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 | ||
| 37 | 1.0 has been released: | ||
| 38 | wifi_da-1.0.sit | ||
| 39 | (StuffIt 3 archive) | ||
| 40 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 41 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 42 | classic 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. | ||
| 43 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 44 | Design Goals | ||
| 45 | I 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 | ||
| 46 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 47 | catch 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 | ||
| 48 | specified 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&#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 | ||
| 10 | missing this option when I am developing API's or other web services. I always | ||
| 11 | knew 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 | ||
| 12 | Viewer</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 | ||
| 14 | virtualenv 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'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'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'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'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 | ||
| 54 | code 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>"prof/"</span> + str(func.__name__) + <span style=color:#a31515>".prof"</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>"/"</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>"awesome random number is "</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>"/test"</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>"dummy test"</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>'__main__'</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>"0.0.0.0"</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 'python app.py'</span> | ||
| 100 | </span></span><span style=display:flex><span><span style=color:green># open browser 'http://0.0.0.0:4000'</span> | ||
| 101 | </span></span></code></pre><p>When browser hits awesome_random_number() function profile is created in prof/ | ||
| 102 | subfolder.<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 'awesome_random_number.prof.log' 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 | ||
| 106 | will be using Profilling Viewer under MacOS. You can open image in new tab. As | ||
| 107 | you can see from this example there is hierarchy of execution order of your | ||
| 108 | code.<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 | ||
| 109 | refresh 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 | ||
| 111 | this can be very illuminating, especially to see which parts of your code are | ||
| 112 | bottlenecks 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 | ||
| 113 | web based profile visualizer <a href=https://jiffyclub.github.io/snakeviz/>SnakeViz</a> | ||
| 114 | that directly takes output from | ||
| 115 | <a href=https://docs.python.org/2/library/profile.html#module-cProfile>cProfile</a> | ||
| 116 | module.<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'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'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 | ||
| 125 | way 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'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 | ||
| 141 | use <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 | ||
| 142 | a lock on a Linux NFS server, which turned | ||
| 143 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 144 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 145 | owns 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 | ||
| 146 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 147 | list where the're doing | ||
| 148 | bad computer history and insisting that a guy Larry Rosen | ||
| 149 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 150 | somethin…<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: | ||
| 151 | i2c, plan9 | ||
| 152 | Another month, another file system. | ||
| 153 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 154 | you, bme680, we’re not | ||
| 155 | done yet). The show must go on, as they say, and I would like my | ||
| 156 | experiments to go on. | ||
| 157 | So a “new” addition to the environmental sensor family connected to | ||
| 158 | the 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 | ||
| 159 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 160 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 161 | unique 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. | ||
| 162 | My 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 | ||
| 163 | 1.0 has been released: | ||
| 164 | wifi_da-1.0.sit | ||
| 165 | (StuffIt 3 archive) | ||
| 166 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 167 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 168 | classic 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. | ||
| 169 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 170 | Design Goals | ||
| 171 | I 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 | ||
| 172 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 173 | catch 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 | ||
| 174 | specified 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 | |||
| 5 | Title1=Metal | ||
| 6 | File1=http://kathy.torontocast.com:2820/ | ||
| 7 | |||
| 8 | Title2=Technolovers Minimal | ||
| 9 | File2=https://stream.technolovers.fm/minimal | ||
| 10 | |||
| 11 | Title3=Indie Rock | ||
| 12 | File3=http://s5.radio.co/s36d03408d/listen | ||
| 13 | |||
| 14 | Title4=Montreal's Classic Rock | ||
| 15 | File4=http://streams.justclassicrock.com:8000 | ||
| 16 | |||
| 17 | Title5=Raute Metal | ||
| 18 | File5=https://metal-high.rautemusik.fm/?ref | ||
| 19 | |||
| 20 | Title6=NCC 1701a Engine Noise | ||
| 21 | File6=https://files.mitjafelicijan.com/haphazard/ncc-1701-a-engine-noise.ogg | ||
| 22 | |||
| 23 | Title7=Funk & Soul | ||
| 24 | File7=http://streams.80s80s.de/soul/mp3-192/ | ||
| 25 | |||
| 26 | Title8=80's Pop | ||
| 27 | File8=http://streams.fluxfm.de/80er/mp3-320 | ||
| 28 | |||
| 29 | Title9=Roots Legacy Radio Dub | ||
| 30 | File9=http://l.rootslegacy.fr/ | ||
| 31 | |||
| 32 | Title10=Ambiental | ||
| 33 | File10=http://radio.stereoscenic.com/ama-h | ||
| 34 | |||
| 35 | #Title6= | ||
| 36 | #File6= | ||
| 37 | |||
| 38 | Length1=-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 | ||
| 10 | making an alternative for make. And so I went. Boldly into the battle. And to my | ||
| 11 | big 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 | ||
| 12 | ambitious. And looking back I should have stuck to the simple version. My | ||
| 13 | laziness was on my side this time though. Because I haven’t implemented some of | ||
| 14 | the features I now realise I really didn’t need them and they would bog the | ||
| 15 | whole 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 | ||
| 16 | without libc, musl dependencies or things like that.<li>Install ruby for rake is a bit overkill and can not be done with certain | ||
| 17 | really lightweight distributions like Alpine Linux. This tool would be usable | ||
| 18 | on 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 | ||
| 19 | entry-point into a project, and I want this to help me indirectly document the | ||
| 20 | project 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 | ||
| 21 | usually put a disclaimer that you should check Makefile to see all available | ||
| 22 | target).<li>Should support passing arguments when you run it from a shell.<li>Normal variable as the same as environmental variables. There is no | ||
| 23 | distinction. Every variable is also essentially an environment variable and | ||
| 24 | can 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> | ||
| 25 | command.<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 | ||
| 26 | compiler 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 | ||
| 27 | Makefiles or/and Bash scripts. But I would like to avoid repeating myself every | ||
| 28 | time 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>"hey"</span> | ||
| 43 | </span></span><span style=display:flex><span>@var TOKEN = <span style=color:#a31515>"sometoken"</span> | ||
| 44 | </span></span><span style=display:flex><span>@var EMAIL = <span style=color:#a31515>"m@m.com"</span> | ||
| 45 | </span></span><span style=display:flex><span>@var PASSWORD = <span style=color:#a31515>"pass"</span> | ||
| 46 | </span></span><span style=display:flex><span>@var EDITOR = <span style=color:#a31515>"vim"</span> | ||
| 47 | </span></span><span style=display:flex><span> | ||
| 48 | </span></span><span style=display:flex><span>@task dev <span style=color:#a31515>"Test chars .:'}{]!//"</span> does | ||
| 49 | </span></span><span style=display:flex><span> echo <span style=color:#a31515>"..."</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>"Cleans the obj files"</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>"Greets the user"</span> does | ||
| 57 | </span></span><span style=display:flex><span> echo <span style=color:#a31515>"Hi user $TOKEN or $WINDOWID $EMAIL"</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>"Starts Docker stack"</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>"Shows all todos in source files and count them"</span> does | ||
| 65 | </span></span><span style=display:flex><span> grep -ir <span style=color:#a31515>"TODO|FIXME"</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>"For testing 1"</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>"test1"</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>"For testing 2"</span> does | ||
| 75 | </span></span><span style=display:flex><span> echo <span style=color:#a31515>"test1"</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 | ||
| 80 | it is available at <a href=https://git.mitjafelicijan.com/errand.git/about/>https://git.mitjafelicijan.com/errand.git/about/</a>. Moving | ||
| 81 | on. One thing that I really like is that a task is a persistent shell. By that I | ||
| 82 | mean, that the whole task, even if it contains multiple command in one shell. | ||
| 83 | In make each line in a target is that and you need to combine lines or add <code>\</code> | ||
| 84 | at 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 | ||
| 89 | task 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, | ||
| 90 | if you only type <code>erd</code> and press enter it should by default display all the | ||
| 91 | possible targets. In make i was doing this by having a first target be something | ||
| 92 | like <code>default</code> that echos the message “Check Makefile for all available target.” | ||
| 93 | Because all of the tasks in Errand require a message I use that to display let’s | ||
| 94 | call it table of contents.<p>Because I don’t use any external dependencies this whole thing can be statically | ||
| 95 | compiled. 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 | ||
| 96 | would work on Windows machines because of the way that I use shell instances. By | ||
| 97 | you could use something like Windows Subsystem for Linux and run it in | ||
| 98 | there. That is a valid option.<p>To finish this essay off, how was it to use it in “real life”. I have to be | ||
| 99 | honest. Some of the missing features still bother me. <code>@dotenv</code> directive is | ||
| 100 | still missing and I need to implement this ASAP.<p>Another thing that needs to happen is support for streaming output. Currently | ||
| 101 | commands like <code>docker-compose</code> that runs in foreground mode is not compatible | ||
| 102 | with Errand. So commands that stream output are an issue. I need to revisit how | ||
| 103 | I initiate shell and how I read stdout and stderr. But that shouldn’t be a | ||
| 104 | problem.<p>I have been very satisfied with this thing. I am pleasantly surprised by how | ||
| 105 | useful it is. I really wanted to test this in the wild before I commit to it. I | ||
| 106 | have more abandoned project than Google and it’s bringing a massive shame to my | ||
| 107 | family at this point. So I wanted to be sure that this is even useful. And it | ||
| 108 | actually is. Quite surprised at myself.<p>I really need to package this now and write proper docs. And maybe rewrite | ||
| 109 | tokeniser. Its atrocious right now. Site to behold! But that is an issue for | ||
| 110 | another 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 | ||
| 111 | a lock on a Linux NFS server, which turned | ||
| 112 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 113 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 114 | owns 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 | ||
| 115 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 116 | list where the're doing | ||
| 117 | bad computer history and insisting that a guy Larry Rosen | ||
| 118 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 119 | somethin…<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: | ||
| 120 | i2c, plan9 | ||
| 121 | Another month, another file system. | ||
| 122 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 123 | you, bme680, we’re not | ||
| 124 | done yet). The show must go on, as they say, and I would like my | ||
| 125 | experiments to go on. | ||
| 126 | So a “new” addition to the environmental sensor family connected to | ||
| 127 | the 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 | ||
| 128 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 129 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 130 | unique 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. | ||
| 131 | My 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 | ||
| 132 | 1.0 has been released: | ||
| 133 | wifi_da-1.0.sit | ||
| 134 | (StuffIt 3 archive) | ||
| 135 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 136 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 137 | classic 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. | ||
| 138 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 139 | Design Goals | ||
| 140 | I 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 | ||
| 141 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 142 | catch 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 | ||
| 143 | specified 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&#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 | ||
| 10 | easy to feel burnt out or disinterested. I have lost the passion for coding over | ||
| 11 | the past couple of months and it looked like I will never enjoy the coding as | ||
| 12 | much as I did.<p>I was feeling burnt out with programming. I thought taking a break from it and | ||
| 13 | focusing on other activities that I enjoy might be helpful. This way, I could | ||
| 14 | come back to programming with a fresh perspective and renewed energy. I also | ||
| 15 | thought about learning a new programming language or technology to keep things | ||
| 16 | interesting and challenging.<p>However, what I didn't realize was that learning a new language or technology | ||
| 17 | wasn't going to solve the underlying issue. I needed to take a step back and | ||
| 18 | re-evaluate why I had lost my passion for programming in the first place. This | ||
| 19 | involved 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 | ||
| 20 | languages, and we can feel like we're missing out if we're not constantly | ||
| 21 | learning and experimenting. However, it's important to remember that the latest | ||
| 22 | and greatest isn't always the best fit for our projects or our | ||
| 23 | interests. Instead of constantly chasing the next big thing, it can be helpful | ||
| 24 | to focus on what truly interests us and what we're passionate about. This can | ||
| 25 | help us stay motivated and engaged with our work, rather than feeling like we're | ||
| 26 | just going through the motions.<p>I expressed that I had lost my passion for coding over the past couple of | ||
| 27 | months, and I realized that the reason behind it was my tendency to spread | ||
| 28 | myself too thin and not focus on completing interesting projects. In order to | ||
| 29 | regain my passion for coding, I need to focus on projects that truly interest me | ||
| 30 | and give me a sense of purpose and motivation.<p>Recently, I have been playing World of Warcraft more frequently and have become | ||
| 31 | interested in developing addons for the game.<p>This quickly resulted in me creating three addons that improve the quality of | ||
| 32 | life, and I subsequently developed a more useful add-on that encapsulates all | ||
| 33 | the others I made.<p>I found it interesting that this action sparked a new interest in me. | ||
| 34 | Additionally, I discovered the Lua language, which reminded me that coding | ||
| 35 | should be fun rather than just a struggle with a language. It should be pure, | ||
| 36 | unadulterated fun.<p>I wasn't fighting the syntax, nor was I focused on finding the most optimal | ||
| 37 | solution. I simply created things without the pressure of making them the best | ||
| 38 | they could possibly be.<p>This made me realize that I actually adore simple languages that get out of the | ||
| 39 | way and let you express what you want to do. It forced me to rethink a lot about | ||
| 40 | what I use and what I actually enjoy.<p>I have decided to stick to the basics. For a scripting language, I will use | ||
| 41 | Lua. For networking, I will use Golang. And for any special needs, I will rely | ||
| 42 | on C. I do not require Rust, Nim, or Zig. This selection is more than sufficient | ||
| 43 | for my needs. I have to stay true to this simplicity. There is something to the | ||
| 44 | Occam's Razor.<p>I've been struggling with a lack of creativity lately, but now I'm experiencing | ||
| 45 | a real change. I realized I needed to take a step back and stop actively trying | ||
| 46 | to address the issue. I needed to stop worrying and overthinking it. I simply | ||
| 47 | needed some time. Looking back, I don't think I've taken any significant time | ||
| 48 | off in the last 10 years.<p>Suddenly, I find myself with the energy and passion to complete multiple small | ||
| 49 | projects. It doesn't feel like a chore at all. Who knew I needed WoW to | ||
| 50 | kickstart 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 | ||
| 51 | a lock on a Linux NFS server, which turned | ||
| 52 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 53 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 54 | owns 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 | ||
| 55 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 56 | list where the're doing | ||
| 57 | bad computer history and insisting that a guy Larry Rosen | ||
| 58 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 59 | somethin…<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: | ||
| 60 | i2c, plan9 | ||
| 61 | Another month, another file system. | ||
| 62 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 63 | you, bme680, we’re not | ||
| 64 | done yet). The show must go on, as they say, and I would like my | ||
| 65 | experiments to go on. | ||
| 66 | So a “new” addition to the environmental sensor family connected to | ||
| 67 | the 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 | ||
| 68 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 69 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 70 | unique 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. | ||
| 71 | My 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 | ||
| 72 | 1.0 has been released: | ||
| 73 | wifi_da-1.0.sit | ||
| 74 | (StuffIt 3 archive) | ||
| 75 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 76 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 77 | classic 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. | ||
| 78 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 79 | Design Goals | ||
| 80 | I 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 | ||
| 81 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 82 | catch 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 | ||
| 83 | specified 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 | ||
| 10 | and 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, | ||
| 11 | having all the free time you want". It was obvious they had no clue what means | ||
| 12 | working remotely. They had this romantic idea of remote work. You can watch TV | ||
| 13 | whenever you like, you can go outside for a picnic if you want and stuff like | ||
| 14 | that.<p>This may be true if you work a day or two in a week from home. But if you go | ||
| 15 | completely remote all these changes completely. I take some time to acclimate | ||
| 16 | but then you start feeling the consequences of going fully remote. And it's not | ||
| 17 | all 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. | ||
| 18 | It felt disoriented and a part of you that is used to procrastinate turns on. | ||
| 19 | You start thinking of a workday as a whole day. And soon this idea of "I can do | ||
| 20 | this later" starts creeping in. Well, I have the whole day ahead of me. I can do | ||
| 21 | this 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 | ||
| 22 | all the interruptions common in the workplace. And you can quickly get used to | ||
| 23 | this 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 | ||
| 24 | self-control</strong> to not waste other people's time. It is paralyzing when people | ||
| 25 | start calling you, sending you chat messages, etc. The thing is, that when I | ||
| 26 | achieve this hyper-performance mode I am completely embroiled in the problem I | ||
| 27 | am solving and this kind of interruptions mess with your head. I need an hour at | ||
| 28 | least to get back in the zone. Sometimes not achieving the same focus the whole | ||
| 29 | day.<p>I know that life is not how you want it to be and takes its route but from what | ||
| 30 | I've learned this kind of interruptions can be avoided in 90% of the case easily | ||
| 31 | just 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 | ||
| 32 | the office either.<li>Do not replace daily chats in the hallways with instant messaging software. | ||
| 33 | It 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 | ||
| 34 | boundaries and maintain your routine.<li>Be prepared that hours will be longer regardless of your good intentions and | ||
| 35 | your well thought of routine.<li>Try to be hyper-focused and do only one thing at the time. Multitasking is the | ||
| 36 | enemy of progress.<li>Avoid long meetings and if possible eliminate them. Rather take time to write | ||
| 37 | them out and allow others to respond in their own time. Meetings are usually a | ||
| 38 | large waste of time and most of the people attending them are there just | ||
| 39 | because the manager said so.<li>The software will not solve your problems. And throwing money at problems | ||
| 40 | neither.<li>If you are in a managerial position don't supervise any single minute of | ||
| 41 | workers. They are probably giving you more hours anyways. Track progress | ||
| 42 | weekly not daily. You hired them and give them the benefit of the doubt that | ||
| 43 | they 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 | ||
| 44 | a lock on a Linux NFS server, which turned | ||
| 45 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 46 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 47 | owns 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 | ||
| 48 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 49 | list where the're doing | ||
| 50 | bad computer history and insisting that a guy Larry Rosen | ||
| 51 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 52 | somethin…<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: | ||
| 53 | i2c, plan9 | ||
| 54 | Another month, another file system. | ||
| 55 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 56 | you, bme680, we’re not | ||
| 57 | done yet). The show must go on, as they say, and I would like my | ||
| 58 | experiments to go on. | ||
| 59 | So a “new” addition to the environmental sensor family connected to | ||
| 60 | the 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 | ||
| 61 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 62 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 63 | unique 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. | ||
| 64 | My 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 | ||
| 65 | 1.0 has been released: | ||
| 66 | wifi_da-1.0.sit | ||
| 67 | (StuffIt 3 archive) | ||
| 68 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 69 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 70 | classic 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. | ||
| 71 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 72 | Design Goals | ||
| 73 | I 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 | ||
| 74 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 75 | catch 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 | ||
| 76 | specified 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 | ||
| 10 | that could <a href=/digitalocean-spaces-to-sync-between-computers.html>replace Dropbox | ||
| 11 | eventually</a>. That solution | ||
| 12 | worked quite nicely, and I was amazed how smashing together a couple of existing | ||
| 13 | solutions would work this fine.<p>I have been running that solution in the background for a couple of months now | ||
| 14 | and kind of forgot about it. But recent developments around deplatforming and | ||
| 15 | having us people hostages of technology and big companies speed up my goals to | ||
| 16 | become 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> | ||
| 19 | etc and take back some control.<p>I am not a conspiracy theory nut, but to be honest, what these companies are | ||
| 20 | doing lately is out of control. It is a matter of principle at this point. I | ||
| 21 | have almost completely degoogled my life all the way from ditching Gmail, | ||
| 22 | YouTube and most of the services surrounding Google. And I must tell you, I feel | ||
| 23 | so 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 | ||
| 24 | Dropbox</a>.<blockquote><p>Also to note, I am using Linux on my machine with Gnome desktop environment. | ||
| 25 | This 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> | ||
| 27 | or <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 | ||
| 28 | synced. 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 | ||
| 34 | are Git repositories. I do not use this sync method for backup per see but in | ||
| 35 | case I reinstall my machine I can easily recreate all the important folder | ||
| 36 | structure 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/ < 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 > vscode-extension.txt | ||
| 53 | </span></span><span style=display:flex><span>dconf dump /com/gexperts/Tilix/ > 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>'node_modules/*'</span> --exclude <span style=color:#a31515>'.git/*'</span> --exclude <span style=color:#a31515>'.venv/*'</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>"%D %T"</span><span style=color:#a31515>`</span> >> ~/.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>"Vault sync succeded at `date +"</span>%D %T<span style=color:#a31515>"`"</span> | ||
| 64 | </span></span></code></pre><p>This script also backups some of the dotfiles I use and sends notification to | ||
| 65 | Gnome notification center. It is a straightforward solution. Nothing special | ||
| 66 | going on.<blockquote><p>One obvious benefit of this is that I can omit syncing Node's <code>node_modules</code> | ||
| 67 | or 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 | ||
| 69 | items 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 | ||
| 70 | flawlessly. 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 | ||
| 71 | remote 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 | ||
| 72 | a lock on a Linux NFS server, which turned | ||
| 73 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 74 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 75 | owns 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 | ||
| 76 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 77 | list where the're doing | ||
| 78 | bad computer history and insisting that a guy Larry Rosen | ||
| 79 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 80 | somethin…<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: | ||
| 81 | i2c, plan9 | ||
| 82 | Another month, another file system. | ||
| 83 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 84 | you, bme680, we’re not | ||
| 85 | done yet). The show must go on, as they say, and I would like my | ||
| 86 | experiments to go on. | ||
| 87 | So a “new” addition to the environmental sensor family connected to | ||
| 88 | the 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 | ||
| 89 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 90 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 91 | unique 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. | ||
| 92 | My 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 | ||
| 93 | 1.0 has been released: | ||
| 94 | wifi_da-1.0.sit | ||
| 95 | (StuffIt 3 archive) | ||
| 96 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 97 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 98 | classic 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. | ||
| 99 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 100 | Design Goals | ||
| 101 | I 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 | ||
| 102 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 103 | catch 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 | ||
| 104 | specified 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 @@ | |||
| 1 | User-agent: * | ||
| 2 | Allow: / | ||
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 | ||
| 22 | a lock on a Linux NFS server, which turned | ||
| 23 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 24 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 25 | owns 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 | ||
| 26 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 27 | list where the're doing | ||
| 28 | bad computer history and insisting that a guy Larry Rosen | ||
| 29 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 30 | somethin…<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: | ||
| 31 | i2c, plan9 | ||
| 32 | Another month, another file system. | ||
| 33 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 34 | you, bme680, we’re not | ||
| 35 | done yet). The show must go on, as they say, and I would like my | ||
| 36 | experiments to go on. | ||
| 37 | So a “new” addition to the environmental sensor family connected to | ||
| 38 | the 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 | ||
| 39 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 40 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 41 | unique 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. | ||
| 42 | My 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 | ||
| 43 | 1.0 has been released: | ||
| 44 | wifi_da-1.0.sit | ||
| 45 | (StuffIt 3 archive) | ||
| 46 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 47 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 48 | classic 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. | ||
| 49 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 50 | Design Goals | ||
| 51 | I 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 | ||
| 52 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 53 | catch 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 | ||
| 54 | specified 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 | ||
| 11 | very intriguing. When you push away all the marketing speak and look at the | ||
| 12 | idea, it makes a lot of sense.<blockquote><p>A unikernel is a specialized, single address space machine image constructed | ||
| 13 | by 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>. | ||
| 15 | Really worth a read.<p>If we compare a normal operating system to a unikernel side by side, they would | ||
| 16 | look 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 | ||
| 17 | the use of Unikernels. This comes with a price, of course. Unikernels are hard | ||
| 18 | to get running and require a lot of work since you don't have an actual proper | ||
| 19 | kernel 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 | ||
| 20 | Linux 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> | ||
| 22 | by <a href=https://landley.net>Rob Landley</a> and apart from statically compiling the | ||
| 23 | application 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. | ||
| 24 | It 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 | ||
| 25 | killed with KILL signal.<li>When any process having children dies for any reason, its children are | ||
| 26 | re-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 | ||
| 27 | result in system crash.</ul><p>PID 1 is considered as an Init application which takes care of running other | ||
| 28 | and 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 | ||
| 29 | by 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> | ||
| 39 | which is a software suite that provides an array of system components for Linux | ||
| 40 | operating 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 | ||
| 42 | this 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 | ||
| 43 | are in their nature layered, the images require quite a lot of space and also a | ||
| 44 | lot of additional software to handle them. They are not as lightweight as they | ||
| 45 | seem, 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, | ||
| 46 | as we will see later in the post.<blockquote><p>You could run a simple init system inside Docker container described more | ||
| 47 | in 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 | ||
| 48 | as init application / PID 1.</ol><p>For the sake of simplicity we will not be cross-compiling any of it and just | ||
| 49 | use 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>. | ||
| 63 | We will use this in QEMU later.<p>To make our lives a bit easier lets move the kernel image to another place. | ||
| 64 | Lets 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 | ||
| 71 | need 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>"fmt"</span> | ||
| 75 | </span></span><span style=display:flex><span> <span style=color:#a31515>"time"</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>"Hello from Golang"</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 | ||
| 85 | second to not overwhelm the CPU. This is because PID 1 should never complete | ||
| 86 | and/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>"-extldflags=-static"</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 | ||
| 94 | is a cpio archive of the initial file system that gets loaded into memory | ||
| 95 | during the Linux startup process).<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>$ echo init | cpio -o --format=newc > 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 | ||
| 105 | the machine's processor through dynamic binary translation and provides a set | ||
| 106 | of different hardware and device models for the machine, enabling it to run a | ||
| 107 | variety 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>"console=ttyS0"</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>"console=ttyS0"</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 | ||
| 141 | together only take around 12 MB, which is impressive as hell. And we need to | ||
| 142 | also know that the size of bzImage (Linux kernel) could be greatly decreased | ||
| 143 | by going into <code>make menuconfig</code> and removing a ton of features from the kernel, | ||
| 144 | making the size even smaller. I managed to get kernel size down to 2 MB and | ||
| 145 | still 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>. | ||
| 149 | You 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> | ||
| 177 | or <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 | ||
| 178 | and sometimes it's not. For embedded systems and very specialized applications | ||
| 179 | it is worth for sure. But in normal uses, I don't think so. It was an interesting | ||
| 180 | exercise in compiling kernels and looking at the guts of the Linux kernel, | ||
| 181 | but sticking to containers for most of the things is a better option in my | ||
| 182 | opinion.<p>An interesting experiment would be creating an image that supports networking | ||
| 183 | and could be deployed to AWS as an EC2 instance and observing how it fares. | ||
| 184 | But in that case, we would need to write some sort of supervisor that would | ||
| 185 | run on a separate EC2 that would check if other EC2 instances are running | ||
| 186 | properly. Remember that if your application fails, kernel panics and the | ||
| 187 | whole 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 | ||
| 188 | a lock on a Linux NFS server, which turned | ||
| 189 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 190 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 191 | owns 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 | ||
| 192 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 193 | list where the're doing | ||
| 194 | bad computer history and insisting that a guy Larry Rosen | ||
| 195 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 196 | somethin…<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: | ||
| 197 | i2c, plan9 | ||
| 198 | Another month, another file system. | ||
| 199 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 200 | you, bme680, we’re not | ||
| 201 | done yet). The show must go on, as they say, and I would like my | ||
| 202 | experiments to go on. | ||
| 203 | So a “new” addition to the environmental sensor family connected to | ||
| 204 | the 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 | ||
| 205 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 206 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 207 | unique 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. | ||
| 208 | My 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 | ||
| 209 | 1.0 has been released: | ||
| 210 | wifi_da-1.0.sit | ||
| 211 | (StuffIt 3 archive) | ||
| 212 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 213 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 214 | classic 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. | ||
| 215 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 216 | Design Goals | ||
| 217 | I 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 | ||
| 218 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 219 | catch 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 | ||
| 220 | specified 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&#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 | ||
| 10 | this 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 | ||
| 12 | a lock on a Linux NFS server, which turned | ||
| 13 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 14 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 15 | owns 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 | ||
| 16 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 17 | list where the're doing | ||
| 18 | bad computer history and insisting that a guy Larry Rosen | ||
| 19 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 20 | somethin…<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: | ||
| 21 | i2c, plan9 | ||
| 22 | Another month, another file system. | ||
| 23 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 24 | you, bme680, we’re not | ||
| 25 | done yet). The show must go on, as they say, and I would like my | ||
| 26 | experiments to go on. | ||
| 27 | So a “new” addition to the environmental sensor family connected to | ||
| 28 | the 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 | ||
| 29 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 30 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 31 | unique 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. | ||
| 32 | My 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 | ||
| 33 | 1.0 has been released: | ||
| 34 | wifi_da-1.0.sit | ||
| 35 | (StuffIt 3 archive) | ||
| 36 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 37 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 38 | classic 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. | ||
| 39 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 40 | Design Goals | ||
| 41 | I 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 | ||
| 42 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 43 | catch 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 | ||
| 44 | specified 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 | ||
| 10 | 5 years and people keep asking me how to approach developing such application | ||
| 11 | and I will give a try explaining it here.<p>IOT applications are really no different than any other kind of applications. | ||
| 12 | We have data that needs to be collected and visualized in some form of tables or | ||
| 13 | charts. The main difference here is that most of the times these data is | ||
| 14 | collected by some kind of device foreign to developer that mainly operates in | ||
| 15 | web 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 | ||
| 16 | default but for the sake of example we will be using commonly known Arduino with | ||
| 17 | wireless module already on the board → <a href=https://store.arduino.cc/arduino-mkr1000>Arduino | ||
| 18 | MKR1000</a>.<p>In order to make this little project as accessible to others as possible I will | ||
| 19 | try to make it as inexpensive as possible. And by this I mean that I will avoid | ||
| 20 | using hosted virtual servers and will be using my own laptop as a server. But | ||
| 21 | you must buy Arduino MKR1000 to follow steps below. But if you would want to | ||
| 22 | deploy this software I would suggest using | ||
| 23 | <a href=https://www.digitalocean.com>DigitalOcean</a> → smallest VPS is only per month | ||
| 24 | making this one of the most affordable option out there. Please notice that this | ||
| 25 | software will not run on stock web hosting that only supports LAMP (Linux, | ||
| 26 | Apache, MySQL, and PHP).<p>But before we begin please take notice that this is strictly experimental code | ||
| 27 | and not well optimized and there are much better ways in handling some aspects | ||
| 28 | of the application but that requires much deeper knowledge of technology that is | ||
| 29 | not 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 | ||
| 30 | to API and another to serving HTML with chart.<p>Schema below represents what we will try to achieve and how different parts | ||
| 31 | correlates 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 | ||
| 32 | Framework</a>. It is a single file web framework | ||
| 33 | that seriously simplifies working with routes, templating and has built-in web | ||
| 34 | server 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 | ||
| 36 | software <code>pip install bottle --user</code>.<p>If you are using Linux or MacOS then Python is already installed. If you will | ||
| 37 | try to test this on Windows please install <a href=https://www.python.org/downloads/windows/>Python for | ||
| 38 | Windows</a>. There may be some problems | ||
| 39 | with path when you will try to launch <code>python webapp.py</code> so please take care | ||
| 40 | of 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>"/"</span>, method=[<span style=color:#a31515>"GET"</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>"howdy from python"</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>"__main__"</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>"0.0.0.0"</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 | ||
| 65 | your 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 | ||
| 67 | root to run your app this will present a problem. The TCP/IP port numbers below | ||
| 68 | 1024 are privileged ports → this is a security feature. So in order of | ||
| 69 | simplicity 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 | ||
| 70 | below will work otherwise.<p>We use 0.0.0.0 as default host so that this app is available over your local | ||
| 71 | network. If you find your local ip <code>ifconfig</code> and try accessing this site | ||
| 72 | with your phone (if on same network/router as your machine) this should work as | ||
| 73 | well (example of such ip <code>http://192.168.1.15:5000</code>). This is a must have | ||
| 74 | because 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 | ||
| 75 | all this can not be written here but to just establish some basic security → you | ||
| 76 | should always use SSL with your application. Some fantastic free certificates | ||
| 77 | are available by <a href=https://letsencrypt.org>Let's Encrypt - Free SSL/TLS | ||
| 78 | Certificates</a>. With SSL certificate installed you | ||
| 79 | should then make use of HTTP headers and send your "API key" via a header. If | ||
| 80 | your key is send via header then this key is encrypted by SSL and send encrypted | ||
| 81 | over 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 | ||
| 83 | sending 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 | ||
| 84 | Application Security Best | ||
| 85 | Practices</a>. Please | ||
| 86 | check 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 | ||
| 87 | SQLite3 because it plays well with Python and can store quite large amount of | ||
| 88 | able to write data received by API to local storage. For example use I will use | ||
| 89 | data. I have been using it to collect gigabytes of data in a single database | ||
| 90 | without 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 | ||
| 91 | people</a>. This package | ||
| 92 | abstracts SQL and simplifies writing and reading data from database. You should | ||
| 93 | install 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 | ||
| 94 | using <a href=https://chrome.google.com/webstore/detail/restlet-client-rest-api-t/aejoelaoggembcahagimdiliamlcdmfm>Restlet Client for Google | ||
| 95 | Chrome</a>. | ||
| 96 | This 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>"dsn"</span>] = dataset.connect(<span style=color:#a31515>"sqlite:///data.db?check_same_thread=False"</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>"api_key"</span>] = <span style=color:#a31515>"JtF2aUE5SGHfVJBCG5SH"</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>"/api"</span>, method=[<span style=color:#a31515>"POST"</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>"Api_Key"</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>">>> </span><span style=color:#a31515>{}</span><span style=color:#a31515> :: </span><span style=color:#a31515>{}</span><span style=color:#a31515>"</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>"api_key"</span>] <span style=color:#00f>and</span> value: | ||
| 129 | </span></span><span style=display:flex><span> app.config[<span style=color:#a31515>"dsn"</span>][<span style=color:#a31515>"point"</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>""</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>"__main__"</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>"0.0.0.0"</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 | ||
| 146 | available via POST method on /api route.<p>After testing the service with Restlet Client you should be able to view your | ||
| 147 | data 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 | ||
| 148 | for 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 | ||
| 150 | would happen to have atomic clock on Arduino it would be then better to generate | ||
| 151 | and send timestamp with the value. This would be particularity useful if we | ||
| 152 | would be collecting sensor data at a higher frequency and then sending this data | ||
| 153 | in bulk to API.<p>If you will deploy this app with uWSGI and multi-threaded, use DSN (Data Source | ||
| 154 | Name) 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 | ||
| 155 | unwanted people can not post data to your database can we proceed further and | ||
| 156 | try 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 | ||
| 157 | you 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 | ||
| 159 | should be able to download and install IDE. Once that task is completed and you | ||
| 160 | have 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. | ||
| 162 | Please 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 | ||
| 163 | your code make sure you have run Python web application. Then change settings | ||
| 164 | for wifi, api endpoint and api_key. If by some reason code bellow doesn't work | ||
| 165 | for 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. | ||
| 166 | Then 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><WiFi101.h></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>"ssid-name"</span>; | ||
| 170 | </span></span><span style=display:flex><span><span style=color:#2b91af>char</span> pass[] = <span style=color:#a31515>"ssid-password"</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>"192.168.6.22"</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>"JtF2aUE5SGHfVJBCG5SH"</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>"WiFi shield not present"</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>"Attempting to connect to SSID: "</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>"SSID: "</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>"IP Address: "</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>"signal strength (RSSI):"</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>" dBm"</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>"POST /api HTTP/1.1"</span>); | ||
| 229 | </span></span><span style=display:flex><span> client.println(<span style=color:#a31515>"Connection: close"</span>); | ||
| 230 | </span></span><span style=display:flex><span> client.println(<span style=color:#a31515>"Api-Key: "</span> + api_key); | ||
| 231 | </span></span><span style=display:flex><span> client.println(<span style=color:#a31515>"Content-Length: "</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>"Data sent successfully ..."</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>"Problem sending data ..."</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 | ||
| 247 | between [ 0 .. 1000 ]. You can easily replace this with a temperature sensor or | ||
| 248 | any other kind of sensor.<p>Now that we have API under the hood and Arduino is sending demo data we can now | ||
| 249 | focus on data visualization.<h2 id=data-visualization>Data visualization</h2><p>Before we continue we should examine our project folder structure. Currently we | ||
| 250 | only 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 | ||
| 251 | for the simplicity reason. And for the bottle framework to be able to scan root | ||
| 252 | application 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> | ||
| 253 | subfolder to store templates. This is not the ideal situation and if you will | ||
| 254 | use bottle to develop web applications you should use native behavior and store | ||
| 255 | templates in it's predefined folder. But for the sake of example we will | ||
| 256 | over-ride this. Be careful to fully replace your code with new code that is | ||
| 257 | provided below. Avoid partially replacing code in file :) Also new code for | ||
| 258 | reading data-points is provided in Python example below.<p>First we add new route to our web application. It should be trigger when browser | ||
| 259 | hits root of application <code>http://0.0.0.0:5000/</code>. This route will do nothing | ||
| 260 | more 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 | ||
| 261 | exactly this is done.<p>Now we will expand <code>/api</code> route and use different methods to write or read | ||
| 262 | data-points. For writing data-point we will use POST method and for reading | ||
| 263 | points we will use GET method. GET method will return JSON object with latest | ||
| 264 | readings 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 | ||
| 267 | transform 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> "date": <span style=color:#a31515>"2017-08-11 01:07:20"</span>, | ||
| 270 | </span></span><span style=display:flex><span> "value": 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> "date": <span style=color:#a31515>"2017-08-11 01:07:30"</span>, | ||
| 274 | </span></span><span style=display:flex><span> "value": 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 | ||
| 278 | will develop now. If you would try to start web app now and go to root app this | ||
| 279 | will 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>"./"</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>"db"</span>] = dataset.connect(<span style=color:#a31515>"sqlite:///data.db?check_same_thread=False"</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>"api_key"</span>] = <span style=color:#a31515>"JtF2aUE5SGHfVJBCG5SH"</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>"/"</span>, method=[<span style=color:#a31515>"GET"</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>"frontend.html"</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>"/api"</span>, method=[<span style=color:#a31515>"GET"</span>, <span style=color:#a31515>"POST"</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>"POST"</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>"Api-Key"</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>">>> </span><span style=color:#a31515>{}</span><span style=color:#a31515> :: </span><span style=color:#a31515>{}</span><span style=color:#a31515>"</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>"api_key"</span>] <span style=color:#00f>and</span> value: | ||
| 325 | </span></span><span style=display:flex><span> app.config[<span style=color:#a31515>"db"</span>][<span style=color:#a31515>"point"</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>""</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>"db"</span>][<span style=color:#a31515>"point"</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>"date"</span>: datetime.datetime.fromtimestamp(int(point[<span style=color:#a31515>"ts"</span>])).strftime(<span style=color:#a31515>"%Y-%m-</span><span style=color:#a31515>%d</span><span style=color:#a31515> %H:%M:%S"</span>), | ||
| 339 | </span></span><span style=display:flex><span> <span style=color:#a31515>"value"</span>: point[<span style=color:#a31515>"value"</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>"application/json"</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>"__main__"</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>"0.0.0.0"</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 | ||
| 356 | and copy code below. When you are done you can start web application. Steps for | ||
| 357 | this part are listed below the code.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f><!DOCTYPE html></span> | ||
| 358 | </span></span><span style=display:flex><span><html> | ||
| 359 | </span></span><span style=display:flex><span> | ||
| 360 | </span></span><span style=display:flex><span> <head> | ||
| 361 | </span></span><span style=display:flex><span> <meta charset=<span style=color:#a31515>"utf-8"</span>> | ||
| 362 | </span></span><span style=display:flex><span> <title>Simple IOT application</title> | ||
| 363 | </span></span><span style=display:flex><span> </head> | ||
| 364 | </span></span><span style=display:flex><span> | ||
| 365 | </span></span><span style=display:flex><span> <body> | ||
| 366 | </span></span><span style=display:flex><span> | ||
| 367 | </span></span><span style=display:flex><span> <h1>Simple IOT application</h1> | ||
| 368 | </span></span><span style=display:flex><span> | ||
| 369 | </span></span><span style=display:flex><span> <div class=<span style=color:#a31515>"chart-placeholder"</span>> | ||
| 370 | </span></span><span style=display:flex><span> <div id=<span style=color:#a31515>"chart"</span>></div> | ||
| 371 | </span></span><span style=display:flex><span> </div> | ||
| 372 | </span></span><span style=display:flex><span> | ||
| 373 | </span></span><span style=display:flex><span> <span style=color:green><!-- application main script --></span> | ||
| 374 | </span></span><span style=display:flex><span> <script src=<span style=color:#a31515>"https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"</span>></script> | ||
| 375 | </span></span><span style=display:flex><span> <script src=<span style=color:#a31515>"https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.min.js"</span>></script> | ||
| 376 | </span></span><span style=display:flex><span> <script src=<span style=color:#a31515>"https://cdnjs.cloudflare.com/ajax/libs/metrics-graphics/2.11.0/metricsgraphics.min.js"</span>></script> | ||
| 377 | </span></span><span style=display:flex><span> <script> | ||
| 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>"/api"</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>"date"</span>, <span style=color:#a31515>"%Y-%m-%d %H:%M:%S"</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>"line"</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>"chart"</span>), | ||
| 387 | </span></span><span style=display:flex><span> x_accessor: <span style=color:#a31515>"date"</span>, | ||
| 388 | </span></span><span style=display:flex><span> y_accessor: <span style=color:#a31515>"value"</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> </script> | ||
| 402 | </span></span><span style=display:flex><span> | ||
| 403 | </span></span><span style=display:flex><span> <span style=color:green><!-- application styles --></span> | ||
| 404 | </span></span><span style=display:flex><span> <style> | ||
| 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> </style> | ||
| 427 | </span></span><span style=display:flex><span> | ||
| 428 | </span></span><span style=display:flex><span> </body> | ||
| 429 | </span></span><span style=display:flex><span> | ||
| 430 | </span></span><span style=display:flex><span></html> | ||
| 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 | ||
| 432 | every 5 seconds.<p>If you navigate to <code>http://0.0.0.0:5000</code> you should see rendered chart as | ||
| 433 | shown 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 | ||
| 435 | this is a minimal example and is far from what can be done in real life with | ||
| 436 | some further dive into other technologies.<p>If you would like to continue exploring IOT world here are some interesting | ||
| 437 | resources 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 | ||
| 438 | a lock on a Linux NFS server, which turned | ||
| 439 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 440 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 441 | owns 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 | ||
| 442 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 443 | list where the're doing | ||
| 444 | bad computer history and insisting that a guy Larry Rosen | ||
| 445 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 446 | somethin…<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: | ||
| 447 | i2c, plan9 | ||
| 448 | Another month, another file system. | ||
| 449 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 450 | you, bme680, we’re not | ||
| 451 | done yet). The show must go on, as they say, and I would like my | ||
| 452 | experiments to go on. | ||
| 453 | So a “new” addition to the environmental sensor family connected to | ||
| 454 | the 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 | ||
| 455 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 456 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 457 | unique 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. | ||
| 458 | My 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 | ||
| 459 | 1.0 has been released: | ||
| 460 | wifi_da-1.0.sit | ||
| 461 | (StuffIt 3 archive) | ||
| 462 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 463 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 464 | classic 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. | ||
| 465 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 466 | Design Goals | ||
| 467 | I 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 | ||
| 468 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 469 | catch 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 | ||
| 470 | specified 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 | ||
| 10 | out there, so writing a new one would be a waste of time if other solutions | ||
| 11 | wouldn't have quite complex install procedures and weren't so hard to maintain. | ||
| 12 | But 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 | ||
| 14 | laughable at the least. Those solutions are enterprise grade and have many | ||
| 15 | mechanisms there to ensure messages aren't lost and much more. Regardless of | ||
| 16 | these drawbacks, this method has been tested on a large website and worked until | ||
| 17 | now 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 | ||
| 18 | form of asynchronous service-to-service communication used in serverless and | ||
| 19 | microservices architectures. In a pub/sub model, any message published to a | ||
| 20 | topic 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 | ||
| 21 | Events</a> | ||
| 22 | to 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 | ||
| 23 | simple. We have subscribers that receive messages, and we have publishers that | ||
| 24 | create and post messages. Similar model is also well know pattern that works on | ||
| 25 | a 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 | ||
| 27 | for delivering messages,<li>if consumer wants to receive messages from a topic, producer and consumer | ||
| 28 | topics 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 | ||
| 30 | messages 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 | ||
| 31 | Events</a> | ||
| 32 | opens a long-running connection between the client and the server so make sure | ||
| 33 | if your setup is load balanced that the load balancer in this case can have | ||
| 34 | long 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 | ||
| 35 | page</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> | ||
| 37 | for 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 | ||
| 38 | automatically in case of a connection interrupt (bug)<li>Reportedly, CORS in EventSource is currently supported in Firefox 10+, Opera | ||
| 39 | 12+, 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><blank line> | ||
| 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><blank line> | ||
| 45 | </span></span></code></pre><p>And you can specify your own event types (the above messages will all trigger | ||
| 46 | the 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><blank line> | ||
| 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 | ||
| 51 | server 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 | ||
| 55 | Events</a> | ||
| 56 | which 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 | ||
| 57 | ones. For debugging server events add <code>console.log</code> to <code>server.js</code> code and | ||
| 58 | print 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 | ||
| 60 | get 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 | ||
| 62 | wheel.<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>'express'</span>); | ||
| 68 | </span></span><span style=display:flex><span><span style=color:#00f>const</span> bodyParser = require(<span style=color:#a31515>'body-parser'</span>); | ||
| 69 | </span></span><span style=display:flex><span><span style=color:#00f>const</span> SSETopic = require(<span style=color:#a31515>'sse-pubsub'</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>'*'</span>, (req, res, next) => { | ||
| 81 | </span></span><span style=display:flex><span> res.header(<span style=color:#a31515>'Access-Control-Allow-Origin'</span>, <span style=color:#a31515>'*'</span>); | ||
| 82 | </span></span><span style=display:flex><span> res.header(<span style=color:#a31515>'Access-Control-Allow-Headers'</span>, <span style=color:#a31515>'X-Requested-With, Content-Type'</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>'*'</span>, <span style=color:#00f>async</span> (req, res) => { | ||
| 88 | </span></span><span style=display:flex><span> res.header(<span style=color:#a31515>'Access-Control-Allow-Origin'</span>, <span style=color:#a31515>'*'</span>); | ||
| 89 | </span></span><span style=display:flex><span> res.header(<span style=color:#a31515>'Access-Control-Allow-Headers'</span>, <span style=color:#a31515>'X-Requested-With, Content-Type'</span>); | ||
| 90 | </span></span><span style=display:flex><span> res.send(<span style=color:#a31515>'OK'</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>'/stream/:topic'</span>, <span style=color:#00f>async</span> (req, res, next) => { | ||
| 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>'/publish'</span>, <span style=color:#00f>async</span> (req, res) => { | ||
| 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>'Incoming message:'</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>'topic'</span>) && | ||
| 117 | </span></span><span style=display:flex><span> body.hasOwnProperty(<span style=color:#a31515>'event'</span>) && | ||
| 118 | </span></span><span style=display:flex><span> body.hasOwnProperty(<span style=color:#a31515>'message'</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>'/status'</span>, <span style=color:#00f>async</span> (req, res) => { | ||
| 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>'/'</span>, <span style=color:#00f>async</span> (req, res) => { | ||
| 144 | </span></span><span style=display:flex><span> res.send(<span style=color:#a31515>'OK'</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) => { | ||
| 149 | </span></span><span style=display:flex><span> res.set(<span style=color:#a31515>'Cache-Control'</span>, <span style=color:#a31515>'private, no-store'</span>); | ||
| 150 | </span></span><span style=display:flex><span> res.status(404).end(<span style=color:#a31515>'Not found'</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, () => { | ||
| 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 | ||
| 158 | accepts. Having structure like this allows us to have multiple separated type of | ||
| 159 | events on each topic.<p>With this we can separate streams and only receive events that belong to the | ||
| 160 | topic.<p>One example would be, that we have index page and we want to receive messages | ||
| 161 | about new upvotes or new subscribers but we don't want to follow events for | ||
| 162 | other pages. This reduces clutter and overall network. And structure is much | ||
| 163 | nicer and maintanable.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>{ | ||
| 164 | </span></span><span style=display:flex><span> "topic": <span style=color:#a31515>"sample-topic"</span>, | ||
| 165 | </span></span><span style=display:flex><span> "event": <span style=color:#a31515>"sample-event"</span>, | ||
| 166 | </span></span><span style=display:flex><span> "message": { "name": <span style=color:#a31515>"John"</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 | ||
| 169 | follow along.<h3 id=publisher>Publisher</h3><p>As talked about above publisher is the one that send messages to the | ||
| 170 | broker/server. Message inside the payload can be whatever you want (string, | ||
| 171 | object, array). I would however personally avoid send large chunks of data like | ||
| 172 | blobs and such.<pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span><span style=color:#00f><!DOCTYPE html></span> | ||
| 173 | </span></span><span style=display:flex><span><html lang=<span style=color:#a31515>"en"</span>> | ||
| 174 | </span></span><span style=display:flex><span> | ||
| 175 | </span></span><span style=display:flex><span> <head> | ||
| 176 | </span></span><span style=display:flex><span> <meta charset=<span style=color:#a31515>"UTF-8"</span>> | ||
| 177 | </span></span><span style=display:flex><span> <meta name=<span style=color:#a31515>"viewport"</span> content=<span style=color:#a31515>"width=device-width, initial-scale=1.0"</span>> | ||
| 178 | </span></span><span style=display:flex><span> <title>Publisher</title> | ||
| 179 | </span></span><span style=display:flex><span> </head> | ||
| 180 | </span></span><span style=display:flex><span> | ||
| 181 | </span></span><span style=display:flex><span> <body> | ||
| 182 | </span></span><span style=display:flex><span> | ||
| 183 | </span></span><span style=display:flex><span> <h1>Publisher</h1> | ||
| 184 | </span></span><span style=display:flex><span> | ||
| 185 | </span></span><span style=display:flex><span> <fieldset> | ||
| 186 | </span></span><span style=display:flex><span> <p> | ||
| 187 | </span></span><span style=display:flex><span> <label>Server:</label> | ||
| 188 | </span></span><span style=display:flex><span> <input type=<span style=color:#a31515>"text"</span> id=<span style=color:#a31515>"server"</span> value=<span style=color:#a31515>"http://localhost:4000"</span>> | ||
| 189 | </span></span><span style=display:flex><span> </p> | ||
| 190 | </span></span><span style=display:flex><span> <p> | ||
| 191 | </span></span><span style=display:flex><span> <label>Topic:</label> | ||
| 192 | </span></span><span style=display:flex><span> <input type=<span style=color:#a31515>"text"</span> id=<span style=color:#a31515>"topic"</span> value=<span style=color:#a31515>"sample-topic"</span>> | ||
| 193 | </span></span><span style=display:flex><span> </p> | ||
| 194 | </span></span><span style=display:flex><span> <p> | ||
| 195 | </span></span><span style=display:flex><span> <label>Event:</label> | ||
| 196 | </span></span><span style=display:flex><span> <input type=<span style=color:#a31515>"text"</span> id=<span style=color:#a31515>"event"</span> value=<span style=color:#a31515>"sample-event"</span>> | ||
| 197 | </span></span><span style=display:flex><span> </p> | ||
| 198 | </span></span><span style=display:flex><span> <p> | ||
| 199 | </span></span><span style=display:flex><span> <label>Message:</label> | ||
| 200 | </span></span><span style=display:flex><span> <input type=<span style=color:#a31515>"text"</span> id=<span style=color:#a31515>"message"</span> value=<span style=color:#a31515>'{"name": "John"}'</span>> | ||
| 201 | </span></span><span style=display:flex><span> </p> | ||
| 202 | </span></span><span style=display:flex><span> <p> | ||
| 203 | </span></span><span style=display:flex><span> <button type=<span style=color:#a31515>"button"</span> id=<span style=color:#a31515>"button"</span>>Publish message to topic</button> | ||
| 204 | </span></span><span style=display:flex><span> </p> | ||
| 205 | </span></span><span style=display:flex><span> </fieldset> | ||
| 206 | </span></span><span style=display:flex><span> | ||
| 207 | </span></span><span style=display:flex><span> <script> | ||
| 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>'#button'</span>); | ||
| 210 | </span></span><span style=display:flex><span> <span style=color:#00f>const</span> server = document.querySelector(<span style=color:#a31515>'#server'</span>); | ||
| 211 | </span></span><span style=display:flex><span> <span style=color:#00f>const</span> topic = document.querySelector(<span style=color:#a31515>'#topic'</span>); | ||
| 212 | </span></span><span style=display:flex><span> <span style=color:#00f>const</span> event = document.querySelector(<span style=color:#a31515>'#event'</span>); | ||
| 213 | </span></span><span style=display:flex><span> <span style=color:#00f>const</span> message = document.querySelector(<span style=color:#a31515>'#message'</span>); | ||
| 214 | </span></span><span style=display:flex><span> | ||
| 215 | </span></span><span style=display:flex><span> button.addEventListener(<span style=color:#a31515>'click'</span>, <span style=color:#00f>async</span> (evt) => { | ||
| 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>'post'</span>, | ||
| 218 | </span></span><span style=display:flex><span> headers: { | ||
| 219 | </span></span><span style=display:flex><span> <span style=color:#a31515>'Accept'</span>: <span style=color:#a31515>'application/json'</span>, | ||
| 220 | </span></span><span style=display:flex><span> <span style=color:#a31515>'Content-Type'</span>: <span style=color:#a31515>'application/json'</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> </script> | ||
| 234 | </span></span><span style=display:flex><span> | ||
| 235 | </span></span><span style=display:flex><span> </body> | ||
| 236 | </span></span><span style=display:flex><span> | ||
| 237 | </span></span><span style=display:flex><span></html> | ||
| 238 | </span></span></code></pre><h3 id=subscriber>Subscriber</h3><p>Subscriber is responsible for receiving new messages that come from server via | ||
| 239 | publisher. The code bellow is very rudimentary but works and follows the | ||
| 240 | implementation guidelines for EventSource.<p>You can use either Developer Tools Console to see incoming messages or you can | ||
| 241 | defer to Debugging with Google Chrome section above to see all EventStream | ||
| 242 | messages.<blockquote><p>Don't be alarmed if the subscriber gets disconnected from the server every so | ||
| 243 | often. The code we have here resets connection every 15s but it automatically | ||
| 244 | get reconnected and fetches all messages up to last received message id. This | ||
| 245 | setting 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><!DOCTYPE html></span> | ||
| 247 | </span></span><span style=display:flex><span><html lang=<span style=color:#a31515>"en"</span>> | ||
| 248 | </span></span><span style=display:flex><span> | ||
| 249 | </span></span><span style=display:flex><span> <head> | ||
| 250 | </span></span><span style=display:flex><span> <meta charset=<span style=color:#a31515>"UTF-8"</span>> | ||
| 251 | </span></span><span style=display:flex><span> <meta name=<span style=color:#a31515>"viewport"</span> content=<span style=color:#a31515>"width=device-width, initial-scale=1.0"</span>> | ||
| 252 | </span></span><span style=display:flex><span> <title>Subscriber</title> | ||
| 253 | </span></span><span style=display:flex><span> <link rel=<span style=color:#a31515>"stylesheet"</span> href=<span style=color:#a31515>"style.css"</span>> | ||
| 254 | </span></span><span style=display:flex><span> </head> | ||
| 255 | </span></span><span style=display:flex><span> | ||
| 256 | </span></span><span style=display:flex><span> <body> | ||
| 257 | </span></span><span style=display:flex><span> | ||
| 258 | </span></span><span style=display:flex><span> <h1>Subscriber</h1> | ||
| 259 | </span></span><span style=display:flex><span> | ||
| 260 | </span></span><span style=display:flex><span> <fieldset> | ||
| 261 | </span></span><span style=display:flex><span> <p> | ||
| 262 | </span></span><span style=display:flex><span> <label>Server:</label> | ||
| 263 | </span></span><span style=display:flex><span> <input type=<span style=color:#a31515>"text"</span> id=<span style=color:#a31515>"server"</span> value=<span style=color:#a31515>"http://localhost:4000"</span>> | ||
| 264 | </span></span><span style=display:flex><span> </p> | ||
| 265 | </span></span><span style=display:flex><span> <p> | ||
| 266 | </span></span><span style=display:flex><span> <label>Topic:</label> | ||
| 267 | </span></span><span style=display:flex><span> <input type=<span style=color:#a31515>"text"</span> id=<span style=color:#a31515>"topic"</span> value=<span style=color:#a31515>"sample-topic"</span>> | ||
| 268 | </span></span><span style=display:flex><span> </p> | ||
| 269 | </span></span><span style=display:flex><span> <p> | ||
| 270 | </span></span><span style=display:flex><span> <label>Event:</label> | ||
| 271 | </span></span><span style=display:flex><span> <input type=<span style=color:#a31515>"text"</span> id=<span style=color:#a31515>"event"</span> value=<span style=color:#a31515>"sample-event"</span>> | ||
| 272 | </span></span><span style=display:flex><span> </p> | ||
| 273 | </span></span><span style=display:flex><span> <p> | ||
| 274 | </span></span><span style=display:flex><span> <button type=<span style=color:#a31515>"button"</span> id=<span style=color:#a31515>"button"</span>>Subscribe to topic</button> | ||
| 275 | </span></span><span style=display:flex><span> </p> | ||
| 276 | </span></span><span style=display:flex><span> </fieldset> | ||
| 277 | </span></span><span style=display:flex><span> | ||
| 278 | </span></span><span style=display:flex><span> <script> | ||
| 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>'#button'</span>); | ||
| 281 | </span></span><span style=display:flex><span> <span style=color:#00f>const</span> server = document.querySelector(<span style=color:#a31515>'#server'</span>); | ||
| 282 | </span></span><span style=display:flex><span> <span style=color:#00f>const</span> topic = document.querySelector(<span style=color:#a31515>'#topic'</span>); | ||
| 283 | </span></span><span style=display:flex><span> <span style=color:#00f>const</span> event = document.querySelector(<span style=color:#a31515>'#event'</span>); | ||
| 284 | </span></span><span style=display:flex><span> | ||
| 285 | </span></span><span style=display:flex><span> button.addEventListener(<span style=color:#a31515>'click'</span>, <span style=color:#00f>async</span> (evt) => { | ||
| 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>'open'</span>, <span style=color:#00f>function</span> (evt) { | ||
| 294 | </span></span><span style=display:flex><span> console.log(<span style=color:#a31515>'connected'</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>'error'</span>, <span style=color:#00f>function</span> (evt) { | ||
| 298 | </span></span><span style=display:flex><span> console.log(<span style=color:#a31515>'error'</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> </script> | ||
| 304 | </span></span><span style=display:flex><span> | ||
| 305 | </span></span><span style=display:flex><span> </body> | ||
| 306 | </span></span><span style=display:flex><span> | ||
| 307 | </span></span><span style=display:flex><span></html> | ||
| 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 | ||
| 309 | a lock on a Linux NFS server, which turned | ||
| 310 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 311 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 312 | owns 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 | ||
| 313 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 314 | list where the're doing | ||
| 315 | bad computer history and insisting that a guy Larry Rosen | ||
| 316 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 317 | somethin…<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: | ||
| 318 | i2c, plan9 | ||
| 319 | Another month, another file system. | ||
| 320 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 321 | you, bme680, we’re not | ||
| 322 | done yet). The show must go on, as they say, and I would like my | ||
| 323 | experiments to go on. | ||
| 324 | So a “new” addition to the environmental sensor family connected to | ||
| 325 | the 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 | ||
| 326 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 327 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 328 | unique 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. | ||
| 329 | My 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 | ||
| 330 | 1.0 has been released: | ||
| 331 | wifi_da-1.0.sit | ||
| 332 | (StuffIt 3 archive) | ||
| 333 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 334 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 335 | classic 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. | ||
| 336 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 337 | Design Goals | ||
| 338 | I 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 | ||
| 339 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 340 | catch 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 | ||
| 341 | specified 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 | ||
| 10 | having 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 | ||
| 11 | extension</a>, | ||
| 12 | and it serves the purpose quite well.<p>But I also have a bunch of electronics that I bought through the time, and I am | ||
| 13 | not using any of them, and it's time to stop hording this stuff and use it in a | ||
| 14 | project.<p>A while ago I bought a small eInk display <a href="https://shop.pimoroni.com/products/inky-phat?variant=12549254217811">Inky | ||
| 15 | pHAT</a> and I | ||
| 16 | have a bunch of <a href=https://www.raspberrypi.org/products/raspberry-pi-zero/>Raspberry Pi's | ||
| 17 | Zero</a> lying around that | ||
| 18 | I 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 | ||
| 19 | pHAT</a> is | ||
| 20 | essentially a HAT, it can easily be added on top of the <a href=https://www.raspberrypi.org/products/raspberry-pi-zero/>Raspberry Pi | ||
| 21 | Zero</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>'America/New_York'</span>, | ||
| 32 | </span></span><span style=display:flex><span> <span style=color:#a31515>'Europe/Ljubljana'</span>, | ||
| 33 | </span></span><span style=display:flex><span> <span style=color:#a31515>'Australia/Brisbane'</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>'P'</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>'TZ="</span><span style=color:#a31515>{}</span><span style=color:#a31515>" date +"</span><span style=color:#a31515>%a</span><span style=color:#a31515>,%H:%M"'</span>.format(clock)) | ||
| 52 | </span></span><span style=display:flex><span> ctime = ctime.read().strip().split(<span style=color:#a31515>','</span>) | ||
| 53 | </span></span><span style=display:flex><span> city = clock.split(<span style=color:#a31515>'/'</span>)[1].replace(<span style=color:#a31515>'_'</span>, <span style=color:#a31515>' '</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 | ||
| 64 | refreshing 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 | ||
| 66 | this 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 | ||
| 67 | here</a>, but make sure that dimensions make | ||
| 68 | sense and also opening for USB port should be added or just use a drill and some | ||
| 69 | hot 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 | ||
| 70 | a lock on a Linux NFS server, which turned | ||
| 71 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 72 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 73 | owns 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 | ||
| 74 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 75 | list where the're doing | ||
| 76 | bad computer history and insisting that a guy Larry Rosen | ||
| 77 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 78 | somethin…<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: | ||
| 79 | i2c, plan9 | ||
| 80 | Another month, another file system. | ||
| 81 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 82 | you, bme680, we’re not | ||
| 83 | done yet). The show must go on, as they say, and I would like my | ||
| 84 | experiments to go on. | ||
| 85 | So a “new” addition to the environmental sensor family connected to | ||
| 86 | the 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 | ||
| 87 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 88 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 89 | unique 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. | ||
| 90 | My 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 | ||
| 91 | 1.0 has been released: | ||
| 92 | wifi_da-1.0.sit | ||
| 93 | (StuffIt 3 archive) | ||
| 94 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 95 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 96 | classic 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. | ||
| 97 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 98 | Design Goals | ||
| 99 | I 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 | ||
| 100 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 101 | catch 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 | ||
| 102 | specified 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 | ||
| 10 | experiment was interesting and I have done some great work on macOS but it was | ||
| 11 | time to move back.<p>I actually really missed Linux. The simplicity of <code>apt-get</code> or just the amount | ||
| 12 | of software that exists for Linux should be a no-brainer. I spent most of my | ||
| 13 | time 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 | ||
| 15 | managers 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 | ||
| 16 | Docker and tooling like this worked without any hiccups. My normal tools like | ||
| 17 | coding IDE worked flawlessly and the whole look and feel is just superb. I have | ||
| 18 | been using MacBook Air for couple of years so I was used to the system but never | ||
| 19 | as a daily driver.<p>One of the things I did after I installed Linux back on my machine was cleaning | ||
| 20 | up my Dropbox folder. I have everything on Dropbox. Even projects folder. I | ||
| 21 | write 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 | ||
| 23 | movies or music or pictures on my PC. All of that stuff is in cloud. I use | ||
| 24 | Google 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 | ||
| 25 | deleted more code than deployed. People find this strange but for me deleting | ||
| 26 | something feels so cathartic and also forces me to write better code next time | ||
| 27 | around when I am faced with similar problem. That was a huge relief if I am | ||
| 28 | being totally honest.<p>Next step was to do something with my webpage. I have been using some scripts I | ||
| 29 | wrote a while ago to generate static pages from markdown source posts. I kept on | ||
| 30 | adding and adding stuff on top of it and it became a source of a | ||
| 31 | frustration. And this is just a simple blog and I was using gulp and npm. | ||
| 32 | Anyways after couple of hours of searching and testing static generators I found | ||
| 33 | an interesting one | ||
| 34 | <a href=https://github.com/piranha/gostatic>https://github.com/piranha/gostatic</a> and I | ||
| 35 | just decided to use this one. It was the only one that had a simple templating | ||
| 36 | engine, not that I really need one. But others had this convoluted way of trying | ||
| 37 | to solve everything and at the end just required quite bigger learning curve I | ||
| 38 | was ready to go with. So I deleted couple of old posts, simplified HTML, trashed | ||
| 39 | most of the CSS and went with | ||
| 40 | <a href=https://motherfuckingwebsite.com/>https://motherfuckingwebsite.com/</a> | ||
| 41 | aesthetics. Yeah, the previous site was more visually stimulating but all I | ||
| 42 | really care is the content at this point. And Times New Roman font is kind of | ||
| 43 | awesome.<p>I stopped working on most of the projects in the past couple of months because | ||
| 44 | the overhead was just too insane. There comes a point when you stretch yourself | ||
| 45 | too 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 | ||
| 46 | a lock on a Linux NFS server, which turned | ||
| 47 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 48 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 49 | owns 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 | ||
| 50 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 51 | list where the're doing | ||
| 52 | bad computer history and insisting that a guy Larry Rosen | ||
| 53 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 54 | somethin…<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: | ||
| 55 | i2c, plan9 | ||
| 56 | Another month, another file system. | ||
| 57 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 58 | you, bme680, we’re not | ||
| 59 | done yet). The show must go on, as they say, and I would like my | ||
| 60 | experiments to go on. | ||
| 61 | So a “new” addition to the environmental sensor family connected to | ||
| 62 | the 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 | ||
| 63 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 64 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 65 | unique 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. | ||
| 66 | My 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 | ||
| 67 | 1.0 has been released: | ||
| 68 | wifi_da-1.0.sit | ||
| 69 | (StuffIt 3 archive) | ||
| 70 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 71 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 72 | classic 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. | ||
| 73 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 74 | Design Goals | ||
| 75 | I 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 | ||
| 76 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 77 | catch 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 | ||
| 78 | specified 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 | ||
| 10 | software development field and also in electronics field and every experience | ||
| 11 | taught me some invaluable lessons about how NOT TO approach development. And | ||
| 12 | through this post I will try to point out some absurd, outdated techniques I | ||
| 13 | find the most annoying and damaging during a development cycle. There will be | ||
| 14 | swearing because this topic really gets on my nerves and I never coherently | ||
| 15 | tried 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 | ||
| 16 | stay old and outdated. This is mainly because we as people are unable to | ||
| 17 | completely shift away from these approaches.<p>I was always struggling with communication, and many times that cost me a | ||
| 18 | relationship or two because I was not on the ball all the time. Through every | ||
| 19 | experience, I became more convinced that I am the problem and never ever doubted | ||
| 20 | that the problem may be that communication never evolved a single step from | ||
| 21 | emails. And if you think for a second, not many things have changed around this | ||
| 22 | topic. We just have different representations of email (message boards, chats, | ||
| 23 | project management tools). And I believe this is the real issue we are facing | ||
| 24 | now.<p>There are many articles written about hyper connectivity and the effects that | ||
| 25 | are a direct result of it. But mainstream does nothing towards it. We are just | ||
| 26 | putting out fires, and we do nothing to prevent it. I am certain this will be a | ||
| 27 | major source of grief in coming years. And what we all can do to avoid this is | ||
| 28 | to change our mindset and experiment on our communication skills, development | ||
| 29 | approaches. We need to maximize possible output that a person can give. And to | ||
| 30 | achieve this we need to listen to them, encourage them. I know that not | ||
| 31 | everybody is a naturally born leader, but with enough practice and encouragement | ||
| 32 | they also can become active participants in leadership.<p>There are many talks now about methodologies such as Scrum, Kanban, Cleanroom | ||
| 33 | and they all fucking piss me of :). These are all boxes that imprison people and | ||
| 34 | take away their freedom of thought. This is a straightforward mindfuck / | ||
| 35 | amputation of creativity.<p>Let me list a couple of things that I find really destructive and bad for a | ||
| 36 | project 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 | ||
| 37 | sole purpose is to inform the sender that you received their email, and you are | ||
| 38 | working on it. Its result is only to calm down the sender that their task is | ||
| 39 | being dealt with. It’s intent basically is, I did my job by sending you this | ||
| 40 | email, so I am on clear grounds. I categorize this email as fuck you email. | ||
| 41 | This is one of the most irritating types of emails I need to write. This is the | ||
| 42 | ultimate control freak show you can experience, and it gives the sender a false | ||
| 43 | feeling of control. Newsflash: We do not live in 1982 where there was a | ||
| 44 | possibility that email never reached the destination. I really hate this from | ||
| 45 | the bottom of my heart.<p>They should be like: “Yes, I am fucking alive, and I am at your service my | ||
| 46 | leash!”. I guess if I would reply like this, I wouldn’t have to write any more | ||
| 47 | of 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 | ||
| 48 | their 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 | ||
| 50 | opportunity. And by getting angry at them, you only provoke yourself. They are | ||
| 51 | not at fault. You just need to tell them they are only giving suggestions and | ||
| 52 | not tasks at the beginning and everything will be alright. But if you give them | ||
| 53 | a feeling that they are in control, you will have immense problems explaining | ||
| 54 | why their features are not in current release.<p>Project mission must be always leading project requirements and any deviation | ||
| 55 | from it will result in major project butchering. And by this, I mean that the | ||
| 56 | project will get its own path, and you will be left with half done software that | ||
| 57 | helps nobody. Clear mission goals and clean execution will allow you to develop | ||
| 58 | software 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 | ||
| 59 | we are infallible and cannot make mistakes. As soon as a procedure or process is | ||
| 60 | established, there is no room for changes or improvements. This is the most | ||
| 61 | idiotic thing someone can say of think. I think that processes need to involve | ||
| 62 | and change over time. This is imperative and need to have in your organization | ||
| 63 | if you want to improve and develop company. We all need to grow balls and change | ||
| 64 | everything in order to adapt to current situations. Being a prisoner of | ||
| 65 | predefined processes kills creativity.<p>I am constantly trying new software for project managing and communication. I | ||
| 66 | believe every team has its own dynamic, and it needs to be discovered | ||
| 67 | organically and naturally through many experiments. By putting the team in a | ||
| 68 | box, you are amputating their creativity and therefore minimizing their | ||
| 69 | potential. But if you talk to an executive, you will mainly find archetypical | ||
| 70 | thinking and a strong need to compartmentalize everything from business | ||
| 71 | processes to resource management. And this type of management that often | ||
| 72 | displays micromanagement techniques only works for short periods (couple of | ||
| 73 | years) and then employees either leave the company or become basically retarded | ||
| 74 | drones on autopilot.<h2 id=micromanaging>Micromanaging</h2><p>This basically implies that everybody on the team is an idiot who needs to have | ||
| 75 | a to-do list that they cannot write themselves. How about spoon-feeding the team | ||
| 76 | at launch because besides the team leader, everybody must be a retarded idiot at | ||
| 77 | best?<p>I prefer milestones as they give developers much more freedom and creativity in | ||
| 78 | developing and not waste their time checking some bizarre to-do list that was | ||
| 79 | not even thought through. Projects constantly change throughout the development | ||
| 80 | cycle, and all you are left at the end is a list of unchecked tasks and the | ||
| 81 | wrath 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 | ||
| 82 | meetings with software, with no regards that we are not machines. Many times a | ||
| 83 | simple 5-min meeting at morning can solve most of the problems. In rapid | ||
| 84 | development, short bursts of man to man communication is possibly the best way | ||
| 85 | to go.<p>We now have all this software available, and all what we get out of it is a | ||
| 86 | giant 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. | ||
| 87 | What I noticed in my experience that all this buzz words around us only mislead | ||
| 88 | and capture us in a circle of solving issues that already have a solution, but | ||
| 89 | we 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 | ||
| 90 | is though only for bad developers. Yes, I said it. There are many types of | ||
| 91 | developers out there. And those unable to minimize feature scope are the ones | ||
| 92 | you don’t need on your team. Their only goal is to solve problems that exist | ||
| 93 | only in their heads. And then you have to argue with them, and waste energy on | ||
| 94 | them, instead of developing your awesome product. They are a cancer and I | ||
| 95 | suggest you cut them off.<p>MVP as an idea is great, but sadly people don’t understand underlying | ||
| 96 | philosophy, and they spent too much time focusing and fixating on something that | ||
| 97 | every sane person with normal IQ will understand without some made up | ||
| 98 | acronym. 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 | ||
| 99 | to 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 | ||
| 100 | confident. We often feel a need that we are in service of others, which is true | ||
| 101 | to some extent. But it is also true that others are in service to us to some | ||
| 102 | extent. And we forget this all the time. We are all pressured all the time to | ||
| 103 | make decisions just to calm other people down. And when they leave your office | ||
| 104 | you 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 | ||
| 105 | will be able to do. So 5-min update email requests will only resolve in mental | ||
| 106 | breakdown and inability to work that day. Constant poking is probably the only | ||
| 107 | thing I lose my mind instantly. For all you that are doing this: “Stop bothering | ||
| 108 | us with your insecurities and let us do our job. We will do it quicker and | ||
| 109 | better 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? | ||
| 110 | You will get much more from and out of me if you ask me like a human person and | ||
| 111 | not your personal butler. On a long run, you are destroying your relationships | ||
| 112 | and nobody would want to work with you. Your schizophrenic approach will damage | ||
| 113 | only 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 | ||
| 114 | to acknowledge this. And I lie to myself and try vigorously to find some | ||
| 115 | explanation why I do these things. There is always space for growth. And maybe | ||
| 116 | you will also find some of yourself in this post and realize what needs to | ||
| 117 | change 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 | ||
| 118 | a lock on a Linux NFS server, which turned | ||
| 119 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 120 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 121 | owns 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 | ||
| 122 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 123 | list where the're doing | ||
| 124 | bad computer history and insisting that a guy Larry Rosen | ||
| 125 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 126 | somethin…<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: | ||
| 127 | i2c, plan9 | ||
| 128 | Another month, another file system. | ||
| 129 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 130 | you, bme680, we’re not | ||
| 131 | done yet). The show must go on, as they say, and I would like my | ||
| 132 | experiments to go on. | ||
| 133 | So a “new” addition to the environmental sensor family connected to | ||
| 134 | the 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 | ||
| 135 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 136 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 137 | unique 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. | ||
| 138 | My 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 | ||
| 139 | 1.0 has been released: | ||
| 140 | wifi_da-1.0.sit | ||
| 141 | (StuffIt 3 archive) | ||
| 142 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 143 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 144 | classic 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. | ||
| 145 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 146 | Design Goals | ||
| 147 | I 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 | ||
| 148 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 149 | catch 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 | ||
| 150 | specified 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 | ||
| 10 | opinionated post! I will learn more about this in the future, and probably | ||
| 11 | slightly 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 | ||
| 12 | use that situation as a learning one. Trying new things, new technologies, new | ||
| 13 | tools. I always considered myself to be an adventurous person when it comes to | ||
| 14 | technology. I never shy away from trying new languages, new operating systems | ||
| 15 | etc. Likewise, I find the whole experience satisfying, and it tickles that part | ||
| 16 | of 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 | ||
| 18 | level up your character and go into these scriptable battles. You know, RPG | ||
| 19 | elements.<p>So, the natural way to go would be some sort of SPA (single page application) | ||
| 20 | with 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 | ||
| 21 | a grain of salt. I have only scratched the surface with these technologies, | ||
| 22 | and my knowledge is full of gaps. This is my experience using some of these | ||
| 23 | products 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 | ||
| 24 | rabbit 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, | ||
| 25 | I have worked with libraries like this in the past and also wrote a couple of | ||
| 26 | them (nothing compared to that level), but I had the basic understanding of what | ||
| 27 | was going on. I rolled up a project quickly and had basic things done in a | ||
| 28 | matter of two hours, which was impressive.<p>I prefer using <a href=https://tailwindcss.com/>Tailwind CSS</a> for my styling | ||
| 29 | pleasures, and integrating that was also a painless experience. It was actually | ||
| 30 | nice to see that some things got better with time. In about 2 minutes I got | ||
| 31 | Tailwind 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 | ||
| 34 | past People will probably call me a lunatic for saying this. But you know, it is | ||
| 35 | the truth. Same same, but different. I still believe that using libraries like | ||
| 36 | this is beneficial. I am not a JavaScript purist. They all have their quirks, | ||
| 37 | but 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 | ||
| 39 | call 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 | ||
| 40 | was an absolute horrific experience. Saying this, it is an absolutely fantastic | ||
| 41 | tool. I felt more like a config editor than actually a programmer. To be fair, | ||
| 42 | I am a huge fan of <a href=https://www.gnu.org/software/make/>make</a>, and you can do as | ||
| 43 | you 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 | ||
| 45 | only one client side scripting available, which is by no accident also | ||
| 46 | JavaScript. 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 | ||
| 47 | some other bundler thingy. Which does not make things better, but at least I | ||
| 48 | didn’t need to worry about it.<p>I really don’t like complicated build systems. I really don’t like abstracting | ||
| 49 | code and making things appear magical. The older I get, the more I appreciate | ||
| 50 | clear 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 | ||
| 51 | best developer experiences I have ever had. Granted, it still has magical | ||
| 52 | properties. And yes, it still is a bundler and abstracts things to the nth | ||
| 53 | degree. But at least it didn’t force me to configure 700 lines of JSON. And I | ||
| 54 | know that this makes me a hypocrite. You can’t have it all. Nonetheless, my | ||
| 55 | reasoning here is, if using bundlers is inevitable, then at least they should | ||
| 56 | provide an excellent developer experience.<p>I also noticed that now the catch-all phrase is “blazingly fast” and “lightning | ||
| 57 | fast” and “next generation” and stuff like that. I mean, yeah, tools should get | ||
| 58 | faster with time. But saying that starting a project now takes 2 seconds instead | ||
| 59 | of 20 seconds is something that is a break it or make it kind of a deal is | ||
| 60 | ridiculous. I don’t mind waiting a couple of seconds every couple of days. I | ||
| 61 | also don’t create 700 projects every day, and also who does? This argument has | ||
| 62 | no bite. All I want is a decent reload time (~100ms is more than good enough for | ||
| 63 | me) and that is it.<p>You don’t need to sell me benefits if I only get them when I start a fresh | ||
| 64 | project, and then try to convince me that this is somehow changing the fate of | ||
| 65 | the universe. First of all, it is not. And second, if this is your only argument | ||
| 66 | for your tool, I would advise you to maybe re-focus your efforts to something | ||
| 67 | else. Vite says that startup times are really fast. And if that would be the | ||
| 68 | only thing differentiating it from other tools, I would ignore it. But it has | ||
| 69 | some really compelling features like <a href=https://www.geeksforgeeks.org/reactjs-hot-module-replacement/>Hot Module | ||
| 70 | Replacement</a> that | ||
| 71 | really 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 | ||
| 72 | talking 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 | ||
| 73 | it makes you have a massive <strong>FOMO</strong> all the time. But on the other hand, you | ||
| 74 | also don’t want to be that old fart that doesn’t move with the times and still | ||
| 75 | writes his trusty jQuery code while listening to Blink 182 All the small things | ||
| 76 | on full blast. It’s a good song, don’t get me wrong, but there are other songs | ||
| 77 | out there.<p>I have to admit. <a href=https://vercel.com/>Vercel</a> is really cool! Love the | ||
| 78 | simplicity of the service. You could compare it to | ||
| 79 | <a href=https://www.netlify.com/>Netlify</a>. I haven’t tried Netlify extensively, but | ||
| 80 | from a couple of experimental deployments I still prefer Vercel. It is much more | ||
| 81 | streamlined, but maybe this is bias in me. I really like Vercel’s Analytics, | ||
| 82 | which give you a <a href=https://web.dev/vitals/>Core Web Vitals report</a> in their | ||
| 83 | admin 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 | ||
| 84 | rendering)</a> looks so good | ||
| 85 | on 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. | ||
| 86 | I’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 | ||
| 88 | thing, just a different library.<p>Now comes the reality. Mixing backend and frontend in this manner creates this | ||
| 89 | weird mental model where you kind of rely on magical properties of these | ||
| 90 | libraries. You relinquish control over to them for better developer experience. | ||
| 91 | But is that really true? Initially, I was so stoked about it. However, the more | ||
| 92 | I used them, the more I felt uncomfortable. I felt dirty, actually. Maybe this | ||
| 93 | is because I come from old ways of doing things where you control every step of | ||
| 94 | request, and allowing something to hijack it feels like blasphemy.<p>More than that, some pretty significant technical issues arose from this. How do | ||
| 95 | you do JWT token authentication? You put it in <code>api</code> folder and then do some | ||
| 96 | fetching and storing into local state management. But doing this also requires | ||
| 97 | some tinkering with await/async stuff on the React/Vue side of things. And then | ||
| 98 | you need to write middleware for it. And the more I look at it, the more I see | ||
| 99 | that this whole thing was not meant to be used like this, and it all feels and | ||
| 100 | looks like a huge hack.<p>The issue I have with this is that they over-promise and under-deliver. They | ||
| 101 | want to be an all-in-one replacement for everything, and they don’t deliver on | ||
| 102 | this 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 | ||
| 103 | when you need to accomplish something a little bit more out of the scope of | ||
| 104 | Hello World, you have to make hacky decisions to make it work. And having a | ||
| 105 | deployment strategy that relies on many moving parts is never a good idea. | ||
| 106 | Abstracting 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. | ||
| 107 | And 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 | ||
| 109 | their billing, and you end up paying more than you really should. And even if | ||
| 110 | that is not an issue, it comes down to the principle of things. AWS is known for | ||
| 111 | having multiple “currencies“ inside their projects like write operations, read | ||
| 112 | operations, etc. which add up, and it creates this impossible to track billing | ||
| 113 | scheme. It all behaves suspiciously like a pay-to-win game you could find on | ||
| 114 | mobile 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 | ||
| 115 | functionalities for the game I want to make. I was battling libraries and cloud | ||
| 116 | providers. How to deploy, what settings are relevant. Bad documentation or | ||
| 117 | multiple versions of achieving the same thing. You are getting bombarded by all | ||
| 118 | this information, and you don’t really have any control over it. | ||
| 119 | Production-ready code becomes a joke, essentially. Especially if you tend to | ||
| 120 | work 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 | ||
| 121 | choose. Unnecessary worrying about if the stack will still be deemed worthy in | ||
| 122 | six months. There is elegance in simplicity.<blockquote><p>JavaScript UI frameworks and libraries work in cycles. Every six months or | ||
| 123 | so, a new one pops up, claiming that it has revolutionized UI development. | ||
| 124 | Thousands of developers adopt it into their new projects, blog posts are | ||
| 125 | written, 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. | ||
| 128 | It is a real concern that I have about them. In my life, I have seen | ||
| 129 | technologies come and go, but the basics always stick around. So surrendering | ||
| 130 | all the power you have to a library or a cloud provider is in my opinion a | ||
| 131 | stupid 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 | ||
| 132 | deliberation, I came to the conclusion that Tailwind is good for two types of | ||
| 133 | developers. Tailwind is good for a complete noob or a senior developer. A | ||
| 134 | complete noob doesn’t really care about inner workings of CSS, and a senior | ||
| 135 | developer also doesn’t care about CSS. Well, at least, not anymore. And | ||
| 136 | developers in between usually have the biggest issues with it. Not always of | ||
| 137 | course, but in a lot of cases.<p>I like the creature comforts of Tailwind. Being utility first would make me | ||
| 138 | argue 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 | ||
| 140 | ideologically. After I started using it, I never looked back. I use it every | ||
| 141 | time I need to do something web related.<p>Writing CSS for general things feels like going several steps back. Instead of | ||
| 142 | focusing 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 | ||
| 144 | size. Just doing things that make 0.1% difference. You know that saying: Early | ||
| 145 | optimization is the root of all evil. Exactly that.<p>I am also not saying that Tailwind is the cure for everything. Sometimes custom | ||
| 146 | CSS is necessary. But from what I found out in using it for almost two years in | ||
| 147 | a production environment (on a site getting quite a lot of traffic and | ||
| 148 | constantly being changed), I can say without any reservations that Tailwind | ||
| 149 | saved our asses countless times. We would be rewriting CSS all the time without | ||
| 150 | it. 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 | ||
| 151 | used it in a real project that has a long lifetime with plenty of changes that | ||
| 152 | will 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 | ||
| 153 | catch the latest and greatest train, you are by that logic always trying new | ||
| 154 | things. Which is a good thing if you want to learn about technologies and try | ||
| 155 | them. But for the production environment, you have to have a stable stack that | ||
| 156 | doesn’t change every 6 months.<p>You can lock dependencies for sure. Nevertheless, the hype train moves along | ||
| 157 | anyway. And the mindset this breeds goes against locking the code. This | ||
| 158 | bleeding-edge rolling release cycle is not helping. That is why enterprise | ||
| 159 | solutions usually look down on these popular stacks and only do bare minimum to | ||
| 160 | appear hip and cool.<p>With that said, I still think that progress is good, but should be taken with a | ||
| 161 | grain of salt. If your project is something that should be built once and then | ||
| 162 | rarely updated, going with the latest stack is a possible way to go. But, if you | ||
| 163 | are working on a project that lasts for years, you should probably approach it | ||
| 164 | with 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. | ||
| 165 | Everything is blazingly fast now. I get it, they are competing for your | ||
| 166 | attention, 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 | ||
| 167 | materials. These open-source projects are now behaving more and more like | ||
| 168 | companies 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, | ||
| 169 | which is a good thing, don't get me wrong. But when it is using open-source to | ||
| 170 | lure people and then lock them in their ecosystem, there is where I have issues | ||
| 171 | with it.<p>This might be because I have been using GNU/Linux for 20 years now and have been | ||
| 172 | so beholden for my success to open-source that I see issues when open-source is | ||
| 173 | being used to trick people into a false sense of security that these projects | ||
| 174 | are built in the spirit of open-source. Because there is a difference. They are | ||
| 175 | NOT! They have a really specific goal in mind. And the open-source is being used | ||
| 176 | as 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 | ||
| 177 | are discovering <a href=https://www.tutorialspoint.com/remote-procedure-call-rpc>RPC</a> | ||
| 178 | now and this is the now the next big thing. <a href=https://graphql.org/>GraphQL</a> is | ||
| 179 | so passé. And I am so tired of it all. Of blazingly fast libraries, of all these | ||
| 180 | new technologies that are actually just a remake of old ones. Of just the | ||
| 181 | general spirit of the web. I will just use what I already know. Which worked 10 | ||
| 182 | years ago and will work 10 years after this. I will adopt a couple of little | ||
| 183 | tools 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 | ||
| 184 | changed that much. FOMO is now cured! Now I have to get my ass back to actually | ||
| 185 | code 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 | ||
| 186 | a lock on a Linux NFS server, which turned | ||
| 187 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 188 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 189 | owns 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 | ||
| 190 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 191 | list where the're doing | ||
| 192 | bad computer history and insisting that a guy Larry Rosen | ||
| 193 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 194 | somethin…<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: | ||
| 195 | i2c, plan9 | ||
| 196 | Another month, another file system. | ||
| 197 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 198 | you, bme680, we’re not | ||
| 199 | done yet). The show must go on, as they say, and I would like my | ||
| 200 | experiments to go on. | ||
| 201 | So a “new” addition to the environmental sensor family connected to | ||
| 202 | the 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 | ||
| 203 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 204 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 205 | unique 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. | ||
| 206 | My 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 | ||
| 207 | 1.0 has been released: | ||
| 208 | wifi_da-1.0.sit | ||
| 209 | (StuffIt 3 archive) | ||
| 210 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 211 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 212 | classic 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. | ||
| 213 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 214 | Design Goals | ||
| 215 | I 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 | ||
| 216 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 217 | catch 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 | ||
| 218 | specified 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, | ||
| 10 | you 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 | ||
| 11 | a 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 | ||
| 12 | make a couple of songs similar to this. But this is the first time I am posting | ||
| 13 | about 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 | ||
| 15 | and 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 | ||
| 16 | while having loud clocks around their necks. Each clock ticks on a different | ||
| 17 | frequency. A lot of other sounds are getting drawn into your dimension, | ||
| 18 | resulting 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 | ||
| 19 | having a discussion about the weather while tearing each other apart. During all | ||
| 20 | this your ship is getting pulled into the event horizon of both black holes, | ||
| 21 | putting 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 | ||
| 22 | plants some of them are highly intelligent, and you were asked to make first | ||
| 23 | contact with the native species. Your visit takes place in a giant cave where | ||
| 24 | you 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 | ||
| 25 | your first one, which happens to be a brain implant. Something goes wrong, and | ||
| 26 | your implant is starting to misbehave, and you are experiencing brain | ||
| 27 | malfunctions. You are on the streets at night a couple of hours after your | ||
| 28 | procedure. 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 | ||
| 29 | more 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 | ||
| 30 | a lock on a Linux NFS server, which turned | ||
| 31 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 32 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 33 | owns 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 | ||
| 34 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 35 | list where the're doing | ||
| 36 | bad computer history and insisting that a guy Larry Rosen | ||
| 37 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 38 | somethin…<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: | ||
| 39 | i2c, plan9 | ||
| 40 | Another month, another file system. | ||
| 41 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 42 | you, bme680, we’re not | ||
| 43 | done yet). The show must go on, as they say, and I would like my | ||
| 44 | experiments to go on. | ||
| 45 | So a “new” addition to the environmental sensor family connected to | ||
| 46 | the 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 | ||
| 47 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 48 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 49 | unique 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. | ||
| 50 | My 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 | ||
| 51 | 1.0 has been released: | ||
| 52 | wifi_da-1.0.sit | ||
| 53 | (StuffIt 3 archive) | ||
| 54 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 55 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 56 | classic 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. | ||
| 57 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 58 | Design Goals | ||
| 59 | I 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 | ||
| 60 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 61 | catch 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 | ||
| 62 | specified 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&#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 | ||
| 10 | single problem with it. Hell, never even known there could be a problem. Just | ||
| 11 | worked. All this time. The first node that I deployed is still being used in | ||
| 12 | production, never updated, upgraded, touched in anyway.<p>All this bliss came to an abrupt end this Friday when I got notification that | ||
| 13 | Elasticsearch cluster went warm. Well, warm is not that bad right? Wrong! | ||
| 14 | Quickly after that I got another email which sent chills down my spine. Cluster | ||
| 15 | is now red. RED! Now, shit really hit the fan!<p>I tried googling what could be the problem and after executing allocation | ||
| 16 | function noticed that some shards were unassigned and 5 attempts were already | ||
| 17 | made (which is BTW to my luck the maximum) and that meant I am basically fucked. | ||
| 18 | They also applied that one should wait for cluster to re-balance itself. So, I | ||
| 19 | waited. One hour, two hours, several hours. Nothing, still RED.<p>The strangest thing about it all was, that queries were still being fulfilled. | ||
| 20 | Data was coming out. On the outside it looked like nothing was wrong but | ||
| 21 | everybody that would look at the cluster would know immediately that something | ||
| 22 | was 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 | ||
| 23 | forums or if you know an expert please consult him. There could be million of | ||
| 24 | reasons and these solution fit my problem. Maybe in your case it would | ||
| 25 | disastrous. I had all the data backed up and even if I would fail spectacularly | ||
| 26 | I would be able to restore the data. It would be a huge pain and I would loose | ||
| 27 | couple 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 | ||
| 29 | splendid! I must also say that our cluster is capable more than enough to handle | ||
| 30 | the traffic. Also JVM memory pressure never was an issue. So what happened | ||
| 31 | really then?<p>I tried also re-routing failed ones with no success due to AWS restrictions on | ||
| 32 | having 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> "Message": <span style=color:#a31515>"Your request: '/_cluster/reroute' is not allowed."</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 | ||
| 37 | because hours/days went by until I was finally able to re-index the problematic | ||
| 38 | index and hoped for the best. Until that moment even re-indexing was giving me | ||
| 39 | errors.<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> "source": { | ||
| 42 | </span></span><span style=display:flex><span> "index": <span style=color:#a31515>"myindex"</span> | ||
| 43 | </span></span><span style=display:flex><span> }, | ||
| 44 | </span></span><span style=display:flex><span> "dest": { | ||
| 45 | </span></span><span style=display:flex><span> "index": <span style=color:#a31515>"myindex-new"</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 | ||
| 49 | dropped 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> "source": { | ||
| 53 | </span></span><span style=display:flex><span> "index": <span style=color:#a31515>"myindex-new"</span> | ||
| 54 | </span></span><span style=display:flex><span> }, | ||
| 55 | </span></span><span style=display:flex><span> "dest": { | ||
| 56 | </span></span><span style=display:flex><span> "index": <span style=color:#a31515>"myindex"</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 | ||
| 60 | me to get all the things working again. Cluster now shows that it is in Green | ||
| 61 | mode but I am also getting a notification that the cluster has processing status | ||
| 62 | which 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 | ||
| 63 | a lock on a Linux NFS server, which turned | ||
| 64 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 65 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 66 | owns 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 | ||
| 67 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 68 | list where the're doing | ||
| 69 | bad computer history and insisting that a guy Larry Rosen | ||
| 70 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 71 | somethin…<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: | ||
| 72 | i2c, plan9 | ||
| 73 | Another month, another file system. | ||
| 74 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 75 | you, bme680, we’re not | ||
| 76 | done yet). The show must go on, as they say, and I would like my | ||
| 77 | experiments to go on. | ||
| 78 | So a “new” addition to the environmental sensor family connected to | ||
| 79 | the 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 | ||
| 80 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 81 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 82 | unique 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. | ||
| 83 | My 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 | ||
| 84 | 1.0 has been released: | ||
| 85 | wifi_da-1.0.sit | ||
| 86 | (StuffIt 3 archive) | ||
| 87 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 88 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 89 | classic 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. | ||
| 90 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 91 | Design Goals | ||
| 92 | I 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 | ||
| 93 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 94 | catch 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 | ||
| 95 | specified 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 &#39;C-b&#39; to &#39;M-a&#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'. | ||
| 10 | unbind C-b | ||
| 11 | set-option -g prefix M-a | ||
| 12 | bind-key M-a send-prefix | ||
| 13 | |||
| 14 | # Split panes using | and -. | ||
| 15 | bind | split-window -h | ||
| 16 | bind - split-window -v | ||
| 17 | unbind '"' | ||
| 18 | unbind % | ||
| 19 | |||
| 20 | # Start counting windows with 1. | ||
| 21 | set-option -g allow-rename on | ||
| 22 | set -g base-index 1 | ||
| 23 | setw -g pane-base-index 1 | ||
| 24 | |||
| 25 | # Statusbar: purple bg and white fg. | ||
| 26 | set -g status-bg '#480b8e' | ||
| 27 | set -g status-fg '#ffffff' | ||
| 28 | |||
| 29 | # Active window: black bg and white fg. | ||
| 30 | set -g window-status-current-format "#[fg=#ffffff]#[bg=#111111]#[fg=#ffffff]#[bg=#111111] #I:#W #[fg=#ffffff]#[bg=#111111]" | ||
| 31 | |||
| 32 | # Disable mouse mode (tmux 2.1 and above). | ||
| 33 | set -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 | ||
| 35 | a lock on a Linux NFS server, which turned | ||
| 36 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 37 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 38 | owns 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 | ||
| 39 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 40 | list where the're doing | ||
| 41 | bad computer history and insisting that a guy Larry Rosen | ||
| 42 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 43 | somethin…<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: | ||
| 44 | i2c, plan9 | ||
| 45 | Another month, another file system. | ||
| 46 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 47 | you, bme680, we’re not | ||
| 48 | done yet). The show must go on, as they say, and I would like my | ||
| 49 | experiments to go on. | ||
| 50 | So a “new” addition to the environmental sensor family connected to | ||
| 51 | the 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 | ||
| 52 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 53 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 54 | unique 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. | ||
| 55 | My 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 | ||
| 56 | 1.0 has been released: | ||
| 57 | wifi_da-1.0.sit | ||
| 58 | (StuffIt 3 archive) | ||
| 59 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 60 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 61 | classic 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. | ||
| 62 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 63 | Design Goals | ||
| 64 | I 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 | ||
| 65 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 66 | catch 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 | ||
| 67 | specified 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, | ||
| 10 | how we interact with computers, the separation of text-based programs and GUI | ||
| 11 | ones. To be perfectly honest, I got pissed off one evening when I was cleaning | ||
| 12 | up files on my computer. Normally, I go into console and do <code>ncdu</code> and check | ||
| 13 | where the junk is. Then I start deleting stuff. Without any discrimination, | ||
| 14 | usually. But when it comes to screenshots, I have learned that it's good to keep | ||
| 15 | them somewhere near if I need to refer to something that I was doing. I am an | ||
| 16 | avid screenshot taker. So at that point I checked Pictures folder and also did a | ||
| 17 | basic search <code>find . -type f -name "*.jpg"</code> for all the JPEG files in my home | ||
| 18 | directory and immediately got pissed off. Why can’t I see thumbnails in my | ||
| 19 | terminal? I know why, but why in the year of 2022 this is still a problem. I am | ||
| 20 | used to traversing my disk via terminal. I am faster, and I am more comfortable | ||
| 21 | this way. But when it comes to visualization, I then need to revert to GUI | ||
| 22 | applications 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 | ||
| 25 | inline. 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 | ||
| 26 | 9</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> | ||
| 28 | handles text editing is just wonderful. Different and fresh somehow, even though | ||
| 29 | it’s super old.<p>So, I went on a lookout for an interesting way of visualizing results of some | ||
| 30 | query. I found these applications to be outstanding examples of how not to be a | ||
| 31 | captive 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 | ||
| 32 | emulators. I like the modes that Vi/Vim provides you with. I like the way the | ||
| 33 | Emacs does its own <code>M-x</code> <code>M-c</code>. Furthermore, I really like how Mathematica and | ||
| 34 | Jupyter present the data in a free flowing form. And I love how Temple OS is | ||
| 35 | basically a C interpreter on some level.<blockquote><p><strong>Note:</strong> This is part 1 of the journey. Nowhere finished yet. I am just | ||
| 36 | tinkering with this at the moment. This whole thing can easily spectacularly | ||
| 37 | fail.</blockquote><p>So I started. I knew that I wanted to have the couple of modes, but I didn’t | ||
| 38 | like the repetition of keystrokes, so the only option was to have some sort of | ||
| 39 | toggle and indicate to the user that they are in a special mode. Like Vi does | ||
| 40 | for 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 | ||
| 41 | from the results and display thumbnails from them in the terminal itself. | ||
| 42 | No 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 | ||
| 43 | and execute that command in it. This would be useful for starting <code>htop</code> | ||
| 44 | in a separate window.</ul></ul><p>The reason for having these modes togglable is to not ask for previews every | ||
| 45 | time. You enable a mode and until you disable it, it behaves that way. Purely | ||
| 46 | out of ergonomic reasons.<p>I would like to treat every terminal I open as a session mentally. When I start | ||
| 47 | using the terminal, I start digging deeper into the issue I am trying to | ||
| 48 | resolve. And while I am doing this, I would like to open detached windows | ||
| 49 | etc. 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 | ||
| 51 | were 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 | ||
| 52 | and a library such as <a href=https://www.libsdl.org/>SDL2</a> in order to achieve the | ||
| 53 | desired 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 | ||
| 55 | reputation in the programming community.<p>At first, I thought the idea of a hardware accelerated terminal was a bit of a | ||
| 56 | joke. It seemed like such a niche and unnecessary feature, especially given the | ||
| 57 | fact that terminal emulators have been around for decades and have always relied | ||
| 58 | on software rendering. But to be fair, <a href=https://alacritty.org/>Alacritty</a> is | ||
| 59 | doing 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 | ||
| 60 | started 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> | ||
| 68 | rendered text really poorly. There were no antialiasing at all. In my wisdom, I | ||
| 69 | never 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 | ||
| 71 | surface. 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, | ||
| 72 | palettized surface. The surface's 0 pixel will be the colorkey, giving a | ||
| 73 | transparent 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 | ||
| 75 | renders Latin1 text at LCD subpixel quality to a new ARGB surface, the text | ||
| 76 | started looking good. Really make sure you read the documentation. It’s actually | ||
| 77 | good. As a side note, you can find all the documentation regarding <a href=https://wiki.libsdl.org/>SDL2 on | ||
| 78 | their Wiki</a>.<p>After that was done, I started working on displaying other things like <code>Preview</code> | ||
| 79 | and <code>Detach</code> modes. This wasn’t really that hard. In SDL2 you can check all the | ||
| 80 | available events with <code>while (SDL_PollEvent(&event) > 0)</code> and have a bunch of | ||
| 81 | switch statements to determine which key is currently being pressed. More about | ||
| 82 | keys, <a href=https://documentation.help/SDL/sdlkey.html>SDLKey</a> and mroe about | ||
| 83 | pooling 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(&event) > 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 | ||
| 102 | would hold all the commands and results and I call them Cells. Yes, I stole that | ||
| 103 | naming 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 | ||
| 112 | sure 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 | ||
| 113 | configuration</a> support. It is done in an | ||
| 114 | <a href=https://github.com/nothings/stb/blob/master/docs/stb_howto.txt>STB style of | ||
| 115 | header</a> and maps | ||
| 116 | to specific options supported by the terminal. It is not universal, and the code | ||
| 117 | below 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>"r"</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>'#'</span> || line[0] == <span style=color:#a31515>'\n'</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>"%[^=]=%s"</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>"dettach"</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>"preview"</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>"debug"</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 | ||
| 187 | prohibits me to work on these things full time. But I should probably get back | ||
| 188 | and finish this. At least have a simple version working out, so I can start | ||
| 189 | testing 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 | ||
| 190 | a lock on a Linux NFS server, which turned | ||
| 191 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 192 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 193 | owns 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 | ||
| 194 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 195 | list where the're doing | ||
| 196 | bad computer history and insisting that a guy Larry Rosen | ||
| 197 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 198 | somethin…<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: | ||
| 199 | i2c, plan9 | ||
| 200 | Another month, another file system. | ||
| 201 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 202 | you, bme680, we’re not | ||
| 203 | done yet). The show must go on, as they say, and I would like my | ||
| 204 | experiments to go on. | ||
| 205 | So a “new” addition to the environmental sensor family connected to | ||
| 206 | the 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 | ||
| 207 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 208 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 209 | unique 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. | ||
| 210 | My 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 | ||
| 211 | 1.0 has been released: | ||
| 212 | wifi_da-1.0.sit | ||
| 213 | (StuffIt 3 archive) | ||
| 214 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 215 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 216 | classic 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. | ||
| 217 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 218 | Design Goals | ||
| 219 | I 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 | ||
| 220 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 221 | catch 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 | ||
| 222 | specified 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 | ||
| 10 | the main reasons was that I wanted something that doesn't burn through CPU and | ||
| 11 | RAM usage is not through the roof. I have been mostly using Visual Studio Code. | ||
| 12 | It's been an outstanding editor. I have no quarrel with it at all. It's just | ||
| 13 | time to spice life up with something new.<p>I have been on this search for a couple of years. I have tried Vim, Neovim, | ||
| 14 | Emacs, Doom Emacs, Micro and couple more. Among most of them, I liked Micro and | ||
| 15 | Doom Emacs the most. Micro editor was a little too basic for me. And Doom Emacs | ||
| 16 | was a bit too hardcore. This does not reflect on any of the editors. It's just | ||
| 17 | my personal preference.<blockquote><p>I tried Helix Editor about a year ago. But I didn't pay attention to it. | ||
| 18 | Tried it and saw it's similar to Vi and just said no. I was premature to | ||
| 19 | dismiss it.</blockquote><p>One of the things I actually miss is line wrapping for certain files. When | ||
| 20 | writing Markdown, line wrapping would be very helpful. Editing such a document | ||
| 21 | is frustrating to say the least. Some of the Markdown to HTML converters don't | ||
| 22 | take kindly of new lines between sentences. Not paragraphs, sentences. And I use | ||
| 23 | Markdown to write this blog you are reading.<p>But other than this, I have been extremely satisfied by it. It's been a pleasant | ||
| 24 | surprise. There have been zero issues with the editor.<p>One thing to do before you are able to use autocompletion and make use Language | ||
| 25 | Server 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 | ||
| 27 | does really well is packing in sane defaults and even though because currently | ||
| 28 | there is no plugin support I haven't found any need for them. It has all that | ||
| 29 | you would need. It goes to extreme measures to show a user what is going on with | ||
| 30 | popups 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 | ||
| 32 | mimics 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 | ||
| 33 | a lock on a Linux NFS server, which turned | ||
| 34 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 35 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 36 | owns 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 | ||
| 37 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 38 | list where the're doing | ||
| 39 | bad computer history and insisting that a guy Larry Rosen | ||
| 40 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 41 | somethin…<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: | ||
| 42 | i2c, plan9 | ||
| 43 | Another month, another file system. | ||
| 44 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 45 | you, bme680, we’re not | ||
| 46 | done yet). The show must go on, as they say, and I would like my | ||
| 47 | experiments to go on. | ||
| 48 | So a “new” addition to the environmental sensor family connected to | ||
| 49 | the 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 | ||
| 50 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 51 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 52 | unique 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. | ||
| 53 | My 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 | ||
| 54 | 1.0 has been released: | ||
| 55 | wifi_da-1.0.sit | ||
| 56 | (StuffIt 3 archive) | ||
| 57 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 58 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 59 | classic 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. | ||
| 60 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 61 | Design Goals | ||
| 62 | I 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 | ||
| 63 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 64 | catch 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 | ||
| 65 | specified 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&#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 | ||
| 10 | product called | ||
| 11 | <a href=https://blog.digitalocean.com/introducing-spaces-object-storage/>Spaces</a> which | ||
| 12 | is Object Storage very similar to Amazon's S3. This really peaked my interest, | ||
| 13 | because this was something I was missing and even the thought of going over the | ||
| 14 | internet for such functionality was in no interest to me. Also in fashion with | ||
| 15 | their previous pricing this also is very cheap and pricing page is a no-brainer | ||
| 16 | compared to AWS or GCE. <a href=https://www.digitalocean.com/pricing/>Prices are clearly and precisely defined and | ||
| 17 | outlined</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&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 | ||
| 21 | intended to be used in real-life situations. Besides that, I am looking into | ||
| 22 | using this approaches but adding caching service in front of it and then | ||
| 23 | dumping everything as an object to storage. This could potentially be some | ||
| 24 | interesting post of itself. But in case you would need real-time data without | ||
| 25 | eventual consistency please take this scripts as they are: not usable in such | ||
| 26 | situations.</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 | ||
| 27 | S3</a> many tools are available and you can find many | ||
| 28 | articles 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 | ||
| 29 | will 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&region=ams3&distro=debian&distroImage=debian-9-x64&options=private_networking,install_agent">create new | ||
| 31 | Droplet</a>. | ||
| 32 | If you click on this link you will already have preselected Debian 9 with | ||
| 33 | smallest VM option.<ul><li>Please be sure to add you SSH key, because we will login to this machine | ||
| 34 | remotely.<li>If you change your region please remember which one you choose because we will | ||
| 35 | need 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 | ||
| 36 | article <a href=https://www.digitalocean.com/community/tutorials/how-to-use-ssh-keys-with-digitalocean-droplets>How To Use SSH Keys with DigitalOcean | ||
| 37 | Droplets</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 | ||
| 38 | on a button <a href=https://cloud.digitalocean.com/spaces/new>Create</a> (right top | ||
| 39 | corner) and selecting Spaces. Choose pronounceable <code>Unique name</code> because we | ||
| 40 | will use it in examples below. You can either choose Private or Public, it | ||
| 41 | doesn'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 | ||
| 42 | key</a>. This link will guide | ||
| 43 | to the page when you can generate this key. After you create new one, please | ||
| 44 | save 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>"KEY:SECRET"</span> > .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>"Hello cruel world"</span> > /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 | ||
| 65 | Spaces</a> and click on your created | ||
| 66 | space. If file hello.txt is present you have successfully mounted space to your | ||
| 67 | machine and wrote data to it.<p>I choose the same region for my Droplet and my Space but you don't have to. You | ||
| 68 | can 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 | ||
| 69 | images. I actually wanted to figure out if using something like SQlite is viable | ||
| 70 | in 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/) |& 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++ < 100 )); <span style=color:#00f>do</span> (time cp 10KB.dat /mnt/10KB.$n.dat) |& 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++ < 100 )); <span style=color:#00f>do</span> (time cp 100KB.dat /mnt/100KB.$n.dat) |& 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++ < 100 )); <span style=color:#00f>do</span> (time cp 1MB.dat /mnt/1MB.$n.dat) |& 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++ < 100 )); <span style=color:#00f>do</span> (time cp 10MB.dat /mnt/10MB.$n.dat) |& 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 | ||
| 90 | error (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 | ||
| 91 | time to test performance over periods of time. But if some of you would do it | ||
| 92 | please 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>. | ||
| 93 | Measurements 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 | ||
| 121 | which is fantastic. But this is a small test and spans only over couple of | ||
| 122 | hours. 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 | ||
| 123 | as I suspected. So I executed code below on a local disk just to get some | ||
| 124 | benchmarks. I inserted 1000 records with DROPTABLE, CREATETABLE, INSERTMANY, | ||
| 125 | FETCHALL, COMMIT for 1000 times to generate statistics. As you can see | ||
| 126 | performance of SQLite is quite amazing. You could then potentially just copy | ||
| 127 | file 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) < 3: | ||
| 132 | </span></span><span style=display:flex><span> print(<span style=color:#a31515>"usage: python sqlite-benchmark.py DB_PATH NUM_RECORDS REPEAT"</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>"m"</span> + str(i), <span style=color:#a31515>"f"</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>"</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>"</span> % (<span style=color:#a31515>"DROPTABLE"</span>, <span style=color:#a31515>"CREATETABLE"</span>, <span style=color:#a31515>"INSERTMANY"</span>, <span style=color:#a31515>"FETCHALL"</span>, <span style=color:#a31515>"COMMIT"</span>) | ||
| 140 | </span></span><span style=display:flex><span><span style=color:#00f>with</span> open(<span style=color:#a31515>"sqlite-benchmarks.tsv"</span>, <span style=color:#a31515>"w"</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>"CONNECT: </span><span style=color:#a31515>%g</span><span style=color:#a31515> seconds"</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>"PRAGMA journal_mode=WAL"</span>) | ||
| 152 | </span></span><span style=display:flex><span>c.execute(<span style=color:#a31515>"PRAGMA temp_store=MEMORY"</span>) | ||
| 153 | </span></span><span style=display:flex><span>c.execute(<span style=color:#a31515>"PRAGMA synchronous=OFF"</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>"PRAGMA: </span><span style=color:#a31515>%g</span><span style=color:#a31515> seconds"</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>"#</span><span style=color:#a31515>%i</span><span style=color:#a31515>"</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>"drop table if exists test"</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>"DROPTABLE: </span><span style=color:#a31515>%g</span><span style=color:#a31515> seconds"</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>"create table if not exists test(a,b)"</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>"CREATETABLE: </span><span style=color:#a31515>%g</span><span style=color:#a31515> seconds"</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>"INSERT INTO test VALUES (?, ?)"</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>"INSERTMANY: </span><span style=color:#a31515>%g</span><span style=color:#a31515> seconds"</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>"select count(*) from test"</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>"FETCHALL: </span><span style=color:#a31515>%g</span><span style=color:#a31515> seconds"</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>"COMMIT: </span><span style=color:#a31515>%g</span><span style=color:#a31515> seconds"</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>"</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>"</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>"sqlite-benchmarks.tsv"</span>, <span style=color:#a31515>"a"</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>"CLOSE: </span><span style=color:#a31515>%g</span><span style=color:#a31515> seconds"</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 | ||
| 202 | again, these results are done on a local block storage and do not represent | ||
| 203 | capabilities of object storage. With my current approach and state of the test | ||
| 204 | code these can not be done. I would need to make Python code much more robust | ||
| 205 | and 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 | ||
| 233 | space on both machines and measured same performance on both machines. But | ||
| 234 | because file is downloaded before write and then uploaded on complete there | ||
| 235 | could potentially be problems is another process is trying to access the same | ||
| 236 | file.<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 | ||
| 237 | that you would need to write additional code to make this one play nice with you | ||
| 238 | applications.<p>Nevertheless, this was extremely simple to setup and use and this is just | ||
| 239 | another excellent product in DigitalOcean product line. I found this exercise | ||
| 240 | very valuable and am thinking about implementing some sort of mechanism for | ||
| 241 | SQLite, so data can be stored on Spaces and accessed by many VM's. For a project | ||
| 242 | where data doesn't need to be accessible in real-time and can have couple of | ||
| 243 | minutes old data this would be very interesting. If any of you find this | ||
| 244 | proposal interesting please write in a comment box below or shoot me an email | ||
| 245 | and 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 | ||
| 246 | a lock on a Linux NFS server, which turned | ||
| 247 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 248 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 249 | owns 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 | ||
| 250 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 251 | list where the're doing | ||
| 252 | bad computer history and insisting that a guy Larry Rosen | ||
| 253 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 254 | somethin…<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: | ||
| 255 | i2c, plan9 | ||
| 256 | Another month, another file system. | ||
| 257 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 258 | you, bme680, we’re not | ||
| 259 | done yet). The show must go on, as they say, and I would like my | ||
| 260 | experiments to go on. | ||
| 261 | So a “new” addition to the environmental sensor family connected to | ||
| 262 | the 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 | ||
| 263 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 264 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 265 | unique 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. | ||
| 266 | My 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 | ||
| 267 | 1.0 has been released: | ||
| 268 | wifi_da-1.0.sit | ||
| 269 | (StuffIt 3 archive) | ||
| 270 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 271 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 272 | classic 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. | ||
| 273 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 274 | Design Goals | ||
| 275 | I 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 | ||
| 276 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 277 | catch 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 | ||
| 278 | specified 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 | ||
| 10 | displaying a couple of charts. But to be honest, I actually never used Google | ||
| 11 | Analytics to the fullest extent and was usually interested in seeing page hits | ||
| 12 | and which pages were visited most often.<p>I recently moved my blog from Firebase to a VPS and also decided to remove | ||
| 13 | Google Analytics tracking code from the site since its quite malicious and | ||
| 14 | tracks users across other pages also and is creating a profile of a user, and | ||
| 15 | I've had it. But I also need some insight of what is happening on a server and | ||
| 16 | which 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 | ||
| 17 | with another one. Don't get me wrong. Some of these solutions are absolutely | ||
| 18 | fantastic but would require installation of databases and something like PHP or | ||
| 19 | Node. And I was not ready to put those things on my fresh server. Also having | ||
| 20 | Docker 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 | ||
| 21 | from this data.<p>I found this amazing software <a href=https://goaccess.io/>GoAccess</a> which provides | ||
| 22 | all 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 | ||
| 23 | go. The Idea is to periodically run cronjob and export this report into a folder | ||
| 24 | that 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 | ||
| 25 | installed <a href=https://nginx.org/en/>Nginx</a>, and | ||
| 26 | <a href=https://letsencrypt.org/getting-started/>Letsencrypt</a> certbot and all the | ||
| 27 | necessary 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's update the system</span> | ||
| 31 | </span></span><span style=display:flex><span>apt update && apt upgrade -y | ||
| 32 | </span></span><span style=display:flex><span> | ||
| 33 | </span></span><span style=display:flex><span><span style=color:green># let'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. | ||
| 36 | Stats 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 | ||
| 51 | is 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 | ||
| 52 | droplet.<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 | ||
| 53 | command <code>certbot --nginx</code>. Follow the wizard and when you are asked about | ||
| 54 | redirection 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 | ||
| 55 | not 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. | ||
| 56 | Otherwise 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* > /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 | ||
| 76 | a 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 | ||
| 77 | in script and instead of <code>0.0.0.0</code> add your own home IP address. You can find | ||
| 78 | your home IP by executing <code>curl ifconfig.me</code> from your local machine and NOT | ||
| 79 | from 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 | ||
| 81 | set.<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 | ||
| 83 | user 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 | ||
| 84 | file looks a bit different from before. This is because <code>certbot</code> added | ||
| 85 | additional 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>"Private</span> <span style=color:#a31515>Property"</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 | ||
| 92 | with <code>service nginx restart</code>.<p>If you now visit <code>https://stats.domain.com</code> you should be prompted for username | ||
| 93 | and password. If not, try reopening your browser.<p>That is all. You now have analytics for your server that gets refreshed every 10 | ||
| 94 | minutes.</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 | ||
| 95 | a lock on a Linux NFS server, which turned | ||
| 96 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 97 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 98 | owns 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 | ||
| 99 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 100 | list where the're doing | ||
| 101 | bad computer history and insisting that a guy Larry Rosen | ||
| 102 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 103 | somethin…<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: | ||
| 104 | i2c, plan9 | ||
| 105 | Another month, another file system. | ||
| 106 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 107 | you, bme680, we’re not | ||
| 108 | done yet). The show must go on, as they say, and I would like my | ||
| 109 | experiments to go on. | ||
| 110 | So a “new” addition to the environmental sensor family connected to | ||
| 111 | the 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 | ||
| 112 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 113 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 114 | unique 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. | ||
| 115 | My 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 | ||
| 116 | 1.0 has been released: | ||
| 117 | wifi_da-1.0.sit | ||
| 118 | (StuffIt 3 archive) | ||
| 119 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 120 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 121 | classic 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. | ||
| 122 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 123 | Design Goals | ||
| 124 | I 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 | ||
| 125 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 126 | catch 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 | ||
| 127 | specified 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 | ||
| 10 | established news sites use click bait titles to drive additional traffic to | ||
| 11 | their sites and generate additional impressions.<p>Goal is to see how article titles and actual content of article differ from each | ||
| 12 | other 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 | ||
| 13 | go with <a href=https://www.theguardian.com>The Guardian</a> World news. While this gets | ||
| 14 | us limited data (~40) articles and also description (actual content) is trimmed | ||
| 15 | this 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 | ||
| 16 | fetch contents directly from website, but for this simple example this will | ||
| 17 | suffice.<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>"https://www.theguardian.com/world/rss"</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>'<[^<]+?>'</span>, <span style=color:#a31515>''</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 | ||
| 27 | performing sentiment analysis.<p>There are many sentiment analysis libraries available that range from rule-based | ||
| 28 | sentiment analysis up to machine learning supported analysis. To keep things | ||
| 29 | simple 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 | ||
| 32 | use.<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>'compound'</span>], sentiment_description[<span style=color:#a31515>'compound'</span>]]) | ||
| 40 | </span></span></code></pre><p>Now that we have this data in a shape that is compatible with matplotlib we can | ||
| 41 | plot results to see the difference between title and description sentiment of an | ||
| 42 | article.<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>'figure.figsize'</span>] = (15, 3) | ||
| 45 | </span></span><span style=display:flex><span>plt.plot(sentiment_results, drawstyle=<span style=color:#a31515>'steps'</span>) | ||
| 46 | </span></span><span style=display:flex><span>plt.title(<span style=color:#a31515>'Sentiment analysis relationship between title and description (Guardian World News)'</span>) | ||
| 47 | </span></span><span style=display:flex><span>plt.legend([<span style=color:#a31515>'title'</span>, <span style=color:#a31515>'description'</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 | ||
| 50 | learning 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 | ||
| 51 | longer period of time and then perform analysis again and use either machine | ||
| 52 | learning 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 | ||
| 53 | specific 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 | ||
| 54 | a lock on a Linux NFS server, which turned | ||
| 55 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 56 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 57 | owns 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 | ||
| 58 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 59 | list where the're doing | ||
| 60 | bad computer history and insisting that a guy Larry Rosen | ||
| 61 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 62 | somethin…<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: | ||
| 63 | i2c, plan9 | ||
| 64 | Another month, another file system. | ||
| 65 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 66 | you, bme680, we’re not | ||
| 67 | done yet). The show must go on, as they say, and I would like my | ||
| 68 | experiments to go on. | ||
| 69 | So a “new” addition to the environmental sensor family connected to | ||
| 70 | the 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 | ||
| 71 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 72 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 73 | unique 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. | ||
| 74 | My 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 | ||
| 75 | 1.0 has been released: | ||
| 76 | wifi_da-1.0.sit | ||
| 77 | (StuffIt 3 archive) | ||
| 78 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 79 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 80 | classic 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. | ||
| 81 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 82 | Design Goals | ||
| 83 | I 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 | ||
| 84 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 85 | catch 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 | ||
| 86 | specified 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 | ||
| 10 | stores 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 | ||
| 11 | a lock on a Linux NFS server, which turned | ||
| 12 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 13 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 14 | owns 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 | ||
| 15 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 16 | list where the're doing | ||
| 17 | bad computer history and insisting that a guy Larry Rosen | ||
| 18 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 19 | somethin…<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: | ||
| 20 | i2c, plan9 | ||
| 21 | Another month, another file system. | ||
| 22 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 23 | you, bme680, we’re not | ||
| 24 | done yet). The show must go on, as they say, and I would like my | ||
| 25 | experiments to go on. | ||
| 26 | So a “new” addition to the environmental sensor family connected to | ||
| 27 | the 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 | ||
| 28 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 29 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 30 | unique 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. | ||
| 31 | My 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 | ||
| 32 | 1.0 has been released: | ||
| 33 | wifi_da-1.0.sit | ||
| 34 | (StuffIt 3 archive) | ||
| 35 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 36 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 37 | classic 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. | ||
| 38 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 39 | Design Goals | ||
| 40 | I 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 | ||
| 41 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 42 | catch 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 | ||
| 43 | specified 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 | ||
| 11 | smartphone</a> about the history of | ||
| 12 | smartphones and phones in general. It brought back so many memories. I never had | ||
| 13 | an actual smartphone before the Android. The closest to smartphone was <a href=https://www.gsmarena.com/sony_ericsson_p1-1982.php>Sony | ||
| 14 | Ericsson P1</a>. A fantastic | ||
| 15 | phone and I broke it in Prague after a party and that was one of those rare | ||
| 16 | occasions where I was actually mad at myself. But nevertheless, after that | ||
| 17 | phone, the next one was an Android one.<p>Before that, I only owned normal phones from Nokia and Siemens etc. Nothing | ||
| 18 | special, actually. These are the phones we are talking about. Before 2007. | ||
| 19 | Apple 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 | ||
| 20 | B's song 😃<p>WAP stands for Wireless Application Protocol. It is a protocol designed for | ||
| 21 | micro-browsers, and it enables the access of internet in the mobile devices. It | ||
| 22 | uses the mark-up language WML (Wireless Markup Language and not HTML), WML is | ||
| 23 | defined as XML 1.0 application. Furthermore, it enables creating web | ||
| 24 | applications for mobile devices. In 1998, WAP Forum was founded by Ericson, | ||
| 25 | Motorola, Nokia and Unwired Planet whose aim was to standardize the various | ||
| 26 | wireless 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 | ||
| 28 | Forum. In 2002, WAP forum was merged with various other forums of the industry, | ||
| 29 | resulting 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 | ||
| 31 | were abominable. But they were capable of rendering WML (Wireless Markup | ||
| 32 | Language). This was very similar to HTML, actually. It is a markup language, | ||
| 33 | after all.<p>These pages could be served by <a href=https://apache.org/>Apache</a> and could be | ||
| 34 | generated by CGI scripts on the backend. The only difference was the limited | ||
| 35 | markup 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 | ||
| 36 | browsers use WML - if you need to support really old mobile phones using WML | ||
| 37 | browsers, you will need to know about it. WML is XML-based (an XML vocabulary | ||
| 38 | just like XHTML and MathML, but not HTML) and does not use the same metaphor as | ||
| 39 | HTML. HTML is a single document with some metadata packed away in the head, and | ||
| 40 | a body encapsulating the visible page. With WML, the metaphor does not envisage | ||
| 41 | a page, but rather a deck of cards. A WML file might have several pages or cards | ||
| 42 | contained 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><?xml version="1.0"?></span> | ||
| 44 | </span></span><span style=display:flex><span><span style=color:#00f><!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml"></span> | ||
| 45 | </span></span><span style=display:flex><span><wml> | ||
| 46 | </span></span><span style=display:flex><span> <card id=<span style=color:#a31515>"home"</span> title=<span style=color:#a31515>"Example Homepage"</span>> | ||
| 47 | </span></span><span style=display:flex><span> <p>Welcome to the Example homepage</p> | ||
| 48 | </span></span><span style=display:flex><span> </card> | ||
| 49 | </span></span><span style=display:flex><span></wml> | ||
| 50 | </span></span></code></pre><p>There is an amazing tutorial on <a href=https://www.tutorialspoint.com/wml/index.htm>Tutorialpoint about | ||
| 51 | WML</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 | ||
| 52 | give it a try for old-time sake. Since the data is already there in a form of | ||
| 53 | RSS feed, I could take this feed and parse it and create a WML version of the | ||
| 54 | homepage.<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><?xml version="1.0"?></span> | ||
| 68 | </span></span><span style=display:flex><span><span style=color:#00f><!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.2//EN" "http://www.wapforum.org/DTD/wml_1.2.xml"></span> | ||
| 69 | </span></span><span style=display:flex><span> | ||
| 70 | </span></span><span style=display:flex><span><wml> | ||
| 71 | </span></span><span style=display:flex><span> | ||
| 72 | </span></span><span style=display:flex><span> <card title=<span style=color:#a31515>"Digg - What the Internet is talking about right now"</span>> | ||
| 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> <p><img src=<span style=color:#a31515>"/images/${item.id}.jpg"</span> width=<span style=color:#a31515>"175"</span> height=<span style=color:#a31515>"95"</span> alt=<span style=color:#a31515>"${item.title}"</span> /></p> | ||
| 76 | </span></span><span style=display:flex><span> <p><small>${item.kicker}</small></p> | ||
| 77 | </span></span><span style=display:flex><span> <p><big><b>${item.title}</b></big></p> | ||
| 78 | </span></span><span style=display:flex><span> <p>${item.description}</p> | ||
| 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> </card> | ||
| 82 | </span></span><span style=display:flex><span> | ||
| 83 | </span></span><span style=display:flex><span></wml> | ||
| 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>'mkdir -p www/images'</span>) | ||
| 89 | </span></span><span style=display:flex><span> | ||
| 90 | </span></span><span style=display:flex><span>template = Template(filename=<span style=color:#a31515>'template.wml'</span>) | ||
| 91 | </span></span><span style=display:flex><span> | ||
| 92 | </span></span><span style=display:flex><span>feed = feedparser.parse(<span style=color:#a31515>'https://digg.com/rss/top.xml'</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>'Processing image with id </span><span style=color:#a31515>{}</span><span style=color:#a31515>'</span>.format(entry.id)) | ||
| 98 | </span></span><span style=display:flex><span> os.system(<span style=color:#a31515>'wget -q -O www/images/</span><span style=color:#a31515>{}</span><span style=color:#a31515>.jpg "</span><span style=color:#a31515>{}</span><span style=color:#a31515>"'</span>.format(entry.id, entry.links[1].href)) | ||
| 99 | </span></span><span style=display:flex><span> os.system(<span style=color:#a31515>'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'</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>'www/index.wml'</span>, <span style=color:#a31515>'w+'</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 | ||
| 106 | storing resized images.<blockquote><p>Be sure you don't use SSL and use just normal HTTP for serving the content. | ||
| 107 | These 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&W images. | ||
| 108 | They should be WBMP (Wireless BitMaP) but I choose JPEGs for this, and it seems | ||
| 109 | to work properly.<p>Because I currently don't have a phone old enough to test it on, I used an | ||
| 110 | emulator. And it was really hard to find one. I found <a href=http://wap-proof.sharewarejunction.com/>WAP | ||
| 111 | Proof</a> on shareware junction, and it | ||
| 112 | did 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 | ||
| 113 | that 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. | ||
| 117 | I will try to find an old phone to test it on. If you have any questions, feel | ||
| 118 | free 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 | ||
| 119 | a lock on a Linux NFS server, which turned | ||
| 120 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 121 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 122 | owns 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 | ||
| 123 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 124 | list where the're doing | ||
| 125 | bad computer history and insisting that a guy Larry Rosen | ||
| 126 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 127 | somethin…<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: | ||
| 128 | i2c, plan9 | ||
| 129 | Another month, another file system. | ||
| 130 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 131 | you, bme680, we’re not | ||
| 132 | done yet). The show must go on, as they say, and I would like my | ||
| 133 | experiments to go on. | ||
| 134 | So a “new” addition to the environmental sensor family connected to | ||
| 135 | the 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 | ||
| 136 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 137 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 138 | unique 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. | ||
| 139 | My 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 | ||
| 140 | 1.0 has been released: | ||
| 141 | wifi_da-1.0.sit | ||
| 142 | (StuffIt 3 archive) | ||
| 143 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 144 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 145 | classic 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. | ||
| 146 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 147 | Design Goals | ||
| 148 | I 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 | ||
| 149 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 150 | catch 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 | ||
| 151 | specified 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 | ||
| 10 | contextually matches ads and displays them in different template forms on | ||
| 11 | variety of websites. This project grew from serving thousands of ads per day to | ||
| 12 | millions.<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 | ||
| 13 | search but was later replaced by <a href=https://www.elastic.co/>Elasticsearch</a> for | ||
| 14 | better CPU utilization and better search performance. This provided us with many | ||
| 15 | amazing functionalities of <a href=https://www.elastic.co/>Elasticsearch</a>. You should | ||
| 16 | check it out if you do any search related operations.<p>Because the premise of the server is to provide native ad experience, they are | ||
| 17 | rendered on the client side via simple templating engine. This ensures that ads | ||
| 18 | can be displayed number of different ways based on the visual style of the | ||
| 19 | page. And this makes JavaScript client library quite complex.<p>So now that you know basic information about the product lets get into the | ||
| 20 | lessons we learned.<h2 id=aggregate-everything>Aggregate everything</h2><p>After beta version was released everything (impressions, clicks, etc) was | ||
| 21 | written 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 | ||
| 23 | 200GB in disk space. And that was problematic. Statistics took disturbingly long | ||
| 24 | time to aggregate. Also using indexes on stats table in database was no help | ||
| 25 | after we reached 500 million datapoints.<blockquote><p>There is a marketing product information and there is real life experience. | ||
| 26 | And the tend to be quite the opposite.</blockquote><p>This was the reason that now everything is aggregated on daily basis and this | ||
| 27 | data is then fed to Elastic in form of daily summary. With this we achieved we | ||
| 28 | can now track many more dimensions such as zone, channel and platform | ||
| 29 | information. And with this information we can now adapt occurrences of ads on | ||
| 30 | specific places more precisely.<p>We have also adapted <a href=https://redis.io/>Redis</a> as a full-time citizen in our | ||
| 31 | stack. Because Redis also stores information on a local disk we have some sort | ||
| 32 | of backup if server would accidentally suffer some failure.<p>All the real-time statistics for ad serving and redirecting is presented as | ||
| 33 | counters 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 | ||
| 34 | under load until such load is presented. When testing locally everything is fine | ||
| 35 | but when on production things tend to fall apart.<p>As a solution for this we are measuring everything we can. Function execution | ||
| 36 | time (by encapsulating functions with timers), server performance (cpu, memory, | ||
| 37 | disk, etc), Nginx and <a href=https://uwsgi-docs.readthedocs.io/>uWSGI</a> performance. | ||
| 38 | We sacrifice a bit of performance for the sake of this information. And we store | ||
| 39 | all 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> "get_final_filtered_ads": { | ||
| 41 | </span></span><span style=display:flex><span> "counter": 1931250, | ||
| 42 | </span></span><span style=display:flex><span> "avg": 0.0066143431, | ||
| 43 | </span></span><span style=display:flex><span> "elapsed": 12773.9500310003 | ||
| 44 | </span></span><span style=display:flex><span> }, | ||
| 45 | </span></span><span style=display:flex><span> "store_keywords_statistics": { | ||
| 46 | </span></span><span style=display:flex><span> "counter": 1931011, | ||
| 47 | </span></span><span style=display:flex><span> "avg": 0.0004605267, | ||
| 48 | </span></span><span style=display:flex><span> "elapsed": 889.2821669996 | ||
| 49 | </span></span><span style=display:flex><span> }, | ||
| 50 | </span></span><span style=display:flex><span> "match_by_context": { | ||
| 51 | </span></span><span style=display:flex><span> "counter": 1931011, | ||
| 52 | </span></span><span style=display:flex><span> "avg": 0.0055960716, | ||
| 53 | </span></span><span style=display:flex><span> "elapsed": 10806.0758889999 | ||
| 54 | </span></span><span style=display:flex><span> }, | ||
| 55 | </span></span><span style=display:flex><span> "match_by_high_performance": { | ||
| 56 | </span></span><span style=display:flex><span> "counter": 262, | ||
| 57 | </span></span><span style=display:flex><span> "avg": 0.0152770229, | ||
| 58 | </span></span><span style=display:flex><span> "elapsed": 4.00258 | ||
| 59 | </span></span><span style=display:flex><span> }, | ||
| 60 | </span></span><span style=display:flex><span> "store_impression_stats": { | ||
| 61 | </span></span><span style=display:flex><span> "counter": 1931250, | ||
| 62 | </span></span><span style=display:flex><span> "avg": 0.0006189991, | ||
| 63 | </span></span><span style=display:flex><span> "elapsed": 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> | ||
| 67 | and then visualizing with <a href=http://kcachegrind.sourceforge.net/>KCachegrind</a>. | ||
| 68 | This 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 | ||
| 69 | extensively and when in need we need to be able to change behavior of the script | ||
| 70 | quickly.<p>In our case we can not simply replace javascript url in html code. It usually | ||
| 71 | takes 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 | ||
| 73 | and 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 | ||
| 74 | Manager</a> but couple of websites | ||
| 75 | are developed on ASP.net platform that have some problems with tag manager. With | ||
| 76 | a solution below we are certain that we are serving latest version of the | ||
| 77 | script.<p>And it only takes one mistake and users have the script cached and in case of | ||
| 78 | caching 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>"public"</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>"public,</span> <span style=color:#a31515>must-revalidate"</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 | ||
| 97 | we didn't precisely setup cache control and expire headers in response we didn't | ||
| 98 | get the request on the server and therefore couldn't measure clicks. So when | ||
| 99 | redirecting 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>"Cache-Control"</span>, <span style=color:#a31515>"no-store, no-cache, must-revalidate"</span>) | ||
| 102 | </span></span><span style=display:flex><span>response.set_header(<span style=color:#a31515>"Expires"</span>, <span style=color:#a31515>"Thu, 01 Jan 1970 00:00:00 GMT"</span>) | ||
| 103 | </span></span><span style=display:flex><span>response.set_header(<span style=color:#a31515>"Location"</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 | ||
| 106 | avoid 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 | ||
| 107 | applications. We adapted micro-service oriented architecture early in the | ||
| 108 | project to ensure when we scale we can easily add additional servers to our | ||
| 109 | cluster. And Nginx was crucial to perform load balancing and static content | ||
| 110 | delivery.<p>At first our config file was quite simple and later grew larger. After patching | ||
| 111 | and adding new settings I sat down and learned more about the guts of Nginx. | ||
| 112 | This proved to be very useful and we were able to squeeze much more out of our | ||
| 113 | setup. 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. | ||
| 115 | Googling 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 | ||
| 116 | corner stone of our services. At first we were very careful about the quantity | ||
| 117 | of things we stored in <a href=https://redis.io/>Redis</a>. But we later found out that | ||
| 118 | the 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. | ||
| 119 | This improved our performance in order of magnitude. And by using native TTL | ||
| 120 | support 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 | ||
| 122 | of 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 | ||
| 123 | in here deserves it's own post but you probably got the idea about the problems | ||
| 124 | we 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 | ||
| 125 | a lock on a Linux NFS server, which turned | ||
| 126 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 127 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 128 | owns 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 | ||
| 129 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 130 | list where the're doing | ||
| 131 | bad computer history and insisting that a guy Larry Rosen | ||
| 132 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 133 | somethin…<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: | ||
| 134 | i2c, plan9 | ||
| 135 | Another month, another file system. | ||
| 136 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 137 | you, bme680, we’re not | ||
| 138 | done yet). The show must go on, as they say, and I would like my | ||
| 139 | experiments to go on. | ||
| 140 | So a “new” addition to the environmental sensor family connected to | ||
| 141 | the 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 | ||
| 142 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 143 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 144 | unique 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. | ||
| 145 | My 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 | ||
| 146 | 1.0 has been released: | ||
| 147 | wifi_da-1.0.sit | ||
| 148 | (StuffIt 3 archive) | ||
| 149 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 150 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 151 | classic 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. | ||
| 152 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 153 | Design Goals | ||
| 154 | I 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 | ||
| 155 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 156 | catch 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 | ||
| 157 | specified 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 | ||
| 10 | foundation blocks of life and things like that. It's remarkable how complex and | ||
| 11 | on the other hand simple the creation is when you look at it. The miracle of | ||
| 12 | life keeps us grounded when our imagination goes wild. If the DNA are the blocks | ||
| 13 | of life, you could consider them to be an API nature provided us to better | ||
| 14 | understand all of this chaos masquerading as order.<p>I have been reading a lot about superintelligence and our somehow misguided path | ||
| 15 | to create general artificial intelligence. What would the building blocks or our | ||
| 16 | creation look like? Is the compression really the ultimate storage of | ||
| 17 | information? Will our creation also ponder this questions when creating new | ||
| 18 | worlds for themselves, or will we just disappear into the vastness of | ||
| 19 | possibilities? It is a little offensive that we are playing God whilst being | ||
| 20 | completely ignorant of our own reality. Who knows! Like many other | ||
| 21 | breakthroughs, this one will also come at a cost not known to us when it finally | ||
| 22 | happens.<p>To keep things a bit lighter, I decided to convert some popular DNA sequences | ||
| 23 | into an audio files for us to listen to. I am not the first one, nor I will be | ||
| 24 | the last one to do this. But it is an interesting exercise in better | ||
| 25 | understanding the relationship between art and science. Maybe listening to DNA | ||
| 26 | instead of parsing it will find a way into better understanding, or at least | ||
| 27 | enjoying 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 | ||
| 29 | sequence</a> where I have been | ||
| 30 | converting all sorts of data into DNA sequences.<p>This will be a similar exercise but instead of converting to DNA, I will be | ||
| 31 | generating 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 | ||
| 32 | Hz</a>. For this tuning, we also | ||
| 33 | choose <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 | ||
| 34 | a bit. This is a famous quote I also used for the encoding tests, and it goes | ||
| 35 | like this.<blockquote><p>How wonderful that we have met with a paradox. Now we have some hope of | ||
| 36 | making progress. | ||
| 37 | ― Niels Bohr</blockquote><pre tabindex=0 style=background-color:#fff><code><span style=display:flex><span>>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 | ||
| 47 | parser 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 | ||
| 50 | Nucleotides that will be converted into separate tones based on equal-tempered | ||
| 51 | scale 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>'A'</span>: 440, | ||
| 53 | </span></span><span style=display:flex><span> <span style=color:#a31515>'C'</span>: 523.25, | ||
| 54 | </span></span><span style=display:flex><span> <span style=color:#a31515>'G'</span>: 783.99, | ||
| 55 | </span></span><span style=display:flex><span> <span style=color:#a31515>'T'</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 | ||
| 65 | sine notes to a global array we will later use for creating a WAV file out of | ||
| 66 | it.<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 | ||
| 78 | aggressive, 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>'w'</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>'NONE'</span> | ||
| 88 | </span></span><span style=display:flex><span> compname = <span style=color:#a31515>'not compressed'</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>'h'</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 | ||
| 96 | file size, you can adjust it downwards. The standard for low quality is, 8000 or | ||
| 97 | 8kHz.<p>WAV files here are using short, 16 bit, signed integers for the sample size. | ||
| 98 | So, we multiply the floating-point data we have by 32767, the maximum value for | ||
| 99 | a short integer.<blockquote><p>It is theoretically possible to use the floating point -1.0 to 1.0 data | ||
| 100 | directly in a WAV file, but not obvious how to do that using the wave module | ||
| 101 | in 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 | ||
| 102 | out to use the <a href=https://linux.die.net/man/1/sox>SoX - Sound eXchange, the Swiss Army knife of audio | ||
| 103 | manipulation</a> one because it didn't require | ||
| 104 | anything 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, | ||
| 107 | however.<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 > 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 | ||
| 111 | this.<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 "audio.png" | ||
| 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 "#ffffff" | ||
| 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 "audio_only.dat" with lines lt rgb 'red' | ||
| 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 | ||
| 136 | tone generator script. This then generated a WAV file and I converted those to | ||
| 137 | MP3, so they can be played in a browser. The last step was creating a | ||
| 138 | spectrogram 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 | ||
| 139 | can get <a href=http://ftp.ensembl.org/pub/release-106/fasta/mus_musculus/dna/>genom data | ||
| 140 | here</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 | ||
| 141 | get <a href=http://ftp.ensembl.org/pub/release-106/fasta/bison_bison_bison/cdna/>genom data | ||
| 142 | here</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 | ||
| 144 | here</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 | ||
| 146 | really cool piece of equipment that supports MIDI in via USB and 3.5 mm audio | ||
| 147 | jack.<p>Elektron is connected to my MacBook via USB cable and audio out is patched to a | ||
| 148 | Sony Bluetooth speaker I have that supports 3.5 mm audio in. Elektron doesn't | ||
| 149 | have 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 | ||
| 150 | built in. With this, it was rather simple to send notes to the device. All I did | ||
| 151 | was map MIDI notes to the actual Nucleotides.<p>Before all of this I also checked Audio MIDI Setup app under MacOS and checked | ||
| 152 | MIDI 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>'A'</span>: 60, | ||
| 172 | </span></span><span style=display:flex><span> <span style=color:#a31515>'C'</span>: 90, | ||
| 173 | </span></span><span style=display:flex><span> <span style=color:#a31515>'G'</span>: 160, | ||
| 174 | </span></span><span style=display:flex><span> <span style=color:#a31515>'T'</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>"quote.fa"</span>) <span style=color:#00f>as</span> f: | ||
| 178 | </span></span><span style=display:flex><span> sequence = f.read().replace(<span style=color:#a31515>'</span><span style=color:#a31515>\n</span><span style=color:#a31515>'</span>, <span style=color:#a31515>''</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>"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>"</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 | ||
| 188 | instruments for different Nucleotides, or doing more funky stuff with Elektron. | ||
| 189 | But for now, this should be enough. It is just a proof of concept. Something to | ||
| 190 | play 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 | ||
| 191 | to be expected because we are operating only with 4 notes essentially. What | ||
| 192 | could make this more interesting is using something like | ||
| 193 | <a href=https://supercollider.github.io/>Supercollider</a> to create more interesting | ||
| 194 | sounds. By transposing notes or using effects based on repeated data in a | ||
| 195 | sequence. Possibilities are endless.<p>It is really astonishing what can be achieved with a little bit of code and an | ||
| 196 | idea. I could see this becoming an interesting background soundscape instrument | ||
| 197 | if done properly. It could replace random note generator with something more | ||
| 198 | intriguing, biological, natural.<p>I actually find the results fascinating. I took some time and listened to this | ||
| 199 | music of nature. Even though it's quite the same, it's also quite different. | ||
| 200 | The subtle differences on repeat kind of creates music on its own. Makes you | ||
| 201 | wonder. It kind of puts Occam’s Razor in its place. Nature for sure loves to | ||
| 202 | make 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 | ||
| 203 | a lock on a Linux NFS server, which turned | ||
| 204 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 205 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 206 | owns 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 | ||
| 207 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 208 | list where the're doing | ||
| 209 | bad computer history and insisting that a guy Larry Rosen | ||
| 210 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 211 | somethin…<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: | ||
| 212 | i2c, plan9 | ||
| 213 | Another month, another file system. | ||
| 214 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 215 | you, bme680, we’re not | ||
| 216 | done yet). The show must go on, as they say, and I would like my | ||
| 217 | experiments to go on. | ||
| 218 | So a “new” addition to the environmental sensor family connected to | ||
| 219 | the 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 | ||
| 220 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 221 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 222 | unique 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. | ||
| 223 | My 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 | ||
| 224 | 1.0 has been released: | ||
| 225 | wifi_da-1.0.sit | ||
| 226 | (StuffIt 3 archive) | ||
| 227 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 228 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 229 | classic 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. | ||
| 230 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 231 | Design Goals | ||
| 232 | I 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 | ||
| 233 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 234 | catch 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 | ||
| 235 | specified 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 | ||
| 10 | in Flask and Bottle to moving on to static site generators. I have used and | ||
| 11 | tested probably 10s of them my now. From homebrew solutions to the biggest and | ||
| 12 | the baddest. From Bash scripts to Node.js disasters. I've seen some things, no | ||
| 13 | doubt. Not all bad.<p>I have been closely observing the web and where the trends are going, and I | ||
| 14 | don't like what I see. Instead of internet being this weird place where | ||
| 15 | experimentation is happening, it all became stale and formulized. Boring, | ||
| 16 | actually. Really boring. And sad. Where is that old, revolutionary FU spirit I | ||
| 17 | remember? It's still there, I know. But it's being drowned by the voices of | ||
| 18 | mediocrity and formulaic boredom.<p>It almost feels like that the internet stopped for 10 years and only now | ||
| 19 | something has started happening. With all the insanity around the world. People | ||
| 20 | hating people without actual reasons, just because it's fashionable to hate and | ||
| 21 | crowd is saying so. Sad state of affairs.<p>All this is contributing to this overall negativity masked as apathy. Everybody | ||
| 22 | walking in lockstep. Instead of being creative and bold, we are just | ||
| 23 | re-inventing the world and making the same mistakes. Maybe, just maybe, some | ||
| 24 | things are good enough and there is no need to try to be too smart for our own | ||
| 25 | good. After N-attempts, maybe something should click inside our heads to maybe | ||
| 26 | say: "This thing, opinion, etc. is actually really good, and even after several | ||
| 27 | attempts it still holds."<p>The older I get, the more careful I am of my own thoughts and why I think the | ||
| 28 | way I think. More and more, I try to understand people with opposite | ||
| 29 | opinions. Far from perfect, but closer to bearable. And then I see people | ||
| 30 | hearing or reading a thing on internet and let's fucking goooooo! Strong | ||
| 31 | opinions are a sign of a weak and uneducated mind. I am more and more sure of | ||
| 32 | this.<p>It's gotten to a point where you can with great certainty deduce a person's | ||
| 33 | personality based on one or two opinions. How boring have we become. No wonder | ||
| 34 | people 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 | ||
| 35 | Ren"</a>. The ending talks about being | ||
| 36 | stiff and not being able to dance. Such an amazing metaphor. And we as people | ||
| 37 | have gone so far, we can't even walk or even crawl normally anymore. We have | ||
| 38 | forgotten that the most beautiful things in life have a great deal of | ||
| 39 | uncertainty about them. We want instant gratification. Not only that, but we | ||
| 40 | want absolute obedience. Complete control over others, because we have zero | ||
| 41 | control of ourselves. And all the lies we could tell ourselves will not help us | ||
| 42 | out of this situation.<p>It is funny how I catch myself from time to time being a complete idiot. It's | ||
| 43 | like having an outer body experience. I can see myself being an idiot, and | ||
| 44 | cannot stop myself. It serves as a learning lesson to stop before speaking. To | ||
| 45 | think 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 | ||
| 46 | second. Me and you. Us two is a start. Let's not try to change the world, but | ||
| 47 | rather nudge ourselves just a tiny bit. And if we only did that?! Just | ||
| 48 | imagine. Each of us nudged ourselves a small, tiny bit, the world would heal. If | ||
| 49 | we would just put down the phones and ignored Internet for a day or two. Put | ||
| 50 | visiting websites that feed on us on hold. Listened to just one sentence and try | ||
| 51 | to understand it from a person who we completely disagree with. I truly believe | ||
| 52 | that this is possible.<p>Life is about suffering and joy. And instead of wishing suffering on others and | ||
| 53 | excepting joy for yourselves, we should for a brief moment want suffering for | ||
| 54 | ourselves 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 | ||
| 55 | I do it? It is obviously not for me. So why the hell was I being so negative | ||
| 56 | towards it? I think that I know the answer. I was negative because that is | ||
| 57 | easy. Because it's much easier to hate on things than to say to yourself: "Well, | ||
| 58 | you know what? This is not for me. I will focus on creation and not | ||
| 59 | destruction. This is who I want to be. This is what fills me with joy and | ||
| 60 | purpose." Where joy is keeping me happy and purpose scares the shit out of me | ||
| 61 | and keeps me honest. This is who I want to be. Admit to myself when I am wrong | ||
| 62 | and 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 | ||
| 63 | cathartic. Going thought the history of this site and remembering all the | ||
| 64 | decisions and annoyances that came with it. When I was cursing at the tools. And | ||
| 65 | time moved on, and the site is still here. It serves as a reminder that | ||
| 66 | perseverance wins at the end. If we just let things go.<p>This came with a decision that simplifying life and removing all the unnecessary | ||
| 67 | negativity is key. Rather than worrying about what the internet is saying, what | ||
| 68 | the world is trying to take from you, you are the only one who can say no. And | ||
| 69 | create instead of destroy.<p>I don't have an ending for this post, so I will say this. We live in the most | ||
| 70 | amazing times in the recorded history, and we should be internally grateful for | ||
| 71 | it. Create and study, this should be my mantra. Just create and let the world | ||
| 72 | happen. And when you feel yourself to be too certain, stop and check how deep in the | ||
| 73 | shit you are already. Strong opinions are a sign of a weak and uneducated | ||
| 74 | mind. 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 | ||
| 75 | a lock on a Linux NFS server, which turned | ||
| 76 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 77 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 78 | owns 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 | ||
| 79 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 80 | list where the're doing | ||
| 81 | bad computer history and insisting that a guy Larry Rosen | ||
| 82 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 83 | somethin…<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: | ||
| 84 | i2c, plan9 | ||
| 85 | Another month, another file system. | ||
| 86 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 87 | you, bme680, we’re not | ||
| 88 | done yet). The show must go on, as they say, and I would like my | ||
| 89 | experiments to go on. | ||
| 90 | So a “new” addition to the environmental sensor family connected to | ||
| 91 | the 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 | ||
| 92 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 93 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 94 | unique 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. | ||
| 95 | My 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 | ||
| 96 | 1.0 has been released: | ||
| 97 | wifi_da-1.0.sit | ||
| 98 | (StuffIt 3 archive) | ||
| 99 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 100 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 101 | classic 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. | ||
| 102 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 103 | Design Goals | ||
| 104 | I 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 | ||
| 105 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 106 | catch 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 | ||
| 107 | specified 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 | ||
| 10 | can reorder connections between them if one of them is inoperable. This works | ||
| 11 | our of the box when you deploy them. But you have to have in mind that achieving | ||
| 12 | this is not as easy as you would think. None of it is plug&play. So to make | ||
| 13 | your 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 | ||
| 14 | and regulations you need to comply before you get your Xbee radios. What they | ||
| 15 | do is they wait until you prove that you won’t use the technology for some | ||
| 16 | kind of evil take over control of the world project :). For this, they have | ||
| 17 | EAR (Export Administration Regulations) which basically means “This product | ||
| 18 | may 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 | ||
| 19 | radios from Mouser, this was mandatory! What we needed to do was to print out | ||
| 20 | a form and write information about our company and send them a copy via | ||
| 21 | email. 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 | ||
| 22 | clear yet. Then customs will take it from there :). There will be some | ||
| 23 | additional costs. Before purchasing, make sure you have as much information | ||
| 24 | about 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 | ||
| 25 | costs. Here in Slovenia, the best option so far as I know is Farnell. And | ||
| 26 | based 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 | ||
| 27 | orders in December! :) Believe me! You will have problems with stock they can | ||
| 28 | provide for you. So, we were forced to buy some things from Mouser, which was | ||
| 29 | extremely painful because of all the regulations you need to obey when | ||
| 30 | importing goods from the USA.<li>Make sure that firmware version on your Xbee radios is exactly the same! Do | ||
| 31 | not get creative!!! I propose using templates. You can get template by | ||
| 32 | exporting 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 | ||
| 34 | later :)<li>Test, test, test. Wireless networks can be tricky.</ul><p>If you are serious, I suggest you buy this book, Building Wireless Sensor | ||
| 35 | Networks. You will get a glimpse of how networks work in lumens terms. It is a | ||
| 36 | good 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 | ||
| 37 | a lock on a Linux NFS server, which turned | ||
| 38 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 39 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 40 | owns 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 | ||
| 41 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 42 | list where the're doing | ||
| 43 | bad computer history and insisting that a guy Larry Rosen | ||
| 44 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 45 | somethin…<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: | ||
| 46 | i2c, plan9 | ||
| 47 | Another month, another file system. | ||
| 48 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 49 | you, bme680, we’re not | ||
| 50 | done yet). The show must go on, as they say, and I would like my | ||
| 51 | experiments to go on. | ||
| 52 | So a “new” addition to the environmental sensor family connected to | ||
| 53 | the 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 | ||
| 54 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 55 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 56 | unique 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. | ||
| 57 | My 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 | ||
| 58 | 1.0 has been released: | ||
| 59 | wifi_da-1.0.sit | ||
| 60 | (StuffIt 3 archive) | ||
| 61 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 62 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 63 | classic 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. | ||
| 64 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 65 | Design Goals | ||
| 66 | I 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 | ||
| 67 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 68 | catch 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 | ||
| 69 | specified 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 | ||
| 11 | a lock on a Linux NFS server, which turned | ||
| 12 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 13 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 14 | owns 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 | ||
| 15 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 16 | list where the're doing | ||
| 17 | bad computer history and insisting that a guy Larry Rosen | ||
| 18 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 19 | somethin…<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: | ||
| 20 | i2c, plan9 | ||
| 21 | Another month, another file system. | ||
| 22 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 23 | you, bme680, we’re not | ||
| 24 | done yet). The show must go on, as they say, and I would like my | ||
| 25 | experiments to go on. | ||
| 26 | So a “new” addition to the environmental sensor family connected to | ||
| 27 | the 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 | ||
| 28 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 29 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 30 | unique 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. | ||
| 31 | My 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 | ||
| 32 | 1.0 has been released: | ||
| 33 | wifi_da-1.0.sit | ||
| 34 | (StuffIt 3 archive) | ||
| 35 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 36 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 37 | classic 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. | ||
| 38 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 39 | Design Goals | ||
| 40 | I 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 | ||
| 41 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 42 | catch 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 | ||
| 43 | specified 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>'tput sgr0'</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>'\e[38;5;%dm'</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>'\e[48;5;%dm'</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<$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>'%4d '</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>'\e]4;%d;?\a'</span> 0 | ||
| 37 | </span></span><span style=display:flex><span>read -d <span style=color:#a31515>$'\a'</span> -s -t 0.1 </dev/tty | ||
| 38 | </span></span><span style=display:flex><span><span style=color:#00f>if</span> [ -z <span style=color:#a31515>"</span>$REPLY<span style=color:#a31515>"</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'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>'\e]4;%d;?\a'</span> $i | ||
| 50 | </span></span><span style=display:flex><span> read -d <span style=color:#a31515>$'\a'</span> -s -t 0.1 </dev/tty | ||
| 51 | </span></span><span style=display:flex><span> <span style=color:#00f>if</span> [ -z <span style=color:#a31515>"</span>$REPLY<span style=color:#a31515>"</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>"</span>$1<span style=color:#a31515>"</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 | ||
| 78 | a lock on a Linux NFS server, which turned | ||
| 79 | out to be specific to NFS v3 (which I really should have seen coming, | ||
| 80 | since it involved NLM and lockd). Finding the NFS v4 client that | ||
| 81 | owns 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 | ||
| 82 | and Bradley Kuhn, are interacting on the OSI's license-discuss | ||
| 83 | list where the're doing | ||
| 84 | bad computer history and insisting that a guy Larry Rosen | ||
| 85 | coincidentally interviewed for a book years ago is clearly the origin of | ||
| 86 | somethin…<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: | ||
| 87 | i2c, plan9 | ||
| 88 | Another month, another file system. | ||
| 89 | Well, if you can’t fix it in software, fix it in hardware (looking at | ||
| 90 | you, bme680, we’re not | ||
| 91 | done yet). The show must go on, as they say, and I would like my | ||
| 92 | experiments to go on. | ||
| 93 | So a “new” addition to the environmental sensor family connected to | ||
| 94 | the 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 | ||
| 95 | this mortal coil, we are endowed with self-awareness, agency, and free will. | ||
| 96 | Each of the 8 billion members of this human race represents a unique person, a | ||
| 97 | unique 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. | ||
| 98 | My 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 | ||
| 99 | 1.0 has been released: | ||
| 100 | wifi_da-1.0.sit | ||
| 101 | (StuffIt 3 archive) | ||
| 102 | SHA256: ccfc9d27dd5da7412d10cef73b81119a1fec3848e4d1d88ff652a07ffdc6a69aSHA1: ff124972f202ceda6d7fa4788110a67ccda6a13a | ||
| 103 | This is the initial public release of my BlueSCSI Wi-Fi Desk Accessory for | ||
| 104 | classic 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. | ||
| 105 | In this article, I describe my goals, which hardware I picked for my new build (and why) and how I set it up. | ||
| 106 | Design Goals | ||
| 107 | I 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 | ||
| 108 | at <a href=mailto:mitja.felicijan@gmail.com>mitja.felicijan@gmail.com</a> or | ||
| 109 | catch 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 | ||
| 110 | specified 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 | |||
| 3 | mQGNBGU+WGUBDADCwsBTgAEN8WGHQtLd+j3CMHCmzFOVZJeZ6MvRx3BgJvemKYO4 | ||
| 4 | hNLyLpvJFk0XaeomFL4VdPvY6/awIagWgQo43hDVJYemi86c0RYMKxX7lJOldyrM | ||
| 5 | hS/hkwILXWYrUJGWIbulWN6Q66PqMNAMrFKrDAtJv2/g5ykN4U8NRWg2GHC8j2dD | ||
| 6 | ULPmLncbtdmnUm5/+ah7HqUIXzAZkb65h3Sswr0Si6EpzQd2dASfZIECNd+2VO4j | ||
| 7 | +iqnnt0k7ELvCoqz+vbUaK22r2D24BQ9GpZ9SvncWtqZjjtje+RV/VY8WlqLxZN2 | ||
| 8 | ZxMo1lx1Fj2ZijvJEg9SrBRVRj2Hi6AnJSwfREv/447I30+KfJeXWeMbDxdZneoY | ||
| 9 | VH+3LhO6/aVr06Ezy9grSFYuZshIQfBqklA7/wcOhwfrNfKL9IWiEbQRVA1YrpWk | ||
| 10 | h9EZSchTp8OK8ZYeb82SzJy9WmnNNCZTT6TN7rpG1lNYmIeoOoL1myoACeQD7FFO | ||
| 11 | fPNwWkl7zLlkS28AEQEAAbQrTWl0amEgRmVsaWNpamFuIDxtaXRqYS5mZWxpY2lq | ||
| 12 | YW5AZ21haWwuY29tPokB0QQTAQgAOxYhBOWRfEBxolPeoI30PkgS32rvgtmXBQJl | ||
| 13 | PlhlAhsDBQsJCAcCAiICBhUKCQgLAgQWAgMBAh4HAheAAAoJEEgS32rvgtmXxGoM | ||
| 14 | AIr5Ij9dcoi41e7ChY1H8ioPxTcqUrcsJJK1Ls+X+/oCbk+fUUgmDb1ZFoFm9e0/ | ||
| 15 | C+48TpmBNixjpRoOh3hXxzBbQd8aOYjeZvKATxYtErLEKHz+LIw6G8gnBilrvqvv | ||
| 16 | JP2JfhERqTpW1GJlAVRwEPBSQFMbPc8a1WZbrHaciJ2aj2GiTEaDkl5Ft805Vom7 | ||
| 17 | MkcbrD6Tv2Aaq0VTtFnBX1d8dartHln2LpK7gpgSeaJIkJq+FBUQ7S8k2IaMvXOG | ||
| 18 | G8ktNrwrYAC1bUgfyXHMdTTHPIH2TxnxCrNCMi9pT9G96W1P5ZlAcDQR9BnuQ7uf | ||
| 19 | oFcUCErAuKLPL3ajTw0Rj+pNyEY+o5bG9VSo7U35u+9suSbDiYVmoL4vWPffm6MP | ||
| 20 | 2Fk4OQq9wNbP5IUl9LN2nUYQJ2BXXjI+JzjwAT0xBD/+/FUCgTUcgGVdsJBpfOeS | ||
| 21 | VEfu4VanYCVI9D9zGhLjDuz0zxzg7jufo13dwjSux2C6qSMm+2+frTsccrn7ZLks | ||
| 22 | YLkBjQRlPlhlAQwAwjn+MXMOxk4ANP1TLPE+q05thOdvbmxfp6e6jqOmCFGbpHx/ | ||
| 23 | OTYRQ3OUTpovj5SXehhKTnDV6B1FWT9AvwhXjWhNv8NAfaF7xGrgbARb5ecHePak | ||
| 24 | uVi1l4SXTTaYG6A5U2Sw53fhraaanlH0j3DIBON2B3lvQ464vHbMmxangWEijueN | ||
| 25 | 12Me6Jl8gWaoEzxdv+KkTxbwkjyq/yxotdl48aNHczmV8RLKnnIQuQ5VG2aFwGpJ | ||
| 26 | 91fKFUhsALd/o5lb3A6duzBBAnsCipAio6Ukwo0FnYR8GzkTpED69wmGQ/apLv4d | ||
| 27 | WP8Y7GAzxElHaKWSaWSRm9EYEgvjSWhUZLgZpr0ZX60AkHnjQMPJiXUkWdh/XxNH | ||
| 28 | OOTLf4MrUAxOv8iSvmq/iWll3AOJzIGCsho9vjjJ8LG6ZcTvHa1CY6XH5L6NlTFF | ||
| 29 | UGwJ9x6Rx8o7kpOlbUABwjEfUR2OXeJYQcslZ13IfwbZfVtSbmn9HsacEls5Uahw | ||
| 30 | +J/nRleeR7JQQeHdABEBAAGJAbYEGAEIACAWIQTlkXxAcaJT3qCN9D5IEt9q74LZ | ||
| 31 | lwUCZT5YZQIbDAAKCRBIEt9q74LZl+gGDACN6JhNnwWO1q9Mu16Z8R/28jEO7vua | ||
| 32 | kXFV5/38k57qzLe5wFvcynfrnZzwomgrAm9RNuaUaG7gDPllAWPPRYvtMQSY3VJX | ||
| 33 | oLzZje8kWNDL7al9shMKy4suFBxU2EaKYf2m2SO4nk+J6d3qKl6oxr+9Rthx4M6r | ||
| 34 | s+7Jq4UYZ0qsGW7kc62dnDYtzG8kzFvFspUCpzEXyGEAoT4jBPYfqImlKw09lBEN | ||
| 35 | KvB55zc58X3NCIl39cpENsL1eoPRETB6h0oCOqQL4gDjUea/ipOmrPidahF89xsL | ||
| 36 | vILB/RvxawjhWvS0pYfeHJ6hSjc1lEGYFrQdaCq0nFI2LfZ1PHUIOVcRVHI1LfT4 | ||
| 37 | q8CJ09O8zQwLG24Ny0PpEkADsSPqnry4gz86mzQu/fI+bDQuoig/HMRO+Q1HPD/x | ||
| 38 | S9xiNmEDXniGLU9kusSNBQG5oZwFnCEkkW9HAsRVtqtkL9SjYBPug3IzlgNqBU5M | ||
| 39 | IBuToBH0bKUHmWLaHUffu2H5hDrKfC3fF/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 | ||
| 25 | L 720 288 | ||
| 26 | L 720 0 | ||
| 27 | L 0 0 | ||
| 28 | z | ||
| 29 | " style="fill: #ffffff"/> | ||
| 30 | </g> | ||
| 31 | <g id="axes_1"> | ||
| 32 | <g id="patch_2"> | ||
| 33 | <path d="M 90 256.32 | ||
| 34 | L 648 256.32 | ||
| 35 | L 648 34.56 | ||
| 36 | L 90 34.56 | ||
| 37 | z | ||
| 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 | ||
| 45 | L 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 | ||
| 57 | Q 1547 4250 1301 3770 | ||
| 58 | Q 1056 3291 1056 2328 | ||
| 59 | Q 1056 1369 1301 889 | ||
| 60 | Q 1547 409 2034 409 | ||
| 61 | Q 2525 409 2770 889 | ||
| 62 | Q 3016 1369 3016 2328 | ||
| 63 | Q 3016 3291 2770 3770 | ||
| 64 | Q 2525 4250 2034 4250 | ||
| 65 | z | ||
| 66 | M 2034 4750 | ||
| 67 | Q 2819 4750 3233 4129 | ||
| 68 | Q 3647 3509 3647 2328 | ||
| 69 | Q 3647 1150 3233 529 | ||
| 70 | Q 2819 -91 2034 -91 | ||
| 71 | Q 1250 -91 836 529 | ||
| 72 | Q 422 1150 422 2328 | ||
| 73 | Q 422 3509 836 4129 | ||
| 74 | Q 1250 4750 2034 4750 | ||
| 75 | z | ||
| 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 | ||
| 93 | L 3431 531 | ||
| 94 | L 3431 0 | ||
| 95 | L 469 0 | ||
| 96 | L 469 531 | ||
| 97 | Q 828 903 1448 1529 | ||
| 98 | Q 2069 2156 2228 2338 | ||
| 99 | Q 2531 2678 2651 2914 | ||
| 100 | Q 2772 3150 2772 3378 | ||
| 101 | Q 2772 3750 2511 3984 | ||
| 102 | Q 2250 4219 1831 4219 | ||
| 103 | Q 1534 4219 1204 4116 | ||
| 104 | Q 875 4013 500 3803 | ||
| 105 | L 500 4441 | ||
| 106 | Q 881 4594 1212 4672 | ||
| 107 | Q 1544 4750 1819 4750 | ||
| 108 | Q 2544 4750 2975 4387 | ||
| 109 | Q 3406 4025 3406 3419 | ||
| 110 | Q 3406 3131 3298 2873 | ||
| 111 | Q 3191 2616 2906 2266 | ||
| 112 | Q 2828 2175 2409 1742 | ||
| 113 | Q 1991 1309 1228 531 | ||
| 114 | z | ||
| 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 | ||
| 133 | L 825 1625 | ||
| 134 | L 2419 1625 | ||
| 135 | L 2419 4116 | ||
| 136 | z | ||
| 137 | M 2253 4666 | ||
| 138 | L 3047 4666 | ||
| 139 | L 3047 1625 | ||
| 140 | L 3713 1625 | ||
| 141 | L 3713 1100 | ||
| 142 | L 3047 1100 | ||
| 143 | L 3047 0 | ||
| 144 | L 2419 0 | ||
| 145 | L 2419 1100 | ||
| 146 | L 313 1100 | ||
| 147 | L 313 1709 | ||
| 148 | L 2253 4666 | ||
| 149 | z | ||
| 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 | ||
| 168 | Q 1688 2584 1439 2293 | ||
| 169 | Q 1191 2003 1191 1497 | ||
| 170 | Q 1191 994 1439 701 | ||
| 171 | Q 1688 409 2113 409 | ||
| 172 | Q 2538 409 2786 701 | ||
| 173 | Q 3034 994 3034 1497 | ||
| 174 | Q 3034 2003 2786 2293 | ||
| 175 | Q 2538 2584 2113 2584 | ||
| 176 | z | ||
| 177 | M 3366 4563 | ||
| 178 | L 3366 3988 | ||
| 179 | Q 3128 4100 2886 4159 | ||
| 180 | Q 2644 4219 2406 4219 | ||
| 181 | Q 1781 4219 1451 3797 | ||
| 182 | Q 1122 3375 1075 2522 | ||
| 183 | Q 1259 2794 1537 2939 | ||
| 184 | Q 1816 3084 2150 3084 | ||
| 185 | Q 2853 3084 3261 2657 | ||
| 186 | Q 3669 2231 3669 1497 | ||
| 187 | Q 3669 778 3244 343 | ||
| 188 | Q 2819 -91 2113 -91 | ||
| 189 | Q 1303 -91 875 529 | ||
| 190 | Q 447 1150 447 2328 | ||
| 191 | Q 447 3434 972 4092 | ||
| 192 | Q 1497 4750 2381 4750 | ||
| 193 | Q 2619 4750 2861 4703 | ||
| 194 | Q 3103 4656 3366 4563 | ||
| 195 | z | ||
| 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 | ||
| 214 | Q 1584 2216 1326 1975 | ||
| 215 | Q 1069 1734 1069 1313 | ||
| 216 | Q 1069 891 1326 650 | ||
| 217 | Q 1584 409 2034 409 | ||
| 218 | Q 2484 409 2743 651 | ||
| 219 | Q 3003 894 3003 1313 | ||
| 220 | Q 3003 1734 2745 1975 | ||
| 221 | Q 2488 2216 2034 2216 | ||
| 222 | z | ||
| 223 | M 1403 2484 | ||
| 224 | Q 997 2584 770 2862 | ||
| 225 | Q 544 3141 544 3541 | ||
| 226 | Q 544 4100 942 4425 | ||
| 227 | Q 1341 4750 2034 4750 | ||
| 228 | Q 2731 4750 3128 4425 | ||
| 229 | Q 3525 4100 3525 3541 | ||
| 230 | Q 3525 3141 3298 2862 | ||
| 231 | Q 3072 2584 2669 2484 | ||
| 232 | Q 3125 2378 3379 2068 | ||
| 233 | Q 3634 1759 3634 1313 | ||
| 234 | Q 3634 634 3220 271 | ||
| 235 | Q 2806 -91 2034 -91 | ||
| 236 | Q 1263 -91 848 271 | ||
| 237 | Q 434 634 434 1313 | ||
| 238 | Q 434 1759 690 2068 | ||
| 239 | Q 947 2378 1403 2484 | ||
| 240 | z | ||
| 241 | M 1172 3481 | ||
| 242 | Q 1172 3119 1398 2916 | ||
| 243 | Q 1625 2713 2034 2713 | ||
| 244 | Q 2441 2713 2670 2916 | ||
| 245 | Q 2900 3119 2900 3481 | ||
| 246 | Q 2900 3844 2670 4047 | ||
| 247 | Q 2441 4250 2034 4250 | ||
| 248 | Q 1625 4250 1398 4047 | ||
| 249 | Q 1172 3844 1172 3481 | ||
| 250 | z | ||
| 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 | ||
| 269 | L 1825 531 | ||
| 270 | L 1825 4091 | ||
| 271 | L 703 3866 | ||
| 272 | L 703 4441 | ||
| 273 | L 1819 4666 | ||
| 274 | L 2450 4666 | ||
| 275 | L 2450 531 | ||
| 276 | L 3481 531 | ||
| 277 | L 3481 0 | ||
| 278 | L 794 0 | ||
| 279 | L 794 531 | ||
| 280 | z | ||
| 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 | ||
| 294 | L 4031 4666 | ||
| 295 | L 3928 4134 | ||
| 296 | L 1606 4134 | ||
| 297 | L 1338 2753 | ||
| 298 | L 3566 2753 | ||
| 299 | L 3463 2222 | ||
| 300 | L 1234 2222 | ||
| 301 | L 909 531 | ||
| 302 | L 3284 531 | ||
| 303 | L 3181 0 | ||
| 304 | L 172 0 | ||
| 305 | L 1081 4666 | ||
| 306 | z | ||
| 307 | " transform="scale(0.015625)"/> | ||
| 308 | <path id="DejaVuSans-Oblique-70" d="M 3175 2156 | ||
| 309 | Q 3175 2616 2975 2859 | ||
| 310 | Q 2775 3103 2400 3103 | ||
| 311 | Q 2144 3103 1911 2972 | ||
| 312 | Q 1678 2841 1497 2591 | ||
| 313 | Q 1319 2344 1212 1994 | ||
| 314 | Q 1106 1644 1106 1300 | ||
| 315 | Q 1106 863 1306 627 | ||
| 316 | Q 1506 391 1875 391 | ||
| 317 | Q 2147 391 2380 519 | ||
| 318 | Q 2613 647 2778 891 | ||
| 319 | Q 2956 1147 3065 1494 | ||
| 320 | Q 3175 1841 3175 2156 | ||
| 321 | z | ||
| 322 | M 1394 2969 | ||
| 323 | Q 1625 3272 1939 3428 | ||
| 324 | Q 2253 3584 2638 3584 | ||
| 325 | Q 3175 3584 3472 3232 | ||
| 326 | Q 3769 2881 3769 2247 | ||
| 327 | Q 3769 1728 3584 1258 | ||
| 328 | Q 3400 788 3053 416 | ||
| 329 | Q 2822 169 2531 39 | ||
| 330 | Q 2241 -91 1919 -91 | ||
| 331 | Q 1547 -91 1294 64 | ||
| 332 | Q 1041 219 916 525 | ||
| 333 | L 556 -1331 | ||
| 334 | L -19 -1331 | ||
| 335 | L 922 3500 | ||
| 336 | L 1497 3500 | ||
| 337 | L 1394 2969 | ||
| 338 | z | ||
| 339 | " transform="scale(0.015625)"/> | ||
| 340 | <path id="DejaVuSans-Oblique-6f" d="M 1625 -91 | ||
| 341 | Q 1009 -91 651 289 | ||
| 342 | Q 294 669 294 1325 | ||
| 343 | Q 294 1706 417 2101 | ||
| 344 | Q 541 2497 738 2766 | ||
| 345 | Q 1047 3184 1428 3384 | ||
| 346 | Q 1809 3584 2291 3584 | ||
| 347 | Q 2888 3584 3255 3212 | ||
| 348 | Q 3622 2841 3622 2241 | ||
| 349 | Q 3622 1825 3500 1412 | ||
| 350 | Q 3378 1000 3181 728 | ||
| 351 | Q 2875 309 2494 109 | ||
| 352 | Q 2113 -91 1625 -91 | ||
| 353 | z | ||
| 354 | M 891 1344 | ||
| 355 | Q 891 869 1089 633 | ||
| 356 | Q 1288 397 1691 397 | ||
| 357 | Q 2269 397 2648 901 | ||
| 358 | Q 3028 1406 3028 2181 | ||
| 359 | Q 3028 2634 2825 2865 | ||
| 360 | Q 2622 3097 2228 3097 | ||
| 361 | Q 1903 3097 1650 2945 | ||
| 362 | Q 1397 2794 1197 2484 | ||
| 363 | Q 1050 2253 970 1956 | ||
| 364 | Q 891 1659 891 1344 | ||
| 365 | z | ||
| 366 | " transform="scale(0.015625)"/> | ||
| 367 | <path id="DejaVuSans-Oblique-63" d="M 3431 3366 | ||
| 368 | L 3316 2797 | ||
| 369 | Q 3109 2947 2876 3022 | ||
| 370 | Q 2644 3097 2394 3097 | ||
| 371 | Q 2119 3097 1870 3000 | ||
| 372 | Q 1622 2903 1453 2725 | ||
| 373 | Q 1184 2453 1037 2087 | ||
| 374 | Q 891 1722 891 1331 | ||
| 375 | Q 891 859 1127 628 | ||
| 376 | Q 1363 397 1844 397 | ||
| 377 | Q 2081 397 2348 469 | ||
| 378 | Q 2616 541 2906 684 | ||
| 379 | L 2797 116 | ||
| 380 | Q 2547 13 2283 -39 | ||
| 381 | Q 2019 -91 1741 -91 | ||
| 382 | Q 1044 -91 669 257 | ||
| 383 | Q 294 606 294 1253 | ||
| 384 | Q 294 1797 489 2255 | ||
| 385 | Q 684 2713 1069 3078 | ||
| 386 | Q 1331 3328 1684 3456 | ||
| 387 | Q 2038 3584 2456 3584 | ||
| 388 | Q 2700 3584 2940 3529 | ||
| 389 | Q 3181 3475 3431 3366 | ||
| 390 | z | ||
| 391 | " transform="scale(0.015625)"/> | ||
| 392 | <path id="DejaVuSans-Oblique-68" d="M 3566 2113 | ||
| 393 | L 3156 0 | ||
| 394 | L 2578 0 | ||
| 395 | L 2988 2091 | ||
| 396 | Q 3016 2238 3031 2350 | ||
| 397 | Q 3047 2463 3047 2528 | ||
| 398 | Q 3047 2791 2881 2937 | ||
| 399 | Q 2716 3084 2419 3084 | ||
| 400 | Q 1956 3084 1617 2771 | ||
| 401 | Q 1278 2459 1178 1941 | ||
| 402 | L 800 0 | ||
| 403 | L 225 0 | ||
| 404 | L 1172 4863 | ||
| 405 | L 1747 4863 | ||
| 406 | L 1375 2950 | ||
| 407 | Q 1594 3244 1934 3414 | ||
| 408 | Q 2275 3584 2650 3584 | ||
| 409 | Q 3113 3584 3367 3334 | ||
| 410 | Q 3622 3084 3622 2631 | ||
| 411 | Q 3622 2519 3608 2391 | ||
| 412 | Q 3594 2263 3566 2113 | ||
| 413 | z | ||
| 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 | ||
| 429 | L -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 | ||
| 454 | L 3169 4666 | ||
| 455 | L 3169 4134 | ||
| 456 | L 1269 4134 | ||
| 457 | L 1269 2991 | ||
| 458 | Q 1406 3038 1543 3061 | ||
| 459 | Q 1681 3084 1819 3084 | ||
| 460 | Q 2600 3084 3056 2656 | ||
| 461 | Q 3513 2228 3513 1497 | ||
| 462 | Q 3513 744 3044 326 | ||
| 463 | Q 2575 -91 1722 -91 | ||
| 464 | Q 1428 -91 1123 -41 | ||
| 465 | Q 819 9 494 109 | ||
| 466 | L 494 744 | ||
| 467 | Q 775 591 1075 516 | ||
| 468 | Q 1375 441 1709 441 | ||
| 469 | Q 2250 441 2565 725 | ||
| 470 | Q 2881 1009 2881 1497 | ||
| 471 | Q 2881 1984 2565 2268 | ||
| 472 | Q 2250 2553 1709 2553 | ||
| 473 | Q 1456 2553 1204 2497 | ||
| 474 | Q 953 2441 691 2322 | ||
| 475 | L 691 4666 | ||
| 476 | z | ||
| 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 | ||
| 509 | L 3525 4666 | ||
| 510 | L 3525 4397 | ||
| 511 | L 1831 0 | ||
| 512 | L 1172 0 | ||
| 513 | L 2766 4134 | ||
| 514 | L 525 4134 | ||
| 515 | L 525 4666 | ||
| 516 | z | ||
| 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 | ||
| 589 | L 2028 4666 | ||
| 590 | L 2572 1522 | ||
| 591 | L 4378 4666 | ||
| 592 | L 5350 4666 | ||
| 593 | L 4441 0 | ||
| 594 | L 3828 0 | ||
| 595 | L 4622 4091 | ||
| 596 | L 2791 897 | ||
| 597 | L 2175 897 | ||
| 598 | L 1581 4103 | ||
| 599 | L 788 0 | ||
| 600 | L 172 0 | ||
| 601 | L 1081 4666 | ||
| 602 | z | ||
| 603 | " transform="scale(0.015625)"/> | ||
| 604 | <path id="DejaVuSans-Oblique-65" d="M 3078 2063 | ||
| 605 | Q 3088 2113 3092 2166 | ||
| 606 | Q 3097 2219 3097 2272 | ||
| 607 | Q 3097 2653 2873 2875 | ||
| 608 | Q 2650 3097 2266 3097 | ||
| 609 | Q 1838 3097 1509 2826 | ||
| 610 | Q 1181 2556 1013 2059 | ||
| 611 | L 3078 2063 | ||
| 612 | z | ||
| 613 | M 3578 1613 | ||
| 614 | L 903 1613 | ||
| 615 | Q 884 1494 878 1425 | ||
| 616 | Q 872 1356 872 1306 | ||
| 617 | Q 872 872 1139 634 | ||
| 618 | Q 1406 397 1894 397 | ||
| 619 | Q 2269 397 2603 481 | ||
| 620 | Q 2938 566 3225 728 | ||
| 621 | L 3116 159 | ||
| 622 | Q 2806 34 2476 -28 | ||
| 623 | Q 2147 -91 1806 -91 | ||
| 624 | Q 1078 -91 686 257 | ||
| 625 | Q 294 606 294 1247 | ||
| 626 | Q 294 1794 489 2264 | ||
| 627 | Q 684 2734 1063 3103 | ||
| 628 | Q 1306 3334 1642 3459 | ||
| 629 | Q 1978 3584 2356 3584 | ||
| 630 | Q 2950 3584 3301 3228 | ||
| 631 | Q 3653 2872 3653 2272 | ||
| 632 | Q 3653 2128 3634 1964 | ||
| 633 | Q 3616 1800 3578 1613 | ||
| 634 | z | ||
| 635 | " transform="scale(0.015625)"/> | ||
| 636 | <path id="DejaVuSans-Oblique-64" d="M 2675 525 | ||
| 637 | Q 2444 222 2128 65 | ||
| 638 | Q 1813 -91 1428 -91 | ||
| 639 | Q 903 -91 598 267 | ||
| 640 | Q 294 625 294 1247 | ||
| 641 | Q 294 1766 478 2236 | ||
| 642 | Q 663 2706 1013 3078 | ||
| 643 | Q 1244 3325 1534 3454 | ||
| 644 | Q 1825 3584 2144 3584 | ||
| 645 | Q 2481 3584 2739 3421 | ||
| 646 | Q 2997 3259 3138 2956 | ||
| 647 | L 3513 4863 | ||
| 648 | L 4091 4863 | ||
| 649 | L 3144 0 | ||
| 650 | L 2566 0 | ||
| 651 | L 2675 525 | ||
| 652 | z | ||
| 653 | M 891 1350 | ||
| 654 | Q 891 897 1095 644 | ||
| 655 | Q 1300 391 1663 391 | ||
| 656 | Q 1931 391 2161 520 | ||
| 657 | Q 2391 650 2566 903 | ||
| 658 | Q 2750 1166 2856 1509 | ||
| 659 | Q 2963 1853 2963 2188 | ||
| 660 | Q 2963 2622 2758 2865 | ||
| 661 | Q 2553 3109 2194 3109 | ||
| 662 | Q 1922 3109 1687 2981 | ||
| 663 | Q 1453 2853 1288 2613 | ||
| 664 | Q 1106 2353 998 2009 | ||
| 665 | Q 891 1666 891 1350 | ||
| 666 | z | ||
| 667 | " transform="scale(0.015625)"/> | ||
| 668 | <path id="DejaVuSans-Oblique-69" d="M 1172 4863 | ||
| 669 | L 1747 4863 | ||
| 670 | L 1606 4134 | ||
| 671 | L 1031 4134 | ||
| 672 | L 1172 4863 | ||
| 673 | z | ||
| 674 | M 909 3500 | ||
| 675 | L 1484 3500 | ||
| 676 | L 800 0 | ||
| 677 | L 225 0 | ||
| 678 | L 909 3500 | ||
| 679 | z | ||
| 680 | " transform="scale(0.015625)"/> | ||
| 681 | <path id="DejaVuSans-Oblique-61" d="M 3438 1997 | ||
| 682 | L 3047 0 | ||
| 683 | L 2472 0 | ||
| 684 | L 2578 531 | ||
| 685 | Q 2325 219 2001 64 | ||
| 686 | Q 1678 -91 1281 -91 | ||
| 687 | Q 834 -91 548 182 | ||
| 688 | Q 263 456 263 884 | ||
| 689 | Q 263 1497 752 1853 | ||
| 690 | Q 1241 2209 2100 2209 | ||
| 691 | L 2900 2209 | ||
| 692 | L 2931 2363 | ||
| 693 | Q 2938 2388 2941 2417 | ||
| 694 | Q 2944 2447 2944 2509 | ||
| 695 | Q 2944 2788 2717 2942 | ||
| 696 | Q 2491 3097 2081 3097 | ||
| 697 | Q 1800 3097 1504 3025 | ||
| 698 | Q 1209 2953 897 2809 | ||
| 699 | L 997 3341 | ||
| 700 | Q 1322 3463 1633 3523 | ||
| 701 | Q 1944 3584 2234 3584 | ||
| 702 | Q 2853 3584 3176 3315 | ||
| 703 | Q 3500 3047 3500 2534 | ||
| 704 | Q 3500 2431 3484 2292 | ||
| 705 | Q 3469 2153 3438 1997 | ||
| 706 | z | ||
| 707 | M 2816 1759 | ||
| 708 | L 2241 1759 | ||
| 709 | Q 1534 1759 1195 1570 | ||
| 710 | Q 856 1381 856 984 | ||
| 711 | Q 856 709 1029 553 | ||
| 712 | Q 1203 397 1509 397 | ||
| 713 | Q 1978 397 2328 733 | ||
| 714 | Q 2678 1069 2791 1631 | ||
| 715 | L 2816 1759 | ||
| 716 | z | ||
| 717 | " transform="scale(0.015625)"/> | ||
| 718 | <path id="DejaVuSans-Oblique-6e" d="M 3566 2113 | ||
| 719 | L 3156 0 | ||
| 720 | L 2578 0 | ||
| 721 | L 2988 2091 | ||
| 722 | Q 3016 2238 3031 2350 | ||
| 723 | Q 3047 2463 3047 2528 | ||
| 724 | Q 3047 2791 2881 2937 | ||
| 725 | Q 2716 3084 2419 3084 | ||
| 726 | Q 1956 3084 1622 2776 | ||
| 727 | Q 1288 2469 1184 1941 | ||
| 728 | L 800 0 | ||
| 729 | L 225 0 | ||
| 730 | L 903 3500 | ||
| 731 | L 1478 3500 | ||
| 732 | L 1363 2950 | ||
| 733 | Q 1603 3253 1940 3418 | ||
| 734 | Q 2278 3584 2650 3584 | ||
| 735 | Q 3113 3584 3367 3334 | ||
| 736 | Q 3622 3084 3622 2631 | ||
| 737 | Q 3622 2519 3608 2391 | ||
| 738 | Q 3594 2263 3566 2113 | ||
| 739 | z | ||
| 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 | ||
| 743 | L 1069 3500 | ||
| 744 | L 1581 525 | ||
| 745 | L 3256 3500 | ||
| 746 | L 3866 3500 | ||
| 747 | L 1875 0 | ||
| 748 | L 1100 0 | ||
| 749 | L 459 3500 | ||
| 750 | z | ||
| 751 | " transform="scale(0.015625)"/> | ||
| 752 | <path id="DejaVuSans-Oblique-6c" d="M 1172 4863 | ||
| 753 | L 1747 4863 | ||
| 754 | L 800 0 | ||
| 755 | L 225 0 | ||
| 756 | L 1172 4863 | ||
| 757 | z | ||
| 758 | " transform="scale(0.015625)"/> | ||
| 759 | <path id="DejaVuSans-Oblique-75" d="M 428 1388 | ||
| 760 | L 838 3500 | ||
| 761 | L 1416 3500 | ||
| 762 | L 1006 1409 | ||
| 763 | Q 975 1256 961 1147 | ||
| 764 | Q 947 1038 947 966 | ||
| 765 | Q 947 700 1109 554 | ||
| 766 | Q 1272 409 1569 409 | ||
| 767 | Q 2031 409 2368 721 | ||
| 768 | Q 2706 1034 2809 1563 | ||
| 769 | L 3194 3500 | ||
| 770 | L 3769 3500 | ||
| 771 | L 3091 0 | ||
| 772 | L 2516 0 | ||
| 773 | L 2631 550 | ||
| 774 | Q 2388 244 2052 76 | ||
| 775 | Q 1716 -91 1338 -91 | ||
| 776 | Q 878 -91 622 161 | ||
| 777 | Q 366 413 366 863 | ||
| 778 | Q 366 956 381 1097 | ||
| 779 | Q 397 1238 428 1388 | ||
| 780 | z | ||
| 781 | " transform="scale(0.015625)"/> | ||
| 782 | <path id="DejaVuSans-Oblique-28" d="M 2731 4856 | ||
| 783 | Q 1903 3822 1495 2892 | ||
| 784 | Q 1088 1963 1088 1100 | ||
| 785 | Q 1088 606 1206 120 | ||
| 786 | Q 1325 -366 1563 -844 | ||
| 787 | L 1063 -844 | ||
| 788 | Q 775 -306 634 201 | ||
| 789 | Q 494 709 494 1197 | ||
| 790 | Q 494 2125 923 3036 | ||
| 791 | Q 1353 3947 2222 4856 | ||
| 792 | L 2731 4856 | ||
| 793 | z | ||
| 794 | " transform="scale(0.015625)"/> | ||
| 795 | <path id="DejaVuSans-Oblique-6d" d="M 5747 2113 | ||
| 796 | L 5338 0 | ||
| 797 | L 4763 0 | ||
| 798 | L 5166 2094 | ||
| 799 | Q 5191 2228 5203 2325 | ||
| 800 | Q 5216 2422 5216 2491 | ||
| 801 | Q 5216 2772 5059 2928 | ||
| 802 | Q 4903 3084 4622 3084 | ||
| 803 | Q 4203 3084 3875 2770 | ||
| 804 | Q 3547 2456 3450 1953 | ||
| 805 | L 3066 0 | ||
| 806 | L 2491 0 | ||
| 807 | L 2900 2094 | ||
| 808 | Q 2925 2209 2937 2307 | ||
| 809 | Q 2950 2406 2950 2484 | ||
| 810 | Q 2950 2769 2794 2926 | ||
| 811 | Q 2638 3084 2363 3084 | ||
| 812 | Q 1938 3084 1609 2770 | ||
| 813 | Q 1281 2456 1184 1953 | ||
| 814 | L 800 0 | ||
| 815 | L 225 0 | ||
| 816 | L 909 3500 | ||
| 817 | L 1484 3500 | ||
| 818 | L 1375 2956 | ||
| 819 | Q 1609 3263 1923 3423 | ||
| 820 | Q 2238 3584 2597 3584 | ||
| 821 | Q 2978 3584 3223 3384 | ||
| 822 | Q 3469 3184 3519 2828 | ||
| 823 | Q 3781 3197 4126 3390 | ||
| 824 | Q 4472 3584 4856 3584 | ||
| 825 | Q 5306 3584 5551 3325 | ||
| 826 | Q 5797 3066 5797 2591 | ||
| 827 | Q 5797 2488 5784 2364 | ||
| 828 | Q 5772 2241 5747 2113 | ||
| 829 | z | ||
| 830 | " transform="scale(0.015625)"/> | ||
| 831 | <path id="DejaVuSans-Oblique-73" d="M 3200 3397 | ||
| 832 | L 3091 2853 | ||
| 833 | Q 2863 2978 2609 3040 | ||
| 834 | Q 2356 3103 2088 3103 | ||
| 835 | Q 1634 3103 1373 2948 | ||
| 836 | Q 1113 2794 1113 2528 | ||
| 837 | Q 1113 2219 1719 2053 | ||
| 838 | Q 1766 2041 1788 2034 | ||
| 839 | L 1972 1978 | ||
| 840 | Q 2547 1819 2739 1644 | ||
| 841 | Q 2931 1469 2931 1166 | ||
| 842 | Q 2931 609 2489 259 | ||
| 843 | Q 2047 -91 1331 -91 | ||
| 844 | Q 1053 -91 747 -37 | ||
| 845 | Q 441 16 72 128 | ||
| 846 | L 184 722 | ||
| 847 | Q 500 559 806 475 | ||
| 848 | Q 1113 391 1394 391 | ||
| 849 | Q 1816 391 2080 572 | ||
| 850 | Q 2344 753 2344 1031 | ||
| 851 | Q 2344 1331 1650 1516 | ||
| 852 | L 1591 1531 | ||
| 853 | L 1394 1581 | ||
| 854 | Q 956 1697 753 1886 | ||
| 855 | Q 550 2075 550 2369 | ||
| 856 | Q 550 2928 970 3256 | ||
| 857 | Q 1391 3584 2113 3584 | ||
| 858 | Q 2397 3584 2667 3537 | ||
| 859 | Q 2938 3491 3200 3397 | ||
| 860 | z | ||
| 861 | " transform="scale(0.015625)"/> | ||
| 862 | <path id="DejaVuSans-Oblique-29" d="M -397 -844 | ||
| 863 | Q 434 191 840 1120 | ||
| 864 | Q 1247 2050 1247 2913 | ||
| 865 | Q 1247 3406 1130 3892 | ||
| 866 | Q 1013 4378 775 4856 | ||
| 867 | L 1275 4856 | ||
| 868 | Q 1563 4316 1703 3812 | ||
| 869 | Q 1844 3309 1844 2822 | ||
| 870 | Q 1844 1891 1411 973 | ||
| 871 | Q 978 56 116 -844 | ||
| 872 | L -397 -844 | ||
| 873 | z | ||
| 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 | ||
| 898 | L 120.487603 242.970811 | ||
| 899 | L 125.61157 233.817081 | ||
| 900 | L 130.735537 243.515676 | ||
| 901 | L 135.859504 242.752865 | ||
| 902 | L 140.983471 241.11827 | ||
| 903 | L 146.107438 241.445189 | ||
| 904 | L 151.231405 241.554162 | ||
| 905 | L 156.355372 239.047784 | ||
| 906 | L 161.479339 242.861838 | ||
| 907 | L 166.603306 242.752865 | ||
| 908 | L 171.727273 241.990054 | ||
| 909 | L 176.85124 238.393946 | ||
| 910 | L 181.975207 205.92 | ||
| 911 | L 187.099174 242.534919 | ||
| 912 | L 192.22314 239.919568 | ||
| 913 | L 197.347107 243.842595 | ||
| 914 | L 202.471074 240.137514 | ||
| 915 | L 207.595041 241.11827 | ||
| 916 | L 212.719008 240.682378 | ||
| 917 | L 217.842975 239.810595 | ||
| 918 | L 222.966942 239.592649 | ||
| 919 | L 228.090909 240.137514 | ||
| 920 | L 233.214876 239.047784 | ||
| 921 | L 238.338843 245.368216 | ||
| 922 | L 243.46281 206.791784 | ||
| 923 | L 248.586777 241.554162 | ||
| 924 | L 253.710744 243.29773 | ||
| 925 | L 258.834711 240.355459 | ||
| 926 | L 263.958678 244.823351 | ||
| 927 | L 269.082645 241.11827 | ||
| 928 | L 274.206612 242.534919 | ||
| 929 | L 279.330579 203.304649 | ||
| 930 | L 284.454545 244.605405 | ||
| 931 | L 289.578512 237.958054 | ||
| 932 | L 294.702479 243.188757 | ||
| 933 | L 299.826446 238.720865 | ||
| 934 | L 304.950413 238.829838 | ||
| 935 | L 310.07438 242.425946 | ||
| 936 | L 315.198347 245.041297 | ||
| 937 | L 320.322314 242.861838 | ||
| 938 | L 325.446281 243.515676 | ||
| 939 | L 330.570248 240.464432 | ||
| 940 | L 335.694215 240.900324 | ||
| 941 | L 340.818182 245.15027 | ||
| 942 | L 345.942149 240.791351 | ||
| 943 | L 351.066116 242.970811 | ||
| 944 | L 356.190083 242.425946 | ||
| 945 | L 361.31405 245.477189 | ||
| 946 | L 366.438017 245.259243 | ||
| 947 | L 371.561983 245.695135 | ||
| 948 | L 376.68595 240.355459 | ||
| 949 | L 381.809917 203.958486 | ||
| 950 | L 386.933884 244.605405 | ||
| 951 | L 392.057851 242.425946 | ||
| 952 | L 397.181818 242.208 | ||
| 953 | L 402.305785 239.374703 | ||
| 954 | L 407.429752 242.752865 | ||
| 955 | L 412.553719 243.079784 | ||
| 956 | L 417.677686 244.823351 | ||
| 957 | L 422.801653 237.413189 | ||
| 958 | L 427.92562 241.663135 | ||
| 959 | L 433.049587 240.137514 | ||
| 960 | L 438.173554 243.29773 | ||
| 961 | L 443.297521 245.586162 | ||
| 962 | L 448.421488 245.586162 | ||
| 963 | L 453.545455 187.067676 | ||
| 964 | L 458.669421 243.188757 | ||
| 965 | L 463.793388 241.227243 | ||
| 966 | L 468.917355 242.425946 | ||
| 967 | L 474.041322 245.041297 | ||
| 968 | L 479.165289 244.823351 | ||
| 969 | L 484.289256 245.804108 | ||
| 970 | L 489.413223 242.970811 | ||
| 971 | L 494.53719 245.15027 | ||
| 972 | L 499.661157 245.913081 | ||
| 973 | L 504.785124 239.919568 | ||
| 974 | L 509.909091 241.445189 | ||
| 975 | L 515.033058 242.099027 | ||
| 976 | L 520.157025 244.932324 | ||
| 977 | L 525.280992 245.368216 | ||
| 978 | L 530.404959 242.643892 | ||
| 979 | L 535.528926 245.259243 | ||
| 980 | L 540.652893 245.913081 | ||
| 981 | L 545.77686 244.605405 | ||
| 982 | L 550.900826 243.079784 | ||
| 983 | L 556.024793 241.445189 | ||
| 984 | L 561.14876 244.278486 | ||
| 985 | L 566.272727 244.932324 | ||
| 986 | L 571.396694 243.406703 | ||
| 987 | L 576.520661 239.592649 | ||
| 988 | L 581.644628 242.643892 | ||
| 989 | L 586.768595 204.394378 | ||
| 990 | L 591.892562 241.445189 | ||
| 991 | L 597.016529 241.663135 | ||
| 992 | L 602.140496 176.60627 | ||
| 993 | L 607.264463 243.188757 | ||
| 994 | L 612.38843 242.752865 | ||
| 995 | L 617.512397 240.246486 | ||
| 996 | L 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 | ||
| 1001 | L 120.487603 116.453189 | ||
| 1002 | L 125.61157 243.515676 | ||
| 1003 | L 130.735537 244.714378 | ||
| 1004 | L 135.859504 242.970811 | ||
| 1005 | L 140.983471 238.502919 | ||
| 1006 | L 146.107438 242.643892 | ||
| 1007 | L 151.231405 242.099027 | ||
| 1008 | L 156.355372 242.316973 | ||
| 1009 | L 161.479339 242.861838 | ||
| 1010 | L 166.603306 244.278486 | ||
| 1011 | L 171.727273 243.842595 | ||
| 1012 | L 176.85124 237.413189 | ||
| 1013 | L 181.975207 242.425946 | ||
| 1014 | L 187.099174 241.445189 | ||
| 1015 | L 192.22314 243.951568 | ||
| 1016 | L 197.347107 152.850162 | ||
| 1017 | L 202.471074 243.733622 | ||
| 1018 | L 207.595041 177.913946 | ||
| 1019 | L 212.719008 157.862919 | ||
| 1020 | L 217.842975 245.695135 | ||
| 1021 | L 222.966942 244.060541 | ||
| 1022 | L 228.090909 245.477189 | ||
| 1023 | L 233.214876 242.425946 | ||
| 1024 | L 238.338843 243.733622 | ||
| 1025 | L 243.46281 243.515676 | ||
| 1026 | L 248.586777 243.733622 | ||
| 1027 | L 253.710744 244.823351 | ||
| 1028 | L 258.834711 243.406703 | ||
| 1029 | L 263.958678 176.933189 | ||
| 1030 | L 269.082645 244.714378 | ||
| 1031 | L 274.206612 244.496432 | ||
| 1032 | L 279.330579 243.188757 | ||
| 1033 | L 284.454545 245.586162 | ||
| 1034 | L 289.578512 244.605405 | ||
| 1035 | L 294.702479 245.15027 | ||
| 1036 | L 299.826446 245.259243 | ||
| 1037 | L 304.950413 243.515676 | ||
| 1038 | L 310.07438 82.126703 | ||
| 1039 | L 315.198347 242.425946 | ||
| 1040 | L 320.322314 44.64 | ||
| 1041 | L 325.446281 239.701622 | ||
| 1042 | L 330.570248 244.932324 | ||
| 1043 | L 335.694215 245.368216 | ||
| 1044 | L 340.818182 245.259243 | ||
| 1045 | L 345.942149 244.823351 | ||
| 1046 | L 351.066116 245.804108 | ||
| 1047 | L 356.190083 245.477189 | ||
| 1048 | L 361.31405 244.169514 | ||
| 1049 | L 366.438017 244.605405 | ||
| 1050 | L 371.561983 245.586162 | ||
| 1051 | L 376.68595 245.586162 | ||
| 1052 | L 381.809917 243.079784 | ||
| 1053 | L 386.933884 242.861838 | ||
| 1054 | L 392.057851 244.823351 | ||
| 1055 | L 397.181818 242.970811 | ||
| 1056 | L 402.305785 245.259243 | ||
| 1057 | L 407.429752 241.663135 | ||
| 1058 | L 412.553719 243.624649 | ||
| 1059 | L 417.677686 244.714378 | ||
| 1060 | L 422.801653 246.24 | ||
| 1061 | L 427.92562 243.733622 | ||
| 1062 | L 433.049587 245.15027 | ||
| 1063 | L 438.173554 138.138811 | ||
| 1064 | L 443.297521 240.573405 | ||
| 1065 | L 448.421488 243.951568 | ||
| 1066 | L 453.545455 243.406703 | ||
| 1067 | L 458.669421 242.208 | ||
| 1068 | L 463.793388 242.208 | ||
| 1069 | L 468.917355 242.534919 | ||
| 1070 | L 474.041322 244.278486 | ||
| 1071 | L 479.165289 242.534919 | ||
| 1072 | L 484.289256 242.534919 | ||
| 1073 | L 489.413223 244.714378 | ||
| 1074 | L 494.53719 242.534919 | ||
| 1075 | L 499.661157 245.15027 | ||
| 1076 | L 504.785124 243.29773 | ||
| 1077 | L 509.909091 245.259243 | ||
| 1078 | L 515.033058 245.041297 | ||
| 1079 | L 520.157025 243.515676 | ||
| 1080 | L 525.280992 244.496432 | ||
| 1081 | L 530.404959 244.605405 | ||
| 1082 | L 535.528926 244.387459 | ||
| 1083 | L 540.652893 244.714378 | ||
| 1084 | L 545.77686 244.060541 | ||
| 1085 | L 550.900826 245.15027 | ||
| 1086 | L 556.024793 244.387459 | ||
| 1087 | L 561.14876 245.913081 | ||
| 1088 | L 566.272727 245.15027 | ||
| 1089 | L 571.396694 160.587243 | ||
| 1090 | L 576.520661 244.823351 | ||
| 1091 | L 581.644628 243.624649 | ||
| 1092 | L 586.768595 243.951568 | ||
| 1093 | L 591.892562 244.714378 | ||
| 1094 | L 597.016529 188.157405 | ||
| 1095 | L 602.140496 243.624649 | ||
| 1096 | L 607.264463 242.534919 | ||
| 1097 | L 612.38843 243.951568 | ||
| 1098 | L 617.512397 173.010162 | ||
| 1099 | L 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 | ||
| 1104 | L 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 | ||
| 1109 | L 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 | ||
| 1114 | L 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 | ||
| 1119 | L 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 | ||
| 1127 | L 4122 3641 | ||
| 1128 | Q 3803 3938 3442 4084 | ||
| 1129 | Q 3081 4231 2675 4231 | ||
| 1130 | Q 1875 4231 1450 3742 | ||
| 1131 | Q 1025 3253 1025 2328 | ||
| 1132 | Q 1025 1406 1450 917 | ||
| 1133 | Q 1875 428 2675 428 | ||
| 1134 | Q 3081 428 3442 575 | ||
| 1135 | Q 3803 722 4122 1019 | ||
| 1136 | L 4122 359 | ||
| 1137 | Q 3791 134 3420 21 | ||
| 1138 | Q 3050 -91 2638 -91 | ||
| 1139 | Q 1578 -91 968 557 | ||
| 1140 | Q 359 1206 359 2328 | ||
| 1141 | Q 359 3453 968 4101 | ||
| 1142 | Q 1578 4750 2638 4750 | ||
| 1143 | Q 3056 4750 3426 4639 | ||
| 1144 | Q 3797 4528 4122 4306 | ||
| 1145 | z | ||
| 1146 | " transform="scale(0.015625)"/> | ||
| 1147 | <path id="DejaVuSans-6f" d="M 1959 3097 | ||
| 1148 | Q 1497 3097 1228 2736 | ||
| 1149 | Q 959 2375 959 1747 | ||
| 1150 | Q 959 1119 1226 758 | ||
| 1151 | Q 1494 397 1959 397 | ||
| 1152 | Q 2419 397 2687 759 | ||
| 1153 | Q 2956 1122 2956 1747 | ||
| 1154 | Q 2956 2369 2687 2733 | ||
| 1155 | Q 2419 3097 1959 3097 | ||
| 1156 | z | ||
| 1157 | M 1959 3584 | ||
| 1158 | Q 2709 3584 3137 3096 | ||
| 1159 | Q 3566 2609 3566 1747 | ||
| 1160 | Q 3566 888 3137 398 | ||
| 1161 | Q 2709 -91 1959 -91 | ||
| 1162 | Q 1206 -91 779 398 | ||
| 1163 | Q 353 888 353 1747 | ||
| 1164 | Q 353 2609 779 3096 | ||
| 1165 | Q 1206 3584 1959 3584 | ||
| 1166 | z | ||
| 1167 | " transform="scale(0.015625)"/> | ||
| 1168 | <path id="DejaVuSans-6e" d="M 3513 2113 | ||
| 1169 | L 3513 0 | ||
| 1170 | L 2938 0 | ||
| 1171 | L 2938 2094 | ||
| 1172 | Q 2938 2591 2744 2837 | ||
| 1173 | Q 2550 3084 2163 3084 | ||
| 1174 | Q 1697 3084 1428 2787 | ||
| 1175 | Q 1159 2491 1159 1978 | ||
| 1176 | L 1159 0 | ||
| 1177 | L 581 0 | ||
| 1178 | L 581 3500 | ||
| 1179 | L 1159 3500 | ||
| 1180 | L 1159 2956 | ||
| 1181 | Q 1366 3272 1645 3428 | ||
| 1182 | Q 1925 3584 2291 3584 | ||
| 1183 | Q 2894 3584 3203 3211 | ||
| 1184 | Q 3513 2838 3513 2113 | ||
| 1185 | z | ||
| 1186 | " transform="scale(0.015625)"/> | ||
| 1187 | <path id="DejaVuSans-65" d="M 3597 1894 | ||
| 1188 | L 3597 1613 | ||
| 1189 | L 953 1613 | ||
| 1190 | Q 991 1019 1311 708 | ||
| 1191 | Q 1631 397 2203 397 | ||
| 1192 | Q 2534 397 2845 478 | ||
| 1193 | Q 3156 559 3463 722 | ||
| 1194 | L 3463 178 | ||
| 1195 | Q 3153 47 2828 -22 | ||
| 1196 | Q 2503 -91 2169 -91 | ||
| 1197 | Q 1331 -91 842 396 | ||
| 1198 | Q 353 884 353 1716 | ||
| 1199 | Q 353 2575 817 3079 | ||
| 1200 | Q 1281 3584 2069 3584 | ||
| 1201 | Q 2775 3584 3186 3129 | ||
| 1202 | Q 3597 2675 3597 1894 | ||
| 1203 | z | ||
| 1204 | M 3022 2063 | ||
| 1205 | Q 3016 2534 2758 2815 | ||
| 1206 | Q 2500 3097 2075 3097 | ||
| 1207 | Q 1594 3097 1305 2825 | ||
| 1208 | Q 1016 2553 972 2059 | ||
| 1209 | L 3022 2063 | ||
| 1210 | z | ||
| 1211 | " transform="scale(0.015625)"/> | ||
| 1212 | <path id="DejaVuSans-63" d="M 3122 3366 | ||
| 1213 | L 3122 2828 | ||
| 1214 | Q 2878 2963 2633 3030 | ||
| 1215 | Q 2388 3097 2138 3097 | ||
| 1216 | Q 1578 3097 1268 2742 | ||
| 1217 | Q 959 2388 959 1747 | ||
| 1218 | Q 959 1106 1268 751 | ||
| 1219 | Q 1578 397 2138 397 | ||
| 1220 | Q 2388 397 2633 464 | ||
| 1221 | Q 2878 531 3122 666 | ||
| 1222 | L 3122 134 | ||
| 1223 | Q 2881 22 2623 -34 | ||
| 1224 | Q 2366 -91 2075 -91 | ||
| 1225 | Q 1284 -91 818 406 | ||
| 1226 | Q 353 903 353 1747 | ||
| 1227 | Q 353 2603 823 3093 | ||
| 1228 | Q 1294 3584 2113 3584 | ||
| 1229 | Q 2378 3584 2631 3529 | ||
| 1230 | Q 2884 3475 3122 3366 | ||
| 1231 | z | ||
| 1232 | " transform="scale(0.015625)"/> | ||
| 1233 | <path id="DejaVuSans-74" d="M 1172 4494 | ||
| 1234 | L 1172 3500 | ||
| 1235 | L 2356 3500 | ||
| 1236 | L 2356 3053 | ||
| 1237 | L 1172 3053 | ||
| 1238 | L 1172 1153 | ||
| 1239 | Q 1172 725 1289 603 | ||
| 1240 | Q 1406 481 1766 481 | ||
| 1241 | L 2356 481 | ||
| 1242 | L 2356 0 | ||
| 1243 | L 1766 0 | ||
| 1244 | Q 1100 0 847 248 | ||
| 1245 | Q 594 497 594 1153 | ||
| 1246 | L 594 3053 | ||
| 1247 | L 172 3053 | ||
| 1248 | L 172 3500 | ||
| 1249 | L 594 3500 | ||
| 1250 | L 594 4494 | ||
| 1251 | L 1172 4494 | ||
| 1252 | z | ||
| 1253 | " transform="scale(0.015625)"/> | ||
| 1254 | <path id="DejaVuSans-20" transform="scale(0.015625)"/> | ||
| 1255 | <path id="DejaVuSans-6d" d="M 3328 2828 | ||
| 1256 | Q 3544 3216 3844 3400 | ||
| 1257 | Q 4144 3584 4550 3584 | ||
| 1258 | Q 5097 3584 5394 3201 | ||
| 1259 | Q 5691 2819 5691 2113 | ||
| 1260 | L 5691 0 | ||
| 1261 | L 5113 0 | ||
| 1262 | L 5113 2094 | ||
| 1263 | Q 5113 2597 4934 2840 | ||
| 1264 | Q 4756 3084 4391 3084 | ||
| 1265 | Q 3944 3084 3684 2787 | ||
| 1266 | Q 3425 2491 3425 1978 | ||
| 1267 | L 3425 0 | ||
| 1268 | L 2847 0 | ||
| 1269 | L 2847 2094 | ||
| 1270 | Q 2847 2600 2669 2842 | ||
| 1271 | Q 2491 3084 2119 3084 | ||
| 1272 | Q 1678 3084 1418 2786 | ||
| 1273 | Q 1159 2488 1159 1978 | ||
| 1274 | L 1159 0 | ||
| 1275 | L 581 0 | ||
| 1276 | L 581 3500 | ||
| 1277 | L 1159 3500 | ||
| 1278 | L 1159 2956 | ||
| 1279 | Q 1356 3278 1631 3431 | ||
| 1280 | Q 1906 3584 2284 3584 | ||
| 1281 | Q 2666 3584 2933 3390 | ||
| 1282 | Q 3200 3197 3328 2828 | ||
| 1283 | z | ||
| 1284 | " transform="scale(0.015625)"/> | ||
| 1285 | <path id="DejaVuSans-64" d="M 2906 2969 | ||
| 1286 | L 2906 4863 | ||
| 1287 | L 3481 4863 | ||
| 1288 | L 3481 0 | ||
| 1289 | L 2906 0 | ||
| 1290 | L 2906 525 | ||
| 1291 | Q 2725 213 2448 61 | ||
| 1292 | Q 2172 -91 1784 -91 | ||
| 1293 | Q 1150 -91 751 415 | ||
| 1294 | Q 353 922 353 1747 | ||
| 1295 | Q 353 2572 751 3078 | ||
| 1296 | Q 1150 3584 1784 3584 | ||
| 1297 | Q 2172 3584 2448 3432 | ||
| 1298 | Q 2725 3281 2906 2969 | ||
| 1299 | z | ||
| 1300 | M 947 1747 | ||
| 1301 | Q 947 1113 1208 752 | ||
| 1302 | Q 1469 391 1925 391 | ||
| 1303 | Q 2381 391 2643 752 | ||
| 1304 | Q 2906 1113 2906 1747 | ||
| 1305 | Q 2906 2381 2643 2742 | ||
| 1306 | Q 2381 3103 1925 3103 | ||
| 1307 | Q 1469 3103 1208 2742 | ||
| 1308 | Q 947 2381 947 1747 | ||
| 1309 | z | ||
| 1310 | " transform="scale(0.015625)"/> | ||
| 1311 | <path id="DejaVuSans-69" d="M 603 3500 | ||
| 1312 | L 1178 3500 | ||
| 1313 | L 1178 0 | ||
| 1314 | L 603 0 | ||
| 1315 | L 603 3500 | ||
| 1316 | z | ||
| 1317 | M 603 4863 | ||
| 1318 | L 1178 4863 | ||
| 1319 | L 1178 4134 | ||
| 1320 | L 603 4134 | ||
| 1321 | L 603 4863 | ||
| 1322 | z | ||
| 1323 | " transform="scale(0.015625)"/> | ||
| 1324 | <path id="DejaVuSans-61" d="M 2194 1759 | ||
| 1325 | Q 1497 1759 1228 1600 | ||
| 1326 | Q 959 1441 959 1056 | ||
| 1327 | Q 959 750 1161 570 | ||
| 1328 | Q 1363 391 1709 391 | ||
| 1329 | Q 2188 391 2477 730 | ||
| 1330 | Q 2766 1069 2766 1631 | ||
| 1331 | L 2766 1759 | ||
| 1332 | L 2194 1759 | ||
| 1333 | z | ||
| 1334 | M 3341 1997 | ||
| 1335 | L 3341 0 | ||
| 1336 | L 2766 0 | ||
| 1337 | L 2766 531 | ||
| 1338 | Q 2569 213 2275 61 | ||
| 1339 | Q 1981 -91 1556 -91 | ||
| 1340 | Q 1019 -91 701 211 | ||
| 1341 | Q 384 513 384 1019 | ||
| 1342 | Q 384 1609 779 1909 | ||
| 1343 | Q 1175 2209 1959 2209 | ||
| 1344 | L 2766 2209 | ||
| 1345 | L 2766 2266 | ||
| 1346 | Q 2766 2663 2505 2880 | ||
| 1347 | Q 2244 3097 1772 3097 | ||
| 1348 | Q 1472 3097 1187 3025 | ||
| 1349 | Q 903 2953 641 2809 | ||
| 1350 | L 641 3341 | ||
| 1351 | Q 956 3463 1253 3523 | ||
| 1352 | Q 1550 3584 1831 3584 | ||
| 1353 | Q 2591 3584 2966 3190 | ||
| 1354 | Q 3341 2797 3341 1997 | ||
| 1355 | z | ||
| 1356 | " transform="scale(0.015625)"/> | ||
| 1357 | <path id="DejaVuSans-4e" d="M 628 4666 | ||
| 1358 | L 1478 4666 | ||
| 1359 | L 3547 763 | ||
| 1360 | L 3547 4666 | ||
| 1361 | L 4159 4666 | ||
| 1362 | L 4159 0 | ||
| 1363 | L 3309 0 | ||
| 1364 | L 1241 3903 | ||
| 1365 | L 1241 0 | ||
| 1366 | L 628 0 | ||
| 1367 | L 628 4666 | ||
| 1368 | z | ||
| 1369 | " transform="scale(0.015625)"/> | ||
| 1370 | <path id="DejaVuSans-4c" d="M 628 4666 | ||
| 1371 | L 1259 4666 | ||
| 1372 | L 1259 531 | ||
| 1373 | L 3531 531 | ||
| 1374 | L 3531 0 | ||
| 1375 | L 628 0 | ||
| 1376 | L 628 4666 | ||
| 1377 | z | ||
| 1378 | " transform="scale(0.015625)"/> | ||
| 1379 | <path id="DejaVuSans-42" d="M 1259 2228 | ||
| 1380 | L 1259 519 | ||
| 1381 | L 2272 519 | ||
| 1382 | Q 2781 519 3026 730 | ||
| 1383 | Q 3272 941 3272 1375 | ||
| 1384 | Q 3272 1813 3026 2020 | ||
| 1385 | Q 2781 2228 2272 2228 | ||
| 1386 | L 1259 2228 | ||
| 1387 | z | ||
| 1388 | M 1259 4147 | ||
| 1389 | L 1259 2741 | ||
| 1390 | L 2194 2741 | ||
| 1391 | Q 2656 2741 2882 2914 | ||
| 1392 | Q 3109 3088 3109 3444 | ||
| 1393 | Q 3109 3797 2882 3972 | ||
| 1394 | Q 2656 4147 2194 4147 | ||
| 1395 | L 1259 4147 | ||
| 1396 | z | ||
| 1397 | M 628 4666 | ||
| 1398 | L 2241 4666 | ||
| 1399 | Q 2963 4666 3353 4366 | ||
| 1400 | Q 3744 4066 3744 3513 | ||
| 1401 | Q 3744 3084 3544 2831 | ||
| 1402 | Q 3344 2578 2956 2516 | ||
| 1403 | Q 3422 2416 3680 2098 | ||
| 1404 | Q 3938 1781 3938 1306 | ||
| 1405 | Q 3938 681 3513 340 | ||
| 1406 | Q 3088 0 2303 0 | ||
| 1407 | L 628 0 | ||
| 1408 | L 628 4666 | ||
| 1409 | z | ||
| 1410 | " transform="scale(0.015625)"/> | ||
| 1411 | <path id="DejaVuSans-76" d="M 191 3500 | ||
| 1412 | L 800 3500 | ||
| 1413 | L 1894 563 | ||
| 1414 | L 2988 3500 | ||
| 1415 | L 3597 3500 | ||
| 1416 | L 2284 0 | ||
| 1417 | L 1503 0 | ||
| 1418 | L 191 3500 | ||
| 1419 | z | ||
| 1420 | " transform="scale(0.015625)"/> | ||
| 1421 | <path id="DejaVuSans-73" d="M 2834 3397 | ||
| 1422 | L 2834 2853 | ||
| 1423 | Q 2591 2978 2328 3040 | ||
| 1424 | Q 2066 3103 1784 3103 | ||
| 1425 | Q 1356 3103 1142 2972 | ||
| 1426 | Q 928 2841 928 2578 | ||
| 1427 | Q 928 2378 1081 2264 | ||
| 1428 | Q 1234 2150 1697 2047 | ||
| 1429 | L 1894 2003 | ||
| 1430 | Q 2506 1872 2764 1633 | ||
| 1431 | Q 3022 1394 3022 966 | ||
| 1432 | Q 3022 478 2636 193 | ||
| 1433 | Q 2250 -91 1575 -91 | ||
| 1434 | Q 1294 -91 989 -36 | ||
| 1435 | Q 684 19 347 128 | ||
| 1436 | L 347 722 | ||
| 1437 | Q 666 556 975 473 | ||
| 1438 | Q 1284 391 1588 391 | ||
| 1439 | Q 1994 391 2212 530 | ||
| 1440 | Q 2431 669 2431 922 | ||
| 1441 | Q 2431 1156 2273 1281 | ||
| 1442 | Q 2116 1406 1581 1522 | ||
| 1443 | L 1381 1569 | ||
| 1444 | Q 847 1681 609 1914 | ||
| 1445 | Q 372 2147 372 2553 | ||
| 1446 | Q 372 3047 722 3315 | ||
| 1447 | Q 1072 3584 1716 3584 | ||
| 1448 | Q 2034 3584 2315 3537 | ||
| 1449 | Q 2597 3491 2834 3397 | ||
| 1450 | z | ||
| 1451 | " transform="scale(0.015625)"/> | ||
| 1452 | <path id="DejaVuSans-41" d="M 2188 4044 | ||
| 1453 | L 1331 1722 | ||
| 1454 | L 3047 1722 | ||
| 1455 | L 2188 4044 | ||
| 1456 | z | ||
| 1457 | M 1831 4666 | ||
| 1458 | L 2547 4666 | ||
| 1459 | L 4325 0 | ||
| 1460 | L 3669 0 | ||
| 1461 | L 3244 1197 | ||
| 1462 | L 1141 1197 | ||
| 1463 | L 716 0 | ||
| 1464 | L 50 0 | ||
| 1465 | L 1831 4666 | ||
| 1466 | z | ||
| 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 | ||
| 1499 | L 641 71.91625 | ||
| 1500 | Q 643 71.91625 643 69.91625 | ||
| 1501 | L 643 41.56 | ||
| 1502 | Q 643 39.56 641 39.56 | ||
| 1503 | L 589.085938 39.56 | ||
| 1504 | Q 587.085938 39.56 587.085938 41.56 | ||
| 1505 | L 587.085938 69.91625 | ||
| 1506 | Q 587.085938 71.91625 589.085938 71.91625 | ||
| 1507 | z | ||
| 1508 | " style="fill: #ffffff; opacity: 0.8"/> | ||
| 1509 | </g> | ||
| 1510 | <g id="line2d_17"> | ||
| 1511 | <path d="M 591.085938 47.658437 | ||
| 1512 | L 601.085938 47.658437 | ||
| 1513 | L 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 | ||
| 1526 | L 601.085938 62.336562 | ||
| 1527 | L 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 | ||
| 10 | X0lEQVR4nO3dvbqjOKIFUNf9KujHm9CP6HAeb4IJbnCm3RQ/sgQbI2CtrwMXxpIQAvYR2P3r8Xg9 | ||
| 11 | AADI+b+jGwAAcDUCFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUA | ||
| 12 | ECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUA | ||
| 13 | ECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUA | ||
| 14 | ECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUA | ||
| 15 | ECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUA | ||
| 16 | ECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUA | ||
| 17 | ECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUA | ||
| 18 | ECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUA | ||
| 19 | ECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUA | ||
| 20 | ECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUA | ||
| 21 | ECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUA | ||
| 22 | ECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUA | ||
| 23 | ECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUA | ||
| 24 | ECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUA | ||
| 25 | ECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQ9jtV0OuVKgnO7fl8vhwP9Mr4 | ||
| 26 | hB/P577lm8ECAAgTsAAAwgQsONrz+b//IqvtZ6n2A5tUo/PmARclYEEHXq+ZxxhHyWB2nbJ3Jtse | ||
| 27 | Mp7PNQ34vt7i1H7t6W1LgT/FHnIH+vITiZb+GVQudr96ATomYMH9DCc/3unnJwm936pMRT/rj1ae | ||
| 28 | LWQp8BXqnW1nuSWtTWoqv6mdS+2ZJs5hV8yW83G/SLHQn10C1tPcNfRm6QI//Ofs63JwGV77ywUW | ||
| 29 | LNXbNAM3+6lg+a3lFNozW2Prfmlq+bhmp2ju62s/U7LXDJbfWeG2Tnz1mj1sPwaFnertsPyjTmuF | ||
| 30 | elftF+dnbuub52e3CIGeLN1620Oq/G9G6u88VwdsJmABUSse5CoUtasLzGzJWNArP9MAvcpeOL98 | ||
| 31 | 4/IUv+lwAdNn4IA+CFjQq1NfOMu/v7Vi09wuXCJjQZfcIoSLGl133/NJS8tXmP2CYeFbdcNbhx8z | ||
| 32 | wbp2vj/1cf1UP5TLmbZnuGT41pb2uFcI/fn1eGSOyT/PqP5v7dxX8/ivfGIp9WDT3r72A6es4vzM | ||
| 33 | nQ3H/94zv2aw4Gj1czOnEJwhAzgtAQvCTA8IVT0zPuFvS1NYmWPEQ+4AAGECFgBAmIAFABAmYAEA | ||
| 34 | hAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEA | ||
| 35 | hAlYAABhAhYAQJiAdR3P57Orcrr1fD6/uY0f67p8hwPc0JEB6/mn2XcPaVjE3o0/S+f01s7n8/l6 | ||
| 36 | vV6v137l71Tyd5y9/QCd+H1s9cPr3M+Vb/iWcz13sF/aA+AoBwesVsPINQpnkeVN9f4kwvdbw+XD | ||
| 37 | Fx/rXSrnY2Om5Q/f3bK9reUsbddsOwvbWy7n/anpW/XbNeuo/fJx5Zp6y+0frlPutxXj9r1kdisA | ||
| 38 | 7uxMAWvpgpFa3lrv0uvZWlaUs2Sp/KVyWre3tZyl5cF2jlZ4R5/W/Th8URlE9tsv70+NZmqD47Np | ||
| 39 | /RXjdna/FKoGuI+DA1ZkBqLyg3uc+lNlXqmcms/OrrP3tXlFCDhLf35zfQBqdPQMVo2lp7Jmlxfu | ||
| 40 | XLQ+3ZV6GqymnD0ueLs+zRa8Q3TUfqnxtSDS2p97r//w5DtAuzPdInwsXBKmtzBG608vJ0f9lX/U | ||
| 41 | bMHXJoe21FXYj+V6r6e1P7+zPgD1bvE7WK/Xa/qkC3H6Oau1P0frD18vTfHaXwA7OXHAmr0wDBdW | ||
| 42 | Xjl6vl24h3i9e2zIijIvExSCA/InP62YGlxX3Wi1y+wRgBU6vUU4+4Wv0V/bw68yzf7VXrP+o+L2 | ||
| 43 | R+v6o0+trre1/I9rbqx3XX+ua2fNzMre27WxtJpymsb5xxpn159+vHV/ZfsH4CZ+PR6pp4v+ee3b | ||
| 44 | 2tAbRyXA6EdzFtbKnCo7ncECtjPzBHAUAQsuS6gCOMqJH3IHAOiTgAUAECZgAQCECVgAAGECFgBA | ||
| 45 | mIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBA | ||
| 46 | mIAFAOzi+Xwe3YTD9BiwUvvj8vu1tw3srT1Zq7fua91Srmi/ZiyV/Hw+Z9+69ji5Lbt1o6Xj5Vgd | ||
| 47 | NulEjgxYzzkHtqes57ZdSefD4KOr/nnQ2p7n8/l6vV6v107tuaq997vxeWDJhYvd3Y6X3sbPTn4f | ||
| 48 | WPd7MP2MrQNbclK9ddq69oz2/uv1usmxF3fUeGitt7dxC9/xM/Jd7+7jyIBV9r7KDsfi8NJbOUab | ||
| 49 | ypld/l7482KUC+vLH645LWrddo1Wbi0nuP60PTX907oTaz4yPX+9lyztl0g7l8ZJoaim8VZTe02l | ||
| 50 | hXpn+6Fmu+ovGE3jdst+H/6zsL3T9QvjobxRleUX1h++2HI+KTeysvwV5TwWhtyK/bj9eAmeB6Yl | ||
| 51 | HCg1zstVjAr5WH6h35YKaT11nFGnAWs0aGaDf+VAqS9naXnhz47Wdo5WeA/N1u16zM30tJaTXX92 | ||
| 52 | 5ulj/7TuxMqP1HxwqRlL7fxYXWqcFMop114YD8O3Wvuh3J7ZeocvRp+qH7er9/tI6ryRKr91v7ee | ||
| 53 | T5bqXVF+UzmPhX7b+7z9cds3ngeaWr5CKnDscbxsOW8sWXd+O6keH3J/5FLtlnIqU0620qCPzdjY | ||
| 54 | ztX906FD+uqbnVNZV6RJr9frfeULbmOH3RX57FmOkRo9nLd3qne/QLDT8RLxzfPGJXU6g7WkZiJh | ||
| 55 | tVfdTHuN1nZGtmtF+5vqDfZPq133+8g3t+6b29VDvUtm23PgeBs14+MKTe3c+zjtUKr9R50HbjLd | ||
| 56 | QtzJAtbeo/w9e7mlrulUamW92zW1f3U7N/bPq/EBly119WxF/6f01p9L7YmMty9obee69c/rAjNb | ||
| 57 | MhYrdHqL8Fg/U7Xn/atx7/ZHyu9wPpw+VY634TqHHLyjdn5sz9nPM7fSz546fJxT78QBKz629his | ||
| 58 | K8pc3Ywt7a/5bLZ/nn9b8cFgMzqp9MDyeztHb7l4/Fx7Vkw27HTszLZnY4f3tr9anfF24Y/ZjLXu | ||
| 59 | JBZpyRfG+dkH2+HOdItwNL4jt6iG5ZTLr39yYumv2Nb2FMx+8aS1nGA7m74IU/42SnC7Rrts7/6Z | ||
| 60 | 1r6l/KYndT72W6GuLU8ONe33mnYOC1ndzqWWF8rfMj/x8bzRuv6oM1PnvWz568Z5ffmt5RS2a+N5 | ||
| 61 | YFrL6k1oPV7KLZlt23SFLef57eeNj7Vc+z7Gr8cjdXf8n9duV1NQCFiQ0tu46q09XINx1Wr2T/qJ | ||
| 62 | TJeeaQaLa8j+JQRvvY2r3trDNRhXZyFgcQAnBfbQ27jqrT1cg3F1Fid+yB0AoE8CFgBAmID1j6t+ | ||
| 63 | JfWq27Xky9v7sbq79T9dqR9+vsO/ziG/1HBhV+rMIwPWNfrxGltR74bbe7dNbrLUP1fttP2266o9 | ||
| 64 | 9uO8P3/1GPxo33S0/3wlzUNRS5b217VH+5sZLChx6izTP5fRuivvs+vfEUqW+oJ1PdxnYuvlW4Sj | ||
| 65 | n6YY/b7ZcLX369H6S6WV65qtvb7e4YuaX1n8+AObhe16/7PQP+XaK7er0J7hiy37671kWtRsez5u | ||
| 66 | 1HT91eOn5ndlWju/qT0rtO7HLcfXx/45y3GxetzOjv/ZLWrt/9lOKG/CtPzHp8E2+xuPs0sK7Zzd | ||
| 67 | ud85byw1frr+ivPkflLjvFzFUjmR80/qejG7fGlhTfsP37lLughYHxPP8ARa+akv1Dv77grrDqTC | ||
| 68 | +b1y/fKFarq8sL2t+2u0wvsQar2QF05YK8ZPpaUzY/1H9mtPZfm7tueqx8XH7So3+GP/N21pofzC | ||
| 69 | +Jw97t5vTQdzoZ3T9fc+byyVs7qfNyoHhaZydj0PLL1OnW9b91f5OKofh7vu3JTjbxHOds1RnbW0 | ||
| 70 | y7/fkrLWJm3ZhJrP9tBvo7P/9yvdvlrE6v21Yp3efPO42KJQb/2l4gs78eznjV337+v1eieJHg6W | ||
| 71 | Qhv2aF5v57Q+HTyD1W3wHKmcqDhEvANfuf9LVGu/Na0fbOdRuhpXF+jPoS1b8c39smX24krjZ9QP | ||
| 72 | sWbNlX9VNf22up8L+7ercdiVgwPWa9v/O/M7plOgBzbmO95zsI8NJ6YV/bZuBuK8saC3Np+9P1MO | ||
| 73 | nNmqPx92eF466rzB49Dz7SHHy6unB+yWHH+LcPae6yUNt/QUm/wz9d1/U8/SzrP4cn+e7rjY1QVG | ||
| 74 | suNx1mXGeVf7t5P7s0uOD1iPU51TNrbzZ0tXTNp9s3/2qGtFmR8/0kM7K9evWW36yPC6DVzdLSsa | ||
| 75 | mdLzcfH9U9OK8+HS+jc8b9SXfNSe/cI4P/B8++Veff7tm5XW6+JbhI+6ufHReee98vDecM3s9Or1 | ||
| 76 | p22oL2Ta7Prtmq13u5p6pw2u397W9pfr3W/9QjtHf3G+n2lt3S+zs9mV/dxUeH3568qp6Z/Rmpc5 | ||
| 77 | Lkbvfjz/tPb/tJZ156UV/VPYj/Xrf+e8Uej/2XojWvunYL9xftT5dt1+n13e1M/Pxm9BHuLX45Fp | ||
| 78 | 03DT+tzU3uglyu45Qu651dyNcb7R6oD1/PP3HRbWyuyaXmawbmLvv7S4jFudfx0X3IFxHvSFmcvt | ||
| 79 | BKyv6nMQ0KFbDZVbbSy3ZZxn9d+fXTzkDgBwJQIWAECYgNWvbr96Cl+Q+t74UTpvHrA3AYuMXX+x | ||
| 80 | ZqeSr+1c/Xau1gJ8JGABp7TuEVdJDviOI79FuPQ7Fj8vpj/M2FrOY+Frsal6K8sfltxa/rCK2R9k | ||
| 81 | G9X7XjL6obamr7MW2lmud1rpbD8UyvnYP1t+vCA1TspVTMspl980zt9rtu7f6baU11+q+rHDOCz/ | ||
| 82 | uuBS/8z+SuHHcVu5sanzw1LVreOh/6+jA1Od/kzD6OK3+k/VFRfI+no/ll9esro9hXpHKwyDXaFV | ||
| 83 | G+udfbfQD+WgU5PPslK/CFy+MM+u1joe1u3f+v5PbVdTOwvjp9A/r7nfqv44bjcOob2P39b1gZ51 | ||
| 84 | eovwqDPI3vW2ln/VflhR7+muK6O0UV4nUtGseL99cy/0drzs3Z5zjXCgrNMZrB5c6WQ3/Vv/2HJq | ||
| 85 | XOmv9r37ban8pX5ras/0Tt9q3xw/Pavph6VbhMBZCFi3kEonB85snTdjFZ5/2rv8pX5bN7OyPWYd | ||
| 86 | sgdXPDi1NzNbcAed3iJsMjyB+lPvqmafuVldwn3GyfZ+GxYVLO3Lfhp/dCuAG+klYI3O2q0n8Z/z | ||
| 87 | /opJjpNeLbY44+3CH0vPNde35JvjZPYjh9wrLKeij03aqc1fHj/Pv7V+qvDPiO1NuuFJDE7hyFuE | ||
| 88 | o6n76a2N9+vK0grlD1co1NvkY/nBh1dq6k2tv66c6cYu9cOW9kzvebXuwf3Gyd7jrabepfKH/ZYa | ||
| 89 | P9lx2HSwjGYimx7z/xivs+elcvk15aSOX+DLfj0eqadz/nkd/C709z/O6azb48bJTaR+5sCAgQsY | ||
| 90 | /RjKwlqZI/0iD7n7C++2mi57xskNmQECDtFjwFpxBnTSvK3WO4z7tYRuRfa7wQM06eUhdwCAyxCw | ||
| 91 | AADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOw | ||
| 92 | AADCBCwAgDABCwAgTMACAAgTsAAAwgQsAICwIwPW8/ks/HNjaQAARzGDBQAQ9vvoBswbTke9Xq/y | ||
| 93 | 8vfCnxfD5a/X6/1ufTnvT03fGpUzrRQAoMeA9ROMpv9cWj777rSoj+VMi3pHtKX1AQCmDg5YWx6c | ||
| 94 | qkk5s+tk45GwBQCMHBywlm7bLa2cuh/XGuw8QQ8A1OvxFmHB+87dY0PMmt7yq6wXAKDGKb9F+Hq9 | ||
| 95 | hk+vH+v5fHbSEgCgE2cKWHvkmBVlilMAQFmPtwhHs1PDr/gVfi6h/gmt0W831D/7tVRv+eMAwN38 | ||
| 96 | ejwy+WAYM/yQAQDQm9GPNy2slQkwZ7pFCABwCgIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm | ||
| 97 | YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGG/j6r4+Tyq5nmv | ||
| 98 | 1/zy3toJAEwtXcePYgYLACBMwAIACOsoYH2c3Nu+AgDAF3QUsAAAruFSAcsD6QBADw77FuGP9029 | ||
| 99 | UTYa3uxbemt2eU05r9fj+VwsBwBgoyMD1k/Qeb+eXT5dbfb14/FHZtpSDgDARr3cIqyMOE1JqLCy | ||
| 100 | RAUA7OfgW4RLUt8H9L1CAOD7Og1YkRmm6S1CAIAv6OUWIQDAZfQSsArTS6Pn3+PlAwBkHXmLcPRb | ||
| 101 | CbOvH4/FrwrO3v4b/lhDoUwAgP0c/AzWKDzNvh4tLLxVWf5o5aXlb7PJbCmxWW655ZZbbrnl31/e | ||
| 102 | m1+PR6aZf845PV+ftr63H0pYam9v7QQApmpS1zCfPBcv8JlcdNgM1ini5+M87QQA+tHLQ+4AAJch | ||
| 103 | YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm | ||
| 104 | YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWABwU8/n8+gmXNbvoxtwjOGQer1e2wvZWM7qzwJwSZHr | ||
| 105 | 1LsoV5nvu1HAeo+w0VDbMvJS5cxySADcyh7XqbKdinX9etwnYFXu7NRfDEvlfCx/2M7X62WMAtzE | ||
| 106 | luvUz2ffbw2XD1+Myp8uLJSzFPhm2+P69bhJwCrv5poBtKW6+r9IpkuMUYA72H6dmn09e/UZFjt9 | ||
| 107 | BmupzJpmmyMYun7A2nUHLyX3ms9+TFfv1W4+RgGuLXKST10mgpebm1+/Lh6wyrt2OgvaqmbKtMbH | ||
| 108 | v13uPEYBLuzsp/fy9e7O16+LB6zyrn3PnWYrnU6ZfvxIuZ23HZ0Al3f2CNJ0D/FWrv87WLP3mDu0 | ||
| 109 | 1M47j06AO/h4nTrFVWzq5tev6wesR3Hs7j1qC+VP35q28+ajE+AmzjIX8Ki+rrl+XfwW4dtwDnb0 | ||
| 110 | HdTZ14+6B7MKX09dV/6wnUYnwH0sXaceC9eXR/UDxO9PzT6+MvsLDkslFF4PC3H9ejwevx6P1PcO | ||
| 111 | /nmtZwGA3tR9HS0TYG5xixAA4JsELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA | ||
| 112 | wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA | ||
| 113 | wgQsAIAwAQsAIEzAAgAI+71Tuc/nc6eSAQA6t0vAer1eexQLAHAKbhECAIQJWAAAYQIWAECYgAUA | ||
| 114 | ECZgAQCECVgAAGECFgBA2K/HY+/frPKLowDAWWRykRksAIAwAQsAIEzAAgAIE7AAAMIELACAMAEL | ||
| 115 | ACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAI+/V4vI5uAwDApZjB | ||
| 116 | AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA | ||
| 117 | AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA | ||
| 118 | AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA | ||
| 119 | AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA | ||
| 120 | AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA | ||
| 121 | AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA | ||
| 122 | AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA | ||
| 123 | AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA | ||
| 124 | AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA | ||
| 125 | AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA | ||
| 126 | AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA | ||
| 127 | AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAICw30c3AADg | ||
| 128 | vJ6zS81gAQCECVgAAGHJgPWf//4rWBoQ0fmB2XnzANYpPYM1e+L76/e/d2vMdQy77mI99rNp2zfq | ||
| 129 | P//915d7Zjqeaxrw/Xaus3c7e+uHpfb01k7gtmYC1vsM9T5PbTxn3eSU997M0fZ+bfO/U9Ffv/99 | ||
| 130 | rimHYbccMg4PH/93OPoAejMOWJUXg8IMzfut4VWt6RozLGE0XzJbbyHQLLXzY/tbr0k1G/izzrR/ | ||
| 131 | VrRzdnlrP6+oN1LOe+G0q7vaL63tXCpn7/1SaOdS45uOlxX7a8UM7mz/z7ZzqT2p/bWu/QAjfwSs | ||
| 132 | +nRVOEHPvm69xoymgt6nwqaZocIJOjvDVC7hY1+1trPQ/qZ+TvVPazmz766o96N1XbGlnZHxn+rP | ||
| 133 | YdVb6m3thxX7canfZi21J7W/4uMQuKd/Alb9eaQyTEzf6vNUNXuarjd7ol+ablm6BK5oZ2G1df28 | ||
| 134 | 965pLT++Xx7LMxOpbY+M/+x4qLfTAAhuclzPbQPO7n8Ba8stjHo7ZaxhsdO/PpfWf+z5pPbwXkbl | ||
| 135 | pGBrvYV3K/u50A/Z9lT62n7ZrmZ7Z+N1/STxypZVaD1eCvY+vg5x9vYDnfhfwNp4C6Oysu/PYC1V | ||
| 136 | 1xqACuUXNqp87+ZtRX82FfixnGk/bJxtWu07+2W7dSWvvgW/oq4VguMwtR+Pcvb2Az3453ew6p/V | ||
| 137 | WKfD+4N//f73dKv/899/NfXDbAmZ9q2yop9n++FAO+2XY3U4/vfW27hqdfb2A8f644dGV5xNKrPF | ||
| 138 | 3leXn5aXa3m37eP9tXW116z5cbXCCoW+Hb6ub3+qzZXrb9n2x877ZYuaKlaP/xXjocbH42VF4ZXH | ||
| 139 | 17rqvplyJCogYvwzDTX3VobXrdE1bPTWz4tUuprWtW791nLq2/bX39+6KjxMPe2fpf5sbX9rP6/o | ||
| 140 | n9FFtLy95X6ePumy9355TK6dNVVsb+eW/VIzHpba+VjYX631LpUfPL6ajovC9ja1s6Yxle0HmPr1 | ||
| 141 | eLyObkNf9ptsu+FNoiC9B0CXnrNL/c+ex1zF+2S/AAAAAAAAAAAAAAAAAAAAAAAAAAAU/T9NrMo+ | ||
| 142 | adlPnAAAAABJRU5ErkJggg== | ||
| 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 | ||
| 145 | AElEQVR4nO3dzZKjuLYGUPJGDfrxeuhH9PA83hn04A582kUBkiWxBQKvFR0dLieWNuLvS8DkzzQ9 | ||
| 146 | JwAA4vzf2QUAANyNgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzA | ||
| 147 | AgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADB | ||
| 148 | BCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUA | ||
| 149 | EEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglY | ||
| 150 | AADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCY | ||
| 151 | gAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAA | ||
| 152 | gglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAEL | ||
| 153 | ACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQT | ||
| 154 | sAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBA | ||
| 155 | MAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmAB | ||
| 156 | AAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGAC | ||
| 157 | FgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAI | ||
| 158 | JmABAAQTsAAAgglYAADBBCwAgGC/aj/wfPYoA77X4/F42q74xHoCx3g8YtpxBgsAIJiABQAQTMCC | ||
| 159 | q3k8/vffKR/vp7akY2Zh3cuAQweMR8CCC3o+N26HTB34F+9vfjbjHchCYtmYKaqH61YORKi+yR34 | ||
| 160 | OvNA9nj0+qpLbbNn3fHtTnOggIAFtJqfpHnHjlcCe/9o/v78xSKmrN+snb62nozMxOX9LibYnLXC | ||
| 161 | eoAL2hWwHs6Bw9dah4ZFplm8fv0/dQJsnoHe71RNX1tPyXytd3FV/ZZMUHNG0C4X+gl/DMreM1ie | ||
| 162 | ywI7XeCouXnGJbPtj7ZbaK5nHadq+/qYn2pqs7+FTnrsh10iBD5JHddLdkm3zwTvELZ5PXH9ZmZ6 | ||
| 163 | 4EYELKBJ5r6ib/O+mjn9GZteWWozY21OD9yIxzTAXaQO1Q7hx3g9/2J9J1kqem5OD9yFgAV3Ufgc | ||
| 164 | rCO7vrqS+fo4zSJF3XWsgD+5RAg0WTz7oDA3bN6BlHkiQ/n0ixpCbmxPZaPafufXCqPqBMb2M011 | ||
| 165 | m/efezl/3R32qt6Oqh7pFP5xTmJ/C/3Mt6+os8zOYMHV7DzKOkgD9CdgwcmclqCE9QSOkjqFVbcN | ||
| 166 | uskdACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmAB | ||
| 167 | AAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEOzMgPV4PAZvkCr58b/c0jmr4GEHqrawqBkZ | ||
| 168 | c0DWVR1QZ0gXx4xn+fg8Ho/NH6Xe/0733pru6oiA9dhyQL9tGo4i9g43YGG9nJWivkfziD0ej+fz | ||
| 169 | GVvM6V4ztZ6v1PsH1DNUO1zaEQHr+a/F6x4d9Wi2rdPb7ArL9xS3meVTjL9Hrl2+UetDWzvHj+dV | ||
| 170 | 1v+zxvMq4wNRfp1dwO/tdr75zTfmws3y9ZFFI8/ns7z995ubTdXWkyly3W+qzqp2erS/Hs/MP9eN | ||
| 171 | pzqtGs9Mv5n5TX18s/2qWWhYrz7Wv/kbfOpH6ykb6tmcr/mLzXHYbLxw+tp6Mv1+nN+qnUb5Rz4u | ||
| 172 | r9r1vPyk1HrK2u0iVWeP8Swcn1q160/g+l9VT6qd5vp3bke1y5EoJwesxU7h9br2APkyX7fa2t/8 | ||
| 173 | aXM9a/kdYup4XN5Oj/bLZ3Y9/qk9/gHjWSW13KeyMWxebzPjXLsIauvZfJ0Zh2lr+dZO37Z+tm3X | ||
| 174 | tYNW8pHU+pyq82P7zWtsXr7fY8azcHzmLz4GlNr1J3b9z89vSTt76i/cf1a1wwFO/hZh70BdmMz2 | ||
| 175 | N7LTni7en800cvovLqcX0CZV9gjr7cfpR14fFkLmt3enOz97TLr62G/zND06fSeSRQTcfH9nd3um | ||
| 176 | D2lzz/a4GJ8eNdDD+ZcIN3UN2u/fpcrXtqh6StrZsw1c5ReUq9RZYuR9Vu/17erO2s90TVcN+7er | ||
| 177 | qF2fHUc416AB65gzBIWbx/qU7M5+O4mq81l5w1ZbFz2avZbe4xy43l5C7XgeMD6p/cyr1K4Za7Pf | ||
| 178 | 2kZ67wdqjXCmat3+wceRb9uuL23QgHWM2ovuX2WcMZkfje63NxlnnO9hwPHc3M/0zlipftsaIcNx | ||
| 179 | hJQLPMk9/Ji6p8HAYrqeLt7f+ONf5Z3mW2v40dvraNSwCxstkG3eX5wZ5+Zmaye4jbbx7DH9x2me | ||
| 180 | W/ebt028uAm6sM0Sx4xng9NLOvI4csB+mB5GPIO12JUUnu2fv8h/JN/++sr64lT55r5s8ZHN9xvm | ||
| 181 | q6r+TJ1VUt9SqR2H1PRt47CeLHYc9t+5UltPapx3dt1jHDLbV/n0vbfr2vGsHZ8963+q+D3nsRq2 | ||
| 182 | r7PGs6rfkvZLGmnezxQWGXgc+dh+4bKuaocD/ExT7VXt36/3HBIYVuCBv4fR6mkWNc63GZCdBl9v | ||
| 183 | Qxw5U98wnvA2X8PTMbRuExjxDBbnijrTFmi0ekIMOM6X9g3jeeRMfcN4QlcCFhtG25mOVk+UkPm6 | ||
| 184 | 6+A0MBSxjCfscYGb3AEArkXAAgAINmLAOvFrDmN+wyLzHd0xC97prvN1jP1DZ/BjFY7nYcOe7+i6 | ||
| 185 | 3/w/q/JxRiDWXefrSCMGrBNd6Fusr6883O8mibvO19VdaLvYLLVfal80O1qcupnr5r97OH77ujQB | ||
| 186 | 6wKkDY506fUtVfyJM3VM1+WHt0sv34za+Yoah+anq4T03k/qyW3lE3PQtwg/PvhuWi2h9YMTU9Ov | ||
| 187 | n6K2+TSLwn6rHv2XqmfzwY9t9jyab17P5j8z9ac+nmp/Pb+ZcWh+4GRh+1V6j0+qnXz7VfOVmrjh | ||
| 188 | a/br9a32KZG122N+/Zk3+3G7rnLMc55qx3P/cs/PV1WnH9fbwiKr9gOZ9eHjLNSOc8n85rfHzX4/ | ||
| 189 | zm/5uG3+M3C/nXpn/3GH6ZiAlVrw+RVo/Toz/WKC9ype22/IfGVeN1hftaw94KUEHmBK5v3j+Kfm | ||
| 190 | 65hxzs/Unvaj1v+S9uerSlv96/Vts9qPjUyrOe0xv7WFHa9qPPcs98JB2NyfVK0/qelrS61dH/Lr | ||
| 191 | Ye16mx+HknpS7ZTMb9TOdmdTmRY254taJ1wiTK0Ni7X2qHK69NW1/ufz+d7jDHJoKVmmJY3Uztcg | ||
| 192 | s19l8VtBfprmxgcUNb9jzuPj8dh/QDp91moL2LOd9lj/O+k0LNzeEWewnqsrBc1qd2Gb0wfWU8LG | ||
| 193 | 9rL4ravqsyXTX3Gcv+13xKj5/bZxO0vvcb7rdg0vB92DNb8GtPN6Wcj0UfXQxm+EU+LmmBuLmt8B | ||
| 194 | x219mfsAz7gbPTNd9Gj2ZcDl2NUBy4vRHHqJ8HXpZ5wNabR6OpnP4+1ntoHx+U73WO7j3CdAiar7 | ||
| 195 | H26wfn65IwJW+Y2QPZpdT5//YO97ZkPu1aj12lYbZq3Tstvz2fKSylvuPT4fP/Jt186iFvrO+c0s | ||
| 196 | 99r1Z/HiMI9/pX5a21rVj6L2D1dZb/fLL6+FI/dL9HDoPVjvf+bfr22nd79R9Wx+Km8RCmOvrpaM | ||
| 197 | T2G1VWe/ey/3zU+VTF/Yb+34BI7zx/YzbZaMW2Z923/n4p5xK5zHVP35+WqbnRJdx3N9ie3573dE | ||
| 198 | qsandv2J2j+0rf+b41Y7zh/HYSpbLlX759Tyyjtgv7QeotrtKPA4dTM/01R7N8zv1w3JenDHzNG5 | ||
| 199 | 4xbe+7CrQVthw84OXV1uubcdsI83bGEH27m8DGNv8xFOx9O6RXDQTe5Xcdd0FXLG7lqqxvkLx4fp | ||
| 200 | 4ss96kw8x9hzhqxwekbjDBYA8NV6nMHytwgBAIIJWAAAwYYOWJ2+a3r1r7Bevf6vNeaCG7OqEgdX | ||
| 201 | ft2BAk5xfsCq3W2lHiJS/nAReqgd/94Ly8owpqssl6vUmZLZTx5fDHyn8wNWxuYd9Knb6t1ufy7j | ||
| 202 | /5EhimU8MwwOnO6gxzRsft00/3Sy3o8s23wwZqrO1PNLen/tNjN9bf3l0zfUWVV/ZrnX1p/vtLD9 | ||
| 203 | TDtV45Z/zk1mJc+3s/nOutRUO/n6CxduyHbRsNzf76Q+UjKemffzM5vv4rD1KvV+7XOVorYLoNAR | ||
| 204 | ASu1I3j9P7VfKH+2786S3q8bdlhnTV9bf9X0tXXW1p9a7rX1pzS0XzILO8dnvT5/bKew5T3LvWQT | ||
| 205 | i1pvG5bL4iOLHxWOZ239mf1S1PpwyvYYuF0AJU64RDjC1puKdMd32vbx2voLE0BbYQc0eNY6M8K6 | ||
| 206 | +tGe5d4wg7UfudOyi2pzTzuD76aAt0P/FuH4m+7mL/Sv+lO/Te5vP1BU+2e1UzL9CAfs2vUkZbTl | ||
| 207 | FeKs7T3T78jbXeF6NXUbzwvtn+FaDroH633UmQbejBvCU9W87AxnR7Yfsox6j+eJRjiT8dZ7vWpw | ||
| 208 | 1vae6vcqZ31S7fQez0vsn+FyDr1E+Hw+13dOALd01vZ+1/1M7/m667jBWY4IWFfcYhc1v/Y7+es+ | ||
| 209 | VbPZMCZntR+y+HrP74nmdZasJyXthBTTqdPNj8zfPGvBFfY78uXCzXYKv4iwv6PUT6+yJcJoDr0H | ||
| 210 | 6/3PzZ9uXuZY/Kj2/eY6S36Ty8/Xdduv7XdKjH++nvVyb+g3o1/7PcZns87Cm2P2LPeo9STT5sft | ||
| 211 | /bDxLG9/s86PU1a1X95O7fhP2f1h7+0OePuZKv869Hzra/tNHQBgHI8/H56SmKou8Az9JHcAgCsS | ||
| 212 | sAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBA | ||
| 213 | MAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGBDBKzH4/F4PM6uImnk2qrkZ6R2NscZ | ||
| 214 | lrMq7z0Cg28X4Y6Z2XUvXzXI0+3m96Kz01z2xw8Wtrxz3GxHJQ4KWI8/LX70fD6fz+cxlXBR181/ | ||
| 215 | be66XVx3uVy38hKpNH9Wyh9/tMevcExfNW4HBaz3oeKWx4xzla+vdx352vmKGoe2dr5q/1LlrPXz | ||
| 216 | rttFyub8pgbh2wbnBmxH4/h1dgEVXr/Tb/5zftCav5maPtPFup3FjxZtbk4f9f7HOjMzuP5n4UyV | ||
| 217 | 1FlY5PP5LB+31PTvdzKzsNl44fS19WT6/Ti/O/dBDXWO007Dcqxaf0rqXE9cvj4sJmhelL33Y+sJ | ||
| 218 | 1l30OBa2be/rIvPrSab3wn5LGqltZ3Nnm2mnfP+Zeqd8v5Svv217H2E7uoQzA1bbhrTZTm2Qqm1n | ||
| 219 | 83VmBxHyfkmd5TM73/dttpMqYLPOwtMwVeOWer35qcx81U5fW0+qnZL5rUr5i+2irc7N9k9pp3a5 | ||
| 220 | pNrZub187Pdj+52OClH7sXwLm+McJWR55deTfv0275/zE+zZf5b0+HG/1GN7H3k7GsqZN7k/n8/3 | ||
| 221 | nnfAgV6stV3bP11tMeWpruqzQ43JdNLFx4btoqrfA8Z/tHb2NPiFR4Vmtevh/HeJPaMatd01TNZW | ||
| 222 | +c6Co8aquR3bUaErXSK8uvcOZb1i9fudsk3vekra/4bNr4eScYtavkeut4vfhrt2lNlOrZYNUssr | ||
| 223 | M9Rd+62avmF9GG1/fgrb0SRgHex9rnja8ZvEs/JGmQZd1/71qeN+fY3ggOVVJXD8z5qd3v1mttPv | ||
| 224 | OTYEusR6ktkuatcHa8iL7WiI52AVWpxSPreYPV6XfnbOwpjXVUmxvC5nczsN2XLvsR/b73WU3T+k | ||
| 225 | x+i0PtzeN4/blQLW9O9SaQi/DcsyfPEXNlg+2cueRkqm3/xR1Lx8wzb2kl9eZwms56xZq71feP80 | ||
| 226 | m8eGqoV75H5sNJv3Xe083IYs1tTEbetD/uMnLseQrvttRzdz0CXCxW9ssfczLpbT5kZbsixT7dRO | ||
| 227 | H/V+SurbGZn53Rz/1PRR47n+SHM78yk3T+OnzkKXTF87/vl+NyfeXF61Gur82M6efVxbPbXLcX+/ | ||
| 228 | e7aLVPvraxy1I3nAfmw91Klxrn2/SuB6UtJF8361dn+4/mx+/QlcjilR+7d8Pes2A7ejm/mZptrv | ||
| 229 | Sf1+fe7Q3HvBZEQdsHsbtrCDXWV5sVPbkrU+wAjmW2I6/tZtqhe7yT0kiV9d1G8kHMPy+gZVOcn6 | ||
| 230 | AN/gYgHLzujlEuNwiSKPYShur2oRWx/gG1zsJncAgPEJWAAAwc4MWAd/RfNjd4N/ZXTw8gCAt/uc | ||
| 231 | wap6Dg0AQD/3CVjuGwUABnH0g0anVRJaPyAuNX3D84Q2G2/4SMiDQDPtfHxffASACzkiYOUDx/p1 | ||
| 232 | 1IMZy54blvtIv3pK2m+oHwAYwQmXCBd/X+L4TvdPFsKDcwDgro44g1X1V6XGFHICKTMOTlABwJ0c | ||
| 233 | dA/W+5rXdM2YFVVzahyuOCYAQMqhlwifz2ft35y/JeMAAPd2RMDqkSRq2yy/yT226/nEe2pYv+m5 | ||
| 234 | XwAwrEPvwXr/s236+fuLad6v51ffMtOXdL3Zb239mRo+tt9QPwAwgp9pqrv7Z54umh9YAAAwiLLn | ||
| 235 | ItUFnvs8yR0AYBACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAEL | ||
| 236 | ACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEOxWAevxeHSdvnc7 | ||
| 237 | newsb/C5A4ABHRGwHn/a31rX6a/u2+YXAAb065huns/n+/Xj8Zj/s1MvPaaPbaffOAAA5zooYKXM | ||
| 238 | T7e808Yrebx/NH9//mKRTtZv1k5fW0+m39T0qUY2zSde9JKqs2TWNuspr3OzcQBg7syAtTiFM//n | ||
| 239 | 5uvX/1MnfuaZ5v1O1fS19aTaSU2faSRl8cF3dNusMzO/H+vJ1PmxSABg4aCAtXmmJJMwRjtBctbF | ||
| 240 | xyjN9aRiKwCQccI9WHMlJ0gc0decWAKAkY11ifDEYg6QuZGroamIigCALk6+yf0LXT0buckdAD4a | ||
| 241 | 5UGjtz999Rb1PLB5g1FNHdw4ANzVmWewFpfMCo/l62cWTNknFJRPv6ih6kkKJed1Mt9SrJKvc3N+ | ||
| 242 | q9rJLxfnrgDgo59pqv1+3O/XHpVZJSpgAQCByp5PVHfIdg/WcRrOkAEAVyRgHUqoAoBvMMpN7gAA | ||
| 243 | tyFgAQAEE7AAAIIJWAAAwQQsAIBgAhYAQDABCwAgmIAFABBMwAIACCZgAQAEE7AAAIIJWAAAwQQs | ||
| 244 | AIBgAhYAQDABCwAg2K+zC+AiHo+zKwD40/N5dgWQ5AwWAEAwAQsAIJiARX/50/i1J/ldFDhmBNa9 | ||
| 245 | GHmAYgIWNZ7P3//R1XVH+LqVA8RxkzvFns8/bnVf/DPDDfKxzhpPyxGgmIDFbvng9TqfsTg2v09y | ||
| 246 | pN5f/Cg1fYhM/R/rKSxpc/pXR+tZe7+TGbp1wZtD1FzneuL8cky1X57CAe5FwKJV+emrxTWjVIJJ | ||
| 247 | BZ3U9L2V1LP+Z3k7qdebvbytxzPVzp46113kl+Nm+9IV8MXcg8Wpag/AJx6we3Qd1WZ4bQ0NSlcA | ||
| 248 | M85gUa/fBbuQE1SbZ18avM/ZpK6X7Smpn9Qlwh4dZcZHugK+m4BFvfcVqE4tj9DIvKl1jLjKibfe | ||
| 249 | /WbGR8YCvptLhPDJ47F95xMvm+NjxIDvJmDRJHXsDLx2tvmj3sfsxU33tR/pMX2Uqn5LJv44jYwF | ||
| 250 | fDGXCCm2eBbAx9dT4okDhZ99X2DKTBNiTz1TwWW42ukXn9q8pyp189Oefvcsx1T7rhUC3+pnmuoO | ||
| 251 | V3/uUR9Pv6F+CcdIYDQOQASZ55lH8nhXt765RAgAEMwlQsr4TREAijmDBQAQTMACAAgmYNFd+obB | ||
| 252 | zz/dP/39HDMC617GHPkxqwIQsKjwmDm7lpu77ghft/K54+ci1WMq6S7ev8eww524yZ1Si6dylD+k | ||
| 253 | w7M8Yp01npYjQDkBi73ywev1i/Xi2Pz+bTv1/uJHqelDZOr/WE9hSZvTvzpaz9r7nczQrQveHKLm | ||
| 254 | OtcT55djqv3CFF41Pvk6y9vP9Dt/8bGL1PqTqT/KvK/wxoGdBCwalZ++Wl/L2Eww+QPVevreSupZ | ||
| 255 | /7O8ndTrzV7e1uOZamdPnesu8stxs/3ydFU1PrXrQ+1yzI9/ldS8VHmN/P52gIO5B4sz1R4qTjy0 | ||
| 256 | 9Og6qs3w2hoabEtX+b4+trC/zq569/XKXiIXjMkZLKr1u+oRcoJq8+xLQzvvczap62V7SuondQms | ||
| 257 | R0eZ8aka8xPr7Ncv8OUELKr1u+0jJLEFxr75nM6bvcqJtwPOoEyJ8SnPWJs37cWKWo5neY/nelSv | ||
| 258 | MgvwhVwihA+ez+fmnU+8bI7PgCNmOQJHErBoUf7MnrZ2Uj/qfXRc3HRf+5Ee00ep6rfw5vH8BA1p | ||
| 259 | psf0nZZjSSOBy7rqpCAwApcIKbX4zvnH11PiG++Fn30fSzLTHDZfqXqmgms0tdMvPrV5+azkCQJ7 | ||
| 260 | 6qxdjqn2S2JB7fLdM/1UvBwzd26V17P4Ub6daRXIxCm4tJ9pqr2b5Pdrv1EBbLJ7hAspe/5L3Rbt | ||
| 261 | EiEAQDABCyCe01fw5QQsAIBgAhYAQDABi+7y3/O6ymMOxnHMCGz+xcMD+q01ZlVYLiBgUeExc3Yt | ||
| 262 | N3fdEb5u5XP3mIv9+o1D+bP0Xu/0e8YYdOI5WJRa/0mT/X/NlwZ3/cM7AHciYLFXPnhtPq0x9fTF | ||
| 263 | 1IMf+/156Slb/8d6CkvanP791+XW789fbA7RuuDNIWquM/V3kQuX16K28n6ngvHJ11nefqbf+YuP | ||
| 264 | XaTWn0z9VXXWLt/MelVVZ2YcTtlOFzX3aB9iCVg0qn0i+VsqweQPAOvpeyupZ/3P8nZSrzd7edt8 | ||
| 265 | dvlmO3vqXHeRX46b7Zenq6rxqV0fapdjfvyrpOalqs7U69rpa+tMjUPv7XTx9P+QBQGncA8WZ6rd | ||
| 266 | dZ64q+3RdVSb4bU1NNiWrvJ9lfyZmpIudn6k2ZHLdz7N6ZtVp0F+ZS+Ri6twBotq/S4EhJyg2jz7 | ||
| 267 | 0tDOM/3X6GrrPPLEW+pSTo+OMuNTNeYn1tmv3wY96umRRUYbNxiTgEW1frdBhBwMAo8o8zkd6gzB | ||
| 268 | IP1mxqc8Y60vOUWXGbYcexutnpQD1qv3nWGLvq4yRDC5RAgfPZ/PzTufeNkcnwFH7MuX43zev3YQ | ||
| 269 | 4EgCFi1SO+jAa2ebP+p9YFjcdF/7kR7TR6nqt/Dm8fwEDWmmx/SdlmNJI3va7DEUqXuYwuvcP5hV | ||
| 270 | J0FhTC4RUur553e5P76eEt/0Lvzse9+ameaw+UrVMxVcs6idfvGpzctnqZuK9vS7Zzmm2i85TNYu | ||
| 271 | 3z3TT8XLMXPnVnk9ix+11Rk1fWayTJ3rcQjcTtdnPUtmAa7iZ5pq7yb5/dpvGACbBt89ph73AN+p | ||
| 272 | 7DkjdVuKM1gAX6HhjBfQTMACiDdggkldHzy+EvgGbnIHAAgmYAEABBOwAACCCViUCnzGT1vvno4I | ||
| 273 | wFUIWFyDW3EBuBDfIqTC/Nk5i/ffr+ePEtl8gOH6b89tPn1EogLgugQs9soHplSuqmoHAK7FJUIq | ||
| 274 | bP4ts0wMqkpI4hQAt+EMFgGibj93GzsA9yBgUWd9nml9aa+t5ah2AOB0LhECAAQTsIhUe9opNb3T | ||
| 275 | VwBcmkuE7LV4FsPHbJSaPtPO+/XrhdvhARjczzTVHavmhzZfpAcAri71RMY/1QUelwgBAIIJWAAA | ||
| 276 | wQQsAIBgAhYAQDABCwAgmIAFABBMwAIACCZgAQAEE7AAAIIJWAAAwQQsAIBgAhYAQDABCwAgmIAF | ||
| 277 | ABBMwAIACCZgAQAEE7AAAIIJWAAAwQQsAIBgAhYAQDABCwAg2K+zC+jr8Xi8Xz+fz/2N7Gyn+bMA | ||
| 278 | wIXcMGC9c8wi0OzJN1HtbBK8AOBm7hawCsNKyJmtTDsf25/X+Xw+ZSwAuJNbBax8THn/KOrMVqqd | ||
| 279 | j+2v35GxAOBO7hOwugaUzTNShd19TFfvyWQsALiHmwSsfDR5x6Pwe7AW979/9PEcm4wFADdwk8c0 | ||
| 280 | vKJJ5qc9UssrDL2VfCRfp3QFAPdwk4A1fcou40jVKV0BwG3cJ2BN2YzVO3vlz0st3lnXKV0BwJ3c | ||
| 281 | 5B6st/ltTPMck3o9ld2YlbrJvbn9eZ3SFQDczM801R3a50lAMgAArq7s62t1gedWlwgBAEYgYAEA | ||
| 282 | BBOwAACCCVgAAMEELACAYAIWAEAwAQsAIJiABQAQTMACAAgmYAEABBOwAACCCVgAAMEELACAYAIW | ||
| 283 | AEAwAQsAIJiABQAQTMACAAgmYAEABBOwAACCCVgAAMEELACAYAIWAEAwAQsAIJiABQAQ7NfOzz8e | ||
| 284 | j5A6AABuY1fAej6fUXUAANyGS4QAAMEELACAYAIWAEAwAQsAIJiABQAQTMACAAgmYAEABPuZpqhn | ||
| 285 | WXniKABwV3V5yRksAIBgAhYAQDABCwAgmIAFABBMwAIACCZgAQAEE7AAAIIJWAAAwQQsAIBgAhYA | ||
| 286 | QDABCwAgmIAFABBMwAIACCZgAQAEE7AAAIL9TNPz7BoAAG7FGSwAgGACFgBAMAELACCYgAUAEEzA | ||
| 287 | AgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADB | ||
| 288 | BCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFjjIp80AAAS+SURB | ||
| 289 | VABAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAI | ||
| 290 | JmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwA | ||
| 291 | gGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzA | ||
| 292 | AgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADB | ||
| 293 | BCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUA | ||
| 294 | EEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglY | ||
| 295 | AADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCY | ||
| 296 | gAUAEEzAAgAIJmABAAQTsAAAgv06uwAAgOt6bL7rDBYAQDABCwAgWGTA+u8/fwe2BoQYfMMcvDyA | ||
| 297 | Nrl7sDZ3fH/9+k+3Yu5jPnQ3G7HXrO2fqf/+8/fBI7Nen0sKOL7ONr3rHG0cUvWMVifwtTYC1nsP | ||
| 298 | 9d5P7dxnfcku7z2bi/k9bPaP6eivX/+51imH+bCcsh6evv5/w9YHMJplwCo8GGTO0Lx/ND+qVR1j | ||
| 299 | 5i0szpds9psJNKk6P9Zfe0wqmcHXNOvxaahz8/3acW7oN6Sd95vroR5qudTWmWqn93LJ1Jkqvmp7 | ||
| 300 | aVheDWdwN8d/s85UPVHLq61+gIU/AlZ5usrsoDdf1x5jFqeC3rvCqjNDmR107BmmfAsfx6q2zkz9 | ||
| 301 | VeMcNT617Wz+tKHfj9qGYk+dIet/1HjOu97Tb+04NCzH1LhtStUTtbzC10PgO/0OWOX7kcIwsf7R | ||
| 302 | mLuqzd10uc0dfep0S+oQ2FBnZrK2ce69aGrbD18uU/rMRNS8h6z/setDuU4rQOAshxu5NuDq/hew | ||
| 303 | 9lzCKNcpY82bXf/2mZp+6nmn9vxaRuFJwdp+Mz8tHOfMOMTWU+iw5bJfyfxuxuvyk8SNlRWo3V4y | ||
| 304 | em9fp7h6/cAg/hewdl7CKOzs+DNYqe5qA1Cm/cxM5a/dvDWMZ1WDH9tZj8POs03Njlku+7W13HwJ | ||
| 305 | vqGvBoHrYdRyPMvV6wdG8Ps5WOX3arQZ8PrgX7/+s57r//7zd9U4bLYQU1+ThnHeHIcTdVou5xpw | ||
| 306 | /e9ttPWq1tXrB871x4NGG/Ymhdmi99HlVXm+l3dtH6+vtfVeMuXHyTITZMZ2/rq8/qiaC6ffM+9T | ||
| 307 | 5+WyR0kXzet/w/pQ4uP20tB44fbV1t2RKUeiAkIsH9NQcm1lftxaHMMWP3q9iEpX677apq9tp7y2 | ||
| 308 | v/791lXmZur1+KTGs7b+2nFuGJ/FQTQ/v/lxXt/p0nu5TKtjZ0kX++vcs1xK1odUnVNiedX2m2o/ | ||
| 309 | cPuq2i4y81tVZ0kxhfUDrP1M0/PsGsbS72TbF14kCmT0ABjSY/Ndf+x5yVF8TJYLAAAAAAAAAAAA | ||
| 310 | AAAAAAAAAAAAAEDW/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 | ||
| 315 | fElEQVR4nO3dwXaqZgNAUdOVQR+vQx6RYR+vgw7+Qbr8jQqCHoWYvVcHXoJ8BJPLuR9oPw6H8QAA | ||
| 316 | QOePrXcAAODdCCwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwA | ||
| 317 | gJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjA | ||
| 318 | AgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCI | ||
| 319 | CSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwA | ||
| 320 | gJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjA | ||
| 321 | AgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCI | ||
| 322 | CSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwA | ||
| 323 | gJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjA | ||
| 324 | AgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCI | ||
| 325 | CSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwA | ||
| 326 | gJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjA | ||
| 327 | AgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCI | ||
| 328 | CSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwA | ||
| 329 | gJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjA | ||
| 330 | AgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCI | ||
| 331 | CSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwA | ||
| 332 | gJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjA | ||
| 333 | AgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCI | ||
| 334 | CSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCICSwAgJjAAgCIfa59 | ||
| 335 | wjg+Yzfg5xmGYfT7wE/j5xbmDUOzHTNYAAAxgQUAEBNYwHfV/PiLh3vxbgPMEljwfMPw7b8HN3XH | ||
| 336 | 0MuXP5sMmuf4wLsQWPB84/jf20OOD1459Krl81+aoQwATqx+FyHQGIbDOP6/S06z5jRWjsuPC78e | ||
| 337 | 3Fz/7r263PjN/Vwy6Mz+T23qju9r1XbWLr856OH763V5GOfXP32w/Ofh+Op4byDsyUOBNfg3Kzzi | ||
| 338 | 7KT79XjqxHz1qzPr3+e0pZbv55JBp/Z/yfYXDrFqO2uXLxn0kfXveH3PnrL4pfdXN1zKP77k0Rks | ||
| 339 | n6fCrxWcpZb8+iwMl6d69hDV9q9uZ+HGn7oPLxh33Zj+3oZvnvGvDpcIYWfuuOLzrhMST32D4cxx | ||
| 340 | XjXu2tfL6wu/g8CC/Tle8TksOA1fXkJ6jakbs9ohHjdzfKaO832zUMuz6b71gR/Fuwhhr77ecrjz | ||
| 341 | 2YvXvy8yVx3ns+2cPp6aQtv/6wvcS2DBzjxyxn392Tr5cK+FAz2+zukKC/d51TbPfPVTO8UoyOCH | ||
| 342 | cIkQnm/+EwrOnM1qnK18eQfP1KzJzLhrl19137sXl9+BNH8cbj7l5vGZ2v7acW++XmvXn3l9l+wP | ||
| 343 | sA8fh8O6X9fvf6P6v7Lze/32n//24yHe3m6Oz2//uYVrTn8vqmliM1jAXcys3OT4wC8msOBOpgFE | ||
| 344 | ww27PD5+buGWqSmsdb87bnIHAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJ | ||
| 345 | LACAmMACAIgJLACAmMACAIgJLACAmMACAIh9Pn2EYXj6EGxnOIxb7wIATBo3Ok2ZwQIAiAksAICY | ||
| 346 | wAIAiD3/HiyAWf/8+9fx8Z+ffy9cflzyz79/nX4VYA8EFrClszw6/vHm8q8H6grYJ5cIAQBiZrCA | ||
| 347 | LU3NP80sP14iNH0F7JbAAnbh7M6qmeVXryEC7IrAArY3VUsqCvih3IMFbOyOujre4X76TkOA/RBY | ||
| 348 | wJYeqas/P/8+3pIFsCsCCwAg5h4sYGNnU1CnnyB6ufw4s3X6dsIX7SjAYgIL2NIdH9Nwcx2AzblE | ||
| 349 | CAAQe/4M1jg+fQi249UFgEtmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAA | ||
| 350 | YgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsAAAYgILACAmsK4YhmEP497cjWEYrq4z | ||
| 351 | s/yR3QMAFvp8wRiX5/VxHJc8a8lqd3v29mfGPSw7Aje3c3Ujy7+v+14XAOCmVwTW4aedue/b24Vl | ||
| 352 | M47j1EzSs4/S2fbP/mh+CwAqLwqsq86K5PjH45n+bLLna4XjV8+ee3x8c/nU9qcWLhk3mZG6up1q | ||
| 353 | iGrmDAC4acvAmnLMrKu1cdZbl2veXD6z/cPEDNPNcR+/4Lhq3OOSw+JwnJk5S/YfADh6UWBdnUn6 | ||
| 354 | OuXP586ZqSRasg+PBMRW8THz/V4esVVHEgB4no3vwTpOq9zRBFOXAgEAtrXHS4RrXV4KfM24Uzdm | ||
| 355 | /TgmvQCgtXFgrb1EuEM/dLcBgOfZ8oNGT6Nq/hbsVdu840sPjjj1wZ7Jxp+x2YVDr/0UUxdqAeDL | ||
| 356 | Bje5H5bN+iy/PevsUt3Vx5fbubr9+TfinZl6l+L8U65uf2p5dRVy1fcFADzo43BYd649PTX/3Ot6 | ||
| 357 | iTsCCwDYm7MPRZpYa90p/h1uct/K/AwZAPBrCayHiCoA4NKWN7kDALwlgQUAEBNYAAAxgQUAEBNY | ||
| 358 | AAAxgQUAEBNYAAAxgQUAEBNYAAAxgQUAEBNYAAAxgQUAEBNYAAAxgQUAEBNYAAAxgQUAEBNYAAAx | ||
| 359 | gQUAEBNYAAAxgQUAEBNYAAAxgQUAEPt88PnDMCT7AQDwNh4KrHEcq/0AAHgbLhECAMQEFgBATGAB | ||
| 360 | AMQEFgBATGABAMQEFgBATGABAMQ+Dofqs6x84igA8K7W9ZIZLACAmMACAIgJLACAmMACAIgJLACA | ||
| 361 | mMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACAmMACAIgJLACA2MfhMG69DwAAb8UM | ||
| 362 | FgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBA | ||
| 363 | TGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGAB | ||
| 364 | AMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQE | ||
| 365 | FgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBA | ||
| 366 | TGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGAB | ||
| 367 | AMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQE | ||
| 368 | FgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBA | ||
| 369 | TGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGAB | ||
| 370 | AMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQE | ||
| 371 | FgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBA | ||
| 372 | TGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGAB | ||
| 373 | AMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQE | ||
| 374 | FgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBA | ||
| 375 | TGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGAB | ||
| 376 | AMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQE | ||
| 377 | FgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBATGABAMQEFgBA | ||
| 378 | TGABAMQEFgBATGABAMQEFgBA7HPrHQAA+LmGq0vNYAEAxAQWAEBMYAEAxAQWAEBMYAEAxAQWAEBM | ||
| 379 | YAEAxAQWAEBMYAEAxAQWAEBMYAEAxAQWAEBMYAEAxAQWAEBMYAEAAAAAAAAAAAAAAAAAAAAAAAAA | ||
| 380 | wBv4H+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 | ||
| 383 | AElEQVR4nO3dwbKjOLYFUOeLHPTn9dCf6GF/Xg968Aa3ykUaJEuwAWGvFR0dTl8sHQSIbbBdv263 | ||
| 384 | xw0AgJz/O7sAAIBPI2ABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 385 | AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 386 | AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 387 | AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 388 | AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 389 | AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 390 | AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 391 | AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 392 | AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 393 | AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 394 | AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 395 | AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 396 | AABhv/fu4PHYuwfoc7/fH/ZL2Ifji6u43/dt3xUsAIAwAQsAIEzAgnfu97/+F1lsP6XeTyypxeDl | ||
| 397 | Aayy+2ew4BMsfqbkfv/j+Z/HXXFhuvDGj628FDOs8escv0LgClzBgpP8nMif/9vvQk49LriAlHWV | ||
| 398 | 8bxKnXBZrmDBeBavbP0EsuefGq+y/Cz/svBiIy9Xbp7/rPTbdQXuuXBXSV3t99b5tv35mNTbKa1U | ||
| 399 | qf3FhZ9rMd3083a2rG9Lnev2N+Bvhwasu/dMUPJyYnua/nPxcT24zK+NlRqsKPVbyWdzi68Ktt/b | ||
| 400 | ztv26wsstlMZ25b6Xxp8Rpze/SFV54pd5a9lTfWM67CfETn6CpbfR+F0F579Fw+fSnDZtd8B26+M | ||
| 401 | T+9r5+N51txV6XfL+m7s+s3rzPMM6sj53y1CoEfpVtQeUu33tlNKqyvaidi735blZSboJGDBlwl+ | ||
| 402 | sOYSV7Yqn6Oq9Ntyx3C68PPxSzvb9dZ/Vp3AnwQsWCt7Wjr41wGcU+sWM1Z9+Uu4Sp1wfX6mAda6 | ||
| 403 | 7me5bu9+FnXFqo1wu7Dl6k77nyq/nTF/vj6eLbW12H7v75g6AVew4DQv5+/npYXS8yssfsGw9K2x | ||
| 404 | l1tIb0+06+qc/wZBsP3Fu2Cl9Wppf3odq/TalvFsrL9lpbq2y5F1An/6dbvtezj9eUT7r6xzvu79 | ||
| 405 | sPETS1f5xaAVPx9wCWetyFXG86g6zfOMbLp/7n251hUseGfd9/yH5YpF1lXG8yp1wqcQsPg63l5/ | ||
| 406 | 5sn1xJW6yngeUqfji+soXcLK7MM+5A4AECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYA | ||
| 407 | QJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYC+73+9kl | ||
| 408 | 7MJ6HWleVarO+/2+2NS69uOjd9bmGHM3AL7WoAHrPnF2Lfyhd4tU0kBXU/aEH/f7/fF4PB6Pswv5 | ||
| 409 | y97bZe9JwCQD7GTEgPU8hfw4fvpbd/Yaf5o+5axc6jRYzDhpo27vOq8yDl0MGnBRv88uoM80xExn | ||
| 410 | xsXnf4La809vn5829dJ4aflSI6Xi582+rX++fL3+Su8r1uulnkpT8+VX6O23/uS8na5xmy750svb | ||
| 411 | /XDeeHud60T22656WrZLqd+W9lu63q/fxZUCaHeBgNUYOObPr3h8m5xNpxaXrzTSpVJ/y0sau163 | ||
| 412 | XtN/Lv51Xf1vV6ql39J6rdgfSl66fkaWt/vhfKi76lxUDzSr99vV9VS2S9d+1at3+6b6Begy4i3C | ||
| 413 | n1PF2ztuz1myMl2m7k+NNiOn6mlMZuMUM34X7R2t2AmfibPxtVu23Zax2nWcd6p53tRoRz1wLYNe | ||
| 414 | wXq+9by1TZrjf/5pP/HTwPyO2Fup8b/KdvzI9V2x3XudNW5DjTPwJQYNWD/q94ae5rcAdq/sdrv9 | ||
| 415 | eVPmw97sdgXc1PiftR1XiGzuAde3943NuvY3WjFuH3Z4Apcw4i3CEc407bru17x8jGZwP6t2iVIJ | ||
| 416 | st1vfr4B2GzEgNVocfo7fk68/61l4efHy3rfUh+5Xlv6+sh7Z3WR/fCs9X35kPtZXacaaWnzQrsW | ||
| 417 | cGkj3iJ8efc8/TD72+c3vvOuf1FrvvCKbyfNlxltvUr1vPy1pc5Sv4vP19d38RNCb9t5u7IrrNhe | ||
| 418 | K9a3y+rtW6mh97psywfqe9vvHbfFu/aVfivj5q4isNGv223feWQ6TX3YF6Q3fv37w0YDAAZ3r/6e | ||
| 419 | zt8yp+YRr2BdxZZ35I3LAwBXJGBtsuKnjHaqBAAYx4U/5A4AMCYBCwAgTMACAAgTsAAAwgQsAIAw | ||
| 420 | AQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAj73fuCx2OPMgAA | ||
| 421 | PocrWAAAYQIWAEDYJwSs+/2+cYGL+tT1Ykz3+31xl6s839v+ysr2NGZVwPi6P4N1gOmM9hj7M1+L | ||
| 422 | pd7v92nZz3+Wnp+3ubj8ON5WvrGd0sK3bfvDy5mysalSv9vrGVDl0Ett9JSzxv85RKtHozI/vCxZ | ||
| 423 | er70p7fzTGm+KrVfWYXSkovbpT6ld+1aXcfjulNJV7+VRl6WL21fPtiIAetWDisbW8uqT2QHHDwn | ||
| 424 | ntjan+9tp7RwJHS2BNz5S0pnoA+7ttH4BqBd78u7lj9l/Otj0l5PqZ36k/NXlQ6KUkRY3L69s1bL | ||
| 425 | vFeZDOf/LPVS6brlTey6/bmr30oj8+Ur4Y9PNfotwpdp9D7xsmT9+dLCL41X2jlG+1ltXmSp/sXF | ||
| 426 | Ks+vKK/3ZNy1/MskFd80K8ah0tTi/lPZ3xb/WdnPr6L9uFu3/Ipi5uP/fKbyp+mT9XT15RckVhyn | ||
| 427 | XfNJqf3g/NDV7/Ovlf3k896G0WXTFayWXSc46dwb3jnNF1s8JFa089a8095173rJ4qG7pf7GTrue | ||
| 428 | 723n0kr7VWV/62rnLPc/E/n81tLL8z+6jrsVy3fVX2rnZQP9PHg5iFZ08da6+SHb/uregwd7aj5J | ||
| 429 | Oazf0w9qjrH1FuEge8nqJLSlnQGtnuW/5ICfni/3Xt+PGc/SHrJxz3n7qtQAbmlnfgV93mzw2Nl1 | ||
| 430 | /3yuS7barkvRwd7fOubq0ccc5uxh0M9glaQOmOyB92xty0WsUyJOfM4d3K5XhiqD2bu/RfbPeSOX | ||
| 431 | 28qjHe/B/WdxfghuoEr7kUO+d/XPmt+mBbw8WFwMgi4WsCJHwvyWwcYGp9MW36x0AjvlFurVTxup | ||
| 432 | 4zR+vC92UepuQNsvWl8iXZWcXslQo8GuRv+Q+6W1X6M+65D76dcnMbMah/Tx5wd196+LXTwmbj3n | ||
| 433 | 772Pu8r9zS0una7i5h9yh6fRA1bl4IzMHSPcgzhyAiq91d5vru+dgObLPwrfGNrDxu3Yu9jPqtVX | ||
| 434 | 6lOn79694vhOg/1+g72P01L7Lf1uqad3vY6crxjcoLcIK59qmv5z8U+V++7Pt5jThVfPoS3tVJZp | ||
| 435 | OfDmUePl+ZaPU6TWt9JvVz0rlk99Vmxx/Cvj07W+pe1b3+7zNVqxn0QE++0an5blG7fLot79v7T8 | ||
| 436 | HtulfpFp+3G0U/2lOkvHae88Vnq+1P7bfhtXtrffUsup+Yqr+3W79X465J/HrhUzoFLSPb6SLm+P | ||
| 437 | jouuF8A4pjNt+e1WZl4d9AoWrHahzNF1ReFC6wWAgAWnkZkAxpO5sjX6h9wBAC5HwAIACBOwAADC | ||
| 438 | BCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADC | ||
| 439 | BCwAgDABCwAgTMACAAgTsPLu9/vZJfxhtHqezirsfr8POyZT5xZZ6n3+fG+dlxj8t7aPQ6XlKw7R | ||
| 440 | 3jVfcUz4ciMGrP1mrm8w2lgNWM/j8Xg8HmcX8uGk53Xsnz/G34jjV8jpRgxYfAlnkbp143P8vN9b | ||
| 441 | 567b/cSdyv5Mu6vks6vUOabfZxew4PF4/LyN+/nny+PpYvMF5v+c+1ng2dTLa9+239LFtKne9t+u | ||
| 442 | 79sefx7Ma26sp6WLef3z9lvqKRXZ0n5vnSuU2ul6vjI+lfWaj0/Lftu4sm/rb9l5KnWW/lR/8qWL | ||
| 443 | 3uO017Tll6p6x+fWs15bSr1tOC5WzDMr6i/t56UyKi3sNI+t2K/etj9fx3o7W/aT3v12y/ruND9/ | ||
| 444 | jxEDVknvgdrY1PPx2/bbe1zXfqWRluUXezmmnsXHlXpuk9lhdfu9ddYn7q52up5f8fi2ND6l5bsG | ||
| 445 | p7H+adel50t17r3dg/PAS4PPU0XX+KxYr0Wl/TN1XFT67d2fW5paXc/e81hvO73nhcb9Z3UAvXXu | ||
| 446 | t1vWt7HOyHb/SIPeInzOVjttrb33gNKpZddOK05Z39Hafzwez+S3osHSS57PV9p8+9qNNcQbSRW8 | ||
| 447 | 0WjHUVcNKzZu7/452tx4iXmg1M66MZ+foc7aP3vnn2CdIxySYxr3CtY8kn+A+Rvf259rOn+XcHw9 | ||
| 448 | /HjMrsC/dZXxvEqdJVc5Lo4c5y2X8Ur7+VX2k7O2V+kMtaKdruVT7eyx/IedsjcaN2B9nhXh6Srv | ||
| 449 | CD/VM/XeGsbq4HD89Oj/gNopdaYcUH/kuLjQOJf286vMD2dtr8WrAKV2KsfpKfWfVedXEbDgjcqH | ||
| 450 | QsYxcm1cwk77+csV+mDLI+i903KV4/QqdQ5u0M9grXaVA3j+ueD7/V4/UEe+LXKVYe/SuFKLix0/ | ||
| 451 | IPe/9b4q8vxZDqgnsn1HHrct+3njMi3zW8qWOlsWmP/psfR9lNLCb4/TyK6yff88ps6Pd6UrWC/7 | ||
| 452 | 8fTDxYuXN+Ptr/hQTqn9ljpL9TS+6u3yve1Xlq9fVZ7X81x4+qd169tVZ6SdvffDW/kLZaWFX8a2 | ||
| 453 | vnypzt7H9Tr32+7r6mm3Yvu+Xa895qUt7VRqe7uft3fx8qd11cbnsVKdveMzb7C+3UvH6d7bt3f5 | ||
| 454 | vev8Kr9ut979/p/Hve9IjnkHw8Fs1nP1Biw40en751kFXOU4vUqdq03XqP9tT99QXOkKFjDnnSWD | ||
| 455 | s3/ernOcXqXOSxCw2MoReDqbgJENtX+eWMxQ41BxlTrH92kfcgcAOJ2ABQAQNnrA2um7oL5iusJo | ||
| 456 | g3ZwPVu+2r26xxHGfIQavpnx/zHIOLSXMcjx+9aYdQ5Y0gpDB6zI9xcWt9PGb9Evtnz8+X6xx9TR | ||
| 457 | 8hn7d7vRZpmfnf/4D0MMNQgnOmscjP8x9h7ns47fRfc/vfxpnDo/z9ABa3wnzoalQ8Khso5xAz7S | ||
| 458 | M0LJUgcb91uEi5evFr8++rPk/Ifj6r86OP1puLh1dc5/Wy/yddne3zWpj9viDwmW6ux9/m1JW+pZ | ||
| 459 | 8fsupV9N7H1JcDt2re/zmcVNWap8+3Z/28XG+o/pt2XQVrT/tpGDx793v6o0Xjq+UsfjrXMcerfv | ||
| 460 | 23a2nC/2Pn73dsD2LY1zZP48xbgBa66+geePf/5/vxR1K6S03jrnpT4PxRUT0HaVcVusv1Rn7/Ml | ||
| 461 | veOZGrfSDNL+ktXrO33wdt0r7S/uV6V+U9u9sl69+0PkuOjtt3feSO3nZ41/qv0V/W5pavU8Uxrn | ||
| 462 | lnZa5oGzjt9elTp729l1vj3rPBhxpVuEb88N4+uqc8CV2lJSanWm7Rw2RI0dRep5PB7PM8FLg2ft | ||
| 463 | Env0+3IWOUy8uwP2jb2HaMCpZtHpdbYUMODxu6hS5+lGq2e1K13BujVfSDjS/C11+wvfLjPg+i5a | ||
| 464 | rPNRvrLdtV6Vdq5ij+04wmiktmPv+JzVb1c9B+y3e88PV5l/Uo5c3xGOX/Z2pYA1v1R4YjEHuND6 | ||
| 465 | liaL55Xtl2V6J5dSO1dxxZpbRLbjiv08tf9Etkul/r33W1e2sr5tfdnblW4RDuuR+NGH/Tz+/C+l | ||
| 466 | n1JAZIhS7XCus7bjt/V7sNPnGXZl+64wbsCqT0kvf1qxvUv39e73+4B7z8aSfgbzmI8H9h6Ebxfb | ||
| 467 | Y3PsdE+q6zOwHyayHdcdyJE2I9vl5cO52xtc1/VZ7a+eZ47cRo0W+xrn4D3lPLX39l29/LCudIvw | ||
| 468 | 8ed3XF8uxU//tPiqXbNFvbZ4m6UvgFS+GLLirkrjuJXWt/f53va31NMynpXlW7pevb69su1v3+69 | ||
| 469 | y/eO8x79zttZNw7b54Hjxz+1fGmx1Hafv6S9/Xlh83EO1tll7/nhlvvC4OJr9ziu9zifnuLX7dZ7 | ||
| 470 | 3v3ncW+SXZd8375kp2Y/1TevO3AM88xnu+72vXf+7saf+lZ59CtYO23Ci+4Zq133HQBwFeaZz2b7 | ||
| 471 | 9ho9YLWwpd8yRMDezDOfzfbtNe6H3AEALkrAAgAI+8aA9TFfAV2ntPrz57/zu7XbxyFeQO8CnP59 | ||
| 472 | /iMdU8DpqwmX8zkBy/F/jLPG+ZTffTnAaCs1Wj1nGWccxqkE6PI5AYu4FT+dtVMlezc+bNeLRqtn | ||
| 473 | QF81RF+1snAhI36L8OdnKhZ/OHTxa6LrfkWtq/2XZRZ/RaOl30r783oq/Xa1fyusbOX529Jg1se5 | ||
| 474 | 8uTierWPf6/5L9S93V5d4xCvs97F6nFu6frWdhz1bseufoPtL9bfe/zuPZ+0NFJafj4JLG6synzS | ||
| 475 | VeeKwQeeRgxYt9kk+Pj7v5m6OFEu/jXYfksjG5cvPe5Sar90Rqn/3tr8t3fr4zxfvnd9VwTKkpcG | ||
| 476 | n6eWrvFZsV5biix18bLA9np6j6PUftsy/lvaf5oPUVc9w84niy0srmzLGL6ts35cAG8Neotw7zdM | ||
| 477 | pYhwfKfBrlsaKS1z8DvUU8a/xZYxPLiM1GuP7GvxtXsfF43OGofGNrsCX/wwH+HYhMsZ9ArWWRbf | ||
| 478 | qE0vfszf7W1vP+jqbzSvMj5DjfNjdic0u/ztOtuly4px6NW1XpV6tlzNbTHU/gwfQ8D6x4rw1DXr | ||
| 479 | bQxnp7e/twPqj5ylBhznZ/q/9VyE611+JyeOZ+84rGt/ez3zG9xZLlDBHga9Rcjtz09XjHAWZ3CP | ||
| 480 | x6Px40frlv9Uo43DYj1DVQi0ELCWLc5u9TeRXdNf48It/Xa13/v8WQ6oZ7GL7fd8f7bX+rL6HXyf | ||
| 481 | +uV7EpF2Ig32dhrsq/Ez9RsXaM9YWw7zxu1y/H4Ol3OlW4Qv88tL5tj+iYrHn99h7p3v3vbb235j | ||
| 482 | s2/b7318m8ynpbsVL08uLh8cn0o97Ur19PZb3469Vxq69tv4OM+Xn9dTWf5lKNb1u+64aNe4z2+Z | ||
| 483 | TxbHIbtdpss8/1Q6LkrbpavOvbcLfLxft1vvpwT+edx7ZWXvj2p+NqN3FV+ypUZbzXvhmyjfprT6 | ||
| 484 | Xz4s8GPxLUqzviPoSlewvlDXO2BG4DR2lu3XsAGCBKyhOVVczvdssgHXdMCSjlcaBIMDB/MhdwCA | ||
| 485 | MAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACA | ||
| 486 | MAELACBMwAIACBOwAADCBCwAgDABCwAg7JIB636/3+/3s6t4r7HIS6wL881kw/348nH48tUHSn6f | ||
| 487 | XcCylznr8XhM/zT959cyDt/p59Cw6c/a/x13QKNBr2A9Ho+fWez54IquWzktTtm+A+5UA5YEcLpB | ||
| 488 | r2BFvLzXnP5zeoVs+mTXpbL5AvMu5gvM+33509vT1XPJeReV9utNNbZTGbcV9T9f1bJdFtvvWt/e | ||
| 489 | fm/VjdK7fdv1jmel39Tzb7ueHzhd26tru1f2/3qRje1Xlq/029VOZPsGj4vecajMe8DTlQLWiom1 | ||
| 490 | 1E72nuNiC9M5622/pceLfv76dprrDYjPf/Y+31v/fBWeU3xX+yu2Y1e/pUT+bKp9+/bqGs/UdlxX | ||
| 491 | /3wcSvWn9qvS/l+S2q8q/fbun5Htu6Lfli7a25GroG7QW4SLHo/Hc6b7gAN7ugojrE6phufzlSL3 | ||
| 492 | rv/08WmMGkd2l2pkj7FNDdfe45Ba9952zup373aAqStdwbq6x+zO1LlW1DO/VnG80i2MLUZrJ9Xv | ||
| 493 | 4vOV7b5r/Rv73XLUjLZdpvaYDUY4TgEB61DPa++3MWJWVz3zWwa71tZiqHfwJ47PYv2Vekrb/Zgr | ||
| 494 | kQf3O9p2+eB+gakr3SLsNf10yAhp4OnnFuc4JY1WD8c4a7vb34Bv8MkB6/Z3xlrxYcw9Zv/RziiN | ||
| 495 | 9SwuNtq63Ha+zdfb+OLnvtsb2bIub+vfst23OKvfwxofs+uD++3az+GzDXqL8OXK05Yr3vPXvrx7 | ||
| 496 | nn6I+/l8yzvs6WdKXupcrL/U7zrzTnvbbxmH0vN7XIFI1Z/qt7K+b7fvfHy6RuylqfZ+W+rv3e4V | ||
| 497 | XcdpsN/pq7r2k67jerGedf22LJ9q57DjYrQPlcJoft1uvd9/+edx75Whc7/W60vFnKtxD7SjAuzk | ||
| 498 | 5UdJOl/dNzMPegUrJXjFCLYQmwC+yocHLKc0BtG+K9ppAT7Ah3/IHQDgeAIWAECYgAUAECZgAQCE | ||
| 499 | CVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCE | ||
| 500 | CVgAAGECFgBAmIB1Aff7/ewSdjHmes2rGrNOAEb2++wClk1PaY/H48RK3rrf74NX+KO3zp9NMH9J | ||
| 501 | 6flUv5d2of0WgF2NGLBeTslfdYZedMrqPx6PxSs3pefXdRFpZ2+NddpvAXgaMWBVlK4QLD7/c4Z7 | ||
| 502 | /qnlbFdpZ7rMzz+fC79c1Kn0u+IKx/yKUW/7pTrX1VMpsr3f+pPzdrq243TJ+aaZt//yksXWWuoE | ||
| 503 | gKetAevtxYztp5+WoFO6clB6vKj3CsRi75V+113hWLxi1NV+qc7UFZfefkvrldqO866fEe3t/jMf | ||
| 504 | 6vY6JS0AnjYFrJ3OKPMLD/XeK4tFKpyem9tT0U7FtDfVmEKOKWb8Lp4dRd4zuD8I8OUGvUU4vQfX | ||
| 505 | e2tvi1I7jZmv9Nq37UesKHLvcRvNMesrXQEwaMD60XjRaH7LZmOPOwnWWdIVTFP1HLBeKZHte6H1 | ||
| 506 | BeAsI/4O1oBnrJ9zavALdLu6UKkfyeUrAEYMWI0WA0QwVUy/BDf9vFekiz3Sz5Y2v+1e4S20/+y9 | ||
| 507 | EwJwUSPeInwJMaVws/j8lgBUar/xVS0fKu+ts/5LB5X25wvP66zUU/kFivnz9fVaHJ+37bxd2RVW | ||
| 508 | 7D8r1hcAbrfbr9ut7zS25aznw78AwFnqv8vzTl+AufAtQgCAMXXfIiwHvuIPHPR2AQBwaa5gAQCE | ||
| 509 | CVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCE | ||
| 510 | CVgAAGECFgBA2O9cU49cUwDAse73fdt/XCUnZOp0BQsAIEzAAgAIE7AAAMKCn8H6BPfJHejH2rvF | ||
| 511 | 9z9vY29pZ/VrATjefN7+kJn88fjjE1ov/2SJK1j/5KGfw+DpvmHvSbWzKN4gAFt87Dw/jYZdMfED | ||
| 512 | MuVm334Fq/G9ReTKVqWdt+1P6/wJbZ/wlgjg+irz88vj50vezv9DzPONl6mmRT6Xv99d5frqgFXf | ||
| 513 | fRePkLevau/u+c+37c+fGeLYA/h67e/Se+f/k+f5eTxazEyVW4dfn7G+9xbhrjvufWJ6tLS8tvH+ | ||
| 514 | /R43HwFotzg/PyfnFWeZxffSG4tcIxWMfjLWt/rSK1j1/f65Q69OYKV3JL2HyttrbK5jAZyiMv0u | ||
| 515 | Ts6L8/8zQnU1ta9KulpxUeqLr2N9acCq77LPK7fZTueXgt++pF6ndAVwlt7o03LGmS9zwjyfjUTf | ||
| 516 | mq5u33yL8Cq32Ep1SlcA5wqeRxa/dX7aPF+5tdd11++L09XtmwPWrXps7J29Ku3P/zTQUQfAxLqM | ||
| 517 | Nf15oMoyZ87z2z8+9d3p6va1twifptd4p8dJ6fGt7YNZla/drmt/Wqd0BTCOlnuFpXm+9PwQ83zp | ||
| 518 | XuE0e73ksOfCX5+ubrfbr9R/Nbrkz5EfYI8BAOb2jkQDBIC2r51l6vzqW4QAAHv49luEAMDtNsQV | ||
| 519 | pk/iChYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 520 | AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABD2++D+7vf7 | ||
| 521 | wT0CABzs0ID1eDyO7A4A4BRuEQIAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAEDYr9vtrN+m | ||
| 522 | 8oujAMBoMrnIFSwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBM | ||
| 523 | wAIACBOwAADCBCwAgDABCwAgTMACAAj7dbs9zq4BAOCjuIIFABAmYAEAhAlYAABhAhYAQJiABQAQ | ||
| 524 | JmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQ | ||
| 525 | JmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQ | ||
| 526 | JmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAPEh2noAAAUSSURB | ||
| 527 | VABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 528 | AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 529 | AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 530 | AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 531 | AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 532 | AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 533 | AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 534 | AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 535 | AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGG/zy4AAOC67ovPuoIFABAm | ||
| 536 | YAEAhCUD1n//9+9ga0DE4Afm4OUBrFP7DNbixPev3//ZrZjPMR26Dxuxn1XbvlL//d+/Dx6Z+f7c | ||
| 537 | UsDxda6zd52jjUOpntHqBL7WQsB6zlDPeWrjnPUlU95zNV/W97DVP6ajf/3+z7UuOUyH5ZT98PT9 | ||
| 538 | /xuOPoDRvAasxpNB5QrN80/Ts1rXOWbawsv1ksV+K4GmVOfb+nvPSS0r+LPMfHxW1Ln4fO84r+g3 | ||
| 539 | 0s7zyflQD7VdeusstbP3dqnUWSq+63hZsb1WXMFdHP/FOkv1pLbXuvoBXvwRsNrTVWWCXnzce455 | ||
| 540 | uRT0nAq7rgxVJujsFaZ6C2/HqrfOSv1d45wan952Fv+6ot+31g3Fljoj+39qPKddb+m3dxxWbMfS | ||
| 541 | uC0q1ZPaXvH9EPhO/wSs9nmkMUzM/zTmVLU4TbdbnOhLl1tKp8AVdVYWWzfOe2+a3vbj2+VWvjKR | ||
| 542 | WvfI/p/dH9rttAMEVzlu5NqAq/srYG25hdFup4w1bXb+7rO0/G3PT2pP72U0XhTs7bfy18ZxroxD | ||
| 543 | tp5Gh22X7VrWdzFet18kXllZg97jpWLv4+sUV68fGMRfAWvjLYzGzo6/glXqrjcAVdqvrFT93s3T | ||
| 544 | ivHsavBtO/Nx2Hi1abVjtst261pefQt+RV8rBPfD1HY8y9XrB0bwz+9gtX9WY50B7w/+6/d/5mv9 | ||
| 545 | 3//9u2scFlvI1LfKinFeHIcT7bRdzjXg/r+30farXlevHzjXHz80umI2acwWe59dfiqv9/Ks7e39 | ||
| 546 | tXW9tyz5drHKApWxnT5urz9Vc+PyW9b9tvN22aKli9X7/4r9ocXb42VF443H17rujkw5EhUQ8foz | ||
| 547 | DS33VqbnrZdz2Muffh6k0tW8r3XL97bTXtu//v7WVeXD1PPxKY1nb/2947xifF5OovX1rY/z/JMu | ||
| 548 | e2+X2+zc2dLF9jq3bJeW/aFU562wvXr7LbUfPL66jovK+nbV2VJMY/0Ac79ut8fZNYxlv4ttX3iT | ||
| 549 | KMjoATCk++Kz/mPPr5zFx2S7AAAAAAAAAAAAAAAAAAAAAAAAAABU/T+x9xtLJOr2IAAAAABJRU5E | ||
| 550 | rkJggg== | ||
| 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 | ||
| 559 | AElEQVR4nO3dsbarOJcuUNcdFfyP16Ef0WE/Xgcd3GB3uXwMkiXxAcJ7zlGBy1uWloQQy4A5f91u | ||
| 560 | jxsAADn/7+wAAAC+jQQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBM | ||
| 561 | ggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAA | ||
| 562 | wiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQL | ||
| 563 | ACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJ | ||
| 564 | sAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBA | ||
| 565 | mAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2AB | ||
| 566 | AIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJ | ||
| 567 | FgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAI | ||
| 568 | k2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwA | ||
| 569 | gDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbB | ||
| 570 | AgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABh | ||
| 571 | EiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUA | ||
| 572 | ECbBAgAIk2ABAIRJsAAAwiRYAABhf6cqejxSNUHG/X5/mJdwLPsdV3G/71u/M1gAAGESLACAMAkW | ||
| 573 | /ON+/7//IsX2U2p975BO7PJUjAPQQIIFLx6PldsJ3w6oq2XqnjnZ9mPz/T4SAHvnxLNlXal4ZusX | ||
| 574 | XIcEC3b2TIl+/tvviFXPura3O5bVTXKEDqakslugQexXhEC31+Tjedj+Scief2o8nP+Ufyu8WslP | ||
| 575 | /cv/rbe7rL9Sviv4lnpuDeNT6le96fb6Xz+yGuTbn1Lx9MZZimeg/lI9QINdEqz7JN9ZYUItB+DV | ||
| 576 | 1/UD3vLcWKnCispHVs+9leKMtNs7Pr3G6l+Ow2q0wXh64yzF01v/hn45BDCzwx4jstcZLM9B4XQX | ||
| 577 | XuVXd5/Ugby33WD5qdqtVDLD8tUSwx5xJuq0/jOtI48LLhECa37DMbJlqY2Pw7LRw4Z6tb/Pc3K/ | ||
| 578 | YYvDgSRY8KUGbuS6dLu9lpfGjnHimJSafr0GPfMmg0vxK0L4JHvIOfjC5VnPdPAsiddE8xJXq/f+ | ||
| 579 | lSv8MhIs+OTSh5z687f261rXc796w/hYPl7hmJ98Zey2ucMeG3vp6Q0Tc4kQdvZ2VuB5rC29P2D1 | ||
| 580 | B4aVX4e9XsJrOb52/WJ/4PEEq1cVK+PzsfzbZ1fjz45D6U6m9s2anSfLeMbqd4cWjPrrdsvsNn+u | ||
| 581 | qP41dc7XPQ8b7xy6xA1Gt6FE55R2ewM7rCNZFw27n/Wfmb3Oz73P3jqDBf9oPzdwCcEzZJdod0LG | ||
| 582 | AX4xCRZfy9fo0w7qXe2e9fCtA1wo1Bz7HddROoWVmcNucgcACJNgAQCESbAAAMIkWAAAYRIsAIAw | ||
| 583 | CRYAQJgECwAgTIIFABAmwQIACJNgAQCESbAAAMIkWAAAYRIsAIAwCRYAQJgECwAgTIIFABAmwQIA | ||
| 584 | CJNgAQCEzZhg3e/3s0OAy9hpf1lWu/eO+VZ/vLljFhbLV0njyEw7gKnADu7gbOM5Wzy7OjPBuq85 | ||
| 585 | MZ66mWP7zSafNk+pOC/R2dt5cV5lfHpdZZ73Ojhrj5ffu57ZnDWeF3VmgvX4x9traHeVOXOVOCv2 | ||
| 586 | 7sLV69/VpYP/cfUupOK/+jjQ7u+zAyh6Zr6v0/E1HW6Zpqvl7/f7W52vf1ot//riYzyvkS8/Ugly | ||
| 587 | Wb43/o9NLOtpH+dS+VI8wX51bffs+Kz2qzIOq+MZibMyD29/jna9Xy1NLAvXG7017C/18SntKQPz | ||
| 588 | rRJqY/xd23E1yI/1L+MvlW9ptzH+SPlKMMvuv3VttfL2+Vxpehnn8Lq9ff5E6qm8X1Ip3zsfXsu0 | ||
| 589 | 7F+VYPZbr+Y3aYL1tme+HthWy3ysZEv51dbr9b995GPTq+UHEoWufpVe95bfu1+pcQjW3zIm8Tgr | ||
| 590 | cym+v7yudM/W397s3V9KcZbqr5dfqu9r7fH3tlsat7PWq9LrYPm61ZLL8R+bJx+bG163U/MnVc+J | ||
| 591 | 82FV47GspXx2vs1sxpvcb/tkr711nr51UwFU6rncmBwQQ0v9pTJnjU+83YEKt4xbMIyI4XZn2EFu | ||
| 592 | +4zzkV3b0lbjt764vZfrLf2aZFo+zRbPfiY9g1Wy/I5b8Wi7QjdcvjeeAan6945zVwPbZar6T7Tr | ||
| 593 | dt84bt832kur4/94OYm7/NZ+fDxvnvFcZb84a92ecF269Dp/u378SxdLsMa+mbVP07HyO0ktvgcv | ||
| 594 | 4nvo3S6z1X+WY872fd+4pcx2xm7v9fMsXXEG18Op1qWvWee/yaSXCLMej8fjz7s4n69LXzGXV8rn | ||
| 595 | 8TH+gx0WT+N2GY7n4O0+23YcNvn+wkZX2b5nxbl3u1cZf5YunGB9nHCVAj/zNZvy77oDLO8PXcY/ | ||
| 596 | UE/KcDwlbzcL7xpPS/3L+1KHq3oVH7eKrtgGxmQPW/bxU1Tief1Ty3bf0rXI5pttbEv2Hqg9PttS | ||
| 597 | bTC2LVc/hmPY6CrTr+5KlwjfsviWm/4q5Zcf/1j+7VRtbzy9Smfdepur11Mv397QWDy3wnhWYl7N | ||
| 598 | iZdn0feLZ/mnj+9H4nxrYuP8r5d/++xq/L37S0VpfFbH8+N+sWx3IP52A/P2Yz0b4/84bhvjqZdf | ||
| 599 | boL6/G+fJwNx1tft/ebP9nqC+2/XfBgYn5ao4vPtEv663VK/ffj39THfyFOuFe3SbPF/fTylCjc2 | ||
| 600 | NNu4cVEmElTc/3xIRKFUZg+60hmsoKtnyrPFL54xV4kTgF7OYAEAv8KRZ7AufJM7AMCcJFgAAGES | ||
| 601 | rJjv+FnphL7m9+QHO2zceuv5eUJBpOmIvYO5+vhkbe/awHhubPEUs4WdWk9m69euvucm999z49d3 | ||
| 602 | 9/TqvTs+/tUFa9oxPGv7XmVeVX6jept4swJL35Ng0egqR5p2X9adXq83bHYNRWrcrj7+e8cfqX/5 | ||
| 603 | RKJfa+DRcTtFwivjvHRmgrV8mtnqvf2rD2pbLdz4Je++eID7WLtvXag3+myo/iDKxvcrfemKc7jd | ||
| 604 | ZRjL8pX+1itZ3Y71LjT2ayD+1zL1eVKJv15++7MWK3Ydt9V6erd7qd1SPb3rRsu8ahmHgX6t1j9W | ||
| 605 | z2rNvfMztf4M71/b15/eeRvZvqesJ29/Gm63N/7l97TVUCPbpSWeSzv5DNbP4D6333OKr07E0vur | ||
| 606 | fx3Q225pD2lsoqv+5f9+LFCK8+MO/7HdSqfam1uqbMdKPctv9sH4u8qX4q/Uvzr/K0332nXcSvWU | ||
| 607 | 2i0lOgPzp2vdqI9t1zh0zedS/aV66olgu974t6x7y/+tx/M6FGP1987b7dv3rPWk8rqrnrH9erVk | ||
| 608 | aj0Z2I8u6sI3ue+9VbrqbyxcWuIHPruclzsNyJZqUyEdGcPe5Y901rYrzfNnxrNlf4kUHrPrfB4Y | ||
| 609 | n0i7A2WGyw/068j98fTxeSt/2DEo28THz868ZmZd6R6sx55XUur1N56gGtZbfynrH6hn+ebe47y3 | ||
| 610 | 3vj3Ln/bf/5ETL7dW6K6xDgfIDUOe68PkThPPC6cEk/FV67nl3alBOv2crb/ts90KdW/69Rcnkr9 | ||
| 611 | +JHH4oJIpZ5H+YaPUr/2Hue99cZ/TPn5XXq7D+xH32rvM8epeZKN8/jjwlnxrKrM/0vv15d2yUuE | ||
| 612 | P6fQ91tA964/ojfCgesOlxiHit7438q/vi59Nbz0+JR8a7/Imm2ezHZc+G3jw9KVEqw9ZsbbTZfD | ||
| 613 | YWz5bGOB5Z8qe8vqfbU/PtZ/9T0wcp30x88IZ0+NtE+VgzfE1bf7q2/qS4uudWOsqsj6MBDnljUz | ||
| 614 | IrietJSJdGfguLa3ScI42IyXCN/yhuexrfT+218/nqcpnaXobbfy2camx+JZVvj4597Y0tmXt/xg | ||
| 615 | Wb6lvy2dainfWFtLPW+Lfr1fH1tcLb/8eO88zI5PRGTcSvX0So1PfX9cnVepcSiJjE9LnL3rxqst | ||
| 616 | 615v/VvW21v/9jpgfWgvn9peLe1G5kP7Urz3fnRdf91C/2r06+jdv/qHl8POGpZSgkUX4wZwdfc/ | ||
| 617 | HxJRKJVZ6mc8g0WWbxLDjBsAYyRYxznxCC05GGPcABhzpZvcAQAuQYIFABAmwTqOX92PiXek9ASE | ||
| 618 | c0ds2frBvz/fY5yzFQJcyDckWL9zHT/+OUnHOCCr+Hng3n7171Szdl8bfaq/CXCWb0iwNrrochxP | ||
| 619 | ES46DkGz3dK+dzwXrf+ZIv94+6Xn8k2AU5z5K8KfhXL54M1b+efxH382v3zmU72et0qG212GUSrf | ||
| 620 | 3t+B51eV+tVbPtLfyvatV7L6dLuueTJg9SmUXfNz4KmSlcGpD0JLu/XxLwW5LF+ahy3bqzH+rnnS | ||
| 621 | 4rH2j3UCHOnkxzS8PfLruXCXFvR6wlEvsFpP6XVXu5VOtTSXehBo2/PTiuWHE7ve/pasjkalnoE4 | ||
| 622 | X1+8FV497dHVbiX+UjyV7bWMZ6Ddyvi397ek3t/2+HvbXQ0DYDYnXyIsLc0Dn12uyzutvL3Vvh3V | ||
| 623 | 0uF8bvREqTBSZzWeGcnYHBsus0cle8R21rSZZLoCBE36oNHeWyhK33oH6lm++Wj+J5nGyjPsyFtt | ||
| 624 | nlvzrO27sV2zEeBIMyZYlfuoSlZvuSjVU7nho3QQer3ppP3MweRpVvzGl+Ode8bl+O17iXkFwO30 | ||
| 625 | S4RBq/eU1MsPXEDpaqW3/CkGxoEfZ23fS8yrwxgHYE4nJ1gfF8dKgZb7giuF7//4WH/kOuNG+8Xw | ||
| 626 | cRyu4rAunLV9D+jglv1xKqvns68SPPAdTr5EuHqV6u3N1de3wiWS12uFpc9Wfo21Wn9Lu6VObSlf | ||
| 627 | 6fvqD+Iq5Vf1jkNv/GPa7zQKtlv/gWFXu2Px927fLe2W6l+G9DHOUrsD8ber1HP1S97AN/nrdkv9 | ||
| 628 | zuvf140/tO79PXZK5efiv4pxAOBXuVefj/OPzKFwxpvc95Y943JdxgEAdnJmgnXiEV0y8cM4AMAe | ||
| 629 | vudXhAAAk5BgAQCESbAAAMIkWAAAYRIsAIAwCRYAQJgECwAgTIIFABAmwQIACJNgAQCESbAAAMIk | ||
| 630 | WAAAYRIsAIAwCRYAQJgECwAg7O/eDzwee4QBAPA9nMECAAiTYAEAhE2dYN3v9/v9fnYURTPHdgm9 | ||
| 631 | A3jRAb9o2Nsd3PHh5lJxXmVDnxXnVcYHUk5OsO5/evvT4/F4uOer02yr2G+LR3/5JgfMn9UmJv92 | ||
| 632 | zbBftVlPTrCeKZRc6hfq3eJmyLVcZXul4vxt/Y20WwrmKoMJFd2/IpzQz7mu1f99TZZf3yyVrzSx | ||
| 633 | rOftT291rpZPvV8P8ufFlnoej0d7v0rlK/HU31yNc7VTvXFWqiq1266lvxvb7ZrPvf19jfDtI73j | ||
| 634 | WX9zp/4ue/GxX71xds3Pevyr86GkK556/e37UX37rga5bOuttj3Spkr8pf0iMv6960/l/YF2l/3q | ||
| 635 | jbP3OFjZvsP9bTn4XtqmBCtyWKpUu3GfHEikeutZfV3fsbe/X7L6qYF6evtVel2K5xnt27niepzL | ||
| 636 | 8r1xBsdnVaW/veO56oD58PaR59LcNZ7Pqrq27/b+3spzcrVfvXH2zs/e/aWlU43xVOpv34/q27c9 | ||
| 637 | 4Eq7KV3j2Vt+7/V/oN1InMPqgbX39+uzq9v2M1h7DNDwjn2Mt9Vq1/rPUjpkdpXfI4aWMjMM4JtI | ||
| 638 | SGf1a6d2e6sdng8blerc0tYen92yLk24y3Q5q79nzcleM8TwZtrje9Y3XCK8usfalYsf+33nG9MS | ||
| 639 | zwy7Te+4nTXO3xpnRGW/OKXd2eJp/3g6oqnN3N/I/v56Unl5luhjnXuMT6ndyvszb6YgCdYUnnvL | ||
| 640 | bds30V0N7MynmGTRadHV7lnjf+J2L+0XZ7U7Wzxcy95n2mZbxyrv/5Ica+rnYDV6vbo/7VG/xePx | ||
| 641 | 2PVOBbiis/aLUruzxQMDzj1u/pKZ/A0J1u2frTV2P2ZvW/Fp0VjhkdPxY1sHBNPSxB5xLm9VPmbk | ||
| 642 | u1rpPSefEqw/su2WG2tTTNVKJr8+uyW8rz/UndjB1HR6Ld9yvGs8cz923Kxo7+9qjnXYenuMky8R | ||
| 643 | vmXQ2Xs/37bfs8Djz9+sftycpXp6y6feb2x9Sz1vQ7T6ZuNusHoHyep2r8RZmicDcfaOT+83rfY7 | ||
| 644 | ZrbMq5bXpXhS7Zbqv/Vv34/tluJfllnOh4quOHvn59j+uxRcH7r2o7c/tW+v5UdK7fa+32VsvarX | ||
| 645 | 0xJManvtXb6r2K28fbf097G4VvhlZ7b+ut16r/L++7qU+WYz4l7ntv4FrjKAh8V5lQGBAaY3t5mm | ||
| 646 | wd6R3P98aEWhVCaAL7nJPfJNEZbmWXcAgiY8bn7ZevslCdY3bZLTXWUwj4nzKqMBY8zwX2vCTT9N | ||
| 647 | SJkzW19ykzsAwDwkWAAAYV+YYK3+8vOUSFJS8V90HHYK+/h5ssczBXat8MRWvoCBWjXPsFhXv6mh | ||
| 648 | ObfCFyZYk+jd3lff268ef6+rj/Nsrvv8m/uas4MqjmcqvKvM/9+2LjGVX5Fgjd03N88elbrvb5r7 | ||
| 649 | Bye19/hcvf5dXTf4xz/eXp8eVdf7v5B19Ri/eXxmedDorfDgvtf3f37AufpAvMrTBVefgjhQT3v8 | ||
| 650 | lafk9Zavv7lTPZX3V/X2d6CeW2HT9P7MuGuelOqvPB2x8sDG0iMTl+Xvi3/77/HyT9HVQ22MvxLn | ||
| 651 | qnqnGuMvlW9ptzH+SPms7LzdWE+k/oH93bpaf78kdXxsaWLLul3a32+d47ws9rb0leKcNoc7M8Gq | ||
| 652 | HEgqC/TydWkF//FYezJsSz3DE2u1FwPlS/HvXU99h1mtuau/vfXcGrZXS/2982RgnCtTqH0elqS2 | ||
| 653 | b2+7pXHbMv4by/fOh8j8GRCft3vE31t/7/5e3+/a4/lt62rq+NjYxE77Rde61FJgeF6dYqJLhC1b | ||
| 654 | 8WOZxqkQX0lb6tyj0WC1pXp2CrtLPIaBCiPzc3sYEcPtzjAZbvuM8ylrwiR1HtbuHvvdL1lXn+Ur | ||
| 655 | H7zK+hM3bUfOPIP1KP8rV9MmpK8q8ZdE+jXQ7lT1B+06TzaOw/yjt93q+D9e/n2x5bfP4+N583qg | ||
| 656 | Omuez7a+peI5a337bevqDPvRU2V/j9Q/UH4eJ9+D9dwqtz+n3SkHp0f/BexS/KuCB5uudiesP2Xv | ||
| 657 | 2K4yDmeZ7RvzWDzHb9/Z5tLeZ2vG6rGurjrgS8uc++kVTfFP5XQlv8cEM/CR4+Pfu92ptsuJjMN3 | ||
| 658 | s33nZF3l6s68B6sx9e7K0Len8/d/7NrWWZ9tqfai52Pj8+SAcfjYxGzbohLP659+TgbXDyF77wIb | ||
| 659 | x7ZxEdhutsslpfojcVpXt9fz8c2NdQ6Uadnft9T/sfxs6+TTX7fOf7zwdQBLA9o+0G+Lcv39+q8n | ||
| 660 | noUrPy4o3RdSf38g/te/rvbrLc6P5d+aGG63sZ56/SX1dofradnujfV3zZOP9dfjXG33taqf8qtX | ||
| 661 | pXedJ1vmeWXcPgZZKT8Qf33cluXr/WqMv64+sJF5e2vbv1rGs/R++/7bvr/X5/OSdbWxnkf1fsd6 | ||
| 662 | E737UUuolf391jw+j8XNaql59fxUaY9o0JcvnZxgTWXgwAMczI4JDDsywZriHqxJPP58YodFHAAY | ||
| 663 | I8H6g6QKJmcnBS5hogeNAgB8BwkWAEDYNyRY0/5E87t9HPbtBQDgor4hwaorHcUPO7qfHgARthcA | ||
| 664 | 7b4/wWJac96tLJECYLuTf0XY+yDBlqqWj7goPbVs9UGRvQ9eqz+QsOVRYWMPTuyKMzXOpcIfx6f0 | ||
| 665 | fks9W+JsrOdj5Z69BECXMxOs+pOOWx7EXP/s6vNtK++X6hl+AGn7g1h72+0qnxrn0vPZxup/e+rY | ||
| 666 | TnG21POxctkVAL0mvUTYezxLHf9a6lmma9tb36O/qTJbPthVf6XwkdsXALbzoNHPlv80Uosv+3eE | ||
| 667 | 6lL3LR15/9PG05AAUCHBavK8lnRzFmRNZEyWl/a219li4IY/AKiTYHUo3dJ0W7tZ+/ecvvoOthcA | ||
| 668 | QZPeg3WW1bMmvadSBrKrgSYiZeofr9TQ+KfhGNo/WI+zq8W3qurZVapdAL7SmWew3n5HttOpgtId | ||
| 669 | VKvvr14tqscZCbu33a7yqXF+a3T1dUuct8KTMip1Dsd5a+jv8K9EAaDkr9ut9/dr/77+sgthZ4Xd | ||
| 670 | 2+5Fh3daEiyAX6L0vKE2fYcG92Dx2x1zJhWAX0WC9a+zjqxnPfSLJ0MKQJab3AEAwiRYAABhEiwA | ||
| 671 | gDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbB | ||
| 672 | AgAIk2ABAIRJsAAAwiRYwMXc7/fV18B29q+UGROsj1t0p00+XO1Fp+BFw97bclhKA3W/31f/NDaw | ||
| 673 | Z037/Zwb8OWGa1h2HmLcSPn7xLZX5/Hj8Tg+Erb72Zrtm+9+v196W189fr5jC35HL7brXX8G6p9q | ||
| 674 | nFPxzNavL3PmGazHP95et3xw59D6zBbPKb54EHq79sVD0WVsHGY7fzBbPO3q43/dfq0K7nT2X1LO | ||
| 675 | PINV99z/36b76jeV18WiZfeolF9t92P5xnhSca6+//NdpDRuH5vYEufHyt/ifH0R79drybcmPo7n | ||
| 676 | svKBM3PL8gPt1uu/LcbntcDHI+vqeJbqqZdv308r5XvH4bXYx3pa5s+y7+3xtPRry/tb9uvGxa1r | ||
| 677 | u1fiL0XSVU/v/Kw33V7/60dWg1wuJpF4euPsXT8r9ZfqKb2m16QJ1utkfZu4r3NutUDjAeZjW28L | ||
| 678 | Tenj7fGk4uyNv7GJ4Th7419tJduvtyaeS9XH8Vx+rV/dvq8v3oIZmw/Ldlf1jkOqnpZt8XG/KJXf | ||
| 679 | qVMt8a++MxBP136U2q+3zMM9+hWsJzIlxupfjltpvUrF0xtn7/rZuw4TNONN7rdtWXPvZ/fO1lN1 | ||
| 680 | PuupVLil73HByg9bAloaejwezxUqvnEjxeL1lMpPNd8qDVXajRxg9l6vVsvsMQ9b2j2gnki7wXVy | ||
| 681 | D8Pb/YB2SZn0DFaXx+JK0LQaT1QcVs/e9ffW01J+/q28tPf22uKK45nSlV2tnt1cFns7WzAc22yu | ||
| 682 | 2K9T1pPGebKH1f5e6Pj4fb4hwbq9nO28zT2NIrEtT/lur/PNWXHOvO22+NZ+RTz6bzDKNl25uLbx | ||
| 683 | 9PZU2z04zlP1q+SAdXLViYNTP9M8//Hx+0x6iXDMz6nyq3y7gojXOX/dyb/fda6P7Za+93/loehb | ||
| 684 | +3W8y+13jo/H+4YEa+OMOetyW+Ty2QF9j4zPQCWnLAQHNLplO5aK/aybwftVjx/8+z9StVX+983q | ||
| 685 | UScbTyWGg4e63q+d9tP4rQJ73HswYMt+d9hxJ9tQdqf4ehe7RPg2aZ73eL5u8o9zPVi+K55Uu2+n | ||
| 686 | +rdM99WrBr1x3hrGYRnn8s6AgXa7DIznar8qhudD43asXOWJ3Kmdmldd47a8lDPWl0r8H6+OvV4r | ||
| 687 | 3COeW8M8D87/1fEv9at3uw/E2bvOfCzfsp8OzOfKvF2uV8uw67LbvX39rNdf6hcRf91uvb/v+Pd1 | ||
| 688 | aekJfpMGulxu70slNI31nx7PWc7q18bxv4qLhv0LvW6p/q+RfZv4YmewgKVdz/ztbe8zl71miyfl | ||
| 689 | W/t1IuNJnQQLLu/qi/uu8Q9UfvXxLDmlX72NXmjwLxQqp/iGm9wBAKYiwQIACJNgAQCESbAAAMIk | ||
| 690 | WAAAYRIsAIAwCRYAQJgECwAgTIIFABAmwQIACJNgAQCESbAAAMIkWAAAYRIsAIAwCRYAQJgECwAg | ||
| 691 | TIIFABAmwQIACPsVCdb9ft+1/N52ime2bgLA1/j7xLbfDvCPx2NjbRtryBJPr/kj/LVed1XbCKDF | ||
| 692 | mQnW7c/Fer/ja2+1sx1CZotnTrPlZ7PFM+ytI1/TL4BdnZxglax+Y/5Z2Z9/en3/9cXb6l95862e | ||
| 693 | UvlSu5U4K1WV2i3piqdSw2pVr38djrN3fFrqXx7U6/W0b9+WtpabsjH+SDyl8qU4K/tFV78kUgBB | ||
| 694 | WxOs9sN8V52VA8Py9ethZlnb67HnY/2r5UvtluopxTN2AGuPp1JDqVhXvyq66vlYf73Aaj2VARlO | ||
| 695 | FHrjT8WTGv9U/dIsgAGbEqztK+/qN+lKtXus9Y1ZzjHBNEo1vWs9jZXXs6v2evbWMj93bXdjmQin | ||
| 696 | tQAaTXQP1quWH7jNsNBf/feJJak4B8andMVw13ZXPc8drp752y+eSruNH3+tp3TWbaBm2RVAuxnv | ||
| 697 | wYocDA4wEOdVjk+ROMfGp+WK4Wvh1YCzZ+be0p0D4lltN+gq8xDgun7Fc7C4kNV7zurl904Xfppo | ||
| 698 | jCoYT1e7kebefg+xLHBMJABfYPYE64CjS0sTH8sMxDntmbk3e4/P8k+VrGL1fv8fw7GVCo91fHs8 | ||
| 699 | kQH/8TOS9Ut7b/dBVspfZcYCzGDGS4Rvl1q6jiW3ws/mX//0VufH8suQWuJcxlNpt6QUz4D2O3sG | ||
| 700 | 4uwan5b6X68Vlj5b+jVcb/y9cR4ZT0u7verxOE0FEPHX7dZ7d8jnMl92M+yXdSfurPHpfdzAb4tn | ||
| 701 | o6vHD7B0//OhNp2f7lsSZzyDBS0GzrTtarZ4Blw9foB5dJ/BKnldjX33BQBmc+QZrNlvcgcAuBwJ | ||
| 702 | FgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLAOvvCyoAAAjzSURB | ||
| 703 | VCBMggUAECbBAgAIk2ABAIRJsAAAwv4+OwAAYAL3+771Px771h+TidMZLACAMAkWAECYBAsAIOyX | ||
| 704 | 3oN1f7nS/Bi9Knz/83L1lnqGPwvAPJbr+Zes8I/HH3dovf0va37RGaxnPvQz3Z/uG2ZJqp5V8QoB | ||
| 705 | 2MPXrv+vqWFXmvgFOeVmv+UMVuN3iMiZrUo9H+t/jfMnafuGrz4A36uybr+9fn7k43FhivW/8TTV | ||
| 706 | a5DP8ve7s1y/IsGqT9PVPeHjp9qbe/7vx/qX70yxjwFQ0P7tvfe4cPL6v0yPVnOmyqXDX59jff8l | ||
| 707 | wl0n6P3F617R8tnG6/R7XHwEYLvVdfu5aA8cfVa/Y28MckQqMfrJsX6rLz+DVZ/fz4k7nIGVvnn0 | ||
| 708 | 7hIfz7E5jwUwlcqyvLporx4XnilUV1X7qmRXAyelfvF5rC9PsOpT83mGNtvo8pTvx4/U45RdAcym | ||
| 709 | N/VpORIty5yw/mdTot+aXd1+wyXCq1xiK8UpuwKYU/D4svpr9NPW/8qlva6rfr84u7r9hgTrVt0H | ||
| 710 | 9s69KvUv/zTR3gVAg7Ec6/WxQZUyZ67/22+f+t3Z1e3rLxE+vZ7Lfd0fSq9vbTdmVX5eO1b/a5yy | ||
| 711 | K4D5tVwrLK3/pfenWP9L1wpfc6+3POxZ+NdnV7fb7a/Uvxr95whPMDMAgHZ7p0QTJAZtP0fLxPkr | ||
| 712 | LhECABzpt1wiBABqJjjD9E2cwQIACJNgAQCESbAAAMIkWAAAYRIsAIAwCRYAQJgECwAgTIIFABAm | ||
| 713 | wQIACJNgAQCESbAAAMIkWAAAYRIsAIAwCRYAQJgECwAgTIIFABAmwQIACJNgAQCESbAAAMIkWAAA | ||
| 714 | YRIsAIAwCRYAQNjfO9V7v993qhkAYHK7JFiPx2OPagEALsElQgCAMAkWAECYBAsAIEyCBQAQJsEC | ||
| 715 | AAiTYAEAhEmwAADC/rrd9n5mlSeOAgBXkcmLnMECAAiTYAEAhEmwAADCJFgAAGESLACAMAkWAECY | ||
| 716 | BAsAIEyCBQAQJsECAAiTYAEAhEmwAADCJFgAAGESLACAMAkWAECYBAsAIOyv2+1xdgwAAF/FGSwA | ||
| 717 | gDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbB | ||
| 718 | AgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABh | ||
| 719 | EiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUA | ||
| 720 | ECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRY | ||
| 721 | AABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBM | ||
| 722 | ggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAA | ||
| 723 | wiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQL | ||
| 724 | ACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJ | ||
| 725 | sAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBA | ||
| 726 | mAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2AB | ||
| 727 | AIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJ | ||
| 728 | FgBAmAQLACBMggUAECbBAgAIk2ABAIRJsAAAwiRYAABhEiwAgDAJFgBAmAQLACBMggUAECbBAgAI | ||
| 729 | k2ABAIRJsAAAwv4+OwAAgOu6r77rDBYAQJgECwAgLJlg/c///lewNiBi8h1z8vAAxtTuwVpd+P7z | ||
| 730 | 93/vFsz3eB26Lxuxn65t79T//O9/HTwyy/ncEsDxcY7ZO87ZxqEUz2xxAr/WSoL1XKGe69TGNeuX | ||
| 731 | LHnPbr7197DuH9PQf/7+72udcngdllPm4enz/zfsfQCzeU+wGg8GlTM0zz+9HtW6jjGvNbydL1lt | ||
| 732 | t5LQlOL8GH/vMamlgz9lluMzEOfq+73jPNBupJ7nm8uhnmq79MZZqmfv7VKJsxR81/4ysL0GzuCu | ||
| 733 | jv9qnKV4UttrLH6AN38kWO3ZVWWBXn3de4x5OxX0XAq7zgxVFujsGaZ6DR/HqjfOSvxd45wan956 | ||
| 734 | Vv860O5HY0OxJc7I/E+N52vTW9rtHYeB7Vgat1WleFLbKz4Pgd/p3wSrfR1pTCaWf5pzqVpdptut | ||
| 735 | LvSl0y2lQ+BAnJViY+O896bprT++XW7lMxOpvkfmf3Y+tNtpAgS7HDdzbMDV/V+CteUSRrudcqzX | ||
| 736 | apffPkvlb3veqf16LaPxpGBvu5W/No5zZRyy8TQ6bLts19Lf1fS6/STxYGQNeveXir33r1NcPX5g | ||
| 737 | Ev+XYG28hNHY2PFnsErN9SZAlfornapfu3kaGM+uCj/WsxyHjWebhh2zXbYbq3n4EvxAWwOC8zC1 | ||
| 738 | Hc9y9fiBGfz7HKz2ezXGTHh98D9///ey1//zv//VNQ6rNWTiGzIwzqvjcKKdtsu5Jpz/e5ttXvW6 | ||
| 739 | evzAuf540OjAatKYW+x9dPmJvN7KM7aP19fGWm8p+bFYpUBlbF9ft8efirmx/Ja+33beLlu0NDE8 | ||
| 740 | /wfmQ4uP+8tA5Y3711hzR2Y5Miog4v0xDS3XVl6PW2/HsLc//bxIZVfLtsbK99bTHtt//vnVVeVm | ||
| 741 | 6uX4lMazN/7ecR4Yn7eDaL2/9XFe3umy93a5LY6dLU1sj3PLdmmZD6U4b4Xt1dtuqf7g/tW1X1T6 | ||
| 742 | 2xVnSzCN8QMs/XW7Pc6OYS77nWz7hReJgoweAFO6r77rH3t+5yg+J9sFAAAAAAAAAAAAAAAAAAAA | ||
| 743 | AAAAAKDq/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 | ||
| 746 | AElEQVR4nO3dzbKjOLYGUPJGDurxesgjMuzH60EP7sDZJAeQkMTm12tFRYUTYyEw4O9Isvyr64YO | ||
| 747 | AIA4/3d1BQAA3kbAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmAB | ||
| 748 | AAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGAC | ||
| 749 | FgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAI | ||
| 750 | JmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwA | ||
| 751 | gGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzA | ||
| 752 | AgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADB | ||
| 753 | BCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAsN+1LxiGI6oB | ||
| 754 | 79f3/eD6IZrzCmL1fUw5WrAAAIIJWAAAwaq7CIGTjO3U+Q6gwtWi6qM3qlbfO2jwhQQsuLHVD+bZ | ||
| 755 | B/bncdWogenKhZ/9qZTw9PQQlRqffhyAaAIWfJlZFPjyZDAMYSNaM5sAvo+ABfxPVcvWuPKsEWiZ | ||
| 756 | 2MYlq+V/nl3t6KxtaUutf2g5qeOwuXBZTuo4AA+0K2D1R//lBxwtFYyWqWiWFcZnU1Eg31Q2/efq | ||
| 757 | 49qWtkz9Dy0nfxyWLWS1x6GAWzHsFz7dyd4WLPOvQKG7fAqOH/mFF+9mkCrfbsNTR2zutuW3luk+ | ||
| 758 | DDsdcX/WRQjfZ9o0deZnc8ktLNUlV/LC1B7V3jpvEoWBJxOw4FtFNU0VWnaNbaqtWCo4tpUDsIOJ | ||
| 759 | RuFpdn78v755ZhjO+G4gQJaABU/zgujQsAubLyksM6q78AXvAnAkXYTwZWatO9NvBTZMQLoc+TRd | ||
| 760 | Mn1qNgfBZkCprU/Dfq1+QbLt+KyOAKsqH3iXX11Xd3n/vHv4FXcoVX293O2ncrgl92HYb3odRTVP | ||
| 761 | a8GCu6qaRgGAOxGw4CSaGTiC8wqipZqw6q41g9wBAIIJWAAAwQQsAIBgAhYAQDABCwAgmIAFABBM | ||
| 762 | wAIACCZgAQAEE7AAAIIJWAAAwQQsAIBgAhYAQDABCwAgmIAFABBMwAIACCZgAQAEE7AAAIIJWAAA | ||
| 763 | wd4QsPq+v7oKrHj9+9L3/Z59fP3xSYna8XccwHfsRSAHhNc4L2ClPo1qL6e3Xn5X7dfOlDAtZ38h | ||
| 764 | D9L3/TAMwzCUr39ofaI8pZ5RGu4/qfvYyYeuX7OntMC63X+7tY6u51OOA1VOCljjp5HT6G7KIwKE | ||
| 765 | iDrlLjl1Uxs9vzLD/8weAzfx+8Jtj2Hr82Dz7pBff3x2unya58rLH4Pg+JLVchrWn0bM5cqFx6Fk | ||
| 766 | F0q2mylkdgzzLzn6fcmsX7u/UdutctXxybyP+fN5Wc/a83+zqqmDUFhIqpJV73vt/jbYPG8PikRt | ||
| 767 | 973lTWz1/Im6vlwXbeVnyqndr9r3l1pnBKzpG/l558a/urrF25yRWX92Mq2uWbKh2QvHUy1VTu36 | ||
| 768 | q49rj0NK7XajHP2+5G8E+W0dtN1xSVdwA7rq+NSun6pn7fmf2XQ3+dRprn+qnK7yeDbsb5WS83a5 | ||
| 769 | C/vV1r/h/hNy3rouVldurn/tfhW+JPzz4qu8YZB795yUfVU937Tdwk/f8O1OCx/vvDs3dNXxOboO | ||
| 770 | e+ypT8i5ceYBudvBL3R0tV0X1/rmfY91UhfhEX+o2e5znXl8Zn+9nbbdParqOdT00DWsX1ufWg31 | ||
| 771 | Obr8qP19yvkW5ej9/arr4iaErT1OClhXfci9qeXmTbwveW1/bZd/PLStf5za+hxa/rJLZed2v8fd | ||
| 772 | Wraefl3wdC/pIiTQdHTLN/yJ9hqfLsvp6NT8+zhb/3JH1+du+8s5nn5dFHLfvqEvClgP7S7s+/78 | ||
| 773 | mn+u1XOGN9bu3bd132zWM7PC6vu4/4Tc8/ITCgwsP7Buq0WtjtO/4ZnZUKXL39anXxcNmu/bd6j8 | ||
| 774 | K105TcPHcT3ls79CmrNCbTlt203tV/nfUg3bnf3FM31JQ2v8Qe9Lav2j35eo82dW2sn1XL58c/1Z | ||
| 775 | PQOPw+r5FnveLu3Z39lrU9ut2q9M+SGi7j+19Yy97+0v/0HXRWD55ft19HlI13W/uq72c/Tv43Na | ||
| 776 | OLj2OHuX38H7CEtvvS7eul/H6X9OTpFYq+6QXt+CRd4l10ngX2ZcyPsIS2+9Lt66X88lYN3dJdeJ | ||
| 777 | i/MdvI+w9Nbr4q379VxfNMgdAOAcAhYAQLAHByzfeij0+gP1+h1k1c4ZDY6Yb+JWp+KtKrOpvLap | ||
| 778 | 4xy7v886eiXutkd3u16O8OCAxaPd7dJqmI4rdZe/26690ufLH+WDTk6Ylqm2Ps6fBrXH+W6Oft+f | ||
| 779 | cvI8/X0sJGDxeLf6HsDrbxmEOOH8aSvqKZ/QS4+49C68bzzi+LzMGd8i/GTV6Zxm06fGx1XLZ+dK | ||
| 780 | yNdT+8XEvquzYkwXptbPbGK1npnyU7tcVX6XOHTNx79web6SywkGG97H1UKqzrfY+lSpfd9r6xNy | ||
| 781 | Xi1nIyy5Lo6rf63M+9tVXhfNmz6inOUNZ3nLqr0uCt+U1XL23Of338/33wcy9clvtLz8WrWfF9MH | ||
| 782 | q4e05Djf7fp9tJOmaZhd+Z/HqYBSsnz6zjUEnebK7ym/dn8zj2vrGX78C+u/avVVDeWMpS3/5q7a | ||
| 783 | 39j6lIt6v6LKz5hVYLwFX1L//AfJZuVTm9hTz9X6HH3fyJfcdl0UVrLkXAq/n+ff9/33gVR9Sg5C | ||
| 784 | Sfm1asvPnOfd2vF5yvX7aCcFrPCDuHo5HbStg4z1zFR4z75MX3vEMbnzcS5MZvsLOcjRm350+fkP | ||
| 785 | koai7lOfo0XVMFVOc/mZ+/ms8KrjfGh9ora101X39j3HtnvI9bLfxRONpk7iqpN7KP41q9uqvZgv | ||
| 786 | kTnOT69/yt3264j6nBm27nY8U55Szzvb874fffyf8v7eqp4v+Jw938UBK+ovoWnb4+Pe/mVT6oWV | ||
| 787 | yUsd56cc86rz5Ibvy1OOc8pT6v+UeoYYKgd6tm3i0PVrPeX9vVs9H/05e4lXfYtwGIaGpt3py2fd | ||
| 788 | w6zaeZwv9/T6Q7jPRXF1LXgA989yNwpYVd2Fs0GR+WLLT4XPedPQPdxwtm3u107hF0Bhgbe98PZU | ||
| 789 | 7IY7dcMqVXlK/Z9Sz536/ylcec+Gqgq8pLsw6n4eKGQ4zREVIOPKLsJZCp4O+t5cnnrcLZoua7P2 | ||
| 790 | MlrV1idTckg5teXvqc+e5YVb31NO1RdSCs+Tkvcltd3A+py/fq1n1b98BEnUdjPlVJ0/m9fdcteq | ||
| 791 | zsNlV3jVIQq5z5Tfz1O7MH3Qdt0dcT/vjnzfl+V3aydDbfm1+xu1/iv96rra3vG/jxtaei7RVs+n | ||
| 792 | 7B1As9qA5cbIK/U/J6dIrFV35l88yP0EVbcDiRv4Kloa4CDvD1hV9ws3F+DbuEnCEW40yB0A4B0E | ||
| 793 | LACAYLcOWFUzLAAA3MR9A9ZncPqyv1/kAgBu7r4BCwDgoU76FuHmxGtdwZdTMrO0zV47Llkt//Ps | ||
| 794 | 6kR5vq4MAOx3RsBKTWSXWT4u6X7OYLt8VcmGlv9cfdwwozEAwNIF82CVTLHfReSbzMslJwDgOGcE | ||
| 795 | rPJfAQtXMiI+1UUIANDmpBasad/faTFr2eW3+RItWwDAfqd+i/Az7YJWIgDg3c4IWHdIVA11mL3E | ||
| 796 | rKcAQKFTx2CN/8wvLyxtWc7sqdlcDJvxyK/KAwAhfnVdXYyYpg4TGQAATzebvCmxVl3gMZM7AEAw | ||
| 797 | AQsAIJiABQAQTMACAAgmYAEABBOwAACCCVgAAMEELACAYAIWAEAwAQsAIJiABQAQTMACAAgmYAEA | ||
| 798 | BBOwAACCCVgAAMEELACAYAIWAEAwAQsAIJiABQAQTMACAAh2ZcDq+/7CrQfq+/41+1Liq3YWABqc | ||
| 799 | FLD6iXO2eJq+74dhGIZhufyS+qQ8vT6pk+eVJxUAT3dGwBojyIePw6dbpskLN3pJZQAg7/fVFfjb | ||
| 800 | kjH9pJyGsCOWb1ZmTznjyp8H4/qfoDlb87NktfzPs1XHp6o+teVkCqmqZ2x9yusJAKe5IGAtP5tn | ||
| 801 | j2dBJHx5SkP545Lpfq2+qmRDmWOyZ79S9aktZyxt2QZZVc/Y+gDADV3cgnXEJ2hUmZvlbAap/Rt6 | ||
| 802 | SsIoTGb7Cyn3lEMHwCtd30W439imsnOkeaaco5XUM9WVdlsNx/MR+wUAm94QsLpJY1L38+O8Niql | ||
| 803 | yjnUsmts8yVPaZ6pOp4NxwEA7umCebCO++CM+paibzvGuuR4mr4BgAu9YSb3ws/RzdXu8HncUIc7 | ||
| 804 | VHvVnorddqcAoMQZXYSz1ouSwc6r60ctj9puYWnLcmZPzeY42MwW4fUpLyczw0JtPfP1mb02M/NF | ||
| 805 | qj5P6UUF4JV+dV3tKKW/j32RHgB4utlkQ4m16gLPG7oIAQBuRcACAAgmYAEABBOwAACCCVgAAMEE | ||
| 806 | LACAYAIWAEAwAQsAIJiABQAQTMACAAgmYAEABBOwAACCCVgAAMEELACAYAIWAEAwAQsAIJiABQAQ | ||
| 807 | 7PfVFYA36PurawBxhuHqGsDzacECAAgmYAEABBOwINgw/PkvZLU91di5wjnVeD1HAL6TgAXx+n57 | ||
| 808 | VFbJOlNjIPuSD+z8bn7JQTiN4wnhDHKHxxgD2TAEDKs3MP8cjjN8JwELnqfvf2SsafPD7ON8fGp1 | ||
| 809 | eWrlbhHmUuWsym90+VSm/tM6zFZe7kJ4/UvKmYXd5T+XlUzVp3a745LZVtrKWT0lgGYCFjxb5gM+ | ||
| 810 | 9bjrfnzW7iknX5/pJlLl5wPKas1LVgup/55yxtoue99Wy2nY7uyFY4SqKid1PIGdjMGC16r6yMys | ||
| 811 | 3PzR2/DCfGw6rRq3Kudu9QdKaMGCx4saoXz0SOfV8pc9XNP1L8kEVcdh2mjUUOEjdtCIdbgDAQse | ||
| 812 | L+RDenXwUKxUPcd0Mltn2eF1jqe39Dy9/vAOugiBW/jMWzELdqtjmADuT8CC58m068zGlTeXHyJT | ||
| 813 | zuzLaxn7M9ael5e89lPDe44TF0/hKroI4TFWv9s/yx+pp1a7/6a9crOVmz+YU+Wk6pmp/6zM1V0r | ||
| 814 | KadqmoaS+hSqmgEhartt5WRGwgFtfnVd3X3056XbD/4+gkR82ZwOoGQ1drpnw9LNua/zbaZ5pk/e | ||
| 815 | MuouDC1YEKy8zQCAtzIGC3gzQRa4hIAFABBMwAIACGYMFgQzyB0AAQviFf4McHezr2utfr0//+PB | ||
| 816 | 5esv91SyBF5MwAK6bitIbf5QYMlsCBIV8D2MwQKClc/SDvBWAhawIjNZPACbdBECwaa/u5L6bUTd | ||
| 817 | hcC7CVjAD5lfPNyZioQq4HsIWMAPIV9vlKWAL2cMFlDESCyAcgIWPMkwrKec2uWbWwFgD12EQNf9 | ||
| 818 | bKBKNVZl1inpE5yVqRsReDEBC+KN36HbXKdWqsza5Zsrj49nJayuk9liqhyAdxOwIFhhkhA4AF7M | ||
| 819 | GCwAgGACFgBAMAELACCYMVgQbHUm9ObV7qNk5D4AH1qwIF7fbweRknXONPtW4/Kfd6swwJ0JWAAA | ||
| 820 | wXQRAl338+ecC3/XOTXRaO0EpADvI2ABOWNamo3BmoWwVDgrzGoALyNgAX+Mv36znK59MydJUQBT | ||
| 821 | AhYQzG9FAwhYwB+1Y7BStGYB+BYhAEAwAQueZBjWO+Bql6+uObY8jYOxqipWtRzg3XQRAi1mISwV | ||
| 822 | znQXAt9JwIJ4Jb8q09a0kyqzdvnmmvl/Rm0U4K0ELAhWGC+kEIAXMwYLACCYgAUAEEzAAgAIJmBB | ||
| 823 | sM/MCJtj2AtX4yDmlQAOZZA7xCsZwD7OmX4fq9MrZH68uWr95Z7WfstyVuxmCdfyK9fw5QQsoOu2 | ||
| 824 | gtQyK2TWT6kNHJn1G6ZCBTiTgAUEy7RaHb3d0bK5a7l8+lTJ8obyxxW0ZsG3EbCAFdNA8GkuunlE | ||
| 825 | yHRNlrTMbT5uKD+1BPgGAhYQbOy/m3Xk1f6ETtX6DfO7Vs1E3zZ/rHQFX0vAAn5Y7R0LacQKHIO1 | ||
| 826 | arVHcpr2dmr4AWzpCr6WgAX8EDJ86vxgseyqm1VmZ8zKlJ/yiK5V4CDmwQKKPP2Le31/wS48/aAB | ||
| 827 | zQQseJLU3KS1yze38mipgV8NL69dYXX6rqcfT6CBLkKg637mgFQmyKxTO2i98CX5cqa9fqm6NdRz | ||
| 828 | 9vJ8mSXl6yuEL/Sr6+r+tvp5K+kHf5pBYlakwpnKfe5yN+7rfJtpnumTN+W6C0MLFgRr+z4/AG9i | ||
| 829 | DBYAQDABCwAgmIAFABDMGCwIZpA7AAIWxCucC6C709e1Mj9mPMpPZV4YKFdXjvo1G4CbELCAuVnY | ||
| 830 | Gh+nlhdaDXDjU/fJmgD7CVjAD5kpMU+eMLOk8Wwa/sYls/aw2olGAfYTsIC/7jPheKbLMtUSNlvh | ||
| 831 | 8yCzPsBxBCzgj9rwseencjbXj5qvVZwCLiFgAY32jMEqkf89xPLSjO4CzidgAX/c6jeJl117o+nX | ||
| 832 | GzdrmykH4DgmGgX+etC3+fr+SbUFvo2ABU8yDOuRonZ5Ria1XNW+Na3PnkQljQGn0UUIzM36ClOT | ||
| 833 | zufnDi03ljPt9ZvmvNTjko1mXgtwnF9dV3e/+Xlr6we3K0jM0uSncngo93W+zTTP9Mmbct2FoQUL | ||
| 834 | gkXNLwDAcxmDBQAQTMACAAgmYAEABDMGC4K9dZD7feYgBbg/AQvilQSR6XTkN1H724IApAhYQNet | ||
| 835 | /aTMLGOJXADlBCxg2/KH/z4JbNnRmVreJVrIlrOALp8qLB/gPgQsYMWy+WrZmzmb7T3/ONNCNlth | ||
| 836 | jFCp9VOPAe7DtwiBRqlks7o8MAZJVMD9acECTnKrEf0AhxKwgDMsu/wAXkwXIbBCAALYQ8CCJxmG | ||
| 837 | 9ehTu/xaN6wSQCxdhEDXLb4nuNqdt5ysoa381e8kltcH4P5+dV3d35I/b3n94E9RSMSRl/1UDt/D | ||
| 838 | fZ1vM80zffKmXHdhaMGCYIWBSa4CeDFjsAAAgglYAADBBCwAgGDGYEEwg9wBELAgXklmGn/Y+CYy | ||
| 839 | P67crU3QsFrz1fkXJEjgCwlYwIYxbE1T1/hgFsU6iQrAGCxgNJtQFIBmAhaQM2u1kr0ASugiBP4Y | ||
| 840 | 89POIOUnbgAELGBDbdgSqgAELOCv1Wy0+eVBAGaMwQIACCZgwZMMw3obUu1yAA6lixAINot0hmQB | ||
| 841 | X0jAgnjLec9T69RKlVm7fHPN5YSiqQLNMgqwJGBBsMKEIYgAvJgxWAAAwQQsAIBgAhYAQDBjsCDY | ||
| 842 | OHq9cJC7wVgA7yNgQbySzPRZ5z6TVE1/1DmzfPxn6gcHl3skQQJfSMACGo3JaRbCJCoAY7CAnL7/ | ||
| 843 | 2yiVauWargNAJ2ABAITTRQhsGBuoCvv+UsOzAL6HgAUEE6oAdBECGz5Drwy0AignYAEABBOw4EmG | ||
| 844 | Yb0ZqXZ51RbHLr9UI1bq24UAX8sYLOCPWXjazEypyehrywF4HwEL4pV8566tYSlVZu3y5hKmrVk7 | ||
| 845 | twjwYgIWBCtMGIIIwIsZgwUAEEzAAgAIJmABAAQzBguCpb5b17YaAE+kBQvifeY937/OmVLfapwt | ||
| 846 | n/7zM8nW6lRb5nwHvpwWLKDFbHJRc40CTGnBAnKms7eXpKixQWv/JPIAz6UFC4j0SWAatIAvJ2AB | ||
| 847 | G8ZGLJkJoJAuQgCAYAIWsOHT3zcdjAVAnoAFtDOSHWCVgAVPkgo0tcurtjgOvZo1YmnZAkgxyB34 | ||
| 848 | Y5aT8kPaP7kqNR+9cfHAlxOwIF5Jtmhr9UmVWbu8uYTpP2cTjWaeBfg2AhYEKwwWL8sfL9sdgJ2M | ||
| 849 | wQIACCZgAQAEE7AAAIIZgwXBUl+sa1ttTzWMiwK4ioAF8UqSzfijyAC8jy5CAIBgWrDgGZZdfuOS | ||
| 850 | aTPYcp3V5alNrJazuvyz9WX5s3pO/1lVDsCjCVjwMJkE0y0CTSr3lBd7dPm15QA8gi5CeK09SaV8 | ||
| 851 | GNl+EhXwPlqw4PFCRspnfj2wpPzZD0KnWr/KywF4NAELHi+2Jem4XxUUnoDvoYsQ+KHvf4w6B6CB | ||
| 852 | gAWvMg1GVSGpcOXCbr5h2BiuLsAB76aLEJ5hOkZq2os3a22ade2VT3+QKidTfpWocgAeQcCCeKnR | ||
| 853 | 4st1qkxDz+ry5cKqHJNaOVN+VVEN5QA8lIAFwQoTg2AB8GICFhxo6NZjVN8ZggTwZga5AwAEE7AA | ||
| 854 | AILpIoRghV/c8/PGAC8mYEG88h/ya56qKvUTNKlfTfYjygBnErDgGVKBSZACuCEBC85y++zT0EK2 | ||
| 855 | 7OjMBL6qcgAeTcCCgy1z1ZCavaFC1aSgJRpayFKPq8qvLQfgEQQsONinfWaeIKrnwZr9Qs7m8m7f | ||
| 856 | 7/2VDyPbT6IC3kfAguONIWhf+8x0XPzsNwczyz82w9bOoDb77cJU61d5OQCPJmDB8cZxRrPWrCar | ||
| 857 | 2SWzvKHkLh3U9hCegO9holE42CzyTEd0VxZTtbxZ3zfXEYA/BCw42LLd5pYtOYWJqrCbbxg22tIE | ||
| 858 | OODddBHCWXb3DK5Oc5Ba/pTyAV5JwIJ4qdHiy3WqVE3NsDpC67jym18iaQGvJGBBsMLEIFgAvJiA | ||
| 859 | BQfq6+e7AuAFDHIHAAgmYAEABBOwINhnhoLNMeyFq10lqmK33cHT1B6Bo9cHziFgQbzPXJ371ynn | ||
| 860 | U/bjquPQkIqqXuL9hccRsAAOVDs5RW3s9nVUuCffIoST7P4RwvWJOseFy8m3UutP5/xcXX9Wz6hy | ||
| 861 | UjLlT9dZ7nK37ziMSwrnLVutT2a7qYX5raQqX15+akJXE73CmQQsONYyV7UlrdQHfOo3nvMBZfk4 | ||
| 862 | lWCiyqndr9r1G47D7CVt70v+tbW/6rhcv7b8TBCsOs7ATroI4Vizj8CoD7aSMV4hr40qp5AOsnM4 | ||
| 863 | bnA0LVhwuDFj7UlXhT1ZU2d+E/C0/brwODzF6v42HDdgDwELDjcOVxr/32Y66GezkGWXUJuocjKq | ||
| 864 | 9qt5/e+R/01JMQvOoYsQjjULKLWDcpY+8zu8r1Vmtl/Tx6kmmVceh6M5bnAOAQuOtWwqaGs82POJ | ||
| 865 | GDV35RFzYGbW+eSA2Ca0kGDxoHSSD6nAcXQRwkl2dsrMWh1mpS1H2KRag0rKL3lcW07J+t3aftWu | ||
| 866 | nzkOqwUWyu/X6gin1AwLtcuryk/tb9RxAAr96rq6v2t+XqL94M8iaJoFqnA1PkwrcCb3db7NNM/0 | ||
| 867 | yXtN3YWhBQuClX8bjjwtLsBzCVgQwF/8R3OEgWcxyB0AIJiABQAQTMACAAgmYAEABBOwAACCCVgA | ||
| 868 | AMEELACAYAIWAEAwAQsAIJiABQAQTMACAAgmYAEABBOwAACCCVgAAMEELACAYAIWAEAwAQsAIJiA | ||
| 869 | BQAQTMACbq3v+6urAFDt99UVAJ5qGn2GYdhZ1M4SAG5FCxZQYQxVn0g0Oq6d6aDgpWEMOJQWLKBU | ||
| 870 | YTvTasvW57XjU9Pl0wez8pcLM+UsV8vU51OIZjPgIAIWUCQfRwqDzvLx5/+pwlfbxlJlllR7+k8Z | ||
| 871 | CziOLkJgW0gQiYoygZHo0M5N4JtpwQI2PL2ZJx+htGMBRxCwgA1PjyBVfYgAIXQRAts2u9Ie2tEm | ||
| 872 | XQEHEbCAIg8arpSp5/Qp6Qo4ji5CoNS0r3CWt2ZfzVsuLym5W8zIMH2QL2o2d8Pq4y79bUeAWL+6 | ||
| 873 | ru4WM70juUMBAE+Xmjnvp7rAo4sQACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBA | ||
| 874 | MAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEEzAAgAIJmAB | ||
| 875 | AAQTsAAAgglYAADBBCwAgGACFgBAsN87X9/3fUg9AABeY1fAGoYhqh4AAK+hixAAIJiABQAQTMAC | ||
| 876 | AAgmYAEABBOwAACCCVgAAMEELACAYL+6LmouKzOOAgBvVZeXtGABAAQTsAAAgglYAADBBCwAgGAC | ||
| 877 | FgBAMAELACCYgAUAEEzAAgAIJmABAAQTsAAAgglYAADBBCwAgGACFgBAMAELACCYgAUAEOxX1w1X | ||
| 878 | 1wEA4FW0YAEABBOwAACCCVgAAMEELACAYAIWAEAwAQsAIJiABQAQTMACAAgmYAEABBOwAACCCVgA | ||
| 879 | AMEELACAYAIWAEAwAQsAIJiABQAQTMACAAgmYAEABBOwAACCCVgAAMEELACAYAIWAEAwAQsAIJiA | ||
| 880 | BQAQTMACAAgmYAEABBOwAACCCVgAAMEELACAYAIWAEAwAQsAIJiABQAQTMACAAgmYAEABBOwAACC | ||
| 881 | CVgAAMEELACAYAIWAEAwAQsAIJiABQAQTMACAAgmYAEABBOwAACCCVgAAMEELACAYAIWAEAwAQsA | ||
| 882 | IJiABQAQTMACAAgmYAEABBOwAACCCVgAAMEELACAYAIWAEAwAQsAIJiABQAQTMACAAgmYAEABBOw | ||
| 883 | AACCCVgAAMEELACAYAIWAEAwAQsAIJiABQAQTMACAAgmYAEABBOwAACCCVgAAMEELACAYAIWAEAw | ||
| 884 | AQsAIJiABQAQTMACAAgmYAEABBOwAACCCVgAAMEELACAYAIWAEAwAQsAIJiABQAQTMACAAgmYAEA | ||
| 885 | BBOwAACCCVgAAMEELACAYAIWAEAwAQsAIJiABQAQTMACAAgmYAEABBOwAACCCVgAAMEELACAYAIW | ||
| 886 | AEAwAQsAIJiABQAQ7PfVFQAAeK5+dakWLACAYAIWAECwyID1n//+K7A0IMTNL8ybVw+gTW4M1uqN | ||
| 887 | 75/f/z6sMu8xPXQvO2KfXdu/U//5779OPjLL87mkAufXs83R9bzbcUjV5271BL7WSsAa71DjfWrn | ||
| 888 | PetLbnnjbs7297TdP2dD//z+97OaHKaH5ZLz8PLz/xuuPoC7mQeswg+DTAvN+NT0U63qM2Zawqy9 | ||
| 889 | ZHW7mUCTqudm/Ws/k0p28LPO8vg01HN1ee1xbthuSDnjwuWhvtX7UlvPVDlHv59d7LgAAAJbSURB | ||
| 890 | VC+ZeqYqX3W9NLxfDS24q8d/tZ6p+kS9X231B5j5EbDK01XmBr36uPYzZtYUNN4Kq1qGMjfo2Bam | ||
| 891 | fAmbx6q2npn6Vx3nqONTW87qsw3b3dR2KPbUM+T8jzqe003v2W7tcWh4H1PHbVWqPlHvV/h5CHyn | ||
| 892 | vwGr/D5SGCaWT93zVrV6my63eqNPNbekPgIb6plZre04H/3W1JYf/r506ZaJqH0POf9jz4dyB50A | ||
| 893 | gbsc7s51A57uT8Da04VR7qCMNS12+ddnav3uyJHa076MwkbB2u1mni08zpnjEFufQqe9L/uV7O9q | ||
| 894 | vC5vJG6sWYHa6yXj6OvrEk+vP3ATfwLWzi6Mwo2d34KV2lxtAMqUn9mpfN/NqOF4VhW4Wc7yOOxs | ||
| 895 | bWp2zvuyX1vJzV3wDdtqEHgeRr2PV3l6/YE7+DsPVvlYjTY37B/85/e/l3v9n//+q+o4rJYQU78m | ||
| 896 | Dcd59Thc6KD35Vo3PP+PdrfzqtbT6w9c68dEow13k8JscfSny6fm+a2MddvsX2vbesmam6tlVsgc | ||
| 897 | 2+nj8vpH1blw/T373h38vuxRsonm87/hfCixeb00FF54fbVt7syUI1EBIebTNJT0rUw/t2afYbOn | ||
| 898 | Pg+i0tVyW23r15ZTXrd//vetq8xg6uXxSR3P2vrXHueG4zP7EM3vb/44L0e6HP2+dIvPzpJN7K/n | ||
| 899 | nvel5HxI1bNLvF+1202VH3h9VV0Xmf2tqmdJZQrrD7D0q+uGq+twL8c1tn1hJ1EgRw+AW+pXl/qx | ||
| 900 | 5zmf4vfkfQEAAAAAAAAAAAAAAAAAAAAAAAAAyPp/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 | ||
| 905 | AElEQVR4nO3dO5bjOLYFUOVbadTw2tQQZfbw2mjjGdGlUvIDAeAhCUp7rzKiFBRwCfBzgpSYv263 | ||
| 906 | xw0AgJz/O7sAAIBPI2ABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 907 | AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 908 | AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 909 | AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 910 | AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 911 | AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 912 | AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 913 | AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 914 | AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 915 | AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 916 | AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 917 | AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 918 | AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 919 | AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 920 | AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGG/Uw09HqmWYF/3+/1he4Vt | ||
| 921 | 7Edc3f2+b/uuYAEAhAlYAABhAha8c7//77/IYh/v6iNw9fonPmx14Dpin8GCT7b4WZP7/Y/Xf35u | ||
| 922 | Op9NFt7yiZZJMZVdz9+y9nqq3yav4/PsZW3QJpU8/zc4yB1S8wJcjYAF53kmgONPqI/HchZce/14 | ||
| 923 | a4Hpdlt9fU3r8icaZ/yBbQQsGMxPAnieZSfh4Gl+RWd+8WNx+WCda/2+/vawerKa6m+dl+5iWutZ | ||
| 924 | m5Tb7Mrf2luAXrsErLu/wGCL16ssr7e6Fq/ErF0GK1wBiihcfmuqv6m7YzTV3zovW4ppref1UFwY | ||
| 925 | /7Wf35fmUM/1HPZ4kb2uYHk+CsO6wFmhZvdpui92sL27br0S1rr8JQ5flStSs7X3rq/jPJdz5PHf | ||
| 926 | LUK4iOfJsukT6EPpq2d+96r14tCFPoPVpHU89wxbwISABdfx+rW4tyfC+S2h0/WdvNe+nvmTOL82 | ||
| 927 | EHTM79eOFZzBc7Cg11mnq8fDd80ABidgQa+DI86W7gZMY1seGPa0U9AccLjK1gourMjl1hGuxi1C | ||
| 928 | OE/TN/knYWKy8PwTWpPv3k++ULbYb8eTBeo/GVauv7x8TZAqtN/xIffFD34tttM6LwWL41/Tb+vP | ||
| 929 | lfUAG/y63TK72Z9HM//KOuNq3j4rHxHkSUJ8E8d5ruh1u937Mq4rWPBOx1fVAPhuAhZfx5/dsJ39 | ||
| 930 | iOtbu4SV2bZ9yB0AIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgT | ||
| 931 | sAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwjnO/38fs96zCWl2lzlZ7r9dO | ||
| 932 | 7X/qdJzOwO7qY46HV3G/3792SE8OWPc/TX51VlURqfpb27n6uO2tYzwX39J61Lj6vIxW/9WP2pcu | ||
| 933 | /nad+q9SZ8op61s+jz8ej8fjcXxVIzg5YD2H/pvn4HRXGflT6lzrNFjM3ut1lflt8pEr9aNv1b4t | ||
| 934 | SezngzetnTiPr/l9dgELnkeKnx9qJuz14PK6fNPrzxcfj8ek67V2Oup/7aWynspx6Oj37cKV/T5H | ||
| 935 | 7Fa3XvPuKtdu0nhrv4Wm5st36JjH+vEvrO/bkjbOb01TW8Yzsr6Trah+o6rvN7X86w9vt4ea9ps2 | ||
| 936 | hsX6J9311d96XO2os2l7WKvztj502/eXwvJN47O2vmvz1TEvHceTXbWex8c3YsB63bxqli9scE2v | ||
| 937 | z7t+boJNB+5C/ZODV7me1nFo7ff5rsWLumv/u6hpvZpaLtTZ2u/a+HSs76K+eWwa/8I8rtk+v6nt | ||
| 938 | eU12feu19ptavnV7qGm/dSeteUtwP1o8rnbU2bTKZx0PU+ed1PqeuH+9/tC9faaOz6cYMWBttPfo | ||
| 939 | b2l/7ZC6oZz+foPvPWuLj9SWKn7wedyjzZH3tSP73Xu/HmHeRzirjbCrHjlul96/asL027df3ScE | ||
| 940 | rMf6lef534Ll11vbT2mqZ2/B9T1lvTrqT9U51Dyu+bbtOahmvSZ/be9ZTpvWeT9xPxrKAfvL3lq3 | ||
| 941 | 21N8wDjPfULAur2E5duf07M2VX1/hew0/fNLoNn2O6TW99wrEN2Xpvs6HXAe1+y6Pe/U5gia1mvv | ||
| 942 | 7eHR/gGa1nnvW/7z7L2/7O0qNV99nOc+6jlYj8djfgf9Qu2P5urre/X69/Zh4/O6Lh+zUm/9TGLH | ||
| 943 | W17DWXncPmw76WYcjvFJ4/wJAatyJrpvFx450yNsVTvVcNiqbenoG+4VHlzbkd39HJe3fwy2puam | ||
| 944 | 9dpvEO5/21LD4rhtrHnkXaDJieOwx7mp/nR5iQPF8XU2OfkWYeGLBvV3ZCdp97l86+ut7Ve+q6n9 | ||
| 945 | eXLf9ZMTi+Pft76FSibtvFZYfxdvXmdrv/Pe58tP3rvW79txq5zHXcc/2/72/TG1/O3dcePt29/2 | ||
| 946 | u3j3bct6bdke1szz0Mb9onX5wn70tvjuOrtbO+x4mDrv3Cq2w5rtKjuei5q22zV94zb4ta5ft1vq | ||
| 947 | exn//Lz9L0iALbqPQlc5fLUGrL5mOYuJqNQ6UPc/H06xslRm5D/kQ+4Ae/+lPpQ9rnRubAcONngM | ||
| 948 | FbCADxE51I58vJ5IlXqhVf4eJqXG4KP0CR9yBwAYioAFABA2RMDa6VsAo33L9PQvO4z2jdahitnu | ||
| 949 | 6qtz9fonPmx1TjTmSNZXdUD9Yw4Rpxv3M1ijfXhtyxdQR/CpXzLq+ArJbWkeW+d313FY/NDx/PvY | ||
| 950 | i5XcX/6R1MXlj5Gal9GMtv1zuvLXOdf2x9vfW/va6/Nf2fAuZ4iAdYntZvDnbVzRKfO+No/jzG/h | ||
| 951 | eN36tfw9vsa/k3HGn4mRN5sa49S/Vkn59cH3XArOD1gbn7Y3ect8+fmD2taW73iuzGLjHW/pftDi | ||
| 952 | Tu2UFy5MWWW/a40sPlhvrf1sPfXK22dkfk/UVH/rvHQX01rP2qTcZvt7/S6c2t4Kx5mm41JH/YvL | ||
| 953 | l9sprOz8mZZN45w63nbU3zT+b0safI/mROcHrPlfrq2xvbzDzH/u2LHf9lv5x3eknvIBd/H11yK7 | ||
| 954 | D3Br89I3notXLJrGJ1tPvcL2ucf2duThu6n+1nnZUkxrPa+bVuvxYc3e21tf4Kivv7B8oZ3F/XQy | ||
| 955 | FM+IExnnyuJr1mut/rftb6kTns4PWHGTveuwTmt24z3qeba51njqhHeAymS2vZGd7N1161/YrcuP | ||
| 956 | v4Xc2v+NkY1Njay1/vIhYr9i4uP82P+ff9lD6xVZru4TAtb8SvXlVP6N9aOwvk3tdCx/io75HW29 | ||
| 957 | +uqZ3/Vozcqf+hf5Htv51QcnVf+WdkYY55o/wApXQ0+p7erbHms+IWDd/vw6xhU31r6/RN/e8ov3 | ||
| 958 | e5am+T34oFmjb5wnd3hfX/+ktNTqg7fzSxtwv2tlOyFriOdgpTwej/o77h/A+sLlvG7D37wxGwc+ | ||
| 959 | 3icErD12zp3utdUs9naZSCORtxxjS2EDrlRTSWsL7xQ0BxyusrWCCysywjr+TF/HZciNxR+27pUd | ||
| 960 | nTUONf02rcKWYvhgJ98inPwFs/jtj8p76q//27f848/v+k6+iDSvs7B8TdeL/e5Uf1M7le/qrv9W | ||
| 961 | nPfWOsv11Mxjaz1r/fbVX15+4zx2fMi9fvtsnZeCt/vXWr+tP1fWUxDZ/hcXS+3X5U7n81vQvZ/W | ||
| 962 | 11k/HR3tB48z9Sr3x5ouOo5LDOXX7Zb6aOQ/P3/zB0QA6h12tBz8sDx4eWWXLv7b3Nef9/EiM5sf | ||
| 963 | 8iF3gKsIXlG7tI8Zh0sXz36aA5YNCWCLU87HA4aAAUuCoE/4kDsAwFAELACAsK8IWDs9c2HvMj7M | ||
| 964 | 4rf5AOAjfU7AGiRFHdbRpTOKh8cA8Nk+J2AVtH6U0kcvAYAtznxMw8/jKBYffLf49d215ctPY5u/ | ||
| 965 | 2Lp8az3zdVxsquaBkGv9Fkpdq2F7v4V63ra/9lhFWRaAj7QpYG1/isnkkV+PlX/hfL7M68+L73ot | ||
| 966 | bPH5ufXLt9az9sbW9V17vVz/oki/reNQ9zw3APhAW69gbf93J5raHO2Cx1VuPm7pt/KfWHm7gIwF | ||
| 967 | wPcY9EnuNSfj0cLWxLD3vwr/Nla8fQD4TiMGrPmtqBOL+WzCEADs4Su+RXi8YS9fAQAHODlgvb06 | ||
| 968 | dcXLV4V0NfLqrNUWqXneyNoo3e/3kUcJAGqcfItw8ev9kxcrT7fPJSufyFC//KSGjR8YL69vzeuF | ||
| 969 | +ruL2V5PuX0fcgfgq/y63Vq/B/fPz4WLEDVnfffRvpapB+B4dc8PypyefAaLE0hXAHy2M28ROssC | ||
| 970 | AIPJXNlyBQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA | ||
| 971 | wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACPuKgHW/388u4Q/3+320kr7B1cf86vV3 | ||
| 972 | +9oVLztrWOL9ftv8th7/s+PzbaN9rjMD1mSmP2ni73+a/OrxeDwej7NqG9wnbQZbfNs4XH19964/ | ||
| 973 | 1X5rO1eZl471WnzL3n/9po7/B9S5X+Pf4yuuYPVtzVu2sOcuJEvBRsfvvxzplCPkWqcDHq4XSxqw | ||
| 974 | TuZ+n13AsteD43NL+sn+z1+9ff21qdcXC8uvNbLYzt5+6lz838L4zJcvj89a1/P2C/0+X3kdpfJ8 | ||
| 975 | Ldb52mBNv63rdVuZ4qb1rWm8ss7yeC5uck3tROa9o/74+m7ff1vXd9JdX/1N+8vbIrdvD4V29uu3 | ||
| 976 | ppfW+b1tGP8OweNPffuvv9qyPd8a94sDxvN7jBiwyge4pp9vL0extS4mQWSxkdR6vf7Q3X5hfGre | ||
| 977 | 8nb5clBbXGyyQN+QLvZS7rd1yt7Oe+X6vm28ps615dfGobWdws+71h9c39ue+29qfju228JuMpfa | ||
| 978 | Hmr62qPft710zG/NevXVMxfcv15/WHtjzfmrqc5JkW/b2Xs8v8r5AWueNt4ea+pfb20n+5bFFk7Z | ||
| 979 | Lrf0eNZ792h/7RQe6atju211wHa+X7/BjWGP7eqssd1i73Fu6vfg9rfsjylNXawd/4/ckOrjGhHn | ||
| 980 | B6xF9UGbVlcct723h8X2H3V3cN62c4Cz9pfWfoc6uLfO74dtD5fr98TxP+X4c2I7pJwcsF4vY85f | ||
| 981 | fP7vMcU8QjfUidt1Ogrb2+vG2XHLKVzourM216Z+9x6fjv23aX67lz/YB2+HZ+2PZx1/WjltjeYr | ||
| 982 | vkXY5PF4LG6m9/v94L8PXk8Y/jQ50c8mYQouYW3/ffuW13BW3u9sD+cy/lzFyQHreShcOyYevxfd | ||
| 983 | /3Zwv4t+jiMdH9sK1r+lqbfv7Wh816mZXEmNtHOwPbquabOp3/3Gp37/LSyzuN9trPmUTeKTtsNB | ||
| 984 | 9sfDjj97NDXIee17jPgZrLW/JjusfXFjbeHytzl26rds/t7JmLyG1Mi41bS/WFi5qco655+06Oi3 | ||
| 985 | yVo9rf22jn+5/fpPnKTGp9DO23lsrbNm3m/R/bdcz7zx+v1urf7sdtu3PVSOc7zfyvab5nfL+E/e | ||
| 986 | u9bv4utnHX9SdfadF44/Dn+kX7db6+X0f35eO4R1XHEZQesB+mCj1fPW5Qpm0VXmcaf99yqrD9S4 | ||
| 987 | Nz634k9th4IRr2CdZcCEPlo9MKzg/mu/A7YTsP4w2sF0tHqaXLp4ni40j6lSL7TKwLB8ixAAIEzA | ||
| 988 | AgAIGyhgfcw3SPd4NkG2gM/wJas597Ur/mEGmcezyhhk9Z8clo/xVeMwUMCqlJqe0drZ29rDgSof | ||
| 989 | GtTX44CtXWi+zi5hE6erPvvtj8cI7qdXeeLUfu4vFl9cfKbD5H/XlucA1wtYH2Dvj9Autr/Wqc/z | ||
| 990 | Xk7flDm2jqZpP/02HzMO3fvdz9MEnibfbF18fU3r8qSc/28R/vww2Z0WvyZdeCrd2teqW9vpK36x | ||
| 991 | nfKq1axvod/52ydrt8fhaf60usWnidQ8Gq11fV9/qBnn1LyvtTN5dl98+bfrO3/gU7n9yu2hUP+k | ||
| 992 | u776y8tXPtMy1f4B87i2/GLxhfVter7X2vI19dSs19rrHcfntX4Lq7bWTr3g8eTtfjEvsnWXPEXr | ||
| 993 | vBe2q7dddJ8XLuHMgLV2pF7bcF8PE2vt3GYHlPp2WhXamaza6wLzvyFaD6DlJXf9G2Wyys9dq1x/ | ||
| 994 | eYG369s6zql5Lx9A6/vN1rk4v2/br1nr1Im8dT+dv6XcdbD9Xeex8PNt5/10TU1tb9crOO9Nm2j3 | ||
| 995 | cXIidTypqbNy3evLPkDrvBd+rumie5wvYZTnYB1wuDlytrb0dbmtqumweEDXBwxgaxd717nHKkfW | ||
| 996 | cXB7z+NoY7JWz651fsD4jNZ+65WeLVeGJn+llJdpbfPjjRKwJlrD1vF/CwY96u6MjGxt/NfS1d7z | ||
| 997 | ddb2UNPv5K+0Pctp07oddmy3nzTvrfN43b17u9S8DLW/HGZ+N631YnzqytAn7b/HGDRgfVsifu4w | ||
| 998 | twuuy/zS7vPnx+wG4vP1U+rZW9N67V3no/2DEa3bYd/y+zll3zlxe7uE4Phc4tjYsd+9bfC2NG5r | ||
| 999 | R9edHLCdX2J+m/gW4UAej8cpn8zY1eet0bX8bFQdb3k9STx/XpzKj9xux/F2/BlQx37H5xklYBUO | ||
| 1000 | HKnbhZXt3O/3g49in3TQXDsBB+d3ez3HNNvU9X6DcP/blhp+ZjD7J+wItxviNey0UovjH6znsEPQ | ||
| 1001 | pKMt/c6bOvFAOu+6fr/ra//HAX/YLLZ/wL7/GafFM28Rrv2VPNloJseU+Sc/1pZvbWfxXfVr0fRh | ||
| 1002 | w9e3lOss9zjperH9jtebFOZuskzf+k5arh+fxXr62pksv3gXoHse6+tsmq95Hiov/3Z/aV2+cj/t | ||
| 1003 | E2n/gHlc1LE/1g9XRz1N47Bl3ufvnfd76zpO7nfcrhmHyVXGpv2upt+atSuMT/f2fKubx1aR/e4S | ||
| 1004 | ft1urbcP/vl5bdPp3qQGcfX62dVVNo/Ugb7c7HVddEUuWvYBBhmZnfY7Ul5npD0mtk3loB9yP5H9 | ||
| 1005 | gc8Q/Ivw8/6yvBbj/9Y4x+2PvBJDHwFryv5A2YW2kFSpF1rlehdaqQuVepahhmioYjjRKB9yBwD4 | ||
| 1006 | GAIWAECYgHUBa1/3PfeLrJ/xNdoOp6/46QUA8Nb3BqxCahnqBPbz4c3r3tRvHc9THutyolQ9o60X | ||
| 1007 | wJf73oC1FlkuFGXePgbpsEoKLjSeV2FIAcZ35rcI508tW3w6xeuLiw8oKzx3JPJ12Y7nmjQ98G1t | ||
| 1008 | vWq6mCy89tS+xf8t9Pu2/o3n+LVxeP0hPm6t7Ve21jRut7r1fdvv26cyAnCukx/T8Hqmv72cMguB | ||
| 1009 | aS1XzZ31wLdyoFlcbPHn8olz/izdpsEp9/u2/i2Xx9baX+y9sHzh50Ud7desQtO41axv2Xze+9oB | ||
| 1010 | YFcj3iIsnCdaT0WJcraqKWNxmedHr/b7DFZ3s1vqCa7LWVM8yKYFwLAGfdCoT/4eb+2W1h5a269Z | ||
| 1011 | XugBYBwjBqz5LZVz27mKjg9yFZpKVLSsY16EJwCuZcRbhKN5/PkvpZ9bzFuXfqYDAHyG0QNW6l7S | ||
| 1012 | xmD0k7H6Pkd8cCa7/y1VzNrTwporq248/pa4EWqo1PocMgAiRrxFOLnV9fb0sLZ8oZ21L+gVvrhX | ||
| 1013 | H60eK/+a+trrHRbrLHxbrXs81+qvaWetznI7j9kzO4Ljlmp/8W5s37zP6ykob58e0wAwjl+3W9vh | ||
| 1014 | +PXovXZF57O/MT7s2p31WAoAuIRtzxtqO6WOeAVrQMErKPvJXukBALoJWFWuElauUicAfLbRP+QO | ||
| 1015 | AHA5AhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlY | ||
| 1016 | AABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgJV3v9/PLmGTq9c/8WGrc6IxR7K+qjHrBz7V73O7 | ||
| 1017 | nxzyHo/Hlqaa3v7T9fwta6+n+m3yOj7PXtYGbVLJ83+Dg9whNS+j2XXeGdPi/giw6OSA9UwAxx+t | ||
| 1018 | Ho/H4l+0a68fby0w3f48uNeMXuvyJxpn/JkYebOpsbH+wv4IMHdywFr0c+R6nmUnB7Xnz/MrOvOL | ||
| 1019 | H7v+xVno9/W3h9WT1VR/67x0F9Naz9qk3GZX/tbeUihm4/ZWOGEX6pwv31H/4vLldgor+3xXTf1r | ||
| 1020 | /a4Ny9oqzIvsqL9p/AGabA1Y9Yf11mbnx9+1A+LaZbC9/+IsXH5rqr+pu2M01d86L1uKaa3n9UxZ | ||
| 1021 | PqGune/n9t7e+gJHff2F5QvtLF5ZnAzFM+JExrmy+Jr1Wqv/bfuv/ytpAU02Baz9jjg1LTfdFzvY | ||
| 1022 | 3l23/oXduvwlziWVK1JzWr3E+ha01r+2fGQcCo3Ex3kyv4fNo/uDwFsj3iJcM78T8dZon+bpq2d+ | ||
| 1023 | mbD14tCuV/JO1DqewtYx7YwwzjV/gBWuhhbe+El7ELCfKwWs20uwuFUcQJsOmsfoOy6/rvXk9W8+ | ||
| 1024 | 1nfM79eO1ZEG3O9a2U6A7S75HKzH41H/iQoY0+s2/M0b8+XGQfwCalwpYG05+A544G4qaW3hnYLm | ||
| 1025 | gMNVtlZwYUVGWMef6eu4DLmx+MPWvbKjs8ahpt95FyNsOcD4RnnQaM1dv/IHWuef0Hr8+Z3tyRfK | ||
| 1026 | Fvttqmet3776y8vXBKlC+x0fcl/84NdiO63zUrA4/jX9tv5cWU9BeXurb3++WOv6dlic34Lu/bS+ | ||
| 1027 | zvrp6Gg/eJwBqPTrdmv9/tH7Zb75g0HQ57C9ZvDdc/DygEsrPOelQtuh6WIfcodP4krJD+MAfJ7m | ||
| 1028 | gLUW+BwVodUpYWLABDNgSQAbXelD7gAAlyBgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYA | ||
| 1029 | QJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGG/zy4AAC7lfj+n38fjnH6/TmacXcEC | ||
| 1030 | AAgTsAAAwgQsAICwL/0M1v3lDvqj9672/c/b8Fva6X4vAAN5PKaf0Jq/ckGT85TTVo0vuoL1zEM/ | ||
| 1031 | W8bTfcOmn2pnUbxBAHYRTxtjxJfX01DTKcn56/Y9V7Aq43bkylahnbftv9b5E9r8lQAwtNdrVPf7 | ||
| 1032 | H/87+fnpNX8svj5p5wxbzpvOX7cvCVjlaX7+KnUJdK2dt+3PX7GNAgytMgZNFnv+79rrt5MzVuX5 | ||
| 1033 | qHBec/76/FuEu07w/cXrVlXz3rfp6rmYa60AI1oMQD/BaO23ZZPln00dK3Xe/PLz14dfwSpvJc+J | ||
| 1034 | 796S1pJ76yb19hrbl/8dADCcQn5avPi0eAx/RqimpvZUON10nIy++fz14QGrPLXPO3fZTueXTN++ | ||
| 1035 | pVzn126dAONqjT6FCHW7rcasw+8SZiPRN5+/Pv8W4VUuUa7V+c1bJ8DQgrfw7veF1k76DFbhvNl0 | ||
| 1036 | Sv3y89fnB6xbcYPYO3sV2p//al7nl2+dAKPry1jPtxTee+q3CLdfm3D++vBbhE+v1zxft5u1n291 | ||
| 1037 | H8wqfD21r/3XOm2dABdQc69wksMmXxWcv372Mxpu6/cKa85rzl+32+1X6l+N/nMLMbIAfKizoo8T | ||
| 1038 | 62Z1X0fLjPNX3CIEADjSt9wiBIAMV5Ko4AoWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEA | ||
| 1039 | hAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEA | ||
| 1040 | hAlYAABhAhYAQJiABQAQ9nundu/3+04tAwAMbpeA9Xg89mgWAOAS3CIEAAgTsAAAwgQsAIAwAQsA | ||
| 1041 | IEzAAgAIE7AAAMIELACAsF+3297PrPLEUQDgKjK5yBUsAIAwAQsAIEzAAgAIE7AAAMIELACAMAEL | ||
| 1042 | ACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAI+3W7Pc6uAQDgo7iC | ||
| 1043 | BQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiA | ||
| 1044 | BQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiA | ||
| 1045 | BQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiA | ||
| 1046 | BQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiA | ||
| 1047 | BQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiA | ||
| 1048 | BQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhGh1u2IAAAR7SURB | ||
| 1049 | VAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEA | ||
| 1050 | hAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEA | ||
| 1051 | hAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEA | ||
| 1052 | hAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEA | ||
| 1053 | hAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEA | ||
| 1054 | hAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEA | ||
| 1055 | hAlYAABhv88uAADguu6Lr7qCBQAQJmABAIQlA9Z//vuvYGtAxOA75uDlAfQpfQZr8cD31+9/71bM | ||
| 1056 | 53gdug8bsZ9V275S//nvvw4emfn2XFPA8XX22bvO0cZhrZ7R6gS+1kLAeh6hnsepjcesLznkPVdz | ||
| 1057 | sr6Hrf4xHf31+9/XuuTwOiynbIenb//fsPcBjGYasCpPBoUrNM9fvZ7Vms4xry1Mrpcs9lsINGt1 | ||
| 1058 | vq2/9ZxUs4I/y8zHp6POxddbx7mj30g7zxfnQz3UvLTWudbO3vNSqHOt+Kb9pWO+Oq7gLo7/Yp1r | ||
| 1059 | 9aTmq69+gIk/AlZ9uiocoBd/bj3HTC4FPQ+FTVeGCgfo7BWmcgtvx6q1zkL9TeOcGp/WdhZ/29Hv | ||
| 1060 | W31DsaXOyPafGs/Xrrf02zoOHfO4Nm6L1upJzVd8OwS+0z8Bq/44Uhkm5r8a81C1eJiut3igX7vc | ||
| 1061 | snYK7KizsFjfOO89Na3tx+fltn5lIrXuke0/uz3U22kDCK5y3Mi1AVf3v4C15RZGvZ0y1muz878+ | ||
| 1062 | 15a/7flJ7dd7GZUXBVv7Lfy2cpwL45Ctp9Jh87Jdzfouxuv6i8SdlVVo3V8K9t6/TnH1+oFB/C9g | ||
| 1063 | bbyFUdnZ8Vew1rprDUCF9gsrVb5389Qxnk0Nvm1nPg4brzZ1O2ZetutrufsWfEdfHYLbYWoez3L1 | ||
| 1064 | +oER/PMcrPrPavQZ8P7gX7//PV/r//z3X03jsNhCpr4uHeO8OA4n2mlezjXg9r+30barVlevHzjX | ||
| 1065 | Hw8a7TiaVGaLvc8uP5WXe3nW9vb+Wl/vNUu+XaywQGFsX3+urz9Vc+XyW9b9tvO8bFHTRff237E9 | ||
| 1066 | 1Hi7v3Q0Xrl/9XV3ZMqRqICI6WMaau6tvJ63Juewya9+fkilq3lffcu3tlNf219/f+uq8GHq+fis | ||
| 1067 | jWdr/a3j3DE+k5NoeX3L4zz/pMve83KbnTtruthe55Z5qdke1uq8rcxXa79r7Qf3r6b9orC+TXXW | ||
| 1068 | FFNZP8Dcr9vtcXYNY9nvYtsX3iQKMnoADOm++Kp/7HnKWXxM5gUAAAAAAAAAAAAAAAAAAAAAAAAA | ||
| 1069 | oOj/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 | ||
| 1072 | AElEQVR4nO3dzbajOJoFUEevGOTj1dCP6GE9Xg1q0IOb5SQAyRIcfr336tXrlgNLH0KGY8Dkr8fj | ||
| 1073 | 9QAAIOf/ji4AAOBuBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAEL | ||
| 1074 | ACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAEL | ||
| 1075 | ACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAEL | ||
| 1076 | ACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAEL | ||
| 1077 | ACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAEL | ||
| 1078 | ACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAEL | ||
| 1079 | ACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAEL | ||
| 1080 | ACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAEL | ||
| 1081 | ACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAEL | ||
| 1082 | ACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAEL | ||
| 1083 | ACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAEL | ||
| 1084 | ACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAEL | ||
| 1085 | ACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAEL | ||
| 1086 | ACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAEL | ||
| 1087 | ACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIOx37xtery3KgP08n8+XeQzr | ||
| 1088 | +BxxV89nph1nsAAAwgQsAIAwAQs+eT7//r/IYrd39RG4ev0jN1sduI7ue7DgG83ea/J8/vH6z99d | ||
| 1089 | x7PRwmvuaBkV09j19C2l11P9dhmOz7uX0qCNKnn/z+AgL5DaLsDVCFhwnHcC2P+A+nrNZ8HS6/sr | ||
| 1090 | BabHo/h6Se/yBzrP+APrCFhwMj8J4H2UHYWDt+kZnenJj9nlg3WW+h3+6271ZHXV37tdFhfTW09p | ||
| 1091 | ozwmZ/5KbwGWWhWwnr5pwRaGZ1mGl7pmz8SUToNVzgBFVE6/ddXf1d0+uurv3S5riumtZ7iLrox/ | ||
| 1092 | 6e/PpTkEcB/xx46sPYPlOShczgWOCi0fq67rYjvbuuveM2G9y19it9a4Ii2zfen62v9zG1scF1wi | ||
| 1093 | hIt4Hyy77kA/lWX1TK9e9Z4cutA9WF16x3PLsAWMCFhwHcOfxX08EE4vCR1u2cG79PPMn8T5tYFg | ||
| 1094 | wfb92rGCI3gOFix11OHq9fJbM4CTE7BgqZ0jzpruTpjG1jww7G2joHnC4aorFVxZkcutI1yNS4Rw | ||
| 1095 | nK5f8o/CxGjh6R1ao9/ej35QNtvvgicLtN8ZVq+/vnxLkKq0v+Am99kbv2bb6d0uFbPj39Jv79+N | ||
| 1096 | 9QAr/Ho8+j5mf+61/NfUuZ7uedv4iCBPEuKb2P9zJ8P5nDq96wwWfLLgp2oAfDcBi6/jazes53PE | ||
| 1097 | fZVOYfXNeTe5AwCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIW | ||
| 1098 | AECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAlbR8/k8uoRj3H7F77GC91iLx3Er | ||
| 1099 | cpt+rzITdq7zKsNScvX6R262Oo32CFjTkb3TWO+/Ltker7Itns/nqUrtLaZU/9nWq+QSRT5ydV5l | ||
| 1100 | u6RcfT5v2ulzYPbF0euzhZWW30dq+9LFGSyu4fV6nbCp9Z0eUgwfXWi7XGU+L6vz8MP88/l8DQzr | ||
| 1101 | Kb1e0rv8gS40/8/s9w59/Eym9wYb/T1cbLrA9H9O/Szwbmr03mn7La+3TK/hV5PG9uvtvNeiPj6j | ||
| 1102 | 967vd1r/ozAUve13bZfphq5v+t55Mux6+sauOitNTZdfIDI/S+1Uxi2yvpX53FLq4s/vsu2y7CPf | ||
| 1103 | uHxLU4v3e8N2Tj6fF9e5cj9caiq4Xlvb9HOxuJjeekob5TGZ/727uJPbI2CVLNuhfGzq/Xep/ZbX | ||
| 1104 | G7+OzJa9YL1GTb2nWr2d+gIf+y3V/+gcz4pl7ayZCR/NfnfsqjO43Wel5ueyLyrT/7lgfWfnc2PX | ||
| 1105 | iz+/C+os/f2xyJblG5taOdvPP5/X1Llg59nVfmMX0+72sennYk0xvfUMN33q83gJOwWsd1zYaNTi | ||
| 1106 | bc7uDnbWtbvfs+v929laS52NO/p9LJifveXtvDqHNH7U/Ny636vM5zOMwxq9Z8J6l7/E/rNxRdrP | ||
| 1107 | WdzJfmewtktXFaWNenh4alSpf3Ykt16vVPuXGP9XzxWuH6can976D1zfrZ1quxzlxtu317L1ek6u | ||
| 1108 | XvWeHAqeETyV3vH8nrB15CXCHZQ20iU23vRU6vvvUlq9yjfCS4z/Y7ADfTTUXNley/pdr6v+xcuf | ||
| 1109 | 3Am3y1GOms9dXtvfiLOs2eHojV6/U1rqtWCefM9Y+RXhVZ3hIuaxhiOw6VC8Xq9Lj/ao/o/jdvX1 | ||
| 1110 | vSjzeeinyKOrgFXOHrCCe4Guy4Vn2/uUDoSVOr/hcuHPCGz09XFNYVvP25b2K8vMjtvKmk8yXF0d | ||
| 1111 | BWv+Gc9l7337hvnc3mPXkK7paP3CGwXWsx2GPlpwT87l1rHLkZcIR5NyeGF79tv2Fu2v73d6Z0Op | ||
| 1112 | /TX1l+oZnp1e1m/7nRlbrNdjbtymJY2+2Q+77iqj0k57ndNqp8uP3lvqd/b11Pz8WH9wfWcbbDd7 | ||
| 1113 | Vaj389tS5/S9s1ejurbLbMsL1nf2f9ZdYj731jnN/S1jst1+LPi56/28bPq5qIjsl1r+bqznun49 | ||
| 1114 | Hr2/Lfrn742+acECZuMyxi0lO5Jfu12WBSxY6Vl4rsSf+qbizW9y596+55tQlnGLi+QA2+XxZWc4 | ||
| 1115 | uDcBiwuz813GuMVFhtR2+WEcuIez3+QOAHA5AhYAQNidA9ZRv//cud/13Z3kh7InKYMf8c3xscFU | ||
| 1116 | j2ebSGerh3M65zxZ//CRb+YerFapH7O0/1b2rkrPm9i/kjXOth3P9mOrs9XT62z199ZTmp9d83b2 | ||
| 1117 | ZvPR53f4+uyv/0rLf+z6VOMPCwhYe+t6Xs4+dt6RlfbI13LC7Xh1qclwtkl1SD2l+dk+byuPS+h9 | ||
| 1118 | jILHLrS4+rBcvf4t7BSwSt+EKg/ca2+n8S0tD3yrf2Obfvmr1LPpepUar4zzcJnpKrS0s6DOBbq2 | ||
| 1119 | V6mF0vr2jk9kfadHlNkv943ba7b94R9rtlfXvFpQz8cu1vSbaic4nqVGSvu94P7nulLrm9oP9B6n | ||
| 1120 | SsvX26ms7PQZoV3H0wXPFStNzt76N92vXsIeAas+0O3nM5ZNlGn79Q/S9PXZfz1wvUozdcH4POa+ | ||
| 1121 | 0faOT1DX9lrTeEs78fX9mHSXtb9gfn4sb828KtUz7WK4QPs8rFvfTmo8S/U8Oud5tp7FdjsQbr2+ | ||
| 1122 | qePIguW75v9jMhTviBM57jQW37Jepfo/tr+mzks4+BJh18gu2AxH7XH23Bk1Tus1XWza/mn72rqY | ||
| 1123 | M+9WNppXa1Y5NVxnGPbGZLa+kY30noG4+hmL3ppLy0fWfc/jzstDX9e52D1YW4eJXql6Nm1n+KVn | ||
| 1124 | 5deFo8Y/0u+r57/GFez3wPYvbcH22rSdrZ1wfo56eRfWuzO50xmLMwT9lu1++PfDynHne/Z7VwpY | ||
| 1125 | Z9tIwXrO8KE9Q/tb9/v+tLe0ufV8O9t8PqGu7bVDO1s71fycrWr0+tXT0hXdYL/xPXPmzs/Bglmv | ||
| 1126 | 12uHS6uLDWs7bZF7Sm2vk2/3t6vUeXI+Rz+Mw4GuGrDa76fbupLZjtb02/XeysKja+fP53PZ181S | ||
| 1127 | F9NV3vmCRe/CLW9sXNm4UftrttcW9Vy6hjOsS4vddhrB9k8eBBd/jlau1FHHnZKjxqGl3zPPn/X2 | ||
| 1128 | uESYulHu9edvRBuvQ8/eQDBbT73O6R0SlXpm+30MJtOwqd7xKfW7YJy76jnqhsetx6dl+dF7Z8ft | ||
| 1129 | Yz2jKVSfzwvuq63Mz5YGg/Nqtp6KyOci2M5s/al6PvY4237X/qfU7+J6Wva3lfqPGv/ZxXr3AwuU | ||
| 1130 | 9v8lm26X9jIWtx+c5zfz6/Ho3Y//8/eB37DhS/iUwXq7fY5O/oE9eXkHepafTzHQN3RXuskdvsT3 | ||
| 1131 | fMOD7fgc/TAORxGw4HTsBGG9Qz5HJ/zwnrCkL3HVm9wBAE5LwAIACNs7YN37N5kjvSu70eB81ZhP | ||
| 1132 | 9T6p4XucczTaqzpn/dRNt1rl2Siz/1R6/ZxONZ8vNG73sOs9WM/qf+XxOXis/uiN9den/7TnJefe | ||
| 1133 | H2Vc/ccsl/4Ryivx7OlpC5cek5Wuvu4LPr+PuT1M+zMpHn/urz7uxBr3k+1dX2J7leo8qv6rjFvF | ||
| 1134 | DVbhck56k3tpHtRfP9sEWvAoo40qgamrz7ejbmGePQ3Q/kSiyvfMyvfPUjFdy5/TRcuOMw73s1/A | ||
| 1135 | Os/n/6eS2QfBlb5Zzi5ff7ra9MXe5Xvrma7jbFMtDwCsf8Nu/LLeO84L6vnYfukxg2um4qiF0tNT | ||
| 1136 | Pp6BKJk+5S/b/rCp6Ru7PheVpqbLt7zevl0Oqf/Sguu7ePmVZ/666tlnP1+vp3F+zjZe+VwvmJ+z | ||
| 1137 | u4XFxxcanfQM1tZmD5D1CT39u37abPqNtnf53npKb+xd39LrC04TRvrtHYfSnmhry4LOrNGKvHd5 | ||
| 1138 | wTMWs2dcurZXaT6s2b7t22v/+jey2wEstb5rlp9ustn93vCPj0Fnzf6hZfne/V5lfSv77dn5/LH9 | ||
| 1139 | rsLa26kfX2h30oDV+w24VynidC1/oN56jqo/vo16l2nfbXV5x5099z47dBQZ85WNr9leqTmzuICV | ||
| 1140 | tj6TFBGP9bPtTz9ZC77gHb6ffF3zPwtzlTrP76QBq7SBt97wLTv3k0++037hKAXlLdrfwc7p6see | ||
| 1141 | J+TeXpMrlR+V6rx6/VnTqzC9GWLPM21Dh2zHit799hnqb/xyWDrrtm1xf5axW1/3c9KAdYgDJ/G3 | ||
| 1142 | 8aFd4PCdbHtMmV3mKvXvVuewqtHrp/2a9DjlfvLwM1U7u3r938ODRm/lzPtlNjK8DLHp0e71em10 | ||
| 1143 | yXUfV68fuJb9Atapdm0fKzlPqe0q6erMq7Pp5aT6fdCj13cYpVQXo3Z+PlwbxeuVNc++fc9riGva | ||
| 1144 | 3HpKlNo/1d6yorfIE37ENi1pZeMtn+vGLq4yo27myEuElRsAp8ePelOlH5i0dD28AWL4Yu/Ena1/ | ||
| 1145 | +k/tywdvkPy4vi2vV+pfXMz6eurt77lbaal/TT31dro2R9fnpXc+9I7DgvHZrf7Re0v9Lq6nZX0b | ||
| 1146 | 95Ptt201bq8t6m8czy5r6m/vtH2/d+x8bhc8vlDy6/HovXr9z98LvjGf4RrWGWrgEN+w6b9hHYEF | ||
| 1147 | 7Bwqnn8+nKKwVN/o7X0Gy9blQHedfr6JAh/ZOezsG39FaJJxM6Y0wNn4FSEAQJiABQAQdquAtf8P | ||
| 1148 | dP3wdQcnH+TZJ0EcUgkA53G9gHWqx5yc8OEiZ6tna/s8vwoAulwvYFV8238wgccpN+IJSwJgZ3v8 | ||
| 1149 | ivDn8RLTB10+Cj8vLy1ffxpb19M+6y821vP+n+sfLrKg30ojlaFobKd3e71fKT2Acbpeo+4+1tk+ | ||
| 1150 | DvV2Kgs31l8vpn1eAXBjOz2mYXQQfRX+C+Gzx+D337Pveis927p9+d56UlL9lta30n5LSS3ba7TA | ||
| 1151 | O6J19ZsahwXr21V//Xl0XfMKgLva6RJhKeJ0LX+go+r5qn4vNB/eWgo7bfEAbOfgB4223J7s+PTj | ||
| 1152 | DGErcjv58OTQ9OzO+vZv3A4AV3FkwNro4Mp2Ng15wfmQqjPSjnkO8IVu9StCAIAz2ClgffzWft2v | ||
| 1153 | 9aV7lm//fKaVZ5h+xqd0imh6n/jivja9zLf+qWy3nycA32mnS4SzP/sfvdh4mJn+lv5RfUJB+/Kj | ||
| 1154 | GlZeHlqwRtl+Z8d5Tfu97axZfvre+mMjttiOpXYqdX6sp31WAHBpvx6P3odz/vN34w/Ob/y79Pqq | ||
| 1155 | 3XjFAeA26s/f+Z++A7p7sFaRrgCAqT0C1nfmjO9cawDg4QwWAECcgAUAECZgAQCECVgAAGECFgBA | ||
| 1156 | mIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBA | ||
| 1157 | mIAFABB2yYD1fD63bn+LLrYue2fbrc7NBurtrusFwNQeAes5sEN3Kz2fz9fr9Xq9ji7kg97BvMr4 | ||
| 1158 | p6TGp3fcvmqQASjZ6QzW638ih5/zp58TutCgHVJqqdNgMRfaBACs9Hvn/n4y1vtIM8xbwxeHh6Lp | ||
| 1159 | /3xMjlWz7VRe71Wp8/1Pje3PLt9V//vF2aHo0jtupZWNj890ArSPW2V8tp4PpX7rL07bqYzb+o0O | ||
| 1160 | wA72DlhD9SBVMj0NVmqnt/3SAbLSTunvShfT5Xvrn/3XBXr7LSXj4Pg85rZvqZ3e8Vk236aWbZf2 | ||
| 1161 | eVv5G4CrODJgbWTx0WhBcOnt6xJHysUxaFlTLRpLOk8x23VxiSkEwMEBa/YgPbyMuPLr+553HN/p | ||
| 1162 | yLfgDvGPy8TH5x3y2ltOzQd3sgNQd3DA2jqU3Cn07Gb2pre6o8b5ncJbaliwXpu2A8CNXfI5WDAU | ||
| 1163 | /IHq+X3b4zYALmrvgFW55Df6RdXPgWTBqZHS4ecMh6Uz1NBlwWDuto5rOnKtEIBN7XSJcPY356Oz | ||
| 1164 | Di1ZavaHfqV2FrQ/K9XOqKmPddb77boDafG49f7dWE9XnSW941OpufID0unrlXZm+21p5+PK9i4G | ||
| 1165 | wLF+PR69v4P7528/IAcArq70HKI/9QUe92ABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBA | ||
| 1166 | mIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBA | ||
| 1167 | mIAFABAmYHETz+fz8BYA4MfvowvgMqb54/V6tbyrZTE28rPVppug9DoAEQIWHe59PL7l2r1er9kz | ||
| 1168 | c6XXAYgQsFjr5xzV+2j9jinvV6YnS4aH9uHys+3Uu55duNL+qOzRW1raqbz+schRL13jUKm/q55K | ||
| 1169 | nZXxAaCLgEXA6GD/8/fP/58ep+tBoZQnPnba0n7F9IxOqZ0F7Y/e+I5Q8XForAeArQlYdCidKUkd | ||
| 1170 | 0Re3s8MFr3hqqTTY1Zc4BXBCAhYdUsfyljC0pq/KXUel82rr279BOwCkCFgcYOuTLpdof/YmsAPb | ||
| 1171 | ASDIc7CAx+PPy6xSGsBKAhYHixzLK42M7ht7Pp/Lrg+Wuti6/j2LWTM+AAy5REiH0fG769d574VH | ||
| 1172 | N6RHbmwv/d3Y/uwTJUrtbF1/7/KVdkpPyqg8QUO0Aoj49Xj07U+Hu1/fdOGufLqB71F67s+f+naJ | ||
| 1173 | zmABf4ucmQPgIWDRyl3PX2D0QNijyoBWvgZwYm5yBwAIE7AAAMIELNKOOmm/ab+uRLCSKbSeMeRS | ||
| 1174 | 3IPFUq/XtrfpbN1+u65K1pc9beHnldHRZbjMnz/unW/nY2H15X+6KHU66re9yAVNrVyvR8N4NrY8 | ||
| 1175 | LbLUVOUtswvPDn5j4x/1zueVnbaMz7CkyvI/W+0kuwX4RMCC65gNFr2BY4FSX6V+S2Go/vrHhLc4 | ||
| 1176 | A5V8DJS9jbS88eN6jVrIbt+uk0Cl7d7rYwLuWh4uQsBikdLRqHKo6DoD0fgNvqvfZUrlTdt/v1g/ | ||
| 1177 | 2bPbwWP4df+o7/2lUw6RUxHbrdTsKa5H/3Yszc8FXdfbb6+nfb1Gibl0kmnlPO9a32klcGICFv0q | ||
| 1178 | CWm4o1z8zbvxTEa830al9ktRpree6cHs2MNJ5UC7p/qo1t/YO56Nl+0+Xur6mEjqXdSXXzDPF69X | ||
| 1179 | y/IL6jl8bsOWBCyiur6MLu6i3u/Wu+ze9oP19J4heA9Le7TdtJ4uleJTB+bdzixOPxfT6dqSbIbL | ||
| 1180 | HxVNFvTbcib74/JwNQIWnRbcITtSv3Q1faU3JZT6DVoTRCovdp2B2OLbf+lyT2l9t77++G7/sc2B | ||
| 1181 | dsEZl3jXjaP38VJ15cX4epWWL33eR8t8PIPbtTyclYDFllJ7xq4DbeX+rYje9hvvVxt6Z9CVR5fU | ||
| 1182 | PVj19d36uuF0FXp7TI1n17WzBUpXuj9ejny0zauSrrdU5n9v15Ur+3B9AhY9tt4J1tvf+nwJp/Jx | ||
| 1183 | Mlx0JpTKLp1Ou+hqfrT16Vg4mgeN0mzlNZTRN93Xq/Wu2JZTUF3XLLrU7ypLXVsp9Rs5ffX4tBbr | ||
| 1184 | ldqvbNP1B9SulYoHsq7xPNs165amhsO74LM5fO+yAkr/KopxEc5gsdroBvPZvx8rLheW2mnpd4tg | ||
| 1185 | UW9/esdYsJ6P4/BYMc5BpctVH18fDl3Leq2MTaX2F9czra3+d0s7j0nmmNbTOK9612v29sfe9Voz | ||
| 1186 | bi3Lw1n9ejz6dvd/zvzna+tvZpzEl+/m7vS9ueVO5Cu663rxNv0YOgARMswzz+J+o2++OYMFDe50 | ||
| 1187 | nL7Tugzddb14s4m5FAGLNr4pAkAzN7kDAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAF | ||
| 1188 | ABAmYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBA2O+j | ||
| 1189 | C9jW8/l8//16vdY3srKdxe8FAC7khgHrnWNGgWZNvkm1M0vwAoCbuVvAagwrkTNblXY+tj+s8/V6 | ||
| 1190 | yVgAcCe3Clj1mPL+p9SZrVI7H9ufviJjAcCd3CdgbRpQZs9INXb3MV29F5OxAOAebhKw6tHkHY/i | ||
| 1191 | 92CN7n//6OM5NhkLAG7gJo9p+IkmlX/dIrX8hKG3lrfU65SuAOAebhKwHp+yy3mU6pSuAOA27hOw | ||
| 1192 | HtWMtXX2qp+XGr0yrVO6AoA7uck9WG/D25iGOab096PtxqzSTe6L2x/WKV0BwM38ejz6Du3DJCAZ | ||
| 1193 | AABX1/bztb7Ac6tLhAAAZyBgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmAB | ||
| 1194 | AIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQJmAB | ||
| 1195 | AIQJWAAAYQIWAEDY75Xvfz6fkToAAG5jVcB6vV6pOgAAbsMlQgCAMAELACBMwAIACBOwAADCBCwA | ||
| 1196 | gDABCwAgTMACAAj79XiknmXliaMAwF315SVnsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAEL | ||
| 1197 | ACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIOzX4/E6ugYAgFtxBgsAIEzA | ||
| 1198 | AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA | ||
| 1199 | AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA | ||
| 1200 | AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA | ||
| 1201 | AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA | ||
| 1202 | AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA | ||
| 1203 | AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA | ||
| 1204 | AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA | ||
| 1205 | AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA | ||
| 1206 | AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA | ||
| 1207 | AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA | ||
| 1208 | AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA | ||
| 1209 | AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwn4fXQAAwHU9Z191 | ||
| 1210 | BgsAIEzAAgAISwas//z3X8HWgIiTfzBPXh7AMrV7sGZ3fH/9/vdmxdzHcOhuNmI/q7Z+pf7z33/t | ||
| 1211 | PDLT+dxSwP51LrN1nWcbh1I9Z6sT+FozAeu9h3rvp1bus75kl/dezdH67rb6+3T01+9/X+uUw3BY | ||
| 1212 | DpmHh8//b/j0AZzNOGA1HgwqZ2je/zQ8qnUdY4YtjM6XzPZbCTSlOj/W33tMalnBn2Wm47OgztnX | ||
| 1213 | e8d5Qb+Rdt4vTof6VNult85SO1tvl0qdpeK7Pi8LtteCM7iz4z9bZ6me1PZaVj/AyB8Bqz1dVXbQ | ||
| 1214 | s3/3HmNGp4Leu8KuM0OVHXT2DFO9hY9j1Vtnpf6ucU6NT287s/+6oN+Plg3Fmjoj8z81nsOu1/Tb | ||
| 1215 | Ow4LtmNp3GaV6kltr/g8BL7TPwGrfT/SGCam/3TOXdXsbrrd7I6+dLqldAhcUI+BqLYAAAHNSURB | ||
| 1216 | VGdlsWXjvPWm6W0/vl0e5TMTqXWPzP/sfGi30QQIrnLcmWsDru7vgLXmEka7jTLWsNnpt8/S8o8t | ||
| 1217 | 79QeXstoPCnY22/lXxvHuTIO2Xoa7bZd1mtZ39l43X6SeGFlDXo/LxVbf74OcfX6gZP4O2CtvITR | ||
| 1218 | 2Nn+Z7BK3fUGoEr7lZWqX7t5WzCeXQ1+bGc6DivPNi22z3ZZb1nLiy/BL+hrgeA8TG3Ho1y9fuAM | ||
| 1219 | /nkOVvu9Gsuc8PrgX7//PV3r//z3X13jMNtCpr5FFozz7DgcaKPtcqwTzv+tnW1e9bp6/cCx/njQ | ||
| 1220 | 6IK9SWO22Pro8lN5vZd3bR+vry3rvWXJj4tVFqiM7fDv9vpTNTcuv2bdHxtvlzVaulg8/xfMhxYf | ||
| 1221 | Py8LGm/8fC3rbs+UI1EBEePHNLRcWxket0bHsNE//fyRSlfTvpYt39tOe21//e9XV5WbqafjUxrP | ||
| 1222 | 3vp7x3nB+IwOovX1rY/z9E6XrbfLY3LsbOlifZ1rtkvLfCjV+Shsr95+S+0HP19dn4vK+nbV2VJM | ||
| 1223 | Y/0AU78ej9fRNZzLdifbvvAiUZDRA+CUnrOv+o89jzmKn5PtAgAAAAAAAAAAAAAAAAAAAAAAAABQ | ||
| 1224 | 9f+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 | ||
| 1229 | 3klEQVR4nO3du7ajRrsFUPUZHfjx/lCPqNCP58DBCWTLbC6lqmIhQMw5HMgSqvoobmsDon/dbo8b | ||
| 1230 | AAA5/7d3AQAA30bAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA | ||
| 1231 | wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA | ||
| 1232 | wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA | ||
| 1233 | wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA | ||
| 1234 | wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA | ||
| 1235 | wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA | ||
| 1236 | wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA | ||
| 1237 | wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA | ||
| 1238 | wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA | ||
| 1239 | wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA | ||
| 1240 | wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA | ||
| 1241 | wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA | ||
| 1242 | wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA | ||
| 1243 | wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA | ||
| 1244 | wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA | ||
| 1245 | wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA | ||
| 1246 | wgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAA | ||
| 1247 | wgQsAIAwAQsAIEzAAgAIE7AAAMJ+pxp6PFItwbHc7/eH9ZtvZz3nau73bdt3BgsAIEzAAgAIE7Ag | ||
| 1248 | 7X7/579dvj7b4BbTpyqMn6bf+rz/Xr51vuBLCViwgcdj5rbEpQPk6P3Z7xa8Alk8mW3h4OW9dKTS | ||
| 1249 | 2a+0LpGzjA/wTuwmd2A35UDWeufy2e903qX+x2M+Gy2939cFcB4CFny159F9eGy+338c9UeH7en0 | ||
| 1250 | t5+nVZY+env4f01Z7mJU6lK/5V4q53e2/UKdHfUUiqzvt/zmtJ3C8gU+ZZOAdXeWGw5i9gzK8xg8 | ||
| 1251 | fT07/WiCpe+OJputZGmy2XYK/ZZ7qZzfpfaX6uyrZ6q136ftlsuPJu26+X4fexzJVmewPE+Fr3GC | ||
| 1252 | o07rmZU1m+cojUVsvbuIjMlZZnZFF/bbfL1P7s9dIoTz2/S4+Dp38vmj76a7wo75OuwPJ4HjEbCA | ||
| 1253 | d15Xr26fjVmfObNVOV/TS3J9Uu0Ax+YxDfApS4fws1yXeT4/4vsCwbfOF7ArAQs+pfI5WEdzkPIO | ||
| 1254 | 9TxS1wqBd1wihO9V/uV/5fSjszsrz7fV3/nU0W/T/Jbbn9Y5evbB8LtL/b4dz+mZs9nx+cByAdJ+ | ||
| 1255 | 3W6ZzfLn3sC/ys73aF6fVz6CyBOM2IP9NlcwXM+3PoPsDBakrT/HA8DJCVjwhj/ruQLrOdezdAor | ||
| 1256 | sy24yR0AIEzAAgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQs | ||
| 1257 | AIAwAQsAIEzAAgAIE7AAAMJ+t37h8diiDACA7+EMFgBAmIAFABAmYAGHcL/vXQFAjoAFp3G///hv | ||
| 1258 | ZVMdXde/n+r3LIwDMCJgwWk8Hv/8yuT14pNdN70f7OIUTl08sIXmXxECh3K/3x6P/86IDI/0w9Mk | ||
| 1259 | r/dfbz5fvJ2+r6SmfstvTttZmt+met7W+erl+VGq3w+MP3AEqwLWfbA/eNgfwE6ex/7R6+Gbw/+d | ||
| 1260 | /bQw/Zpiavp9GmaXt/UsvW6qp9D+aILZr3T3u/X4Awex9gyWXAW7q9kK306T2pQ/sEtY08Ve3wWu | ||
| 1261 | xiVC+E6jK1w1Undeu4P7qeOXBMDXELDga72uRt0qYtb0ElWfVDtfoPWMlzNk8E38ihC+3PMnh1cO | ||
| 1262 | OgCfJ2DBd1qTqL74WuFew+JyIVyNS4RwGuUnHYyMzlqNJp7eoTV6BsHwu0v9zr5faGe235p2pvXX | ||
| 1263 | W2qno/23j8Oor788/pX1AEf263Zr245/7lbus78iXHof4KQ8NwG+wDCf3BdPFGc2dZcIAQDCXCIE | ||
| 1264 | eM/pK7iMzJktZ7AAAMIELACAMAFrQ8s30J2jfcpS43/x9WT38nYvAPhKOwes+08rm+rouv79VL9X | ||
| 1265 | c7Xx3Kv+q/W75OJp9Wt8fpxHPb4t4DvWhO+Yi8PaOWA9Ho/nDyZfLz7ZddP7wS7O0n7EKYrsk5o1 | ||
| 1266 | 68m+jA+whSP+ivD5mIpXsh7u/oZxe/ooi+eLt9P3ldTUb/nNaTtL8/u2pJr23zYynb48v69qnx91 | ||
| 1267 | 1H+o5djXfqHI2UVT305rPa3r4dJyDPbbPZ6V7XRsj+V+R43Prs+p+R09JnDpqTyj/cN0+tbtrmO/ | ||
| 1268 | Ol2Xyr001V+Yfviie7/UYTi2b+dr9ouV00+/Pp2+Y7nvsv12H68r9z+t68+hHDFg3SaDOFyxptPM | ||
| 1269 | flqYfk0xNf0+Dde5t/UsvS5oar9pvgrtjCaY/Up3v3stx772p+NfXh/q22mtp3U9nH7ltYuM9Nsx | ||
| 1270 | nk3be9/2WJiL6fjM1rPX+ln5lfg4N1XSUX9wP1DYHa3XOj6pcaj8Svd+bK/td9p13/4ntd1t6qA3 | ||
| 1271 | uVce4dY3kirmgF20trmmhgOu2W+dpeaz1LnG0ebxaPUs+eQ23urItRVquN/vo0N102E+UkNkmk86 | ||
| 1272 | Wj3HcdAzWLMe7WeAp3+b9km1s6mO8dlL63hGxv8s47NjnadYz5m1Zm3ZZfvacX/eaqnfpXTVVOfK | ||
| 1273 | 7X10Fqejhax4PcOTW9OzVuvb39SZAtZtcGrxVrE6phbGiRZq0/jsaK+/bs81Pp+v88hjwnb22r76 | ||
| 1274 | pt/UtIvC/n96YWupkZpO12/vR9t+t67naPM7ddBLhGWPx+Mxd+cET8an7Czjc5Y6aTJcpl+5cEfr | ||
| 1275 | 7dv5PfV6Hqz81OPArDMFrDVr3hWuFa6sba/hXXm58HnPxBYd7eUgdX6yjIPM8sfM3utT4wMDteZM | ||
| 1276 | /9JHs/P7mf1V/f6hu9NyKnrbe015HbNwtG1qTT0128vR5vdp50uEo79s3v7qYXR6dvbT4U8VZv+K | ||
| 1277 | KvQ7+36hndl+a9p5O7NlkfaXpu+oczREa+osL8fC9E1F1rc/q7DeNt1REVxP6tfDty2s7De1/vQt | ||
| 1278 | r/XjX1nqmvmdnaxmfrc4w/G238ohfbtcWqePjPN6NeP/GFwr3GI/XLPcd9x+I/VsPf0uft0a/3Xo | ||
| 1279 | 4VwsJcqOv8w4r90X9+4FQLerrb1Xm1+O5v7zoRKN325bdU92kzuM2F9zOsf/yzvravMLTwIWa+27 | ||
| 1280 | x7S/5nSuttJebX7h6Uw3uQMAnIKABQAQdsSAFf+ZzDF/wLneMedrWtUx63zrpGW/7F7/7gU8HaQM | ||
| 1281 | RvZaLtaHkQ8PyKXGf/+AdZbhbq1z6fkrrc9lOcv4nF1qnL91eW09X8Y/62jjIE71Oft2cfbxX2n/ | ||
| 1282 | gPUBu9xiudRpsJiz3Dp6ljrJstzh+Pq204snp0p7/oqw/JS/8oMrp9OXexk18vbBmMP3C3XGHxxa | ||
| 1283 | 2W/5zWk7S/NbLmb6DLql+S00Xl9nh7f11LSfWg9bn1p5nzzYujzOhenLvVTWX+h3+CK+3aW2r633 | ||
| 1284 | Jx37jWkN5V5al3tkf1XY3peKTO0/by3LpXs/9vl+m8an0O9S/U11th5Haupv2vNsenw/uD0D1nME | ||
| 1285 | Z3c6o53I7JSVB5jZZ+A2tb9UZ189U639Ls1XeUdc2O/PNn6bjMxS+0t7/I46m9TUU9N+aj0sL6/1 | ||
| 1286 | 87Wyqbf1Z+erfrtLbV8f2J/0tVMfhZvqCe6vZrf3yq7XrD+t49m0H9ur39b2g8uxaft6jVLH8bHj | ||
| 1287 | INLUfmUXx3fQS4Rbj2xlMlvfSKqY43dR39FGxWzR7NIuKd7RRo5W6l71nGhT7e5r99o6CthrHlvr | ||
| 1288 | /2Sda447Z1nPj7Zf2s7JHjQ6zdpBj7oz5FvUs+l8BR1qfjuWV8pZlhdlp16fd9xfjcqIt1/TzhZb | ||
| 1289 | /S7js9FyPGOI+b796skC1meSdeXqPj2l2ddpqp0PiIx/cH6bllfKiZYXZUf7i791fe6bfiPx7frD | ||
| 1290 | PrBdL83XLsedVo+WG9G6u9ii2R0d9BLhvh6Px+yVaY7ppMtrWPPpimc7o/X57Xpy0vWfkVMsx2eR | ||
| 1291 | e1dxGicOWPEVcU2Dh7rW8BmzpbbWP3t/ZWUjRxirlTU896cdt3OeaIjOYvdNuPDF2fVkZcGbrhvB | ||
| 1292 | xndZhz/QaeSPq88Pzv1fH+ho6y4+YP9LhPVXoEfpvuaYNFqJy18ptz+tc+mvzEK/s+8X2pntt6ad | ||
| 1293 | tzPbYan91nGonN9IPbfqcehbDyuXV7m1Qvu3unGuLLW+/WlhTfPVtN0ttf/J5Vjffn07w0oi+5/W | ||
| 1294 | 6SPjWS+1XWTrTG3X66W2u746648jS6b5vm+7fjvl63/fNn58v2631t9H/Pd6aYg7/iKHl2uuP9ec | ||
| 1295 | a1pZT9hFX8A6oPvPh0Q0frttlvc/gwVD591uO3zfX2xswXrC7r7yDNPWBCyO5VLb7aVmlm7WE47A | ||
| 1296 | etjqxDe5AwAck4AFABB2iID1HT/InPrW+QIAyg4RsCI6nsC09CSnpqakKABg5BABa5db55Y6DRbj | ||
| 1297 | lkAAuKb9f0U4+/Sz2Qck3hZ+rlx4WlrqZ6Wt/ZbfnLazNL8AwBntH7Bmn0U7ehTY499/C3P2QWez | ||
| 1298 | nxamb9Xa79J8FepZeg0AnNEhLhFOVT6Df30jqWKO3wUA8DH7n8Gq1/qvvN0O8A+4AgAXdKaAdRtc | ||
| 1299 | lbtVxKzpJbm+TlPtAAAXcdBLhGWPx2OLf+0cACDiTAFrTaI677XC1udyAQC72/kSYflJByPlf817 | ||
| 1300 | eofW6NkHw+8u9Tv7fqGd2X5r2nk7swDAef263doO88NUsPRAAQ8aAACOZvRQpMZvtwWbM10iBAA4 | ||
| 1301 | BQELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACA | ||
| 1302 | MAELACBMwAIACBOwAADCBCwAgLDfexcAAJd0v+9dwWc9HntX8FHOYAEAhAlYAABhAhYAXNXFLtt9 | ||
| 1303 | 0kXvwboPrnw/elev+8/L52va6f4uAN9peFxYebfW43G5+70O4EIB65VjRoFmTb5JtTNL8AK4llcS | ||
| 1304 | GkWi7RLSRs2KdNcJWJVhJXJmq9DO2/aHdT4eDxkL4CoqQ8nsma3nd18fDd8fvhi1P32z0M5S4Jut | ||
| 1305 | 59nItTPWJQJWOaa8Pkqd2Vpq523703dkLIBLKMeRyqAzfT17PmzY7PT4stRmTdnD/718xvr+gLVp | ||
| 1306 | QJk9I1XZ3dt09ZpMxgL4ZpEgkooywUh07Yz15QGrHE1e8Sh+D9a9cX16e45NxgL4TmePIOVj04Uz | ||
| 1307 | 1pcHrHI0eV25y3Y6vRT49ivlOqUrgK919gjSdA3xSr7/OVjP7LJ3Fe8t1SldAXy52Xuhhk56FLhw | ||
| 1308 | urpdIWDdihlr6+xVaH/60bRO6QrgEt5mrOMo1Dn86Nrp6vb1lwhfhtfghjlm6fWt7saspZvcu9sf | ||
| 1309 | 1ildAVzI8FrhKG+Nfpo3fb+m5dH05Sc4LLVQeD1s5PLp6na7/brd2g7hP0dyPgFIBgDwxtUiyAGC | ||
| 1310 | wZqfo7XmpUtcIgQA+KSrXCIEgGM5wBkdtuMMFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQtvYx | ||
| 1311 | DcPHlK8uBgDgG6wKWEIVAMCUS4QAAGECFgBAmIAFABAmYAEAhAlYAABhAhYAQJiABQAQ1vwcrH8f | ||
| 1312 | LDrmkVgAAE/OYAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYc2Paah0X3qcAwDAt9skYD08FAsA | ||
| 1313 | uDCXCAEAwgQsAIAwAQsAIEzAAgAIE7AAAMIELACAMAELACDs1+229TOrPHEUADiLTC5yBgsAIEzA | ||
| 1314 | AgAIE7AAAMIELACAMAELACBMwAIACBOwAADCBCwAgDABCwAgTMACAAgTsAAAwgQsAIAwAQsAIEzA | ||
| 1315 | AgAIE7AAAMJ+3W6PvWsAAPgqzmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm | ||
| 1316 | YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm | ||
| 1317 | YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm | ||
| 1318 | YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm | ||
| 1319 | YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm | ||
| 1320 | YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm | ||
| 1321 | YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm | ||
| 1322 | YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm | ||
| 1323 | YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm | ||
| 1324 | YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm | ||
| 1325 | YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm | ||
| 1326 | YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm | ||
| 1327 | YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm | ||
| 1328 | YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm | ||
| 1329 | YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm | ||
| 1330 | YAEAhAlYAABhAhYAQJiABQAQJmABAIQJWAAAYQIWAECYgAUAECZgAQCECVgAAGECFgBAmIAFABAm | ||
| 1331 | YAEAhAlYAABhAhYAQNjvvQsAADiv++y7zmABAIQJWAAAYcmA9dff/wu2BkQcfMM8eHkAfUr3YM3u | ||
| 1332 | +P74/edmxXyP4dB92Yg9Z239TP319/8+PDLT9bmmgM/X2WfrOo82Dkv1HK1O4LJmAtZrD/XaT63c | ||
| 1333 | Z11kl/eazdH8fmz2P9PRH7//PNcph+Gw7LIe7r7+X2HrAziaccCqPBgUztC8Phoe1ZqOMcMWRudL | ||
| 1334 | ZvstBJqlOt/W33pMqpnB5zTT8emoc/b91nHu6DfSzuvN6VAfarm01rnUztbLpVDnUvFN20vH8uo4 | ||
| 1335 | gzs7/rN1LtWTWl599QOM/AhY9emqsIOefd16jBmdCnrtCpvODBV20NkzTOUW3o5Va52F+pvGOTU+ | ||
| 1336 | re3MftrR71t9Q7Gmzsj6nxrPYddr+m0dh47luDRus5bqSS2v+HoIXNN/Aat+P1IZJqYfHXNXNbub | ||
| 1337 | rje7o1863bJ0COyoszBZ3zhvvWha248vl9vymYnUvEfW/+z6UG+jFSA4y3FHrg04u38C1ppLGPU2 | ||
| 1338 | yljDZqd/fS5Nf9vyTu3htYzKk4Kt/RY+rRznwjhk66n0seWyXs38zsbr+pPEnZVVaN1eCrbevnZx | ||
| 1339 | 9vqBg/gnYK28hFHZ2efPYC111xqACu0XZqp87ealYzybGnzbznQcVp5t6vaZ5bJeX8vdl+A7+uoQ | ||
| 1340 | XA9Ty3EvZ68fOIL/noNVf69GnwNeH/zj95/Tuf7r7/81jcNsC5n6unSM8+w47Gij5bKvA67/Wzva | ||
| 1341 | etXq7PUD+/rxoNGOvUllttj66PKsvNzLq7a319f6eq+Z8u1khQkKYzt8XV9/qubK6dfM+23j5bJG | ||
| 1342 | TRfd63/H+lDj7fbS0Xjl9tXX3SdTjkQFRIwf01BzbWV43Bodw0YfPV+k0tW0r77pW9upr+2Pf391 | ||
| 1343 | VbiZejo+S+PZWn/rOHeMz+ggWp7f8jhP73TZerncJsfOmi7W17lmudSsD0t13haWV2u/S+0Ht6+m | ||
| 1344 | 7aIwv0111hRTWT/A1K/b7bF3Dcey3cm2C14kCjJ6ABzSffZd/9jzmKP4MVkuAAAAAAAAAAAAAAAA | ||
| 1345 | AAAAAAAAAABF/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 | ||
| 1348 | CUlEQVR4nO3c0ZKjKhAAUHcq3+hH8pX7kHtTLGgLaoJmznlJVGxbmap0AeM0AQAAAAAAAAAAAAAA | ||
| 1349 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwTVNK6WCDm/qO+zrefd/xHADgfX6maUqZ | ||
| 1350 | 0flsWEy1SPu1uba/jhk3GG4z829y4s1+5fMB4BYez495np9fUkqv77sdj7CoyC3fPCXtTR+4RO2C | ||
| 1351 | 1dWQ59BLdQXAQI9ie57nonDJD+UtX4cW9681nqpibi3OZ7RXZvV9reW/VggGBWKcXl0rrO2Pk5/a | ||
| 1352 | +qXllHf0bzGUWP8R1vvjgluNBcBIvVNs8QxdcGJvnDhssb9Oe3OKsHEOMWi/mP/BKcvN6/ZGKJK8 | ||
| 1353 | bP/GzXZ0nwILgFF+9p3WNdoUNL7FZFOg9znkxceQe2+8qP4FgCPKKcLCWWMA544lLM46FZObLUE+ | ||
| 1354 | //P/qrEuUnlcs38B4O42CqxT6oB6rczBgK8lTQfjcM3+BYC72zlFeE3t65pHzdA9r2v99SmKKdex | ||
| 1355 | yQBAriywgspjx4LlOMgRR+J8sroqHtrruqNqrOCil+rfRs/HOKpcBoA1/00RBqua8s3FQ4vTQ/lK | ||
| 1356 | o6Lx7t/gljhBm5bf4CLm5psCdufZqPfNBV35XK1/iwjFTQX76yBdzwcAgGVmCQG4jj+jE4D9ekco | ||
| 1357 | AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgPOklN7d4CLukicA | ||
| 1358 | cC8/oxPollJSGAEAN3P9Aap9CQxPGwD4JR7Pj1fxMc9zfjgvStYOLe5viZNSmud5LU6XtTyD4HWe | ||
| 1359 | cT6L9wUAsCyvTvIJuGLIJ99fnBIEPBKnJeE4fhy8PjE4xdQkANCoXIPVOELTNZATNL7agFCc6tWy | ||
| 1360 | BQCu6REfPmvMxtgPAPB7bBRYp4zZPNc25ZvHY7Y4a4EXAECXjQLrC5xVWlnkDgA0KtdgBcNL+xak | ||
| 1361 | t8d/k/S/D18XAPi1HlM1lbb4ffp38GZt9q34D77noSBmr834U/UaiPzc/FAdJ2bsCgBg420OAABv | ||
| 1362 | 8md0Au8VvCgVAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | ||
| 1363 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | ||
| 1364 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | ||
| 1365 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | ||
| 1366 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | ||
| 1367 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | ||
| 1368 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | ||
| 1369 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | ||
| 1370 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | ||
| 1371 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | ||
| 1372 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | ||
| 1373 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | ||
| 1374 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | ||
| 1375 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | ||
| 1376 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | ||
| 1377 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | ||
| 1378 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | ||
| 1379 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | ||
| 1380 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | ||
| 1381 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | ||
| 1382 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | ||
| 1383 | AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA | ||
| 1384 | AAAAYJC/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 @@ | |||
| 1 | Packages,Encode to FASTA (ms),FASTA file size (KB),FASTA gzipped (KB) | ||
| 2 | 1KB,5.625224,4.1,1.4 | ||
| 3 | 10KB,32.679975,40.7,13 | ||
| 4 | 100KB,112.864416,406.7,121 | ||
| 5 | 1MB,872.887675,4100,1200 | ||
| 6 | 10MB,8472.693202,40700,12000 | ||
| 7 | 100MB,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 @@ | |||
| 1 | import csv | ||
| 2 | |||
| 3 | import matplotlib.pyplot as plt | ||
| 4 | import pandas as pd | ||
| 5 | |||
| 6 | # Read the data | ||
| 7 | df = pd.read_csv("benchmarks.csv") | ||
| 8 | |||
| 9 | # Settings | ||
| 10 | plt.title("Encode to FASTA out filesize") | ||
| 11 | plt.tight_layout(pad=2) | ||
| 12 | fig = plt.gcf() | ||
| 13 | fig.set_size_inches(10, 4) | ||
| 14 | |||
| 15 | # Plotting | ||
| 16 | plt.plot(df["Packages"], df["FASTA file size (KB)"], label = "Raw", color="black", linestyle="-") | ||
| 17 | plt.plot(df["Packages"], df["FASTA gzipped (KB)"], label = "Gzipped", color="black", linestyle="--") | ||
| 18 | |||
| 19 | # Adding x and y axis labels | ||
| 20 | plt.xlabel("Size of an input file", fontstyle="italic") | ||
| 21 | plt.ylabel("File size (KB)", fontstyle="italic") | ||
| 22 | |||
| 23 | # Legend | ||
| 24 | legend = plt.legend() | ||
| 25 | legend.get_frame().set_linewidth(0) | ||
| 26 | |||
| 27 | # Export as SVG | ||
| 28 | plt.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 | ||
| 25 | L 720 288 | ||
| 26 | L 720 0 | ||
| 27 | L 0 0 | ||
| 28 | z | ||
| 29 | " style="fill: #ffffff"/> | ||
| 30 | </g> | ||
| 31 | <g id="axes_1"> | ||
| 32 | <g id="patch_2"> | ||
| 33 | <path d="M 67.078125 257.1 | ||
| 34 | L 676.304688 257.1 | ||
| 35 | L 676.304688 28.866667 | ||
| 36 | L 67.078125 28.866667 | ||
| 37 | z | ||
| 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 | ||
| 45 | L 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 | ||
| 57 | L 1825 531 | ||
| 58 | L 1825 4091 | ||
| 59 | L 703 3866 | ||
| 60 | L 703 4441 | ||
| 61 | L 1819 4666 | ||
| 62 | L 2450 4666 | ||
| 63 | L 2450 531 | ||
| 64 | L 3481 531 | ||
| 65 | L 3481 0 | ||
| 66 | L 794 0 | ||
| 67 | L 794 531 | ||
| 68 | z | ||
| 69 | " transform="scale(0.015625)"/> | ||
| 70 | <path id="DejaVuSans-4b" d="M 628 4666 | ||
| 71 | L 1259 4666 | ||
| 72 | L 1259 2694 | ||
| 73 | L 3353 4666 | ||
| 74 | L 4166 4666 | ||
| 75 | L 1850 2491 | ||
| 76 | L 4331 0 | ||
| 77 | L 3500 0 | ||
| 78 | L 1259 2247 | ||
| 79 | L 1259 0 | ||
| 80 | L 628 0 | ||
| 81 | L 628 4666 | ||
| 82 | z | ||
| 83 | " transform="scale(0.015625)"/> | ||
| 84 | <path id="DejaVuSans-42" d="M 1259 2228 | ||
| 85 | L 1259 519 | ||
| 86 | L 2272 519 | ||
| 87 | Q 2781 519 3026 730 | ||
| 88 | Q 3272 941 3272 1375 | ||
| 89 | Q 3272 1813 3026 2020 | ||
| 90 | Q 2781 2228 2272 2228 | ||
| 91 | L 1259 2228 | ||
| 92 | z | ||
| 93 | M 1259 4147 | ||
| 94 | L 1259 2741 | ||
| 95 | L 2194 2741 | ||
| 96 | Q 2656 2741 2882 2914 | ||
| 97 | Q 3109 3088 3109 3444 | ||
| 98 | Q 3109 3797 2882 3972 | ||
| 99 | Q 2656 4147 2194 4147 | ||
| 100 | L 1259 4147 | ||
| 101 | z | ||
| 102 | M 628 4666 | ||
| 103 | L 2241 4666 | ||
| 104 | Q 2963 4666 3353 4366 | ||
| 105 | Q 3744 4066 3744 3513 | ||
| 106 | Q 3744 3084 3544 2831 | ||
| 107 | Q 3344 2578 2956 2516 | ||
| 108 | Q 3422 2416 3680 2098 | ||
| 109 | Q 3938 1781 3938 1306 | ||
| 110 | Q 3938 681 3513 340 | ||
| 111 | Q 3088 0 2303 0 | ||
| 112 | L 628 0 | ||
| 113 | L 628 4666 | ||
| 114 | z | ||
| 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 | ||
| 134 | Q 1547 4250 1301 3770 | ||
| 135 | Q 1056 3291 1056 2328 | ||
| 136 | Q 1056 1369 1301 889 | ||
| 137 | Q 1547 409 2034 409 | ||
| 138 | Q 2525 409 2770 889 | ||
| 139 | Q 3016 1369 3016 2328 | ||
| 140 | Q 3016 3291 2770 3770 | ||
| 141 | Q 2525 4250 2034 4250 | ||
| 142 | z | ||
| 143 | M 2034 4750 | ||
| 144 | Q 2819 4750 3233 4129 | ||
| 145 | Q 3647 3509 3647 2328 | ||
| 146 | Q 3647 1150 3233 529 | ||
| 147 | Q 2819 -91 2034 -91 | ||
| 148 | Q 1250 -91 836 529 | ||
| 149 | Q 422 1150 422 2328 | ||
| 150 | Q 422 3509 836 4129 | ||
| 151 | Q 1250 4750 2034 4750 | ||
| 152 | z | ||
| 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 | ||
| 190 | L 1569 4666 | ||
| 191 | L 2759 1491 | ||
| 192 | L 3956 4666 | ||
| 193 | L 4897 4666 | ||
| 194 | L 4897 0 | ||
| 195 | L 4281 0 | ||
| 196 | L 4281 4097 | ||
| 197 | L 3078 897 | ||
| 198 | L 2444 897 | ||
| 199 | L 1241 4097 | ||
| 200 | L 1241 0 | ||
| 201 | L 628 0 | ||
| 202 | L 628 4666 | ||
| 203 | z | ||
| 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 | ||
| 250 | L 3738 3897 | ||
| 251 | Q 3422 4066 3111 4152 | ||
| 252 | Q 2800 4238 2509 4238 | ||
| 253 | Q 1944 4238 1609 3991 | ||
| 254 | Q 1275 3744 1275 3334 | ||
| 255 | Q 1275 3109 1398 2989 | ||
| 256 | Q 1522 2869 2034 2731 | ||
| 257 | L 2413 2638 | ||
| 258 | Q 3053 2472 3303 2217 | ||
| 259 | Q 3553 1963 3553 1503 | ||
| 260 | Q 3553 797 2998 353 | ||
| 261 | Q 2444 -91 1538 -91 | ||
| 262 | Q 1166 -91 791 -17 | ||
| 263 | Q 416 56 38 206 | ||
| 264 | L 166 856 | ||
| 265 | Q 513 641 861 531 | ||
| 266 | Q 1209 422 1556 422 | ||
| 267 | Q 2147 422 2503 684 | ||
| 268 | Q 2859 947 2859 1369 | ||
| 269 | Q 2859 1650 2717 1795 | ||
| 270 | Q 2575 1941 2106 2059 | ||
| 271 | L 1728 2156 | ||
| 272 | Q 1081 2325 845 2545 | ||
| 273 | Q 609 2766 609 3163 | ||
| 274 | Q 609 3859 1145 4304 | ||
| 275 | Q 1681 4750 2541 4750 | ||
| 276 | Q 2875 4750 3203 4690 | ||
| 277 | Q 3531 4631 3859 4513 | ||
| 278 | z | ||
| 279 | " transform="scale(0.015625)"/> | ||
| 280 | <path id="DejaVuSans-Oblique-69" d="M 1172 4863 | ||
| 281 | L 1747 4863 | ||
| 282 | L 1606 4134 | ||
| 283 | L 1031 4134 | ||
| 284 | L 1172 4863 | ||
| 285 | z | ||
| 286 | M 909 3500 | ||
| 287 | L 1484 3500 | ||
| 288 | L 800 0 | ||
| 289 | L 225 0 | ||
| 290 | L 909 3500 | ||
| 291 | z | ||
| 292 | " transform="scale(0.015625)"/> | ||
| 293 | <path id="DejaVuSans-Oblique-7a" d="M 744 3500 | ||
| 294 | L 3475 3500 | ||
| 295 | L 3372 2975 | ||
| 296 | L 738 459 | ||
| 297 | L 2913 459 | ||
| 298 | L 2822 0 | ||
| 299 | L -19 0 | ||
| 300 | L 84 525 | ||
| 301 | L 2719 3041 | ||
| 302 | L 653 3041 | ||
| 303 | L 744 3500 | ||
| 304 | z | ||
| 305 | " transform="scale(0.015625)"/> | ||
| 306 | <path id="DejaVuSans-Oblique-65" d="M 3078 2063 | ||
| 307 | Q 3088 2113 3092 2166 | ||
| 308 | Q 3097 2219 3097 2272 | ||
| 309 | Q 3097 2653 2873 2875 | ||
| 310 | Q 2650 3097 2266 3097 | ||
| 311 | Q 1838 3097 1509 2826 | ||
| 312 | Q 1181 2556 1013 2059 | ||
| 313 | L 3078 2063 | ||
| 314 | z | ||
| 315 | M 3578 1613 | ||
| 316 | L 903 1613 | ||
| 317 | Q 884 1494 878 1425 | ||
| 318 | Q 872 1356 872 1306 | ||
| 319 | Q 872 872 1139 634 | ||
| 320 | Q 1406 397 1894 397 | ||
| 321 | Q 2269 397 2603 481 | ||
| 322 | Q 2938 566 3225 728 | ||
| 323 | L 3116 159 | ||
| 324 | Q 2806 34 2476 -28 | ||
| 325 | Q 2147 -91 1806 -91 | ||
| 326 | Q 1078 -91 686 257 | ||
| 327 | Q 294 606 294 1247 | ||
| 328 | Q 294 1794 489 2264 | ||
| 329 | Q 684 2734 1063 3103 | ||
| 330 | Q 1306 3334 1642 3459 | ||
| 331 | Q 1978 3584 2356 3584 | ||
| 332 | Q 2950 3584 3301 3228 | ||
| 333 | Q 3653 2872 3653 2272 | ||
| 334 | Q 3653 2128 3634 1964 | ||
| 335 | Q 3616 1800 3578 1613 | ||
| 336 | z | ||
| 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 | ||
| 340 | Q 1009 -91 651 289 | ||
| 341 | Q 294 669 294 1325 | ||
| 342 | Q 294 1706 417 2101 | ||
| 343 | Q 541 2497 738 2766 | ||
| 344 | Q 1047 3184 1428 3384 | ||
| 345 | Q 1809 3584 2291 3584 | ||
| 346 | Q 2888 3584 3255 3212 | ||
| 347 | Q 3622 2841 3622 2241 | ||
| 348 | Q 3622 1825 3500 1412 | ||
| 349 | Q 3378 1000 3181 728 | ||
| 350 | Q 2875 309 2494 109 | ||
| 351 | Q 2113 -91 1625 -91 | ||
| 352 | z | ||
| 353 | M 891 1344 | ||
| 354 | Q 891 869 1089 633 | ||
| 355 | Q 1288 397 1691 397 | ||
| 356 | Q 2269 397 2648 901 | ||
| 357 | Q 3028 1406 3028 2181 | ||
| 358 | Q 3028 2634 2825 2865 | ||
| 359 | Q 2622 3097 2228 3097 | ||
| 360 | Q 1903 3097 1650 2945 | ||
| 361 | Q 1397 2794 1197 2484 | ||
| 362 | Q 1050 2253 970 1956 | ||
| 363 | Q 891 1659 891 1344 | ||
| 364 | z | ||
| 365 | " transform="scale(0.015625)"/> | ||
| 366 | <path id="DejaVuSans-Oblique-66" d="M 3059 4863 | ||
| 367 | L 2969 4384 | ||
| 368 | L 2419 4384 | ||
| 369 | Q 2106 4384 1964 4261 | ||
| 370 | Q 1822 4138 1753 3809 | ||
| 371 | L 1691 3500 | ||
| 372 | L 2638 3500 | ||
| 373 | L 2553 3053 | ||
| 374 | L 1606 3053 | ||
| 375 | L 1013 0 | ||
| 376 | L 434 0 | ||
| 377 | L 1031 3053 | ||
| 378 | L 481 3053 | ||
| 379 | L 563 3500 | ||
| 380 | L 1113 3500 | ||
| 381 | L 1159 3744 | ||
| 382 | Q 1278 4363 1576 4613 | ||
| 383 | Q 1875 4863 2516 4863 | ||
| 384 | L 3059 4863 | ||
| 385 | z | ||
| 386 | " transform="scale(0.015625)"/> | ||
| 387 | <path id="DejaVuSans-Oblique-61" d="M 3438 1997 | ||
| 388 | L 3047 0 | ||
| 389 | L 2472 0 | ||
| 390 | L 2578 531 | ||
| 391 | Q 2325 219 2001 64 | ||
| 392 | Q 1678 -91 1281 -91 | ||
| 393 | Q 834 -91 548 182 | ||
| 394 | Q 263 456 263 884 | ||
| 395 | Q 263 1497 752 1853 | ||
| 396 | Q 1241 2209 2100 2209 | ||
| 397 | L 2900 2209 | ||
| 398 | L 2931 2363 | ||
| 399 | Q 2938 2388 2941 2417 | ||
| 400 | Q 2944 2447 2944 2509 | ||
| 401 | Q 2944 2788 2717 2942 | ||
| 402 | Q 2491 3097 2081 3097 | ||
| 403 | Q 1800 3097 1504 3025 | ||
| 404 | Q 1209 2953 897 2809 | ||
| 405 | L 997 3341 | ||
| 406 | Q 1322 3463 1633 3523 | ||
| 407 | Q 1944 3584 2234 3584 | ||
| 408 | Q 2853 3584 3176 3315 | ||
| 409 | Q 3500 3047 3500 2534 | ||
| 410 | Q 3500 2431 3484 2292 | ||
| 411 | Q 3469 2153 3438 1997 | ||
| 412 | z | ||
| 413 | M 2816 1759 | ||
| 414 | L 2241 1759 | ||
| 415 | Q 1534 1759 1195 1570 | ||
| 416 | Q 856 1381 856 984 | ||
| 417 | Q 856 709 1029 553 | ||
| 418 | Q 1203 397 1509 397 | ||
| 419 | Q 1978 397 2328 733 | ||
| 420 | Q 2678 1069 2791 1631 | ||
| 421 | L 2816 1759 | ||
| 422 | z | ||
| 423 | " transform="scale(0.015625)"/> | ||
| 424 | <path id="DejaVuSans-Oblique-6e" d="M 3566 2113 | ||
| 425 | L 3156 0 | ||
| 426 | L 2578 0 | ||
| 427 | L 2988 2091 | ||
| 428 | Q 3016 2238 3031 2350 | ||
| 429 | Q 3047 2463 3047 2528 | ||
| 430 | Q 3047 2791 2881 2937 | ||
| 431 | Q 2716 3084 2419 3084 | ||
| 432 | Q 1956 3084 1622 2776 | ||
| 433 | Q 1288 2469 1184 1941 | ||
| 434 | L 800 0 | ||
| 435 | L 225 0 | ||
| 436 | L 903 3500 | ||
| 437 | L 1478 3500 | ||
| 438 | L 1363 2950 | ||
| 439 | Q 1603 3253 1940 3418 | ||
| 440 | Q 2278 3584 2650 3584 | ||
| 441 | Q 3113 3584 3367 3334 | ||
| 442 | Q 3622 3084 3622 2631 | ||
| 443 | Q 3622 2519 3608 2391 | ||
| 444 | Q 3594 2263 3566 2113 | ||
| 445 | z | ||
| 446 | " transform="scale(0.015625)"/> | ||
| 447 | <path id="DejaVuSans-Oblique-70" d="M 3175 2156 | ||
| 448 | Q 3175 2616 2975 2859 | ||
| 449 | Q 2775 3103 2400 3103 | ||
| 450 | Q 2144 3103 1911 2972 | ||
| 451 | Q 1678 2841 1497 2591 | ||
| 452 | Q 1319 2344 1212 1994 | ||
| 453 | Q 1106 1644 1106 1300 | ||
| 454 | Q 1106 863 1306 627 | ||
| 455 | Q 1506 391 1875 391 | ||
| 456 | Q 2147 391 2380 519 | ||
| 457 | Q 2613 647 2778 891 | ||
| 458 | Q 2956 1147 3065 1494 | ||
| 459 | Q 3175 1841 3175 2156 | ||
| 460 | z | ||
| 461 | M 1394 2969 | ||
| 462 | Q 1625 3272 1939 3428 | ||
| 463 | Q 2253 3584 2638 3584 | ||
| 464 | Q 3175 3584 3472 3232 | ||
| 465 | Q 3769 2881 3769 2247 | ||
| 466 | Q 3769 1728 3584 1258 | ||
| 467 | Q 3400 788 3053 416 | ||
| 468 | Q 2822 169 2531 39 | ||
| 469 | Q 2241 -91 1919 -91 | ||
| 470 | Q 1547 -91 1294 64 | ||
| 471 | Q 1041 219 916 525 | ||
| 472 | L 556 -1331 | ||
| 473 | L -19 -1331 | ||
| 474 | L 922 3500 | ||
| 475 | L 1497 3500 | ||
| 476 | L 1394 2969 | ||
| 477 | z | ||
| 478 | " transform="scale(0.015625)"/> | ||
| 479 | <path id="DejaVuSans-Oblique-75" d="M 428 1388 | ||
| 480 | L 838 3500 | ||
| 481 | L 1416 3500 | ||
| 482 | L 1006 1409 | ||
| 483 | Q 975 1256 961 1147 | ||
| 484 | Q 947 1038 947 966 | ||
| 485 | Q 947 700 1109 554 | ||
| 486 | Q 1272 409 1569 409 | ||
| 487 | Q 2031 409 2368 721 | ||
| 488 | Q 2706 1034 2809 1563 | ||
| 489 | L 3194 3500 | ||
| 490 | L 3769 3500 | ||
| 491 | L 3091 0 | ||
| 492 | L 2516 0 | ||
| 493 | L 2631 550 | ||
| 494 | Q 2388 244 2052 76 | ||
| 495 | Q 1716 -91 1338 -91 | ||
| 496 | Q 878 -91 622 161 | ||
| 497 | Q 366 413 366 863 | ||
| 498 | Q 366 956 381 1097 | ||
| 499 | Q 397 1238 428 1388 | ||
| 500 | z | ||
| 501 | " transform="scale(0.015625)"/> | ||
| 502 | <path id="DejaVuSans-Oblique-74" d="M 2706 3500 | ||
| 503 | L 2619 3053 | ||
| 504 | L 1472 3053 | ||
| 505 | L 1100 1153 | ||
| 506 | Q 1081 1047 1072 975 | ||
| 507 | Q 1063 903 1063 863 | ||
| 508 | Q 1063 663 1183 572 | ||
| 509 | Q 1303 481 1569 481 | ||
| 510 | L 2150 481 | ||
| 511 | L 2053 0 | ||
| 512 | L 1503 0 | ||
| 513 | Q 991 0 739 200 | ||
| 514 | Q 488 400 488 806 | ||
| 515 | Q 488 878 497 964 | ||
| 516 | Q 506 1050 525 1153 | ||
| 517 | L 897 3053 | ||
| 518 | L 409 3053 | ||
| 519 | L 500 3500 | ||
| 520 | L 978 3500 | ||
| 521 | L 1172 4494 | ||
| 522 | L 1747 4494 | ||
| 523 | L 1556 3500 | ||
| 524 | L 2706 3500 | ||
| 525 | z | ||
| 526 | " transform="scale(0.015625)"/> | ||
| 527 | <path id="DejaVuSans-Oblique-6c" d="M 1172 4863 | ||
| 528 | L 1747 4863 | ||
| 529 | L 800 0 | ||
| 530 | L 225 0 | ||
| 531 | L 1172 4863 | ||
| 532 | z | ||
| 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 | ||
| 564 | L -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 | ||
| 589 | L 3169 4666 | ||
| 590 | L 3169 4134 | ||
| 591 | L 1269 4134 | ||
| 592 | L 1269 2991 | ||
| 593 | Q 1406 3038 1543 3061 | ||
| 594 | Q 1681 3084 1819 3084 | ||
| 595 | Q 2600 3084 3056 2656 | ||
| 596 | Q 3513 2228 3513 1497 | ||
| 597 | Q 3513 744 3044 326 | ||
| 598 | Q 2575 -91 1722 -91 | ||
| 599 | Q 1428 -91 1123 -41 | ||
| 600 | Q 819 9 494 109 | ||
| 601 | L 494 744 | ||
| 602 | Q 775 591 1075 516 | ||
| 603 | Q 1375 441 1709 441 | ||
| 604 | Q 2250 441 2565 725 | ||
| 605 | Q 2881 1009 2881 1497 | ||
| 606 | Q 2881 1984 2565 2268 | ||
| 607 | Q 2250 2553 1709 2553 | ||
| 608 | Q 1456 2553 1204 2497 | ||
| 609 | Q 953 2441 691 2322 | ||
| 610 | L 691 4666 | ||
| 611 | z | ||
| 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 | ||
| 669 | L 3431 531 | ||
| 670 | L 3431 0 | ||
| 671 | L 469 0 | ||
| 672 | L 469 531 | ||
| 673 | Q 828 903 1448 1529 | ||
| 674 | Q 2069 2156 2228 2338 | ||
| 675 | Q 2531 2678 2651 2914 | ||
| 676 | Q 2772 3150 2772 3378 | ||
| 677 | Q 2772 3750 2511 3984 | ||
| 678 | Q 2250 4219 1831 4219 | ||
| 679 | Q 1534 4219 1204 4116 | ||
| 680 | Q 875 4013 500 3803 | ||
| 681 | L 500 4441 | ||
| 682 | Q 881 4594 1212 4672 | ||
| 683 | Q 1544 4750 1819 4750 | ||
| 684 | Q 2544 4750 2975 4387 | ||
| 685 | Q 3406 4025 3406 3419 | ||
| 686 | Q 3406 3131 3298 2873 | ||
| 687 | Q 3191 2616 2906 2266 | ||
| 688 | Q 2828 2175 2409 1742 | ||
| 689 | Q 1991 1309 1228 531 | ||
| 690 | z | ||
| 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 | ||
| 731 | Q 3050 2419 3304 2112 | ||
| 732 | Q 3559 1806 3559 1356 | ||
| 733 | Q 3559 666 3084 287 | ||
| 734 | Q 2609 -91 1734 -91 | ||
| 735 | Q 1441 -91 1130 -33 | ||
| 736 | Q 819 25 488 141 | ||
| 737 | L 488 750 | ||
| 738 | Q 750 597 1062 519 | ||
| 739 | Q 1375 441 1716 441 | ||
| 740 | Q 2309 441 2620 675 | ||
| 741 | Q 2931 909 2931 1356 | ||
| 742 | Q 2931 1769 2642 2001 | ||
| 743 | Q 2353 2234 1838 2234 | ||
| 744 | L 1294 2234 | ||
| 745 | L 1294 2753 | ||
| 746 | L 1863 2753 | ||
| 747 | Q 2328 2753 2575 2939 | ||
| 748 | Q 2822 3125 2822 3475 | ||
| 749 | Q 2822 3834 2567 4026 | ||
| 750 | Q 2313 4219 1838 4219 | ||
| 751 | Q 1578 4219 1281 4162 | ||
| 752 | Q 984 4106 628 3988 | ||
| 753 | L 628 4550 | ||
| 754 | Q 988 4650 1302 4700 | ||
| 755 | Q 1616 4750 1894 4750 | ||
| 756 | Q 2613 4750 3031 4423 | ||
| 757 | Q 3450 4097 3450 3541 | ||
| 758 | Q 3450 3153 3228 2886 | ||
| 759 | Q 3006 2619 2597 2516 | ||
| 760 | z | ||
| 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 | ||
| 801 | L 825 1625 | ||
| 802 | L 2419 1625 | ||
| 803 | L 2419 4116 | ||
| 804 | z | ||
| 805 | M 2253 4666 | ||
| 806 | L 3047 4666 | ||
| 807 | L 3047 1625 | ||
| 808 | L 3713 1625 | ||
| 809 | L 3713 1100 | ||
| 810 | L 3047 1100 | ||
| 811 | L 3047 0 | ||
| 812 | L 2419 0 | ||
| 813 | L 2419 1100 | ||
| 814 | L 313 1100 | ||
| 815 | L 313 1709 | ||
| 816 | L 2253 4666 | ||
| 817 | z | ||
| 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 | ||
| 834 | L 3756 4666 | ||
| 835 | L 3653 4134 | ||
| 836 | L 1606 4134 | ||
| 837 | L 1338 2759 | ||
| 838 | L 3188 2759 | ||
| 839 | L 3084 2228 | ||
| 840 | L 1234 2228 | ||
| 841 | L 800 0 | ||
| 842 | L 172 0 | ||
| 843 | L 1081 4666 | ||
| 844 | z | ||
| 845 | " transform="scale(0.015625)"/> | ||
| 846 | <path id="DejaVuSans-Oblique-73" d="M 3200 3397 | ||
| 847 | L 3091 2853 | ||
| 848 | Q 2863 2978 2609 3040 | ||
| 849 | Q 2356 3103 2088 3103 | ||
| 850 | Q 1634 3103 1373 2948 | ||
| 851 | Q 1113 2794 1113 2528 | ||
| 852 | Q 1113 2219 1719 2053 | ||
| 853 | Q 1766 2041 1788 2034 | ||
| 854 | L 1972 1978 | ||
| 855 | Q 2547 1819 2739 1644 | ||
| 856 | Q 2931 1469 2931 1166 | ||
| 857 | Q 2931 609 2489 259 | ||
| 858 | Q 2047 -91 1331 -91 | ||
| 859 | Q 1053 -91 747 -37 | ||
| 860 | Q 441 16 72 128 | ||
| 861 | L 184 722 | ||
| 862 | Q 500 559 806 475 | ||
| 863 | Q 1113 391 1394 391 | ||
| 864 | Q 1816 391 2080 572 | ||
| 865 | Q 2344 753 2344 1031 | ||
| 866 | Q 2344 1331 1650 1516 | ||
| 867 | L 1591 1531 | ||
| 868 | L 1394 1581 | ||
| 869 | Q 956 1697 753 1886 | ||
| 870 | Q 550 2075 550 2369 | ||
| 871 | Q 550 2928 970 3256 | ||
| 872 | Q 1391 3584 2113 3584 | ||
| 873 | Q 2397 3584 2667 3537 | ||
| 874 | Q 2938 3491 3200 3397 | ||
| 875 | z | ||
| 876 | " transform="scale(0.015625)"/> | ||
| 877 | <path id="DejaVuSans-Oblique-28" d="M 2731 4856 | ||
| 878 | Q 1903 3822 1495 2892 | ||
| 879 | Q 1088 1963 1088 1100 | ||
| 880 | Q 1088 606 1206 120 | ||
| 881 | Q 1325 -366 1563 -844 | ||
| 882 | L 1063 -844 | ||
| 883 | Q 775 -306 634 201 | ||
| 884 | Q 494 709 494 1197 | ||
| 885 | Q 494 2125 923 3036 | ||
| 886 | Q 1353 3947 2222 4856 | ||
| 887 | L 2731 4856 | ||
| 888 | z | ||
| 889 | " transform="scale(0.015625)"/> | ||
| 890 | <path id="DejaVuSans-Oblique-4b" d="M 1081 4666 | ||
| 891 | L 1716 4666 | ||
| 892 | L 1331 2700 | ||
| 893 | L 3781 4666 | ||
| 894 | L 4622 4666 | ||
| 895 | L 1850 2438 | ||
| 896 | L 3878 0 | ||
| 897 | L 3109 0 | ||
| 898 | L 1247 2272 | ||
| 899 | L 806 0 | ||
| 900 | L 172 0 | ||
| 901 | L 1081 4666 | ||
| 902 | z | ||
| 903 | " transform="scale(0.015625)"/> | ||
| 904 | <path id="DejaVuSans-Oblique-42" d="M 1081 4666 | ||
| 905 | L 2694 4666 | ||
| 906 | Q 3350 4666 3675 4422 | ||
| 907 | Q 4000 4178 4000 3688 | ||
| 908 | Q 4000 3238 3720 2911 | ||
| 909 | Q 3441 2584 2988 2516 | ||
| 910 | Q 3375 2428 3569 2181 | ||
| 911 | Q 3763 1934 3763 1522 | ||
| 912 | Q 3763 819 3242 409 | ||
| 913 | Q 2722 0 1819 0 | ||
| 914 | L 172 0 | ||
| 915 | L 1081 4666 | ||
| 916 | z | ||
| 917 | M 1234 2228 | ||
| 918 | L 903 519 | ||
| 919 | L 1919 519 | ||
| 920 | Q 2491 519 2800 781 | ||
| 921 | Q 3109 1044 3109 1522 | ||
| 922 | Q 3109 1891 2904 2059 | ||
| 923 | Q 2700 2228 2247 2228 | ||
| 924 | L 1234 2228 | ||
| 925 | z | ||
| 926 | M 1606 4147 | ||
| 927 | L 1331 2741 | ||
| 928 | L 2272 2741 | ||
| 929 | Q 2775 2741 3058 2959 | ||
| 930 | Q 3341 3178 3341 3566 | ||
| 931 | Q 3341 3869 3150 4008 | ||
| 932 | Q 2959 4147 2541 4147 | ||
| 933 | L 1606 4147 | ||
| 934 | z | ||
| 935 | " transform="scale(0.015625)"/> | ||
| 936 | <path id="DejaVuSans-Oblique-29" d="M -397 -844 | ||
| 937 | Q 434 191 840 1120 | ||
| 938 | Q 1247 2050 1247 2913 | ||
| 939 | Q 1247 3406 1130 3892 | ||
| 940 | Q 1013 4378 775 4856 | ||
| 941 | L 1275 4856 | ||
| 942 | Q 1563 4316 1703 3812 | ||
| 943 | Q 1844 3309 1844 2822 | ||
| 944 | Q 1844 1891 1411 973 | ||
| 945 | Q 978 56 116 -844 | ||
| 946 | L -397 -844 | ||
| 947 | z | ||
| 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 | ||
| 969 | L 205.538707 246.705708 | ||
| 970 | L 316.307173 246.518986 | ||
| 971 | L 427.075639 244.634781 | ||
| 972 | L 537.844105 225.96261 | ||
| 973 | L 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 | ||
| 978 | L 205.538707 246.71984 | ||
| 979 | L 316.307173 246.664741 | ||
| 980 | L 427.075639 246.11427 | ||
| 981 | L 537.844105 240.604449 | ||
| 982 | L 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 | ||
| 987 | L 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 | ||
| 992 | L 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 | ||
| 997 | L 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 | ||
| 1002 | L 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 | ||
| 1010 | L 3578 4666 | ||
| 1011 | L 3578 4134 | ||
| 1012 | L 1259 4134 | ||
| 1013 | L 1259 2753 | ||
| 1014 | L 3481 2753 | ||
| 1015 | L 3481 2222 | ||
| 1016 | L 1259 2222 | ||
| 1017 | L 1259 531 | ||
| 1018 | L 3634 531 | ||
| 1019 | L 3634 0 | ||
| 1020 | L 628 0 | ||
| 1021 | L 628 4666 | ||
| 1022 | z | ||
| 1023 | " transform="scale(0.015625)"/> | ||
| 1024 | <path id="DejaVuSans-6e" d="M 3513 2113 | ||
| 1025 | L 3513 0 | ||
| 1026 | L 2938 0 | ||
| 1027 | L 2938 2094 | ||
| 1028 | Q 2938 2591 2744 2837 | ||
| 1029 | Q 2550 3084 2163 3084 | ||
| 1030 | Q 1697 3084 1428 2787 | ||
| 1031 | Q 1159 2491 1159 1978 | ||
| 1032 | L 1159 0 | ||
| 1033 | L 581 0 | ||
| 1034 | L 581 3500 | ||
| 1035 | L 1159 3500 | ||
| 1036 | L 1159 2956 | ||
| 1037 | Q 1366 3272 1645 3428 | ||
| 1038 | Q 1925 3584 2291 3584 | ||
| 1039 | Q 2894 3584 3203 3211 | ||
| 1040 | Q 3513 2838 3513 2113 | ||
| 1041 | z | ||
| 1042 | " transform="scale(0.015625)"/> | ||
| 1043 | <path id="DejaVuSans-63" d="M 3122 3366 | ||
| 1044 | L 3122 2828 | ||
| 1045 | Q 2878 2963 2633 3030 | ||
| 1046 | Q 2388 3097 2138 3097 | ||
| 1047 | Q 1578 3097 1268 2742 | ||
| 1048 | Q 959 2388 959 1747 | ||
| 1049 | Q 959 1106 1268 751 | ||
| 1050 | Q 1578 397 2138 397 | ||
| 1051 | Q 2388 397 2633 464 | ||
| 1052 | Q 2878 531 3122 666 | ||
| 1053 | L 3122 134 | ||
| 1054 | Q 2881 22 2623 -34 | ||
| 1055 | Q 2366 -91 2075 -91 | ||
| 1056 | Q 1284 -91 818 406 | ||
| 1057 | Q 353 903 353 1747 | ||
| 1058 | Q 353 2603 823 3093 | ||
| 1059 | Q 1294 3584 2113 3584 | ||
| 1060 | Q 2378 3584 2631 3529 | ||
| 1061 | Q 2884 3475 3122 3366 | ||
| 1062 | z | ||
| 1063 | " transform="scale(0.015625)"/> | ||
| 1064 | <path id="DejaVuSans-6f" d="M 1959 3097 | ||
| 1065 | Q 1497 3097 1228 2736 | ||
| 1066 | Q 959 2375 959 1747 | ||
| 1067 | Q 959 1119 1226 758 | ||
| 1068 | Q 1494 397 1959 397 | ||
| 1069 | Q 2419 397 2687 759 | ||
| 1070 | Q 2956 1122 2956 1747 | ||
| 1071 | Q 2956 2369 2687 2733 | ||
| 1072 | Q 2419 3097 1959 3097 | ||
| 1073 | z | ||
| 1074 | M 1959 3584 | ||
| 1075 | Q 2709 3584 3137 3096 | ||
| 1076 | Q 3566 2609 3566 1747 | ||
| 1077 | Q 3566 888 3137 398 | ||
| 1078 | Q 2709 -91 1959 -91 | ||
| 1079 | Q 1206 -91 779 398 | ||
| 1080 | Q 353 888 353 1747 | ||
| 1081 | Q 353 2609 779 3096 | ||
| 1082 | Q 1206 3584 1959 3584 | ||
| 1083 | z | ||
| 1084 | " transform="scale(0.015625)"/> | ||
| 1085 | <path id="DejaVuSans-64" d="M 2906 2969 | ||
| 1086 | L 2906 4863 | ||
| 1087 | L 3481 4863 | ||
| 1088 | L 3481 0 | ||
| 1089 | L 2906 0 | ||
| 1090 | L 2906 525 | ||
| 1091 | Q 2725 213 2448 61 | ||
| 1092 | Q 2172 -91 1784 -91 | ||
| 1093 | Q 1150 -91 751 415 | ||
| 1094 | Q 353 922 353 1747 | ||
| 1095 | Q 353 2572 751 3078 | ||
| 1096 | Q 1150 3584 1784 3584 | ||
| 1097 | Q 2172 3584 2448 3432 | ||
| 1098 | Q 2725 3281 2906 2969 | ||
| 1099 | z | ||
| 1100 | M 947 1747 | ||
| 1101 | Q 947 1113 1208 752 | ||
| 1102 | Q 1469 391 1925 391 | ||
| 1103 | Q 2381 391 2643 752 | ||
| 1104 | Q 2906 1113 2906 1747 | ||
| 1105 | Q 2906 2381 2643 2742 | ||
| 1106 | Q 2381 3103 1925 3103 | ||
| 1107 | Q 1469 3103 1208 2742 | ||
| 1108 | Q 947 2381 947 1747 | ||
| 1109 | z | ||
| 1110 | " transform="scale(0.015625)"/> | ||
| 1111 | <path id="DejaVuSans-65" d="M 3597 1894 | ||
| 1112 | L 3597 1613 | ||
| 1113 | L 953 1613 | ||
| 1114 | Q 991 1019 1311 708 | ||
| 1115 | Q 1631 397 2203 397 | ||
| 1116 | Q 2534 397 2845 478 | ||
| 1117 | Q 3156 559 3463 722 | ||
| 1118 | L 3463 178 | ||
| 1119 | Q 3153 47 2828 -22 | ||
| 1120 | Q 2503 -91 2169 -91 | ||
| 1121 | Q 1331 -91 842 396 | ||
| 1122 | Q 353 884 353 1716 | ||
| 1123 | Q 353 2575 817 3079 | ||
| 1124 | Q 1281 3584 2069 3584 | ||
| 1125 | Q 2775 3584 3186 3129 | ||
| 1126 | Q 3597 2675 3597 1894 | ||
| 1127 | z | ||
| 1128 | M 3022 2063 | ||
| 1129 | Q 3016 2534 2758 2815 | ||
| 1130 | Q 2500 3097 2075 3097 | ||
| 1131 | Q 1594 3097 1305 2825 | ||
| 1132 | Q 1016 2553 972 2059 | ||
| 1133 | L 3022 2063 | ||
| 1134 | z | ||
| 1135 | " transform="scale(0.015625)"/> | ||
| 1136 | <path id="DejaVuSans-20" transform="scale(0.015625)"/> | ||
| 1137 | <path id="DejaVuSans-74" d="M 1172 4494 | ||
| 1138 | L 1172 3500 | ||
| 1139 | L 2356 3500 | ||
| 1140 | L 2356 3053 | ||
| 1141 | L 1172 3053 | ||
| 1142 | L 1172 1153 | ||
| 1143 | Q 1172 725 1289 603 | ||
| 1144 | Q 1406 481 1766 481 | ||
| 1145 | L 2356 481 | ||
| 1146 | L 2356 0 | ||
| 1147 | L 1766 0 | ||
| 1148 | Q 1100 0 847 248 | ||
| 1149 | Q 594 497 594 1153 | ||
| 1150 | L 594 3053 | ||
| 1151 | L 172 3053 | ||
| 1152 | L 172 3500 | ||
| 1153 | L 594 3500 | ||
| 1154 | L 594 4494 | ||
| 1155 | L 1172 4494 | ||
| 1156 | z | ||
| 1157 | " transform="scale(0.015625)"/> | ||
| 1158 | <path id="DejaVuSans-46" d="M 628 4666 | ||
| 1159 | L 3309 4666 | ||
| 1160 | L 3309 4134 | ||
| 1161 | L 1259 4134 | ||
| 1162 | L 1259 2759 | ||
| 1163 | L 3109 2759 | ||
| 1164 | L 3109 2228 | ||
| 1165 | L 1259 2228 | ||
| 1166 | L 1259 0 | ||
| 1167 | L 628 0 | ||
| 1168 | L 628 4666 | ||
| 1169 | z | ||
| 1170 | " transform="scale(0.015625)"/> | ||
| 1171 | <path id="DejaVuSans-41" d="M 2188 4044 | ||
| 1172 | L 1331 1722 | ||
| 1173 | L 3047 1722 | ||
| 1174 | L 2188 4044 | ||
| 1175 | z | ||
| 1176 | M 1831 4666 | ||
| 1177 | L 2547 4666 | ||
| 1178 | L 4325 0 | ||
| 1179 | L 3669 0 | ||
| 1180 | L 3244 1197 | ||
| 1181 | L 1141 1197 | ||
| 1182 | L 716 0 | ||
| 1183 | L 50 0 | ||
| 1184 | L 1831 4666 | ||
| 1185 | z | ||
| 1186 | " transform="scale(0.015625)"/> | ||
| 1187 | <path id="DejaVuSans-53" d="M 3425 4513 | ||
| 1188 | L 3425 3897 | ||
| 1189 | Q 3066 4069 2747 4153 | ||
| 1190 | Q 2428 4238 2131 4238 | ||
| 1191 | Q 1616 4238 1336 4038 | ||
| 1192 | Q 1056 3838 1056 3469 | ||
| 1193 | Q 1056 3159 1242 3001 | ||
| 1194 | Q 1428 2844 1947 2747 | ||
| 1195 | L 2328 2669 | ||
| 1196 | Q 3034 2534 3370 2195 | ||
| 1197 | Q 3706 1856 3706 1288 | ||
| 1198 | Q 3706 609 3251 259 | ||
| 1199 | Q 2797 -91 1919 -91 | ||
| 1200 | Q 1588 -91 1214 -16 | ||
| 1201 | Q 841 59 441 206 | ||
| 1202 | L 441 856 | ||
| 1203 | Q 825 641 1194 531 | ||
| 1204 | Q 1563 422 1919 422 | ||
| 1205 | Q 2459 422 2753 634 | ||
| 1206 | Q 3047 847 3047 1241 | ||
| 1207 | Q 3047 1584 2836 1778 | ||
| 1208 | Q 2625 1972 2144 2069 | ||
| 1209 | L 1759 2144 | ||
| 1210 | Q 1053 2284 737 2584 | ||
| 1211 | Q 422 2884 422 3419 | ||
| 1212 | Q 422 4038 858 4394 | ||
| 1213 | Q 1294 4750 2059 4750 | ||
| 1214 | Q 2388 4750 2728 4690 | ||
| 1215 | Q 3069 4631 3425 4513 | ||
| 1216 | z | ||
| 1217 | " transform="scale(0.015625)"/> | ||
| 1218 | <path id="DejaVuSans-54" d="M -19 4666 | ||
| 1219 | L 3928 4666 | ||
| 1220 | L 3928 4134 | ||
| 1221 | L 2272 4134 | ||
| 1222 | L 2272 0 | ||
| 1223 | L 1638 0 | ||
| 1224 | L 1638 4134 | ||
| 1225 | L -19 4134 | ||
| 1226 | L -19 4666 | ||
| 1227 | z | ||
| 1228 | " transform="scale(0.015625)"/> | ||
| 1229 | <path id="DejaVuSans-75" d="M 544 1381 | ||
| 1230 | L 544 3500 | ||
| 1231 | L 1119 3500 | ||
| 1232 | L 1119 1403 | ||
| 1233 | Q 1119 906 1312 657 | ||
| 1234 | Q 1506 409 1894 409 | ||
| 1235 | Q 2359 409 2629 706 | ||
| 1236 | Q 2900 1003 2900 1516 | ||
| 1237 | L 2900 3500 | ||
| 1238 | L 3475 3500 | ||
| 1239 | L 3475 0 | ||
| 1240 | L 2900 0 | ||
| 1241 | L 2900 538 | ||
| 1242 | Q 2691 219 2414 64 | ||
| 1243 | Q 2138 -91 1772 -91 | ||
| 1244 | Q 1169 -91 856 284 | ||
| 1245 | Q 544 659 544 1381 | ||
| 1246 | z | ||
| 1247 | M 1991 3584 | ||
| 1248 | L 1991 3584 | ||
| 1249 | z | ||
| 1250 | " transform="scale(0.015625)"/> | ||
| 1251 | <path id="DejaVuSans-66" d="M 2375 4863 | ||
| 1252 | L 2375 4384 | ||
| 1253 | L 1825 4384 | ||
| 1254 | Q 1516 4384 1395 4259 | ||
| 1255 | Q 1275 4134 1275 3809 | ||
| 1256 | L 1275 3500 | ||
| 1257 | L 2222 3500 | ||
| 1258 | L 2222 3053 | ||
| 1259 | L 1275 3053 | ||
| 1260 | L 1275 0 | ||
| 1261 | L 697 0 | ||
| 1262 | L 697 3053 | ||
| 1263 | L 147 3053 | ||
| 1264 | L 147 3500 | ||
| 1265 | L 697 3500 | ||
| 1266 | L 697 3744 | ||
| 1267 | Q 697 4328 969 4595 | ||
| 1268 | Q 1241 4863 1831 4863 | ||
| 1269 | L 2375 4863 | ||
| 1270 | z | ||
| 1271 | " transform="scale(0.015625)"/> | ||
| 1272 | <path id="DejaVuSans-69" d="M 603 3500 | ||
| 1273 | L 1178 3500 | ||
| 1274 | L 1178 0 | ||
| 1275 | L 603 0 | ||
| 1276 | L 603 3500 | ||
| 1277 | z | ||
| 1278 | M 603 4863 | ||
| 1279 | L 1178 4863 | ||
| 1280 | L 1178 4134 | ||
| 1281 | L 603 4134 | ||
| 1282 | L 603 4863 | ||
| 1283 | z | ||
| 1284 | " transform="scale(0.015625)"/> | ||
| 1285 | <path id="DejaVuSans-6c" d="M 603 4863 | ||
| 1286 | L 1178 4863 | ||
| 1287 | L 1178 0 | ||
| 1288 | L 603 0 | ||
| 1289 | L 603 4863 | ||
| 1290 | z | ||
| 1291 | " transform="scale(0.015625)"/> | ||
| 1292 | <path id="DejaVuSans-73" d="M 2834 3397 | ||
| 1293 | L 2834 2853 | ||
| 1294 | Q 2591 2978 2328 3040 | ||
| 1295 | Q 2066 3103 1784 3103 | ||
| 1296 | Q 1356 3103 1142 2972 | ||
| 1297 | Q 928 2841 928 2578 | ||
| 1298 | Q 928 2378 1081 2264 | ||
| 1299 | Q 1234 2150 1697 2047 | ||
| 1300 | L 1894 2003 | ||
| 1301 | Q 2506 1872 2764 1633 | ||
| 1302 | Q 3022 1394 3022 966 | ||
| 1303 | Q 3022 478 2636 193 | ||
| 1304 | Q 2250 -91 1575 -91 | ||
| 1305 | Q 1294 -91 989 -36 | ||
| 1306 | Q 684 19 347 128 | ||
| 1307 | L 347 722 | ||
| 1308 | Q 666 556 975 473 | ||
| 1309 | Q 1284 391 1588 391 | ||
| 1310 | Q 1994 391 2212 530 | ||
| 1311 | Q 2431 669 2431 922 | ||
| 1312 | Q 2431 1156 2273 1281 | ||
| 1313 | Q 2116 1406 1581 1522 | ||
| 1314 | L 1381 1569 | ||
| 1315 | Q 847 1681 609 1914 | ||
| 1316 | Q 372 2147 372 2553 | ||
| 1317 | Q 372 3047 722 3315 | ||
| 1318 | Q 1072 3584 1716 3584 | ||
| 1319 | Q 2034 3584 2315 3537 | ||
| 1320 | Q 2597 3491 2834 3397 | ||
| 1321 | z | ||
| 1322 | " transform="scale(0.015625)"/> | ||
| 1323 | <path id="DejaVuSans-7a" d="M 353 3500 | ||
| 1324 | L 3084 3500 | ||
| 1325 | L 3084 2975 | ||
| 1326 | L 922 459 | ||
| 1327 | L 3084 459 | ||
| 1328 | L 3084 0 | ||
| 1329 | L 275 0 | ||
| 1330 | L 275 525 | ||
| 1331 | L 2438 3041 | ||
| 1332 | L 353 3041 | ||
| 1333 | L 353 3500 | ||
| 1334 | z | ||
| 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 | ||
| 1370 | L 147.051562 66.222917 | ||
| 1371 | Q 149.051562 66.222917 149.051562 64.222917 | ||
| 1372 | L 149.051562 35.866667 | ||
| 1373 | Q 149.051562 33.866667 147.051562 33.866667 | ||
| 1374 | L 74.078125 33.866667 | ||
| 1375 | Q 72.078125 33.866667 72.078125 35.866667 | ||
| 1376 | L 72.078125 64.222917 | ||
| 1377 | Q 72.078125 66.222917 74.078125 66.222917 | ||
| 1378 | z | ||
| 1379 | " style="fill: #ffffff; opacity: 0.8"/> | ||
| 1380 | </g> | ||
| 1381 | <g id="line2d_18"> | ||
| 1382 | <path d="M 76.078125 41.965104 | ||
| 1383 | L 86.078125 41.965104 | ||
| 1384 | L 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 | ||
| 1392 | Q 3044 2119 3236 1894 | ||
| 1393 | Q 3428 1669 3622 1275 | ||
| 1394 | L 4263 0 | ||
| 1395 | L 3584 0 | ||
| 1396 | L 2988 1197 | ||
| 1397 | Q 2756 1666 2539 1819 | ||
| 1398 | Q 2322 1972 1947 1972 | ||
| 1399 | L 1259 1972 | ||
| 1400 | L 1259 0 | ||
| 1401 | L 628 0 | ||
| 1402 | L 628 4666 | ||
| 1403 | L 2053 4666 | ||
| 1404 | Q 2853 4666 3247 4331 | ||
| 1405 | Q 3641 3997 3641 3322 | ||
| 1406 | Q 3641 2881 3436 2590 | ||
| 1407 | Q 3231 2300 2841 2188 | ||
| 1408 | z | ||
| 1409 | M 1259 4147 | ||
| 1410 | L 1259 2491 | ||
| 1411 | L 2053 2491 | ||
| 1412 | Q 2509 2491 2742 2702 | ||
| 1413 | Q 2975 2913 2975 3322 | ||
| 1414 | Q 2975 3731 2742 3939 | ||
| 1415 | Q 2509 4147 2053 4147 | ||
| 1416 | L 1259 4147 | ||
| 1417 | z | ||
| 1418 | " transform="scale(0.015625)"/> | ||
| 1419 | <path id="DejaVuSans-61" d="M 2194 1759 | ||
| 1420 | Q 1497 1759 1228 1600 | ||
| 1421 | Q 959 1441 959 1056 | ||
| 1422 | Q 959 750 1161 570 | ||
| 1423 | Q 1363 391 1709 391 | ||
| 1424 | Q 2188 391 2477 730 | ||
| 1425 | Q 2766 1069 2766 1631 | ||
| 1426 | L 2766 1759 | ||
| 1427 | L 2194 1759 | ||
| 1428 | z | ||
| 1429 | M 3341 1997 | ||
| 1430 | L 3341 0 | ||
| 1431 | L 2766 0 | ||
| 1432 | L 2766 531 | ||
| 1433 | Q 2569 213 2275 61 | ||
| 1434 | Q 1981 -91 1556 -91 | ||
| 1435 | Q 1019 -91 701 211 | ||
| 1436 | Q 384 513 384 1019 | ||
| 1437 | Q 384 1609 779 1909 | ||
| 1438 | Q 1175 2209 1959 2209 | ||
| 1439 | L 2766 2209 | ||
| 1440 | L 2766 2266 | ||
| 1441 | Q 2766 2663 2505 2880 | ||
| 1442 | Q 2244 3097 1772 3097 | ||
| 1443 | Q 1472 3097 1187 3025 | ||
| 1444 | Q 903 2953 641 2809 | ||
| 1445 | L 641 3341 | ||
| 1446 | Q 956 3463 1253 3523 | ||
| 1447 | Q 1550 3584 1831 3584 | ||
| 1448 | Q 2591 3584 2966 3190 | ||
| 1449 | Q 3341 2797 3341 1997 | ||
| 1450 | z | ||
| 1451 | " transform="scale(0.015625)"/> | ||
| 1452 | <path id="DejaVuSans-77" d="M 269 3500 | ||
| 1453 | L 844 3500 | ||
| 1454 | L 1563 769 | ||
| 1455 | L 2278 3500 | ||
| 1456 | L 2956 3500 | ||
| 1457 | L 3675 769 | ||
| 1458 | L 4391 3500 | ||
| 1459 | L 4966 3500 | ||
| 1460 | L 4050 0 | ||
| 1461 | L 3372 0 | ||
| 1462 | L 2619 2869 | ||
| 1463 | L 1863 0 | ||
| 1464 | L 1184 0 | ||
| 1465 | L 269 3500 | ||
| 1466 | z | ||
| 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 | ||
| 1476 | L 86.078125 56.643229 | ||
| 1477 | L 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 | ||
| 1485 | L 3809 1919 | ||
| 1486 | L 2778 1919 | ||
| 1487 | L 2778 2438 | ||
| 1488 | L 4434 2438 | ||
| 1489 | L 4434 434 | ||
| 1490 | Q 4069 175 3628 42 | ||
| 1491 | Q 3188 -91 2688 -91 | ||
| 1492 | Q 1594 -91 976 548 | ||
| 1493 | Q 359 1188 359 2328 | ||
| 1494 | Q 359 3472 976 4111 | ||
| 1495 | Q 1594 4750 2688 4750 | ||
| 1496 | Q 3144 4750 3555 4637 | ||
| 1497 | Q 3966 4525 4313 4306 | ||
| 1498 | L 4313 3634 | ||
| 1499 | Q 3963 3931 3569 4081 | ||
| 1500 | Q 3175 4231 2741 4231 | ||
| 1501 | Q 1884 4231 1454 3753 | ||
| 1502 | Q 1025 3275 1025 2328 | ||
| 1503 | Q 1025 1384 1454 906 | ||
| 1504 | Q 1884 428 2741 428 | ||
| 1505 | Q 3075 428 3337 486 | ||
| 1506 | Q 3600 544 3809 666 | ||
| 1507 | z | ||
| 1508 | " transform="scale(0.015625)"/> | ||
| 1509 | <path id="DejaVuSans-70" d="M 1159 525 | ||
| 1510 | L 1159 -1331 | ||
| 1511 | L 581 -1331 | ||
| 1512 | L 581 3500 | ||
| 1513 | L 1159 3500 | ||
| 1514 | L 1159 2969 | ||
| 1515 | Q 1341 3281 1617 3432 | ||
| 1516 | Q 1894 3584 2278 3584 | ||
| 1517 | Q 2916 3584 3314 3078 | ||
| 1518 | Q 3713 2572 3713 1747 | ||
| 1519 | Q 3713 922 3314 415 | ||
| 1520 | Q 2916 -91 2278 -91 | ||
| 1521 | Q 1894 -91 1617 61 | ||
| 1522 | Q 1341 213 1159 525 | ||
| 1523 | z | ||
| 1524 | M 3116 1747 | ||
| 1525 | Q 3116 2381 2855 2742 | ||
| 1526 | Q 2594 3103 2138 3103 | ||
| 1527 | Q 1681 3103 1420 2742 | ||
| 1528 | Q 1159 2381 1159 1747 | ||
| 1529 | Q 1159 1113 1420 752 | ||
| 1530 | Q 1681 391 2138 391 | ||
| 1531 | Q 2594 391 2855 752 | ||
| 1532 | Q 3116 1113 3116 1747 | ||
| 1533 | z | ||
| 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 @@ | |||
| 1 | import csv | ||
| 2 | |||
| 3 | import matplotlib.pyplot as plt | ||
| 4 | import pandas as pd | ||
| 5 | |||
| 6 | # Read the data | ||
| 7 | df = pd.read_csv("benchmarks.csv") | ||
| 8 | |||
| 9 | # Settings | ||
| 10 | plt.title("Encode to FASTA speed over time") | ||
| 11 | plt.tight_layout(pad=2) | ||
| 12 | fig = plt.gcf() | ||
| 13 | fig.set_size_inches(10, 4) | ||
| 14 | |||
| 15 | # Plotting | ||
| 16 | plt.plot(df["Packages"], df["Encode to FASTA (ms)"], label = "ALB", color="black", linestyle="--") | ||
| 17 | |||
| 18 | # Adding x and y axis labels | ||
| 19 | plt.xlabel("Size of an input file", fontstyle="italic") | ||
| 20 | plt.ylabel("Encoding time (ms)", fontstyle="italic") | ||
| 21 | |||
| 22 | # Export as SVG | ||
| 23 | plt.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 | ||
| 25 | L 720 288 | ||
| 26 | L 720 0 | ||
| 27 | L 0 0 | ||
| 28 | z | ||
| 29 | " style="fill: #ffffff"/> | ||
| 30 | </g> | ||
| 31 | <g id="axes_1"> | ||
| 32 | <g id="patch_2"> | ||
| 33 | <path d="M 67.078125 257.1 | ||
| 34 | L 676.304688 257.1 | ||
| 35 | L 676.304688 28.866667 | ||
| 36 | L 67.078125 28.866667 | ||
| 37 | z | ||
| 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 | ||
| 45 | L 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 | ||
| 57 | L 1825 531 | ||
| 58 | L 1825 4091 | ||
| 59 | L 703 3866 | ||
| 60 | L 703 4441 | ||
| 61 | L 1819 4666 | ||
| 62 | L 2450 4666 | ||
| 63 | L 2450 531 | ||
| 64 | L 3481 531 | ||
| 65 | L 3481 0 | ||
| 66 | L 794 0 | ||
| 67 | L 794 531 | ||
| 68 | z | ||
| 69 | " transform="scale(0.015625)"/> | ||
| 70 | <path id="DejaVuSans-4b" d="M 628 4666 | ||
| 71 | L 1259 4666 | ||
| 72 | L 1259 2694 | ||
| 73 | L 3353 4666 | ||
| 74 | L 4166 4666 | ||
| 75 | L 1850 2491 | ||
| 76 | L 4331 0 | ||
| 77 | L 3500 0 | ||
| 78 | L 1259 2247 | ||
| 79 | L 1259 0 | ||
| 80 | L 628 0 | ||
| 81 | L 628 4666 | ||
| 82 | z | ||
| 83 | " transform="scale(0.015625)"/> | ||
| 84 | <path id="DejaVuSans-42" d="M 1259 2228 | ||
| 85 | L 1259 519 | ||
| 86 | L 2272 519 | ||
| 87 | Q 2781 519 3026 730 | ||
| 88 | Q 3272 941 3272 1375 | ||
| 89 | Q 3272 1813 3026 2020 | ||
| 90 | Q 2781 2228 2272 2228 | ||
| 91 | L 1259 2228 | ||
| 92 | z | ||
| 93 | M 1259 4147 | ||
| 94 | L 1259 2741 | ||
| 95 | L 2194 2741 | ||
| 96 | Q 2656 2741 2882 2914 | ||
| 97 | Q 3109 3088 3109 3444 | ||
| 98 | Q 3109 3797 2882 3972 | ||
| 99 | Q 2656 4147 2194 4147 | ||
| 100 | L 1259 4147 | ||
| 101 | z | ||
| 102 | M 628 4666 | ||
| 103 | L 2241 4666 | ||
| 104 | Q 2963 4666 3353 4366 | ||
| 105 | Q 3744 4066 3744 3513 | ||
| 106 | Q 3744 3084 3544 2831 | ||
| 107 | Q 3344 2578 2956 2516 | ||
| 108 | Q 3422 2416 3680 2098 | ||
| 109 | Q 3938 1781 3938 1306 | ||
| 110 | Q 3938 681 3513 340 | ||
| 111 | Q 3088 0 2303 0 | ||
| 112 | L 628 0 | ||
| 113 | L 628 4666 | ||
| 114 | z | ||
| 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 | ||
| 134 | Q 1547 4250 1301 3770 | ||
| 135 | Q 1056 3291 1056 2328 | ||
| 136 | Q 1056 1369 1301 889 | ||
| 137 | Q 1547 409 2034 409 | ||
| 138 | Q 2525 409 2770 889 | ||
| 139 | Q 3016 1369 3016 2328 | ||
| 140 | Q 3016 3291 2770 3770 | ||
| 141 | Q 2525 4250 2034 4250 | ||
| 142 | z | ||
| 143 | M 2034 4750 | ||
| 144 | Q 2819 4750 3233 4129 | ||
| 145 | Q 3647 3509 3647 2328 | ||
| 146 | Q 3647 1150 3233 529 | ||
| 147 | Q 2819 -91 2034 -91 | ||
| 148 | Q 1250 -91 836 529 | ||
| 149 | Q 422 1150 422 2328 | ||
| 150 | Q 422 3509 836 4129 | ||
| 151 | Q 1250 4750 2034 4750 | ||
| 152 | z | ||
| 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 | ||
| 190 | L 1569 4666 | ||
| 191 | L 2759 1491 | ||
| 192 | L 3956 4666 | ||
| 193 | L 4897 4666 | ||
| 194 | L 4897 0 | ||
| 195 | L 4281 0 | ||
| 196 | L 4281 4097 | ||
| 197 | L 3078 897 | ||
| 198 | L 2444 897 | ||
| 199 | L 1241 4097 | ||
| 200 | L 1241 0 | ||
| 201 | L 628 0 | ||
| 202 | L 628 4666 | ||
| 203 | z | ||
| 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 | ||
| 250 | L 3738 3897 | ||
| 251 | Q 3422 4066 3111 4152 | ||
| 252 | Q 2800 4238 2509 4238 | ||
| 253 | Q 1944 4238 1609 3991 | ||
| 254 | Q 1275 3744 1275 3334 | ||
| 255 | Q 1275 3109 1398 2989 | ||
| 256 | Q 1522 2869 2034 2731 | ||
| 257 | L 2413 2638 | ||
| 258 | Q 3053 2472 3303 2217 | ||
| 259 | Q 3553 1963 3553 1503 | ||
| 260 | Q 3553 797 2998 353 | ||
| 261 | Q 2444 -91 1538 -91 | ||
| 262 | Q 1166 -91 791 -17 | ||
| 263 | Q 416 56 38 206 | ||
| 264 | L 166 856 | ||
| 265 | Q 513 641 861 531 | ||
| 266 | Q 1209 422 1556 422 | ||
| 267 | Q 2147 422 2503 684 | ||
| 268 | Q 2859 947 2859 1369 | ||
| 269 | Q 2859 1650 2717 1795 | ||
| 270 | Q 2575 1941 2106 2059 | ||
| 271 | L 1728 2156 | ||
| 272 | Q 1081 2325 845 2545 | ||
| 273 | Q 609 2766 609 3163 | ||
| 274 | Q 609 3859 1145 4304 | ||
| 275 | Q 1681 4750 2541 4750 | ||
| 276 | Q 2875 4750 3203 4690 | ||
| 277 | Q 3531 4631 3859 4513 | ||
| 278 | z | ||
| 279 | " transform="scale(0.015625)"/> | ||
| 280 | <path id="DejaVuSans-Oblique-69" d="M 1172 4863 | ||
| 281 | L 1747 4863 | ||
| 282 | L 1606 4134 | ||
| 283 | L 1031 4134 | ||
| 284 | L 1172 4863 | ||
| 285 | z | ||
| 286 | M 909 3500 | ||
| 287 | L 1484 3500 | ||
| 288 | L 800 0 | ||
| 289 | L 225 0 | ||
| 290 | L 909 3500 | ||
| 291 | z | ||
| 292 | " transform="scale(0.015625)"/> | ||
| 293 | <path id="DejaVuSans-Oblique-7a" d="M 744 3500 | ||
| 294 | L 3475 3500 | ||
| 295 | L 3372 2975 | ||
| 296 | L 738 459 | ||
| 297 | L 2913 459 | ||
| 298 | L 2822 0 | ||
| 299 | L -19 0 | ||
| 300 | L 84 525 | ||
| 301 | L 2719 3041 | ||
| 302 | L 653 3041 | ||
| 303 | L 744 3500 | ||
| 304 | z | ||
| 305 | " transform="scale(0.015625)"/> | ||
| 306 | <path id="DejaVuSans-Oblique-65" d="M 3078 2063 | ||
| 307 | Q 3088 2113 3092 2166 | ||
| 308 | Q 3097 2219 3097 2272 | ||
| 309 | Q 3097 2653 2873 2875 | ||
| 310 | Q 2650 3097 2266 3097 | ||
| 311 | Q 1838 3097 1509 2826 | ||
| 312 | Q 1181 2556 1013 2059 | ||
| 313 | L 3078 2063 | ||
| 314 | z | ||
| 315 | M 3578 1613 | ||
| 316 | L 903 1613 | ||
| 317 | Q 884 1494 878 1425 | ||
| 318 | Q 872 1356 872 1306 | ||
| 319 | Q 872 872 1139 634 | ||
| 320 | Q 1406 397 1894 397 | ||
| 321 | Q 2269 397 2603 481 | ||
| 322 | Q 2938 566 3225 728 | ||
| 323 | L 3116 159 | ||
| 324 | Q 2806 34 2476 -28 | ||
| 325 | Q 2147 -91 1806 -91 | ||
| 326 | Q 1078 -91 686 257 | ||
| 327 | Q 294 606 294 1247 | ||
| 328 | Q 294 1794 489 2264 | ||
| 329 | Q 684 2734 1063 3103 | ||
| 330 | Q 1306 3334 1642 3459 | ||
| 331 | Q 1978 3584 2356 3584 | ||
| 332 | Q 2950 3584 3301 3228 | ||
| 333 | Q 3653 2872 3653 2272 | ||
| 334 | Q 3653 2128 3634 1964 | ||
| 335 | Q 3616 1800 3578 1613 | ||
| 336 | z | ||
| 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 | ||
| 340 | Q 1009 -91 651 289 | ||
| 341 | Q 294 669 294 1325 | ||
| 342 | Q 294 1706 417 2101 | ||
| 343 | Q 541 2497 738 2766 | ||
| 344 | Q 1047 3184 1428 3384 | ||
| 345 | Q 1809 3584 2291 3584 | ||
| 346 | Q 2888 3584 3255 3212 | ||
| 347 | Q 3622 2841 3622 2241 | ||
| 348 | Q 3622 1825 3500 1412 | ||
| 349 | Q 3378 1000 3181 728 | ||
| 350 | Q 2875 309 2494 109 | ||
| 351 | Q 2113 -91 1625 -91 | ||
| 352 | z | ||
| 353 | M 891 1344 | ||
| 354 | Q 891 869 1089 633 | ||
| 355 | Q 1288 397 1691 397 | ||
| 356 | Q 2269 397 2648 901 | ||
| 357 | Q 3028 1406 3028 2181 | ||
| 358 | Q 3028 2634 2825 2865 | ||
| 359 | Q 2622 3097 2228 3097 | ||
| 360 | Q 1903 3097 1650 2945 | ||
| 361 | Q 1397 2794 1197 2484 | ||
| 362 | Q 1050 2253 970 1956 | ||
| 363 | Q 891 1659 891 1344 | ||
| 364 | z | ||
| 365 | " transform="scale(0.015625)"/> | ||
| 366 | <path id="DejaVuSans-Oblique-66" d="M 3059 4863 | ||
| 367 | L 2969 4384 | ||
| 368 | L 2419 4384 | ||
| 369 | Q 2106 4384 1964 4261 | ||
| 370 | Q 1822 4138 1753 3809 | ||
| 371 | L 1691 3500 | ||
| 372 | L 2638 3500 | ||
| 373 | L 2553 3053 | ||
| 374 | L 1606 3053 | ||
| 375 | L 1013 0 | ||
| 376 | L 434 0 | ||
| 377 | L 1031 3053 | ||
| 378 | L 481 3053 | ||
| 379 | L 563 3500 | ||
| 380 | L 1113 3500 | ||
| 381 | L 1159 3744 | ||
| 382 | Q 1278 4363 1576 4613 | ||
| 383 | Q 1875 4863 2516 4863 | ||
| 384 | L 3059 4863 | ||
| 385 | z | ||
| 386 | " transform="scale(0.015625)"/> | ||
| 387 | <path id="DejaVuSans-Oblique-61" d="M 3438 1997 | ||
| 388 | L 3047 0 | ||
| 389 | L 2472 0 | ||
| 390 | L 2578 531 | ||
| 391 | Q 2325 219 2001 64 | ||
| 392 | Q 1678 -91 1281 -91 | ||
| 393 | Q 834 -91 548 182 | ||
| 394 | Q 263 456 263 884 | ||
| 395 | Q 263 1497 752 1853 | ||
| 396 | Q 1241 2209 2100 2209 | ||
| 397 | L 2900 2209 | ||
| 398 | L 2931 2363 | ||
| 399 | Q 2938 2388 2941 2417 | ||
| 400 | Q 2944 2447 2944 2509 | ||
| 401 | Q 2944 2788 2717 2942 | ||
| 402 | Q 2491 3097 2081 3097 | ||
| 403 | Q 1800 3097 1504 3025 | ||
| 404 | Q 1209 2953 897 2809 | ||
| 405 | L 997 3341 | ||
| 406 | Q 1322 3463 1633 3523 | ||
| 407 | Q 1944 3584 2234 3584 | ||
| 408 | Q 2853 3584 3176 3315 | ||
| 409 | Q 3500 3047 3500 2534 | ||
| 410 | Q 3500 2431 3484 2292 | ||
| 411 | Q 3469 2153 3438 1997 | ||
| 412 | z | ||
| 413 | M 2816 1759 | ||
| 414 | L 2241 1759 | ||
| 415 | Q 1534 1759 1195 1570 | ||
| 416 | Q 856 1381 856 984 | ||
| 417 | Q 856 709 1029 553 | ||
| 418 | Q 1203 397 1509 397 | ||
| 419 | Q 1978 397 2328 733 | ||
| 420 | Q 2678 1069 2791 1631 | ||
| 421 | L 2816 1759 | ||
| 422 | z | ||
| 423 | " transform="scale(0.015625)"/> | ||
| 424 | <path id="DejaVuSans-Oblique-6e" d="M 3566 2113 | ||
| 425 | L 3156 0 | ||
| 426 | L 2578 0 | ||
| 427 | L 2988 2091 | ||
| 428 | Q 3016 2238 3031 2350 | ||
| 429 | Q 3047 2463 3047 2528 | ||
| 430 | Q 3047 2791 2881 2937 | ||
| 431 | Q 2716 3084 2419 3084 | ||
| 432 | Q 1956 3084 1622 2776 | ||
| 433 | Q 1288 2469 1184 1941 | ||
| 434 | L 800 0 | ||
| 435 | L 225 0 | ||
| 436 | L 903 3500 | ||
| 437 | L 1478 3500 | ||
| 438 | L 1363 2950 | ||
| 439 | Q 1603 3253 1940 3418 | ||
| 440 | Q 2278 3584 2650 3584 | ||
| 441 | Q 3113 3584 3367 3334 | ||
| 442 | Q 3622 3084 3622 2631 | ||
| 443 | Q 3622 2519 3608 2391 | ||
| 444 | Q 3594 2263 3566 2113 | ||
| 445 | z | ||
| 446 | " transform="scale(0.015625)"/> | ||
| 447 | <path id="DejaVuSans-Oblique-70" d="M 3175 2156 | ||
| 448 | Q 3175 2616 2975 2859 | ||
| 449 | Q 2775 3103 2400 3103 | ||
| 450 | Q 2144 3103 1911 2972 | ||
| 451 | Q 1678 2841 1497 2591 | ||
| 452 | Q 1319 2344 1212 1994 | ||
| 453 | Q 1106 1644 1106 1300 | ||
| 454 | Q 1106 863 1306 627 | ||
| 455 | Q 1506 391 1875 391 | ||
| 456 | Q 2147 391 2380 519 | ||
| 457 | Q 2613 647 2778 891 | ||
| 458 | Q 2956 1147 3065 1494 | ||
| 459 | Q 3175 1841 3175 2156 | ||
| 460 | z | ||
| 461 | M 1394 2969 | ||
| 462 | Q 1625 3272 1939 3428 | ||
| 463 | Q 2253 3584 2638 3584 | ||
| 464 | Q 3175 3584 3472 3232 | ||
| 465 | Q 3769 2881 3769 2247 | ||
| 466 | Q 3769 1728 3584 1258 | ||
| 467 | Q 3400 788 3053 416 | ||
| 468 | Q 2822 169 2531 39 | ||
| 469 | Q 2241 -91 1919 -91 | ||
| 470 | Q 1547 -91 1294 64 | ||
| 471 | Q 1041 219 916 525 | ||
| 472 | L 556 -1331 | ||
| 473 | L -19 -1331 | ||
| 474 | L 922 3500 | ||
| 475 | L 1497 3500 | ||
| 476 | L 1394 2969 | ||
| 477 | z | ||
| 478 | " transform="scale(0.015625)"/> | ||
| 479 | <path id="DejaVuSans-Oblique-75" d="M 428 1388 | ||
| 480 | L 838 3500 | ||
| 481 | L 1416 3500 | ||
| 482 | L 1006 1409 | ||
| 483 | Q 975 1256 961 1147 | ||
| 484 | Q 947 1038 947 966 | ||
| 485 | Q 947 700 1109 554 | ||
| 486 | Q 1272 409 1569 409 | ||
| 487 | Q 2031 409 2368 721 | ||
| 488 | Q 2706 1034 2809 1563 | ||
| 489 | L 3194 3500 | ||
| 490 | L 3769 3500 | ||
| 491 | L 3091 0 | ||
| 492 | L 2516 0 | ||
| 493 | L 2631 550 | ||
| 494 | Q 2388 244 2052 76 | ||
| 495 | Q 1716 -91 1338 -91 | ||
| 496 | Q 878 -91 622 161 | ||
| 497 | Q 366 413 366 863 | ||
| 498 | Q 366 956 381 1097 | ||
| 499 | Q 397 1238 428 1388 | ||
| 500 | z | ||
| 501 | " transform="scale(0.015625)"/> | ||
| 502 | <path id="DejaVuSans-Oblique-74" d="M 2706 3500 | ||
| 503 | L 2619 3053 | ||
| 504 | L 1472 3053 | ||
| 505 | L 1100 1153 | ||
| 506 | Q 1081 1047 1072 975 | ||
| 507 | Q 1063 903 1063 863 | ||
| 508 | Q 1063 663 1183 572 | ||
| 509 | Q 1303 481 1569 481 | ||
| 510 | L 2150 481 | ||
| 511 | L 2053 0 | ||
| 512 | L 1503 0 | ||
| 513 | Q 991 0 739 200 | ||
| 514 | Q 488 400 488 806 | ||
| 515 | Q 488 878 497 964 | ||
| 516 | Q 506 1050 525 1153 | ||
| 517 | L 897 3053 | ||
| 518 | L 409 3053 | ||
| 519 | L 500 3500 | ||
| 520 | L 978 3500 | ||
| 521 | L 1172 4494 | ||
| 522 | L 1747 4494 | ||
| 523 | L 1556 3500 | ||
| 524 | L 2706 3500 | ||
| 525 | z | ||
| 526 | " transform="scale(0.015625)"/> | ||
| 527 | <path id="DejaVuSans-Oblique-6c" d="M 1172 4863 | ||
| 528 | L 1747 4863 | ||
| 529 | L 800 0 | ||
| 530 | L 225 0 | ||
| 531 | L 1172 4863 | ||
| 532 | z | ||
| 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 | ||
| 564 | L -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 | ||
| 589 | L 3431 531 | ||
| 590 | L 3431 0 | ||
| 591 | L 469 0 | ||
| 592 | L 469 531 | ||
| 593 | Q 828 903 1448 1529 | ||
| 594 | Q 2069 2156 2228 2338 | ||
| 595 | Q 2531 2678 2651 2914 | ||
| 596 | Q 2772 3150 2772 3378 | ||
| 597 | Q 2772 3750 2511 3984 | ||
| 598 | Q 2250 4219 1831 4219 | ||
| 599 | Q 1534 4219 1204 4116 | ||
| 600 | Q 875 4013 500 3803 | ||
| 601 | L 500 4441 | ||
| 602 | Q 881 4594 1212 4672 | ||
| 603 | Q 1544 4750 1819 4750 | ||
| 604 | Q 2544 4750 2975 4387 | ||
| 605 | Q 3406 4025 3406 3419 | ||
| 606 | Q 3406 3131 3298 2873 | ||
| 607 | Q 3191 2616 2906 2266 | ||
| 608 | Q 2828 2175 2409 1742 | ||
| 609 | Q 1991 1309 1228 531 | ||
| 610 | z | ||
| 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 | ||
| 632 | L 825 1625 | ||
| 633 | L 2419 1625 | ||
| 634 | L 2419 4116 | ||
| 635 | z | ||
| 636 | M 2253 4666 | ||
| 637 | L 3047 4666 | ||
| 638 | L 3047 1625 | ||
| 639 | L 3713 1625 | ||
| 640 | L 3713 1100 | ||
| 641 | L 3047 1100 | ||
| 642 | L 3047 0 | ||
| 643 | L 2419 0 | ||
| 644 | L 2419 1100 | ||
| 645 | L 313 1100 | ||
| 646 | L 313 1709 | ||
| 647 | L 2253 4666 | ||
| 648 | z | ||
| 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 | ||
| 670 | Q 1688 2584 1439 2293 | ||
| 671 | Q 1191 2003 1191 1497 | ||
| 672 | Q 1191 994 1439 701 | ||
| 673 | Q 1688 409 2113 409 | ||
| 674 | Q 2538 409 2786 701 | ||
| 675 | Q 3034 994 3034 1497 | ||
| 676 | Q 3034 2003 2786 2293 | ||
| 677 | Q 2538 2584 2113 2584 | ||
| 678 | z | ||
| 679 | M 3366 4563 | ||
| 680 | L 3366 3988 | ||
| 681 | Q 3128 4100 2886 4159 | ||
| 682 | Q 2644 4219 2406 4219 | ||
| 683 | Q 1781 4219 1451 3797 | ||
| 684 | Q 1122 3375 1075 2522 | ||
| 685 | Q 1259 2794 1537 2939 | ||
| 686 | Q 1816 3084 2150 3084 | ||
| 687 | Q 2853 3084 3261 2657 | ||
| 688 | Q 3669 2231 3669 1497 | ||
| 689 | Q 3669 778 3244 343 | ||
| 690 | Q 2819 -91 2113 -91 | ||
| 691 | Q 1303 -91 875 529 | ||
| 692 | Q 447 1150 447 2328 | ||
| 693 | Q 447 3434 972 4092 | ||
| 694 | Q 1497 4750 2381 4750 | ||
| 695 | Q 2619 4750 2861 4703 | ||
| 696 | Q 3103 4656 3366 4563 | ||
| 697 | z | ||
| 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 | ||
| 719 | Q 1584 2216 1326 1975 | ||
| 720 | Q 1069 1734 1069 1313 | ||
| 721 | Q 1069 891 1326 650 | ||
| 722 | Q 1584 409 2034 409 | ||
| 723 | Q 2484 409 2743 651 | ||
| 724 | Q 3003 894 3003 1313 | ||
| 725 | Q 3003 1734 2745 1975 | ||
| 726 | Q 2488 2216 2034 2216 | ||
| 727 | z | ||
| 728 | M 1403 2484 | ||
| 729 | Q 997 2584 770 2862 | ||
| 730 | Q 544 3141 544 3541 | ||
| 731 | Q 544 4100 942 4425 | ||
| 732 | Q 1341 4750 2034 4750 | ||
| 733 | Q 2731 4750 3128 4425 | ||
| 734 | Q 3525 4100 3525 3541 | ||
| 735 | Q 3525 3141 3298 2862 | ||
| 736 | Q 3072 2584 2669 2484 | ||
| 737 | Q 3125 2378 3379 2068 | ||
| 738 | Q 3634 1759 3634 1313 | ||
| 739 | Q 3634 634 3220 271 | ||
| 740 | Q 2806 -91 2034 -91 | ||
| 741 | Q 1263 -91 848 271 | ||
| 742 | Q 434 634 434 1313 | ||
| 743 | Q 434 1759 690 2068 | ||
| 744 | Q 947 2378 1403 2484 | ||
| 745 | z | ||
| 746 | M 1172 3481 | ||
| 747 | Q 1172 3119 1398 2916 | ||
| 748 | Q 1625 2713 2034 2713 | ||
| 749 | Q 2441 2713 2670 2916 | ||
| 750 | Q 2900 3119 2900 3481 | ||
| 751 | Q 2900 3844 2670 4047 | ||
| 752 | Q 2441 4250 2034 4250 | ||
| 753 | Q 1625 4250 1398 4047 | ||
| 754 | Q 1172 3844 1172 3481 | ||
| 755 | z | ||
| 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 | ||
| 771 | L 4031 4666 | ||
| 772 | L 3928 4134 | ||
| 773 | L 1606 4134 | ||
| 774 | L 1338 2753 | ||
| 775 | L 3566 2753 | ||
| 776 | L 3463 2222 | ||
| 777 | L 1234 2222 | ||
| 778 | L 909 531 | ||
| 779 | L 3284 531 | ||
| 780 | L 3181 0 | ||
| 781 | L 172 0 | ||
| 782 | L 1081 4666 | ||
| 783 | z | ||
| 784 | " transform="scale(0.015625)"/> | ||
| 785 | <path id="DejaVuSans-Oblique-63" d="M 3431 3366 | ||
| 786 | L 3316 2797 | ||
| 787 | Q 3109 2947 2876 3022 | ||
| 788 | Q 2644 3097 2394 3097 | ||
| 789 | Q 2119 3097 1870 3000 | ||
| 790 | Q 1622 2903 1453 2725 | ||
| 791 | Q 1184 2453 1037 2087 | ||
| 792 | Q 891 1722 891 1331 | ||
| 793 | Q 891 859 1127 628 | ||
| 794 | Q 1363 397 1844 397 | ||
| 795 | Q 2081 397 2348 469 | ||
| 796 | Q 2616 541 2906 684 | ||
| 797 | L 2797 116 | ||
| 798 | Q 2547 13 2283 -39 | ||
| 799 | Q 2019 -91 1741 -91 | ||
| 800 | Q 1044 -91 669 257 | ||
| 801 | Q 294 606 294 1253 | ||
| 802 | Q 294 1797 489 2255 | ||
| 803 | Q 684 2713 1069 3078 | ||
| 804 | Q 1331 3328 1684 3456 | ||
| 805 | Q 2038 3584 2456 3584 | ||
| 806 | Q 2700 3584 2940 3529 | ||
| 807 | Q 3181 3475 3431 3366 | ||
| 808 | z | ||
| 809 | " transform="scale(0.015625)"/> | ||
| 810 | <path id="DejaVuSans-Oblique-64" d="M 2675 525 | ||
| 811 | Q 2444 222 2128 65 | ||
| 812 | Q 1813 -91 1428 -91 | ||
| 813 | Q 903 -91 598 267 | ||
| 814 | Q 294 625 294 1247 | ||
| 815 | Q 294 1766 478 2236 | ||
| 816 | Q 663 2706 1013 3078 | ||
| 817 | Q 1244 3325 1534 3454 | ||
| 818 | Q 1825 3584 2144 3584 | ||
| 819 | Q 2481 3584 2739 3421 | ||
| 820 | Q 2997 3259 3138 2956 | ||
| 821 | L 3513 4863 | ||
| 822 | L 4091 4863 | ||
| 823 | L 3144 0 | ||
| 824 | L 2566 0 | ||
| 825 | L 2675 525 | ||
| 826 | z | ||
| 827 | M 891 1350 | ||
| 828 | Q 891 897 1095 644 | ||
| 829 | Q 1300 391 1663 391 | ||
| 830 | Q 1931 391 2161 520 | ||
| 831 | Q 2391 650 2566 903 | ||
| 832 | Q 2750 1166 2856 1509 | ||
| 833 | Q 2963 1853 2963 2188 | ||
| 834 | Q 2963 2622 2758 2865 | ||
| 835 | Q 2553 3109 2194 3109 | ||
| 836 | Q 1922 3109 1687 2981 | ||
| 837 | Q 1453 2853 1288 2613 | ||
| 838 | Q 1106 2353 998 2009 | ||
| 839 | Q 891 1666 891 1350 | ||
| 840 | z | ||
| 841 | " transform="scale(0.015625)"/> | ||
| 842 | <path id="DejaVuSans-Oblique-67" d="M 3816 3500 | ||
| 843 | L 3219 434 | ||
| 844 | Q 3047 -456 2561 -893 | ||
| 845 | Q 2075 -1331 1253 -1331 | ||
| 846 | Q 950 -1331 690 -1286 | ||
| 847 | Q 431 -1241 206 -1147 | ||
| 848 | L 313 -588 | ||
| 849 | Q 525 -725 762 -790 | ||
| 850 | Q 1000 -856 1269 -856 | ||
| 851 | Q 1816 -856 2167 -557 | ||
| 852 | Q 2519 -259 2631 300 | ||
| 853 | L 2681 563 | ||
| 854 | Q 2441 288 2122 144 | ||
| 855 | Q 1803 0 1434 0 | ||
| 856 | Q 903 0 598 351 | ||
| 857 | Q 294 703 294 1319 | ||
| 858 | Q 294 1803 478 2267 | ||
| 859 | Q 663 2731 997 3091 | ||
| 860 | Q 1219 3328 1514 3456 | ||
| 861 | Q 1809 3584 2131 3584 | ||
| 862 | Q 2484 3584 2746 3420 | ||
| 863 | Q 3009 3256 3138 2956 | ||
| 864 | L 3238 3500 | ||
| 865 | L 3816 3500 | ||
| 866 | z | ||
| 867 | M 2950 2216 | ||
| 868 | Q 2950 2641 2750 2872 | ||
| 869 | Q 2550 3103 2181 3103 | ||
| 870 | Q 1953 3103 1747 3012 | ||
| 871 | Q 1541 2922 1394 2759 | ||
| 872 | Q 1156 2491 1023 2127 | ||
| 873 | Q 891 1763 891 1375 | ||
| 874 | Q 891 944 1092 712 | ||
| 875 | Q 1294 481 1672 481 | ||
| 876 | Q 2219 481 2584 976 | ||
| 877 | Q 2950 1472 2950 2216 | ||
| 878 | z | ||
| 879 | " transform="scale(0.015625)"/> | ||
| 880 | <path id="DejaVuSans-Oblique-6d" d="M 5747 2113 | ||
| 881 | L 5338 0 | ||
| 882 | L 4763 0 | ||
| 883 | L 5166 2094 | ||
| 884 | Q 5191 2228 5203 2325 | ||
| 885 | Q 5216 2422 5216 2491 | ||
| 886 | Q 5216 2772 5059 2928 | ||
| 887 | Q 4903 3084 4622 3084 | ||
| 888 | Q 4203 3084 3875 2770 | ||
| 889 | Q 3547 2456 3450 1953 | ||
| 890 | L 3066 0 | ||
| 891 | L 2491 0 | ||
| 892 | L 2900 2094 | ||
| 893 | Q 2925 2209 2937 2307 | ||
| 894 | Q 2950 2406 2950 2484 | ||
| 895 | Q 2950 2769 2794 2926 | ||
| 896 | Q 2638 3084 2363 3084 | ||
| 897 | Q 1938 3084 1609 2770 | ||
| 898 | Q 1281 2456 1184 1953 | ||
| 899 | L 800 0 | ||
| 900 | L 225 0 | ||
| 901 | L 909 3500 | ||
| 902 | L 1484 3500 | ||
| 903 | L 1375 2956 | ||
| 904 | Q 1609 3263 1923 3423 | ||
| 905 | Q 2238 3584 2597 3584 | ||
| 906 | Q 2978 3584 3223 3384 | ||
| 907 | Q 3469 3184 3519 2828 | ||
| 908 | Q 3781 3197 4126 3390 | ||
| 909 | Q 4472 3584 4856 3584 | ||
| 910 | Q 5306 3584 5551 3325 | ||
| 911 | Q 5797 3066 5797 2591 | ||
| 912 | Q 5797 2488 5784 2364 | ||
| 913 | Q 5772 2241 5747 2113 | ||
| 914 | z | ||
| 915 | " transform="scale(0.015625)"/> | ||
| 916 | <path id="DejaVuSans-Oblique-28" d="M 2731 4856 | ||
| 917 | Q 1903 3822 1495 2892 | ||
| 918 | Q 1088 1963 1088 1100 | ||
| 919 | Q 1088 606 1206 120 | ||
| 920 | Q 1325 -366 1563 -844 | ||
| 921 | L 1063 -844 | ||
| 922 | Q 775 -306 634 201 | ||
| 923 | Q 494 709 494 1197 | ||
| 924 | Q 494 2125 923 3036 | ||
| 925 | Q 1353 3947 2222 4856 | ||
| 926 | L 2731 4856 | ||
| 927 | z | ||
| 928 | " transform="scale(0.015625)"/> | ||
| 929 | <path id="DejaVuSans-Oblique-73" d="M 3200 3397 | ||
| 930 | L 3091 2853 | ||
| 931 | Q 2863 2978 2609 3040 | ||
| 932 | Q 2356 3103 2088 3103 | ||
| 933 | Q 1634 3103 1373 2948 | ||
| 934 | Q 1113 2794 1113 2528 | ||
| 935 | Q 1113 2219 1719 2053 | ||
| 936 | Q 1766 2041 1788 2034 | ||
| 937 | L 1972 1978 | ||
| 938 | Q 2547 1819 2739 1644 | ||
| 939 | Q 2931 1469 2931 1166 | ||
| 940 | Q 2931 609 2489 259 | ||
| 941 | Q 2047 -91 1331 -91 | ||
| 942 | Q 1053 -91 747 -37 | ||
| 943 | Q 441 16 72 128 | ||
| 944 | L 184 722 | ||
| 945 | Q 500 559 806 475 | ||
| 946 | Q 1113 391 1394 391 | ||
| 947 | Q 1816 391 2080 572 | ||
| 948 | Q 2344 753 2344 1031 | ||
| 949 | Q 2344 1331 1650 1516 | ||
| 950 | L 1591 1531 | ||
| 951 | L 1394 1581 | ||
| 952 | Q 956 1697 753 1886 | ||
| 953 | Q 550 2075 550 2369 | ||
| 954 | Q 550 2928 970 3256 | ||
| 955 | Q 1391 3584 2113 3584 | ||
| 956 | Q 2397 3584 2667 3537 | ||
| 957 | Q 2938 3491 3200 3397 | ||
| 958 | z | ||
| 959 | " transform="scale(0.015625)"/> | ||
| 960 | <path id="DejaVuSans-Oblique-29" d="M -397 -844 | ||
| 961 | Q 434 191 840 1120 | ||
| 962 | Q 1247 2050 1247 2913 | ||
| 963 | Q 1247 3406 1130 3892 | ||
| 964 | Q 1013 4378 775 4856 | ||
| 965 | L 1275 4856 | ||
| 966 | Q 1563 4316 1703 3812 | ||
| 967 | Q 1844 3309 1844 2822 | ||
| 968 | Q 1844 1891 1411 973 | ||
| 969 | Q 978 56 116 -844 | ||
| 970 | L -397 -844 | ||
| 971 | z | ||
| 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 | ||
| 997 | L 205.538707 246.660118 | ||
| 998 | L 316.307173 246.465577 | ||
| 999 | L 427.075639 244.621633 | ||
| 1000 | L 537.844105 226.183224 | ||
| 1001 | L 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 | ||
| 1006 | L 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 | ||
| 1011 | L 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 | ||
| 1016 | L 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 | ||
| 1021 | L 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 | ||
| 1029 | L 3578 4666 | ||
| 1030 | L 3578 4134 | ||
| 1031 | L 1259 4134 | ||
| 1032 | L 1259 2753 | ||
| 1033 | L 3481 2753 | ||
| 1034 | L 3481 2222 | ||
| 1035 | L 1259 2222 | ||
| 1036 | L 1259 531 | ||
| 1037 | L 3634 531 | ||
| 1038 | L 3634 0 | ||
| 1039 | L 628 0 | ||
| 1040 | L 628 4666 | ||
| 1041 | z | ||
| 1042 | " transform="scale(0.015625)"/> | ||
| 1043 | <path id="DejaVuSans-6e" d="M 3513 2113 | ||
| 1044 | L 3513 0 | ||
| 1045 | L 2938 0 | ||
| 1046 | L 2938 2094 | ||
| 1047 | Q 2938 2591 2744 2837 | ||
| 1048 | Q 2550 3084 2163 3084 | ||
| 1049 | Q 1697 3084 1428 2787 | ||
| 1050 | Q 1159 2491 1159 1978 | ||
| 1051 | L 1159 0 | ||
| 1052 | L 581 0 | ||
| 1053 | L 581 3500 | ||
| 1054 | L 1159 3500 | ||
| 1055 | L 1159 2956 | ||
| 1056 | Q 1366 3272 1645 3428 | ||
| 1057 | Q 1925 3584 2291 3584 | ||
| 1058 | Q 2894 3584 3203 3211 | ||
| 1059 | Q 3513 2838 3513 2113 | ||
| 1060 | z | ||
| 1061 | " transform="scale(0.015625)"/> | ||
| 1062 | <path id="DejaVuSans-63" d="M 3122 3366 | ||
| 1063 | L 3122 2828 | ||
| 1064 | Q 2878 2963 2633 3030 | ||
| 1065 | Q 2388 3097 2138 3097 | ||
| 1066 | Q 1578 3097 1268 2742 | ||
| 1067 | Q 959 2388 959 1747 | ||
| 1068 | Q 959 1106 1268 751 | ||
| 1069 | Q 1578 397 2138 397 | ||
| 1070 | Q 2388 397 2633 464 | ||
| 1071 | Q 2878 531 3122 666 | ||
| 1072 | L 3122 134 | ||
| 1073 | Q 2881 22 2623 -34 | ||
| 1074 | Q 2366 -91 2075 -91 | ||
| 1075 | Q 1284 -91 818 406 | ||
| 1076 | Q 353 903 353 1747 | ||
| 1077 | Q 353 2603 823 3093 | ||
| 1078 | Q 1294 3584 2113 3584 | ||
| 1079 | Q 2378 3584 2631 3529 | ||
| 1080 | Q 2884 3475 3122 3366 | ||
| 1081 | z | ||
| 1082 | " transform="scale(0.015625)"/> | ||
| 1083 | <path id="DejaVuSans-6f" d="M 1959 3097 | ||
| 1084 | Q 1497 3097 1228 2736 | ||
| 1085 | Q 959 2375 959 1747 | ||
| 1086 | Q 959 1119 1226 758 | ||
| 1087 | Q 1494 397 1959 397 | ||
| 1088 | Q 2419 397 2687 759 | ||
| 1089 | Q 2956 1122 2956 1747 | ||
| 1090 | Q 2956 2369 2687 2733 | ||
| 1091 | Q 2419 3097 1959 3097 | ||
| 1092 | z | ||
| 1093 | M 1959 3584 | ||
| 1094 | Q 2709 3584 3137 3096 | ||
| 1095 | Q 3566 2609 3566 1747 | ||
| 1096 | Q 3566 888 3137 398 | ||
| 1097 | Q 2709 -91 1959 -91 | ||
| 1098 | Q 1206 -91 779 398 | ||
| 1099 | Q 353 888 353 1747 | ||
| 1100 | Q 353 2609 779 3096 | ||
| 1101 | Q 1206 3584 1959 3584 | ||
| 1102 | z | ||
| 1103 | " transform="scale(0.015625)"/> | ||
| 1104 | <path id="DejaVuSans-64" d="M 2906 2969 | ||
| 1105 | L 2906 4863 | ||
| 1106 | L 3481 4863 | ||
| 1107 | L 3481 0 | ||
| 1108 | L 2906 0 | ||
| 1109 | L 2906 525 | ||
| 1110 | Q 2725 213 2448 61 | ||
| 1111 | Q 2172 -91 1784 -91 | ||
| 1112 | Q 1150 -91 751 415 | ||
| 1113 | Q 353 922 353 1747 | ||
| 1114 | Q 353 2572 751 3078 | ||
| 1115 | Q 1150 3584 1784 3584 | ||
| 1116 | Q 2172 3584 2448 3432 | ||
| 1117 | Q 2725 3281 2906 2969 | ||
| 1118 | z | ||
| 1119 | M 947 1747 | ||
| 1120 | Q 947 1113 1208 752 | ||
| 1121 | Q 1469 391 1925 391 | ||
| 1122 | Q 2381 391 2643 752 | ||
| 1123 | Q 2906 1113 2906 1747 | ||
| 1124 | Q 2906 2381 2643 2742 | ||
| 1125 | Q 2381 3103 1925 3103 | ||
| 1126 | Q 1469 3103 1208 2742 | ||
| 1127 | Q 947 2381 947 1747 | ||
| 1128 | z | ||
| 1129 | " transform="scale(0.015625)"/> | ||
| 1130 | <path id="DejaVuSans-65" d="M 3597 1894 | ||
| 1131 | L 3597 1613 | ||
| 1132 | L 953 1613 | ||
| 1133 | Q 991 1019 1311 708 | ||
| 1134 | Q 1631 397 2203 397 | ||
| 1135 | Q 2534 397 2845 478 | ||
| 1136 | Q 3156 559 3463 722 | ||
| 1137 | L 3463 178 | ||
| 1138 | Q 3153 47 2828 -22 | ||
| 1139 | Q 2503 -91 2169 -91 | ||
| 1140 | Q 1331 -91 842 396 | ||
| 1141 | Q 353 884 353 1716 | ||
| 1142 | Q 353 2575 817 3079 | ||
| 1143 | Q 1281 3584 2069 3584 | ||
| 1144 | Q 2775 3584 3186 3129 | ||
| 1145 | Q 3597 2675 3597 1894 | ||
| 1146 | z | ||
| 1147 | M 3022 2063 | ||
| 1148 | Q 3016 2534 2758 2815 | ||
| 1149 | Q 2500 3097 2075 3097 | ||
| 1150 | Q 1594 3097 1305 2825 | ||
| 1151 | Q 1016 2553 972 2059 | ||
| 1152 | L 3022 2063 | ||
| 1153 | z | ||
| 1154 | " transform="scale(0.015625)"/> | ||
| 1155 | <path id="DejaVuSans-20" transform="scale(0.015625)"/> | ||
| 1156 | <path id="DejaVuSans-74" d="M 1172 4494 | ||
| 1157 | L 1172 3500 | ||
| 1158 | L 2356 3500 | ||
| 1159 | L 2356 3053 | ||
| 1160 | L 1172 3053 | ||
| 1161 | L 1172 1153 | ||
| 1162 | Q 1172 725 1289 603 | ||
| 1163 | Q 1406 481 1766 481 | ||
| 1164 | L 2356 481 | ||
| 1165 | L 2356 0 | ||
| 1166 | L 1766 0 | ||
| 1167 | Q 1100 0 847 248 | ||
| 1168 | Q 594 497 594 1153 | ||
| 1169 | L 594 3053 | ||
| 1170 | L 172 3053 | ||
| 1171 | L 172 3500 | ||
| 1172 | L 594 3500 | ||
| 1173 | L 594 4494 | ||
| 1174 | L 1172 4494 | ||
| 1175 | z | ||
| 1176 | " transform="scale(0.015625)"/> | ||
| 1177 | <path id="DejaVuSans-46" d="M 628 4666 | ||
| 1178 | L 3309 4666 | ||
| 1179 | L 3309 4134 | ||
| 1180 | L 1259 4134 | ||
| 1181 | L 1259 2759 | ||
| 1182 | L 3109 2759 | ||
| 1183 | L 3109 2228 | ||
| 1184 | L 1259 2228 | ||
| 1185 | L 1259 0 | ||
| 1186 | L 628 0 | ||
| 1187 | L 628 4666 | ||
| 1188 | z | ||
| 1189 | " transform="scale(0.015625)"/> | ||
| 1190 | <path id="DejaVuSans-41" d="M 2188 4044 | ||
| 1191 | L 1331 1722 | ||
| 1192 | L 3047 1722 | ||
| 1193 | L 2188 4044 | ||
| 1194 | z | ||
| 1195 | M 1831 4666 | ||
| 1196 | L 2547 4666 | ||
| 1197 | L 4325 0 | ||
| 1198 | L 3669 0 | ||
| 1199 | L 3244 1197 | ||
| 1200 | L 1141 1197 | ||
| 1201 | L 716 0 | ||
| 1202 | L 50 0 | ||
| 1203 | L 1831 4666 | ||
| 1204 | z | ||
| 1205 | " transform="scale(0.015625)"/> | ||
| 1206 | <path id="DejaVuSans-53" d="M 3425 4513 | ||
| 1207 | L 3425 3897 | ||
| 1208 | Q 3066 4069 2747 4153 | ||
| 1209 | Q 2428 4238 2131 4238 | ||
| 1210 | Q 1616 4238 1336 4038 | ||
| 1211 | Q 1056 3838 1056 3469 | ||
| 1212 | Q 1056 3159 1242 3001 | ||
| 1213 | Q 1428 2844 1947 2747 | ||
| 1214 | L 2328 2669 | ||
| 1215 | Q 3034 2534 3370 2195 | ||
| 1216 | Q 3706 1856 3706 1288 | ||
| 1217 | Q 3706 609 3251 259 | ||
| 1218 | Q 2797 -91 1919 -91 | ||
| 1219 | Q 1588 -91 1214 -16 | ||
| 1220 | Q 841 59 441 206 | ||
| 1221 | L 441 856 | ||
| 1222 | Q 825 641 1194 531 | ||
| 1223 | Q 1563 422 1919 422 | ||
| 1224 | Q 2459 422 2753 634 | ||
| 1225 | Q 3047 847 3047 1241 | ||
| 1226 | Q 3047 1584 2836 1778 | ||
| 1227 | Q 2625 1972 2144 2069 | ||
| 1228 | L 1759 2144 | ||
| 1229 | Q 1053 2284 737 2584 | ||
| 1230 | Q 422 2884 422 3419 | ||
| 1231 | Q 422 4038 858 4394 | ||
| 1232 | Q 1294 4750 2059 4750 | ||
| 1233 | Q 2388 4750 2728 4690 | ||
| 1234 | Q 3069 4631 3425 4513 | ||
| 1235 | z | ||
| 1236 | " transform="scale(0.015625)"/> | ||
| 1237 | <path id="DejaVuSans-54" d="M -19 4666 | ||
| 1238 | L 3928 4666 | ||
| 1239 | L 3928 4134 | ||
| 1240 | L 2272 4134 | ||
| 1241 | L 2272 0 | ||
| 1242 | L 1638 0 | ||
| 1243 | L 1638 4134 | ||
| 1244 | L -19 4134 | ||
| 1245 | L -19 4666 | ||
| 1246 | z | ||
| 1247 | " transform="scale(0.015625)"/> | ||
| 1248 | <path id="DejaVuSans-73" d="M 2834 3397 | ||
| 1249 | L 2834 2853 | ||
| 1250 | Q 2591 2978 2328 3040 | ||
| 1251 | Q 2066 3103 1784 3103 | ||
| 1252 | Q 1356 3103 1142 2972 | ||
| 1253 | Q 928 2841 928 2578 | ||
| 1254 | Q 928 2378 1081 2264 | ||
| 1255 | Q 1234 2150 1697 2047 | ||
| 1256 | L 1894 2003 | ||
| 1257 | Q 2506 1872 2764 1633 | ||
| 1258 | Q 3022 1394 3022 966 | ||
| 1259 | Q 3022 478 2636 193 | ||
| 1260 | Q 2250 -91 1575 -91 | ||
| 1261 | Q 1294 -91 989 -36 | ||
| 1262 | Q 684 19 347 128 | ||
| 1263 | L 347 722 | ||
| 1264 | Q 666 556 975 473 | ||
| 1265 | Q 1284 391 1588 391 | ||
| 1266 | Q 1994 391 2212 530 | ||
| 1267 | Q 2431 669 2431 922 | ||
| 1268 | Q 2431 1156 2273 1281 | ||
| 1269 | Q 2116 1406 1581 1522 | ||
| 1270 | L 1381 1569 | ||
| 1271 | Q 847 1681 609 1914 | ||
| 1272 | Q 372 2147 372 2553 | ||
| 1273 | Q 372 3047 722 3315 | ||
| 1274 | Q 1072 3584 1716 3584 | ||
| 1275 | Q 2034 3584 2315 3537 | ||
| 1276 | Q 2597 3491 2834 3397 | ||
| 1277 | z | ||
| 1278 | " transform="scale(0.015625)"/> | ||
| 1279 | <path id="DejaVuSans-70" d="M 1159 525 | ||
| 1280 | L 1159 -1331 | ||
| 1281 | L 581 -1331 | ||
| 1282 | L 581 3500 | ||
| 1283 | L 1159 3500 | ||
| 1284 | L 1159 2969 | ||
| 1285 | Q 1341 3281 1617 3432 | ||
| 1286 | Q 1894 3584 2278 3584 | ||
| 1287 | Q 2916 3584 3314 3078 | ||
| 1288 | Q 3713 2572 3713 1747 | ||
| 1289 | Q 3713 922 3314 415 | ||
| 1290 | Q 2916 -91 2278 -91 | ||
| 1291 | Q 1894 -91 1617 61 | ||
| 1292 | Q 1341 213 1159 525 | ||
| 1293 | z | ||
| 1294 | M 3116 1747 | ||
| 1295 | Q 3116 2381 2855 2742 | ||
| 1296 | Q 2594 3103 2138 3103 | ||
| 1297 | Q 1681 3103 1420 2742 | ||
| 1298 | Q 1159 2381 1159 1747 | ||
| 1299 | Q 1159 1113 1420 752 | ||
| 1300 | Q 1681 391 2138 391 | ||
| 1301 | Q 2594 391 2855 752 | ||
| 1302 | Q 3116 1113 3116 1747 | ||
| 1303 | z | ||
| 1304 | " transform="scale(0.015625)"/> | ||
| 1305 | <path id="DejaVuSans-76" d="M 191 3500 | ||
| 1306 | L 800 3500 | ||
| 1307 | L 1894 563 | ||
| 1308 | L 2988 3500 | ||
| 1309 | L 3597 3500 | ||
| 1310 | L 2284 0 | ||
| 1311 | L 1503 0 | ||
| 1312 | L 191 3500 | ||
| 1313 | z | ||
| 1314 | " transform="scale(0.015625)"/> | ||
| 1315 | <path id="DejaVuSans-72" d="M 2631 2963 | ||
| 1316 | Q 2534 3019 2420 3045 | ||
| 1317 | Q 2306 3072 2169 3072 | ||
| 1318 | Q 1681 3072 1420 2755 | ||
| 1319 | Q 1159 2438 1159 1844 | ||
| 1320 | L 1159 0 | ||
| 1321 | L 581 0 | ||
| 1322 | L 581 3500 | ||
| 1323 | L 1159 3500 | ||
| 1324 | L 1159 2956 | ||
| 1325 | Q 1341 3275 1631 3429 | ||
| 1326 | Q 1922 3584 2338 3584 | ||
| 1327 | Q 2397 3584 2469 3576 | ||
| 1328 | Q 2541 3569 2628 3553 | ||
| 1329 | L 2631 2963 | ||
| 1330 | z | ||
| 1331 | " transform="scale(0.015625)"/> | ||
| 1332 | <path id="DejaVuSans-69" d="M 603 3500 | ||
| 1333 | L 1178 3500 | ||
| 1334 | L 1178 0 | ||
| 1335 | L 603 0 | ||
| 1336 | L 603 3500 | ||
| 1337 | z | ||
| 1338 | M 603 4863 | ||
| 1339 | L 1178 4863 | ||
| 1340 | L 1178 4134 | ||
| 1341 | L 603 4134 | ||
| 1342 | L 603 4863 | ||
| 1343 | z | ||
| 1344 | " transform="scale(0.015625)"/> | ||
| 1345 | <path id="DejaVuSans-6d" d="M 3328 2828 | ||
| 1346 | Q 3544 3216 3844 3400 | ||
| 1347 | Q 4144 3584 4550 3584 | ||
| 1348 | Q 5097 3584 5394 3201 | ||
| 1349 | Q 5691 2819 5691 2113 | ||
| 1350 | L 5691 0 | ||
| 1351 | L 5113 0 | ||
| 1352 | L 5113 2094 | ||
| 1353 | Q 5113 2597 4934 2840 | ||
| 1354 | Q 4756 3084 4391 3084 | ||
| 1355 | Q 3944 3084 3684 2787 | ||
| 1356 | Q 3425 2491 3425 1978 | ||
| 1357 | L 3425 0 | ||
| 1358 | L 2847 0 | ||
| 1359 | L 2847 2094 | ||
| 1360 | Q 2847 2600 2669 2842 | ||
| 1361 | Q 2491 3084 2119 3084 | ||
| 1362 | Q 1678 3084 1418 2786 | ||
| 1363 | Q 1159 2488 1159 1978 | ||
| 1364 | L 1159 0 | ||
| 1365 | L 581 0 | ||
| 1366 | L 581 3500 | ||
| 1367 | L 1159 3500 | ||
| 1368 | L 1159 2956 | ||
| 1369 | Q 1356 3278 1631 3431 | ||
| 1370 | Q 1906 3584 2284 3584 | ||
| 1371 | Q 2666 3584 2933 3390 | ||
| 1372 | Q 3200 3197 3328 2828 | ||
| 1373 | z | ||
| 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 @@ | |||
| 1 | GGTCAGCCCAAATCCGCACCCTCGGTCACCCTGTTTCCGCCCTCCACGGAGGAGCTCACT | ||
| 2 | GCCAACAAGGCCACCCTGGTGTGTCTCATCAGCGACTTCTACCCGGGTAGCGTGACCGTG | ||
| 3 | GCCTGGAAGGCAGACGGCAGCACCATCACCCGCAACGTGGAGACCACCCGGGCCTCCAAA | ||
| 4 | CAGAGCAACAGCAAGTACGCGAAAAGCGGTTACAGCTGCGAGGTCACGCACGAGGGGAGC | ||
| 5 | ACCGTGACGAAGACAGTGAAGCCCTCAGCGTGTCAGCCCAAGTCCGCACCCTTGGTCACC | ||
| 6 | CTGTTCCCGCCCTCCAAGGAGGAGCTCAGCGCCAACAAGGCCACCCTGGTGTGTCTCATC | ||
| 7 | AGCGACTTCTACCCGGGTAGCGTGACCGTGGTCTGGAAGGCAGACGGCAGCACCATCACC | ||
| 8 | CGCAACGTGGAGACCACCCGGGCCTCCAAACAGAGCAACAGCAAGTACGCGGCCAGCAGC | ||
| 9 | TACCTGAGCCTGACGGGCAGCGACTGGAAATCGAAAGGCAGTTACAGCTGCGAGGTCACG | ||
| 10 | CACGAGGGGAGCACCGTGACGAAGACAGTGAAGGTCTCAGAGTGTCAGCCCAAGTCCGCA | ||
| 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 @@ | |||
| 1 | GAATTCTCAGGGCCTGTGATGGTCTATACTGCATGGCATATCAGTGTAGAGAAAATAAAT | ||
| 2 | AGACACAAGCTCCAATCCCAAACCCAGAAACTATTAATAACAAACGAAAAATTAGTTCTC | ||
| 3 | TCAAATGAAGTCTCCCTGAGGATACAGATCCCATTCAGATGGGCAGGTCTGCAGGCCAAC | ||
| 4 | ACAAAATGAACTCAGGGGCCTCTTTGGAGGTCTTAGGTCTCATAATGTTTTGTCAGGCCT | ||
| 5 | TTTATCTTTTTTTTTTTTTTTTTTTTTTTTTTTTTTGCTTATTTATCTTAAAACCCACTA | ||
| 6 | GCTGTTCTCTCCAGGGTCACACCCTAGCACACTCCGTCTAGGTGCCTTCTTACCATCTCC | ||
| 7 | TCTAAGTGAGTGGAGGCTCCCTGTGTATTTCCACACCCTTGTACTTTAAGTATTTTCAAG | ||
| 8 | GCAGGGCATATCCTCTCTCACTGAGTCCAGACAAAGCAGCTCAAATAGAAGAACATGTCC | ||
| 9 | CACATACAGGCAACAGATTTTGAAGGAGGCCTCCACTCCAGCTGTTAGGGGACCCACATG | ||
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 @@ | |||
| 1 | GACAGCTTGTGTACAAGTGTGCTTGCTCGCGAGCGGGTACGCGCGTGGGCTAACAAGTGA | ||
| 2 | GCCAGCAGGTGAACAAGTGTGCGGACAAGCCAGCAGGTGCGCGGACAAGCTGGCGGGTGA | ||
| 3 | ACAAGTGTGCCGGTGAGCCAACAAGCAGACAAGTAAGCAGGTACGCAGGCGAGCTTGTCA | ||
| 4 | ACTCACAAGATCGCTTGTGTACAAGTGTGCGGACAAGCCAGCAGGTGCGCGGACAAGTAT | ||
| 5 | GCTTGCTGGCGGACAAGCCAGCTTGTAAGCGGACAAGCTTGCGCACAAGCTGGCAGGCCT | ||
| 6 | GCCGGCTCGCGTACAAATTCACAAGTAAGTACGCTTGCGTGTACGCGGGTATGTATACTC | ||
| 7 | AACCTCACCAAACGGGACAAGATCGCCGGCGGGCTAGTATACAAGAACGCTTGCCAGTAC | ||
| 8 | AACC \ 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 @@ | |||
| 1 | GGTCAGCCCAAGTCCCCACCCTCGGTCACCCTGTTCCCGCCCTCCAAGGAGGAGCTCAGC | ||
| 2 | GCCAACAAGGCCACCCTGGTGTGTCTCATCAGCGACTTCTACCCGGGTAGCGTGACCGTG | ||
| 3 | GCCTGGAAGGCAGACGGCAGCACCATCACCCGCAACGTGGAGACCACCCGGGCCTCCAAA | ||
| 4 | CAGAGCAACAGCAAGTACGCGGCCAGCAGCTACCTGAGCCTGACGAGCAGCGACTGGAAA | ||
| 5 | TCGAAAGGCAGTTACAGCTGCGAGGTCACGCACGAGGGGAGCACCGTGACGAAGACAGTG | ||
| 6 | AAGACCTCAGCGTGTCAGCCCAAGTCCCCACCCTCGGTCACCCTGTTCCCGCCCTCCACG | ||
| 7 | GAGGAGCTCAACGGCAACAAGGCCACCCTGGTGTGTCTCATCAGCGACTTCTACCCGGGT | ||
| 8 | AGCGTGACCGTGGTCTGGAAGGCAGACGGCAGCACCATCACCCGCAACGTGGAGACCACC | ||
| 9 | CGGGCCTCCAAACAGAGCAACAGCAAGTACGCGGCCAGCAGCTACCTGAGCCTGACGAGC | ||
| 10 | AGCGACTGGAAATCGAAAGGCAGTTACAGCTGCGAGGTCACGCACGAGGGGAGCACCGTG | ||
| 11 | ACGAAGACAGTGAAGCCCTCAGAGTGGCCCTGGGCCCCCACCGCCGTCCCCACCCTCGTC | ||
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 @@ | |||
| 1 | 10KB 100KB 1MB 10MB | ||
| 2 | 0.15 0.187 0.317 0.653 | ||
| 3 | 0.158 0.237 0.192 0.659 | ||
| 4 | 0.134 0.359 0.236 0.604 | ||
| 5 | 0.136 0.292 0.196 0.501 | ||
| 6 | 4.411 4.479 4.376 0.649 | ||
| 7 | 0.134 0.481 0.265 0.608 | ||
| 8 | 0.146 0.266 0.28 0.516 | ||
| 9 | 4.282 0.307 4.549 0.562 | ||
| 10 | 0.152 0.28 0.229 0.512 | ||
| 11 | 0.162 0.37 0.315 0.652 | ||
| 12 | 0.13 4.735 0.222 5.171 | ||
| 13 | 4.29 8.767 0.283 5.076 | ||
| 14 | 4.555 4.682 0.318 4.941 | ||
| 15 | 4.658 4.691 0.177 9.624 | ||
| 16 | 4.778 4.791 4.415 5.114 | ||
| 17 | 8.794 8.604 0.311 5.223 | ||
| 18 | 4.582 4.727 0.234 9.28 | ||
| 19 | 4.596 4.638 0.212 5.064 | ||
| 20 | 4.7 4.65 4.458 5.221 | ||
| 21 | 8.822 9.159 0.191 5.032 | ||
| 22 | 4.628 4.641 0.324 9.226 | ||
| 23 | 4.6 4.921 0.197 5.22 | ||
| 24 | 8.85 4.58 4.405 5.245 | ||
| 25 | 4.65 9.142 0.215 5.168 | ||
| 26 | 4.884 6.67 0.248 9.273 | ||
| 27 | 4.581 4.594 0.248 5.082 | ||
| 28 | 8.864 4.844 4.502 5.121 | ||
| 29 | 4.704 4.656 0.177 5.173 | ||
| 30 | 4.616 8.883 0.209 9.334 | ||
| 31 | 4.729 4.962 4.366 4.966 | ||
| 32 | 8.918 4.682 0.186 6.702 | ||
| 33 | 4.686 4.58 0.168 5.111 | ||
| 34 | 5.123 8.84 4.747 5.084 | ||
| 35 | 4.846 4.732 8.85 5.065 | ||
| 36 | 8.887 4.639 4.824 9.286 | ||
| 37 | 4.681 8.897 4.791 5.104 | ||
| 38 | 4.649 4.682 4.835 5.194 | ||
| 39 | 8.847 4.663 8.929 5.271 | ||
| 40 | 4.568 4.604 4.762 9.444 | ||
| 41 | 4.657 8.74 4.772 5.076 | ||
| 42 | 4.636 4.724 4.838 5.168 | ||
| 43 | 8.778 4.846 9.065 5.057 | ||
| 44 | 4.995 4.571 5.074 9.314 | ||
| 45 | 2.343 9.222 4.818 5.732 | ||
| 46 | 4.742 4.646 8.909 5.32 | ||
| 47 | 4.82 4.842 4.778 5.167 | ||
| 48 | 8.791 4.66 4.759 5.157 | ||
| 49 | 4.835 8.944 4.804 9.323 | ||
| 50 | 4.599 5.594 8.952 5.299 | ||
| 51 | 4.809 4.628 1.567 5.294 | ||
| 52 | 8.744 4.771 5.59 5.018 | ||
| 53 | 4.71 8.919 4.771 9.257 | ||
| 54 | 4.704 4.7 9.003 5.064 | ||
| 55 | 4.765 4.605 4.781 5.185 | ||
| 56 | 8.866 4.669 4.844 5.392 | ||
| 57 | 4.897 8.925 4.786 9.279 | ||
| 58 | 4.568 5.168 8.893 5.1 | ||
| 59 | 4.679 4.757 5.41 5.232 | ||
| 60 | 8.922 4.702 4.7 1.984 | ||
| 61 | 4.669 8.721 4.906 5.366 | ||
| 62 | 4.707 4.555 8.96 5.245 | ||
| 63 | 8.938 4.615 4.89 5.216 | ||
| 64 | 4.608 4.621 4.677 9.237 | ||
| 65 | 4.58 8.954 4.908 5.194 | ||
| 66 | 4.707 4.575 8.968 5.017 | ||
| 67 | 8.822 4.781 4.882 9.714 | ||
| 68 | 4.674 8.833 4.834 5.02 | ||
| 69 | 5.005 4.689 4.762 5.312 | ||
| 70 | 4.732 4.799 9.111 5.286 | ||
| 71 | 8.894 4.675 4.936 5.185 | ||
| 72 | 4.747 8.764 4.739 9.312 | ||
| 73 | 4.785 4.749 4.845 5.34 | ||
| 74 | 4.656 4.705 9.181 5.256 | ||
| 75 | 8.899 4.601 4.739 5.261 | ||
| 76 | 4.594 8.813 4.576 9.329 | ||
| 77 | 4.585 4.716 8.813 5.343 | ||
| 78 | 8.718 4.723 4.819 5.092 | ||
| 79 | 4.725 4.757 4.83 5.061 | ||
| 80 | 4.737 8.899 4.772 9.488 | ||
| 81 | 4.692 4.717 8.831 5.13 | ||
| 82 | 8.841 4.951 4.787 5.309 | ||
| 83 | 4.66 8.895 4.746 5.228 | ||
| 84 | 4.749 4.595 4.833 5.26 | ||
| 85 | 4.715 4.615 8.928 9.381 | ||
| 86 | 8.849 4.651 4.826 5.289 | ||
| 87 | 4.66 8.897 4.802 5.197 | ||
| 88 | 4.588 4.844 4.883 9.311 | ||
| 89 | 4.753 4.888 9.053 5.072 | ||
| 90 | 8.841 4.737 4.75 5.157 | ||
| 91 | 4.794 8.976 5.063 5.196 | ||
| 92 | 4.544 4.673 9.036 9.335 | ||
| 93 | 8.74 4.654 6.377 5.29 | ||
| 94 | 4.729 4.752 5.001 5.048 | ||
| 95 | 4.654 8.98 4.873 5.544 | ||
| 96 | 4.9 4.606 4.723 5.192 | ||
| 97 | 8.757 4.802 5.427 9.056 | ||
| 98 | 4.859 8.969 4.816 5.3 | ||
| 99 | 4.701 4.662 9.002 5.138 | ||
| 100 | 4.943 4.813 4.894 5.15 | ||
| 101 | 8.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 @@ | |||
| 1 | DROPTABLE CREATETABLE INSERTMANY FETCHALL COMMIT | ||
| 2 | 0.000732 0.000400 0.008133 0.000065 0.000166 | ||
| 3 | 0.000200 0.000214 0.003105 0.000043 0.000171 | ||
| 4 | 0.000246 0.000170 0.006594 0.000044 0.000101 | ||
| 5 | 0.000182 0.000166 0.003892 0.000043 0.000112 | ||
| 6 | 0.000248 0.000654 0.002308 0.000041 0.000090 | ||
| 7 | 0.000240 0.000184 0.002253 0.000053 0.000110 | ||
| 8 | 0.000698 0.000483 0.003737 0.000041 0.000165 | ||
| 9 | 0.000217 0.000179 0.002470 0.000049 0.000107 | ||
| 10 | 0.000243 0.000160 0.002668 0.000054 0.000340 | ||
| 11 | 0.000196 0.000169 0.002247 0.000040 0.000096 | ||
| 12 | 0.000191 0.000162 0.003522 0.000260 0.000102 | ||
| 13 | 0.000195 0.000188 0.002325 0.000041 0.000132 | ||
| 14 | 0.000194 0.000202 0.002291 0.000039 0.000091 | ||
| 15 | 0.000195 0.000196 0.004114 0.000042 0.000108 | ||
| 16 | 0.000204 0.000200 0.002971 0.000040 0.000106 | ||
| 17 | 0.000227 0.000159 0.002208 0.000039 0.000117 | ||
| 18 | 0.000207 0.000176 0.003558 0.000040 0.000124 | ||
| 19 | 0.000255 0.000179 0.002870 0.000040 0.000125 | ||
| 20 | 0.000209 0.000176 0.002248 0.000040 0.000176 | ||
| 21 | 0.000211 0.000174 0.002661 0.000039 0.000180 | ||
| 22 | 0.000208 0.000219 0.002321 0.000039 0.000151 | ||
| 23 | 0.000212 0.000178 0.002609 0.000040 0.000132 | ||
| 24 | 0.000205 0.000209 0.002666 0.000039 0.000126 | ||
| 25 | 0.000205 0.000176 0.002501 0.000041 0.000133 | ||
| 26 | 0.000243 0.000183 0.002220 0.000037 0.000117 | ||
| 27 | 0.000504 0.000173 0.002230 0.000121 0.000414 | ||
| 28 | 0.000270 0.000200 0.002325 0.000040 0.000154 | ||
| 29 | 0.000208 0.000176 0.002386 0.000038 0.000123 | ||
| 30 | 0.000229 0.000182 0.002245 0.000039 0.000127 | ||
| 31 | 0.000211 0.000176 0.002544 0.000039 0.000136 | ||
| 32 | 0.000204 0.000180 0.002133 0.000037 0.000129 | ||
| 33 | 0.000205 0.000178 0.002330 0.000048 0.000146 | ||
| 34 | 0.000210 0.000178 0.002242 0.000039 0.000109 | ||
| 35 | 0.000210 0.000259 0.002766 0.000039 0.000118 | ||
| 36 | 0.000317 0.000495 0.002237 0.000039 0.000195 | ||
| 37 | 0.000454 0.000246 0.002447 0.000040 0.000172 | ||
| 38 | 0.000936 0.000200 0.002305 0.000057 0.000173 | ||
| 39 | 0.000263 0.000178 0.002251 0.000038 0.000166 | ||
| 40 | 0.000240 0.000183 0.002169 0.000068 0.000176 | ||
| 41 | 0.000251 0.000189 0.002221 0.000038 0.000141 | ||
| 42 | 0.000268 0.000215 0.002322 0.000039 0.000226 | ||
| 43 | 0.000287 0.000223 0.002696 0.000045 0.000247 | ||
| 44 | 0.000362 0.000229 0.002551 0.000043 0.000133 | ||
| 45 | 0.000239 0.000200 0.002621 0.000045 0.000133 | ||
| 46 | 0.000634 0.000208 0.002619 0.000046 0.000138 | ||
| 47 | 0.000236 0.000205 0.002589 0.000046 0.000137 | ||
| 48 | 0.000262 0.000205 0.002607 0.000045 0.000142 | ||
| 49 | 0.000239 0.000198 0.002754 0.000044 0.000185 | ||
| 50 | 0.000238 0.000198 0.002593 0.000057 0.000160 | ||
| 51 | 0.000242 0.000221 0.003784 0.000122 0.000174 | ||
| 52 | 0.000242 0.000201 0.002625 0.000054 0.000148 | ||
| 53 | 0.000296 0.000225 0.002934 0.000044 0.000134 | ||
| 54 | 0.000239 0.000245 0.003428 0.000046 0.000158 | ||
| 55 | 0.000261 0.000251 0.002569 0.000046 0.000139 | ||
| 56 | 0.000260 0.000230 0.002603 0.000045 0.000145 | ||
| 57 | 0.000302 0.000212 0.002580 0.000045 0.000176 | ||
| 58 | 0.000794 0.000197 0.002856 0.000046 0.000141 | ||
| 59 | 0.000273 0.000209 0.003173 0.000045 0.000217 | ||
| 60 | 0.000240 0.000201 0.002844 0.000043 0.000167 | ||
| 61 | 0.000389 0.000175 0.004315 0.000055 0.000091 | ||
| 62 | 0.000275 0.000534 0.004991 0.000053 0.000092 | ||
| 63 | 0.000229 0.000215 0.004084 0.000045 0.000074 | ||
| 64 | 0.000172 0.000474 0.002611 0.000043 0.000069 | ||
| 65 | 0.000201 0.000174 0.002485 0.000043 0.000069 | ||
| 66 | 0.000173 0.000220 0.002541 0.000045 0.000068 | ||
| 67 | 0.000167 0.000161 0.002827 0.000043 0.000071 | ||
| 68 | 0.000168 0.000160 0.003512 0.000068 0.000075 | ||
| 69 | 0.000211 0.000167 0.002530 0.000044 0.000069 | ||
| 70 | 0.000193 0.000230 0.003664 0.000046 0.000074 | ||
| 71 | 0.000171 0.000161 0.002575 0.000076 0.000075 | ||
| 72 | 0.000169 0.000161 0.002595 0.000044 0.000076 | ||
| 73 | 0.000981 0.000174 0.002556 0.000045 0.000072 | ||
| 74 | 0.000168 0.000163 0.002568 0.000043 0.000072 | ||
| 75 | 0.000163 0.000158 0.002579 0.000043 0.000386 | ||
| 76 | 0.000168 0.000160 0.002579 0.000059 0.000088 | ||
| 77 | 0.000176 0.000163 0.002559 0.000044 0.000075 | ||
| 78 | 0.000167 0.000161 0.002558 0.000043 0.000075 | ||
| 79 | 0.000169 0.000161 0.002599 0.000043 0.000095 | ||
| 80 | 0.000174 0.000163 0.002633 0.000046 0.000076 | ||
| 81 | 0.000170 0.000165 0.002576 0.000858 0.000079 | ||
| 82 | 0.000169 0.000162 0.002611 0.000044 0.000075 | ||
| 83 | 0.000170 0.000199 0.002621 0.000043 0.000074 | ||
| 84 | 0.000170 0.000167 0.003611 0.000043 0.000073 | ||
| 85 | 0.000171 0.000159 0.002764 0.000046 0.000076 | ||
| 86 | 0.000171 0.000165 0.002639 0.000044 0.000073 | ||
| 87 | 0.000168 0.000162 0.003131 0.000046 0.000075 | ||
| 88 | 0.000170 0.000162 0.002858 0.000044 0.000074 | ||
| 89 | 0.000171 0.000164 0.002841 0.000043 0.000075 | ||
| 90 | 0.000167 0.000161 0.002971 0.000043 0.000074 | ||
| 91 | 0.000170 0.000226 0.002842 0.000044 0.000074 | ||
| 92 | 0.000171 0.000165 0.002822 0.000044 0.000075 | ||
| 93 | 0.000173 0.000160 0.002895 0.000045 0.000073 | ||
| 94 | 0.000167 0.000217 0.002697 0.000044 0.000076 | ||
| 95 | 0.000170 0.000197 0.002699 0.000044 0.000075 | ||
| 96 | 0.000171 0.000163 0.003230 0.000045 0.000097 | ||
| 97 | 0.000170 0.000164 0.003167 0.000046 0.000082 | ||
| 98 | 0.000172 0.000196 0.002559 0.000043 0.000075 | ||
| 99 | 0.000168 0.000165 0.003006 0.000045 0.000075 | ||
| 100 | 0.000176 0.000160 0.002567 0.000043 0.000075 | ||
| 101 | 0.000167 0.000163 0.002757 0.000045 0.000076 | ||
| 102 | 0.000171 0.000162 0.002802 0.000045 0.000076 | ||
| 103 | 0.000169 0.000162 0.003102 0.000043 0.000072 | ||
| 104 | 0.000167 0.000162 0.002624 0.000043 0.000075 | ||
| 105 | 0.000170 0.000161 0.002589 0.000043 0.000072 | ||
| 106 | 0.000222 0.000253 0.002657 0.000045 0.000075 | ||
| 107 | 0.000172 0.000162 0.002586 0.000044 0.000084 | ||
| 108 | 0.000172 0.000165 0.002933 0.000044 0.000075 | ||
| 109 | 0.000169 0.000192 0.002609 0.000044 0.000074 | ||
| 110 | 0.000194 0.000162 0.003020 0.000045 0.000081 | ||
| 111 | 0.000170 0.000164 0.002908 0.000045 0.000076 | ||
| 112 | 0.000169 0.000163 0.002567 0.000042 0.000073 | ||
| 113 | 0.000167 0.000159 0.003071 0.000042 0.000074 | ||
| 114 | 0.000222 0.000163 0.003175 0.000043 0.000076 | ||
| 115 | 0.000167 0.000160 0.002641 0.000046 0.000099 | ||
| 116 | 0.000171 0.000168 0.002586 0.000057 0.000075 | ||
| 117 | 0.000170 0.000168 0.003148 0.000046 0.000075 | ||
| 118 | 0.000171 0.000159 0.002770 0.000041 0.000074 | ||
| 119 | 0.000173 0.000158 0.002643 0.000055 0.000077 | ||
| 120 | 0.000313 0.000174 0.002920 0.000045 0.000075 | ||
| 121 | 0.000170 0.000163 0.002551 0.000044 0.000072 | ||
| 122 | 0.000173 0.000161 0.002599 0.000045 0.000073 | ||
| 123 | 0.000167 0.000160 0.003505 0.000046 0.000075 | ||
| 124 | 0.000171 0.000161 0.002894 0.000045 0.000074 | ||
| 125 | 0.000171 0.000166 0.002572 0.000042 0.000073 | ||
| 126 | 0.000166 0.000160 0.004099 0.000044 0.000102 | ||
| 127 | 0.000181 0.000160 0.002499 0.000046 0.000071 | ||
| 128 | 0.000174 0.000175 0.002560 0.000043 0.000068 | ||
| 129 | 0.000165 0.000168 0.003083 0.000044 0.000070 | ||
| 130 | 0.000210 0.000163 0.002535 0.000040 0.000068 | ||
| 131 | 0.000164 0.000177 0.002906 0.000044 0.000075 | ||
| 132 | 0.000175 0.000227 0.002971 0.000043 0.000073 | ||
| 133 | 0.000167 0.000175 0.003409 0.000046 0.000078 | ||
| 134 | 0.000172 0.000166 0.002640 0.000046 0.000074 | ||
| 135 | 0.000177 0.000164 0.002574 0.000046 0.000076 | ||
| 136 | 0.000170 0.000163 0.002631 0.000046 0.000075 | ||
| 137 | 0.000216 0.000168 0.002596 0.000046 0.000076 | ||
| 138 | 0.000170 0.000163 0.002659 0.000045 0.000074 | ||
| 139 | 0.000172 0.000162 0.002677 0.000046 0.000075 | ||
| 140 | 0.000170 0.000159 0.002604 0.000044 0.000081 | ||
| 141 | 0.000171 0.000161 0.003163 0.000046 0.000076 | ||
| 142 | 0.000171 0.000162 0.002574 0.000313 0.000075 | ||
| 143 | 0.000170 0.000186 0.002988 0.000046 0.000074 | ||
| 144 | 0.000171 0.000162 0.002596 0.000043 0.000077 | ||
| 145 | 0.000168 0.000160 0.002640 0.000055 0.000074 | ||
| 146 | 0.000169 0.000161 0.002567 0.000043 0.000371 | ||
| 147 | 0.000170 0.000162 0.002704 0.000057 0.000078 | ||
| 148 | 0.000255 0.000185 0.002453 0.000293 0.000066 | ||
| 149 | 0.000148 0.000143 0.002169 0.000037 0.000066 | ||
| 150 | 0.000173 0.000141 0.002238 0.000039 0.000085 | ||
| 151 | 0.000154 0.000174 0.002679 0.000041 0.000065 | ||
| 152 | 0.000149 0.000144 0.002187 0.000037 0.000065 | ||
| 153 | 0.000146 0.000140 0.002760 0.000039 0.000071 | ||
| 154 | 0.000147 0.000151 0.002193 0.000039 0.000065 | ||
| 155 | 0.000150 0.000172 0.002207 0.000039 0.000067 | ||
| 156 | 0.000147 0.000141 0.002126 0.000037 0.000060 | ||
| 157 | 0.000191 0.000141 0.002119 0.000036 0.000086 | ||
| 158 | 0.000149 0.000144 0.002440 0.000039 0.000065 | ||
| 159 | 0.000148 0.000143 0.003287 0.000041 0.000068 | ||
| 160 | 0.000152 0.000149 0.002555 0.000040 0.000069 | ||
| 161 | 0.000148 0.000141 0.002203 0.000038 0.000065 | ||
| 162 | 0.000147 0.000139 0.002371 0.000052 0.000075 | ||
| 163 | 0.000148 0.000143 0.002201 0.000037 0.000066 | ||
| 164 | 0.000149 0.000140 0.002186 0.000038 0.000062 | ||
| 165 | 0.000152 0.000154 0.002215 0.000038 0.000062 | ||
| 166 | 0.000149 0.000144 0.002505 0.000039 0.000067 | ||
| 167 | 0.000148 0.000140 0.002216 0.000038 0.000101 | ||
| 168 | 0.000160 0.000144 0.002574 0.000039 0.000067 | ||
| 169 | 0.000150 0.000144 0.002266 0.000040 0.000068 | ||
| 170 | 0.000151 0.000142 0.003640 0.000040 0.000068 | ||
| 171 | 0.000150 0.000142 0.002207 0.000038 0.000066 | ||
| 172 | 0.000148 0.000140 0.002337 0.000041 0.000068 | ||
| 173 | 0.000151 0.000144 0.002138 0.000038 0.000063 | ||
| 174 | 0.000146 0.000178 0.002369 0.000039 0.000060 | ||
| 175 | 0.000150 0.000141 0.002290 0.000039 0.000067 | ||
| 176 | 0.000149 0.000143 0.002569 0.000050 0.000070 | ||
| 177 | 0.000149 0.000143 0.002797 0.000040 0.000068 | ||
| 178 | 0.000149 0.000143 0.002720 0.000039 0.000066 | ||
| 179 | 0.000273 0.000154 0.002255 0.000039 0.000066 | ||
| 180 | 0.000147 0.000141 0.002180 0.000037 0.000065 | ||
| 181 | 0.000884 0.000142 0.002164 0.000036 0.000060 | ||
| 182 | 0.000188 0.000143 0.002248 0.000039 0.000062 | ||
| 183 | 0.000148 0.000142 0.002178 0.000038 0.000064 | ||
| 184 | 0.000151 0.000140 0.002705 0.000038 0.000063 | ||
| 185 | 0.000145 0.000144 0.002588 0.000039 0.000064 | ||
| 186 | 0.000147 0.000142 0.002196 0.000037 0.000064 | ||
| 187 | 0.000147 0.000139 0.002169 0.000035 0.000060 | ||
| 188 | 0.000151 0.000894 0.002267 0.000039 0.000061 | ||
| 189 | 0.000152 0.000145 0.002178 0.000038 0.000061 | ||
| 190 | 0.000185 0.000142 0.002148 0.000036 0.000062 | ||
| 191 | 0.000147 0.000141 0.002845 0.000040 0.000065 | ||
| 192 | 0.000159 0.000178 0.002193 0.000039 0.000063 | ||
| 193 | 0.000145 0.000141 0.002571 0.000039 0.000066 | ||
| 194 | 0.000149 0.000141 0.003380 0.000038 0.000065 | ||
| 195 | 0.000200 0.000149 0.002439 0.000039 0.000066 | ||
| 196 | 0.000152 0.000140 0.002193 0.000037 0.000065 | ||
| 197 | 0.000147 0.000139 0.002239 0.000037 0.000066 | ||
| 198 | 0.000200 0.000143 0.002190 0.000039 0.000066 | ||
| 199 | 0.000147 0.000139 0.002243 0.000038 0.000062 | ||
| 200 | 0.000421 0.000144 0.002229 0.000038 0.000062 | ||
| 201 | 0.000147 0.000149 0.002715 0.000038 0.000063 | ||
| 202 | 0.000151 0.000176 0.002144 0.000036 0.000060 | ||
| 203 | 0.000145 0.000138 0.002184 0.000038 0.000064 | ||
| 204 | 0.000146 0.000207 0.002526 0.000040 0.000067 | ||
| 205 | 0.000163 0.000142 0.002366 0.000038 0.000070 | ||
| 206 | 0.000149 0.000143 0.002143 0.000038 0.000065 | ||
| 207 | 0.000150 0.000142 0.002146 0.000035 0.000059 | ||
| 208 | 0.000162 0.000147 0.002736 0.000038 0.000067 | ||
| 209 | 0.000149 0.000146 0.002383 0.000040 0.000071 | ||
| 210 | 0.000147 0.000139 0.002485 0.000038 0.000065 | ||
| 211 | 0.000147 0.000143 0.002811 0.000039 0.000098 | ||
| 212 | 0.000181 0.000142 0.002503 0.000039 0.000066 | ||
| 213 | 0.000150 0.000143 0.002227 0.000039 0.000065 | ||
| 214 | 0.000149 0.000143 0.002182 0.000036 0.000061 | ||
| 215 | 0.000148 0.000387 0.002159 0.000036 0.000059 | ||
| 216 | 0.000147 0.000173 0.002267 0.000039 0.000063 | ||
| 217 | 0.000147 0.000143 0.002729 0.000039 0.000066 | ||
| 218 | 0.000149 0.000142 0.002574 0.000040 0.000069 | ||
| 219 | 0.000149 0.000143 0.002560 0.000040 0.000068 | ||
| 220 | 0.000152 0.000141 0.002203 0.000038 0.000066 | ||
| 221 | 0.000151 0.000139 0.002234 0.000038 0.000087 | ||
| 222 | 0.000148 0.000140 0.002152 0.000036 0.000060 | ||
| 223 | 0.000185 0.000140 0.002274 0.000039 0.000063 | ||
| 224 | 0.000148 0.000144 0.002211 0.000038 0.000066 | ||
| 225 | 0.000149 0.000141 0.002692 0.000039 0.000066 | ||
| 226 | 0.000148 0.000145 0.002519 0.000039 0.000066 | ||
| 227 | 0.000147 0.000143 0.002188 0.000038 0.000066 | ||
| 228 | 0.000149 0.000171 0.002171 0.000038 0.000093 | ||
| 229 | 0.000150 0.000182 0.002185 0.000038 0.000068 | ||
| 230 | 0.000191 0.000154 0.002172 0.000037 0.000061 | ||
| 231 | 0.000145 0.000140 0.002253 0.000043 0.000065 | ||
| 232 | 0.000147 0.000139 0.002673 0.000038 0.000066 | ||
| 233 | 0.000191 0.000144 0.002740 0.000038 0.000066 | ||
| 234 | 0.000147 0.000142 0.002187 0.000038 0.000064 | ||
| 235 | 0.000146 0.000181 0.002180 0.000038 0.000066 | ||
| 236 | 0.000176 0.000142 0.002152 0.000039 0.000061 | ||
| 237 | 0.000149 0.000142 0.002164 0.000037 0.000064 | ||
| 238 | 0.000245 0.000150 0.002771 0.000055 0.000084 | ||
| 239 | 0.000149 0.000145 0.003006 0.000040 0.000069 | ||
| 240 | 0.000153 0.000144 0.002701 0.000040 0.000067 | ||
| 241 | 0.000149 0.000144 0.002192 0.000038 0.000065 | ||
| 242 | 0.000148 0.000143 0.002220 0.000038 0.000063 | ||
| 243 | 0.000146 0.000140 0.002210 0.000038 0.000062 | ||
| 244 | 0.000157 0.000144 0.002174 0.000038 0.000060 | ||
| 245 | 0.000148 0.000171 0.002208 0.000039 0.000061 | ||
| 246 | 0.000146 0.000141 0.002685 0.000039 0.000064 | ||
| 247 | 0.000146 0.000139 0.002811 0.000038 0.000064 | ||
| 248 | 0.000147 0.000140 0.002234 0.000037 0.000063 | ||
| 249 | 0.000143 0.000143 0.002209 0.000040 0.000066 | ||
| 250 | 0.000149 0.000144 0.002162 0.000037 0.000091 | ||
| 251 | 0.000408 0.000141 0.002140 0.000036 0.000060 | ||
| 252 | 0.000142 0.000149 0.002208 0.000132 0.000061 | ||
| 253 | 0.000148 0.000142 0.002706 0.000040 0.000066 | ||
| 254 | 0.000148 0.000142 0.002502 0.000039 0.000065 | ||
| 255 | 0.000176 0.000144 0.002265 0.000039 0.000066 | ||
| 256 | 0.000150 0.000142 0.002199 0.000039 0.000065 | ||
| 257 | 0.000147 0.000154 0.002201 0.000040 0.000067 | ||
| 258 | 0.000150 0.000142 0.002164 0.000036 0.000094 | ||
| 259 | 0.000183 0.000177 0.002253 0.000039 0.000063 | ||
| 260 | 0.000189 0.000143 0.002480 0.000039 0.000066 | ||
| 261 | 0.000148 0.000141 0.002212 0.000037 0.000064 | ||
| 262 | 0.000150 0.000137 0.002192 0.000037 0.000065 | ||
| 263 | 0.000144 0.000140 0.002271 0.000039 0.000062 | ||
| 264 | 0.000190 0.000171 0.002145 0.000037 0.000061 | ||
| 265 | 0.000146 0.000141 0.005865 0.000099 0.000083 | ||
| 266 | 0.000178 0.000165 0.002792 0.000040 0.000066 | ||
| 267 | 0.000148 0.000233 0.002742 0.000039 0.000079 | ||
| 268 | 0.000157 0.000151 0.002225 0.000039 0.000066 | ||
| 269 | 0.000149 0.000142 0.002215 0.000039 0.000081 | ||
| 270 | 0.000165 0.000141 0.002239 0.000039 0.000081 | ||
| 271 | 0.000150 0.000154 0.002154 0.000036 0.000060 | ||
| 272 | 0.000152 0.000151 0.002216 0.000039 0.000075 | ||
| 273 | 0.000172 0.000141 0.004471 0.000060 0.000092 | ||
| 274 | 0.000250 0.000210 0.002881 0.000040 0.000066 | ||
| 275 | 0.000176 0.000152 0.002262 0.000038 0.000337 | ||
| 276 | 0.000164 0.000154 0.002485 0.000039 0.000074 | ||
| 277 | 0.000149 0.000180 0.002148 0.000039 0.000078 | ||
| 278 | 0.000194 0.000145 0.002345 0.000044 0.000064 | ||
| 279 | 0.000164 0.000201 0.002483 0.000040 0.000062 | ||
| 280 | 0.000148 0.000140 0.002249 0.000038 0.000076 | ||
| 281 | 0.000155 0.000144 0.002504 0.000039 0.000067 | ||
| 282 | 0.000166 0.000150 0.002780 0.000040 0.000079 | ||
| 283 | 0.000150 0.000142 0.002194 0.000038 0.000086 | ||
| 284 | 0.000178 0.000153 0.002360 0.000039 0.000079 | ||
| 285 | 0.000160 0.000154 0.002159 0.000036 0.000079 | ||
| 286 | 0.000195 0.000445 0.002203 0.000038 0.000074 | ||
| 287 | 0.000171 0.000161 0.002220 0.000038 0.000087 | ||
| 288 | 0.000165 0.000151 0.002231 0.000038 0.000088 | ||
| 289 | 0.000149 0.000141 0.003445 0.000040 0.000068 | ||
| 290 | 0.000148 0.000143 0.002465 0.000039 0.000081 | ||
| 291 | 0.000165 0.000150 0.002228 0.000038 0.000067 | ||
| 292 | 0.000160 0.000142 0.003231 0.000039 0.000066 | ||
| 293 | 0.000149 0.000141 0.002215 0.000038 0.000078 | ||
| 294 | 0.000146 0.000152 0.002152 0.000038 0.000077 | ||
| 295 | 0.000168 0.000140 0.002258 0.000040 0.000076 | ||
| 296 | 0.000193 0.000142 0.002266 0.000039 0.000085 | ||
| 297 | 0.000261 0.000164 0.002160 0.000037 0.000061 | ||
| 298 | 0.000151 0.000419 0.002217 0.000037 0.000073 | ||
| 299 | 0.000163 0.000148 0.002856 0.000038 0.000106 | ||
| 300 | 0.000258 0.000204 0.002267 0.000040 0.000075 | ||
| 301 | 0.000178 0.000159 0.002266 0.000038 0.000070 | ||
| 302 | 0.000158 0.000149 0.002665 0.000039 0.000085 | ||
| 303 | 0.000164 0.000154 0.002478 0.000039 0.000077 | ||
| 304 | 0.000148 0.000140 0.002459 0.000038 0.000066 | ||
| 305 | 0.000161 0.000142 0.002206 0.000038 0.000074 | ||
| 306 | 0.000155 0.000151 0.002230 0.000039 0.000083 | ||
| 307 | 0.000161 0.000142 0.002225 0.000037 0.000072 | ||
| 308 | 0.000161 0.000187 0.002450 0.000038 0.000063 | ||
| 309 | 0.000145 0.000155 0.002438 0.000039 0.000079 | ||
| 310 | 0.000166 0.000138 0.002296 0.000039 0.000076 | ||
| 311 | 0.000170 0.000156 0.002446 0.000038 0.000078 | ||
| 312 | 0.000160 0.000159 0.002211 0.000038 0.000078 | ||
| 313 | 0.000159 0.000142 0.002190 0.000036 0.000110 | ||
| 314 | 0.000157 0.000150 0.002336 0.000039 0.000073 | ||
| 315 | 0.000165 0.000182 0.002132 0.000038 0.000072 | ||
| 316 | 0.000160 0.000140 0.002641 0.000066 0.000066 | ||
| 317 | 0.000147 0.000153 0.002153 0.000039 0.000080 | ||
| 318 | 0.000148 0.000156 0.002165 0.000037 0.000077 | ||
| 319 | 0.000147 0.000151 0.002201 0.000038 0.000067 | ||
| 320 | 0.000162 0.000143 0.002216 0.000040 0.000080 | ||
| 321 | 0.000165 0.000148 0.002223 0.000055 0.000080 | ||
| 322 | 0.000193 0.000143 0.002155 0.000037 0.000078 | ||
| 323 | 0.000165 0.000143 0.003005 0.000040 0.000067 | ||
| 324 | 0.000151 0.000145 0.002511 0.000039 0.000070 | ||
| 325 | 0.000149 0.000173 0.002246 0.000039 0.000066 | ||
| 326 | 0.000148 0.000143 0.002808 0.000040 0.000067 | ||
| 327 | 0.000148 0.000142 0.002513 0.000038 0.000066 | ||
| 328 | 0.000148 0.000143 0.002203 0.000037 0.000065 | ||
| 329 | 0.000146 0.000138 0.002123 0.000038 0.000061 | ||
| 330 | 0.000170 0.000149 0.002165 0.000036 0.000062 | ||
| 331 | 0.000144 0.000145 0.002186 0.000037 0.000059 | ||
| 332 | 0.000144 0.000139 0.002520 0.000037 0.000065 | ||
| 333 | 0.000146 0.000139 0.002559 0.000038 0.000066 | ||
| 334 | 0.000153 0.000142 0.002537 0.000038 0.000067 | ||
| 335 | 0.000168 0.000144 0.002217 0.000048 0.000066 | ||
| 336 | 0.000147 0.000141 0.002120 0.000037 0.000063 | ||
| 337 | 0.000188 0.001725 0.002541 0.000040 0.000067 | ||
| 338 | 0.000149 0.000143 0.002229 0.000038 0.000076 | ||
| 339 | 0.000147 0.000143 0.002233 0.000037 0.000062 | ||
| 340 | 0.000182 0.000142 0.002150 0.000037 0.000061 | ||
| 341 | 0.000148 0.000140 0.002196 0.000037 0.000065 | ||
| 342 | 0.000145 0.000140 0.002473 0.000037 0.000065 | ||
| 343 | 0.000147 0.000139 0.002725 0.000040 0.000067 | ||
| 344 | 0.000149 0.000142 0.002217 0.000039 0.000065 | ||
| 345 | 0.000146 0.000140 0.002167 0.000037 0.000061 | ||
| 346 | 0.000176 0.000144 0.002415 0.000039 0.000064 | ||
| 347 | 0.000171 0.000144 0.002925 0.000040 0.000068 | ||
| 348 | 0.000152 0.000167 0.002190 0.000039 0.000066 | ||
| 349 | 0.000149 0.000142 0.002530 0.000039 0.000067 | ||
| 350 | 0.000150 0.000142 0.003059 0.000040 0.000068 | ||
| 351 | 0.000149 0.000142 0.002417 0.000038 0.000072 | ||
| 352 | 0.000149 0.000143 0.002569 0.000038 0.000068 | ||
| 353 | 0.000148 0.000141 0.002262 0.000040 0.000068 | ||
| 354 | 0.000152 0.000144 0.002253 0.000038 0.000066 | ||
| 355 | 0.000149 0.000142 0.002134 0.000037 0.000061 | ||
| 356 | 0.000277 0.000427 0.002186 0.000036 0.000060 | ||
| 357 | 0.000145 0.000139 0.002791 0.000039 0.000065 | ||
| 358 | 0.000149 0.000144 0.002238 0.000039 0.000066 | ||
| 359 | 0.000147 0.000144 0.002514 0.000039 0.000066 | ||
| 360 | 0.000148 0.000143 0.002683 0.000038 0.000063 | ||
| 361 | 0.000147 0.000139 0.002214 0.000037 0.000068 | ||
| 362 | 0.000145 0.000139 0.002149 0.000036 0.000059 | ||
| 363 | 0.000185 0.000139 0.002214 0.000037 0.000060 | ||
| 364 | 0.000145 0.000140 0.003549 0.000039 0.000066 | ||
| 365 | 0.000187 0.000142 0.002160 0.000037 0.000059 | ||
| 366 | 0.000147 0.000158 0.002212 0.000038 0.000065 | ||
| 367 | 0.000148 0.000140 0.002483 0.000039 0.000067 | ||
| 368 | 0.000147 0.000142 0.003034 0.000039 0.000066 | ||
| 369 | 0.000148 0.000142 0.002228 0.000039 0.000066 | ||
| 370 | 0.000145 0.000151 0.002225 0.000040 0.000067 | ||
| 371 | 0.000149 0.000142 0.002858 0.000048 0.000083 | ||
| 372 | 0.000203 0.000185 0.004022 0.000049 0.000086 | ||
| 373 | 0.000212 0.000188 0.005086 0.000056 0.000093 | ||
| 374 | 0.000220 0.000203 0.004209 0.000051 0.000085 | ||
| 375 | 0.000208 0.000247 0.009261 0.000098 0.000089 | ||
| 376 | 0.000211 0.000262 0.002546 0.000041 0.000066 | ||
| 377 | 0.000198 0.000150 0.002534 0.000039 0.000079 | ||
| 378 | 0.000159 0.000143 0.002207 0.000038 0.000094 | ||
| 379 | 0.000157 0.000143 0.002173 0.000038 0.000062 | ||
| 380 | 0.000198 0.000505 0.002157 0.000039 0.000079 | ||
| 381 | 0.000164 0.000143 0.002172 0.000038 0.000076 | ||
| 382 | 0.000156 0.000148 0.002259 0.000039 0.000080 | ||
| 383 | 0.000161 0.000142 0.002219 0.000039 0.000076 | ||
| 384 | 0.000161 0.000143 0.002266 0.000039 0.000085 | ||
| 385 | 0.000161 0.000141 0.002150 0.000036 0.000077 | ||
| 386 | 0.000179 0.000140 0.002140 0.000036 0.000071 | ||
| 387 | 0.000157 0.000151 0.002316 0.000040 0.000079 | ||
| 388 | 0.000149 0.000143 0.002269 0.000039 0.000066 | ||
| 389 | 0.000161 0.000142 0.002206 0.000040 0.000091 | ||
| 390 | 0.000172 0.000143 0.002244 0.000039 0.000067 | ||
| 391 | 0.000168 0.000142 0.002189 0.000039 0.000083 | ||
| 392 | 0.000163 0.000188 0.002156 0.000037 0.000077 | ||
| 393 | 0.000168 0.000143 0.002266 0.000039 0.000084 | ||
| 394 | 0.000166 0.000147 0.002205 0.000325 0.000078 | ||
| 395 | 0.000175 0.000140 0.002173 0.000037 0.000106 | ||
| 396 | 0.000170 0.000153 0.002158 0.000036 0.000083 | ||
| 397 | 0.000168 0.000147 0.002825 0.000039 0.000108 | ||
| 398 | 0.000172 0.000151 0.002483 0.000038 0.000085 | ||
| 399 | 0.000160 0.000143 0.002163 0.000038 0.000066 | ||
| 400 | 0.000161 0.000154 0.002493 0.000039 0.000084 | ||
| 401 | 0.000167 0.000153 0.002564 0.000040 0.000082 | ||
| 402 | 0.000159 0.000151 0.002185 0.000046 0.000088 | ||
| 403 | 0.000157 0.000156 0.002175 0.000039 0.000076 | ||
| 404 | 0.000150 0.000144 0.002151 0.000038 0.000063 | ||
| 405 | 0.000160 0.000140 0.002429 0.000038 0.000064 | ||
| 406 | 0.000160 0.000154 0.002184 0.000048 0.000077 | ||
| 407 | 0.000168 0.000142 0.002686 0.000040 0.000119 | ||
| 408 | 0.000164 0.000152 0.002279 0.000039 0.000075 | ||
| 409 | 0.000161 0.000143 0.002192 0.000068 0.000067 | ||
| 410 | 0.000161 0.000154 0.002190 0.000040 0.000092 | ||
| 411 | 0.000246 0.000146 0.003064 0.000038 0.000072 | ||
| 412 | 0.000163 0.000158 0.002171 0.000037 0.000073 | ||
| 413 | 0.000216 0.000144 0.002209 0.000039 0.000115 | ||
| 414 | 0.000159 0.000141 0.003338 0.000039 0.000079 | ||
| 415 | 0.000277 0.000158 0.002464 0.000039 0.000082 | ||
| 416 | 0.000168 0.000150 0.002227 0.000037 0.000079 | ||
| 417 | 0.000168 0.000146 0.002775 0.000038 0.000077 | ||
| 418 | 0.000146 0.000147 0.002694 0.000042 0.000084 | ||
| 419 | 0.000160 0.000145 0.002807 0.000039 0.000066 | ||
| 420 | 0.000162 0.000177 0.002187 0.000063 0.000066 | ||
| 421 | 0.000147 0.000141 0.002220 0.000038 0.000085 | ||
| 422 | 0.000160 0.000142 0.002216 0.000037 0.000077 | ||
| 423 | 0.000166 0.000159 0.002224 0.000039 0.000108 | ||
| 424 | 0.000147 0.000141 0.002746 0.000039 0.000078 | ||
| 425 | 0.000159 0.000141 0.002194 0.000037 0.000063 | ||
| 426 | 0.000164 0.000143 0.002164 0.000039 0.000067 | ||
| 427 | 0.000169 0.000152 0.002278 0.000074 0.000088 | ||
| 428 | 0.000157 0.000157 0.002155 0.000068 0.000076 | ||
| 429 | 0.000159 0.000140 0.002170 0.000035 0.000078 | ||
| 430 | 0.000156 0.000141 0.002299 0.000040 0.000066 | ||
| 431 | 0.000192 0.000160 0.002241 0.000039 0.000082 | ||
| 432 | 0.000149 0.000143 0.002288 0.000039 0.000079 | ||
| 433 | 0.000161 0.000142 0.002185 0.000049 0.000077 | ||
| 434 | 0.000147 0.000149 0.002284 0.000039 0.000063 | ||
| 435 | 0.000456 0.000144 0.002203 0.000046 0.000064 | ||
| 436 | 0.000187 0.000144 0.002147 0.000037 0.000061 | ||
| 437 | 0.000147 0.000140 0.002238 0.000040 0.000067 | ||
| 438 | 0.000147 0.000140 0.003077 0.000041 0.000068 | ||
| 439 | 0.000151 0.000142 0.002226 0.000038 0.000065 | ||
| 440 | 0.000146 0.000142 0.002188 0.000039 0.000065 | ||
| 441 | 0.000145 0.000141 0.002156 0.000036 0.000061 | ||
| 442 | 0.000143 0.000172 0.002379 0.000037 0.000060 | ||
| 443 | 0.000152 0.000231 0.002172 0.000038 0.000065 | ||
| 444 | 0.000153 0.000142 0.002181 0.000039 0.000065 | ||
| 445 | 0.000148 0.000142 0.002567 0.000039 0.000067 | ||
| 446 | 0.000150 0.000142 0.002177 0.000038 0.000072 | ||
| 447 | 0.000147 0.000146 0.002328 0.000038 0.000063 | ||
| 448 | 0.000146 0.000150 0.002211 0.000038 0.000063 | ||
| 449 | 0.000149 0.000143 0.002222 0.000040 0.000072 | ||
| 450 | 0.000150 0.000144 0.002455 0.000039 0.000065 | ||
| 451 | 0.000147 0.000144 0.002206 0.000039 0.000066 | ||
| 452 | 0.000145 0.000141 0.002153 0.000055 0.000070 | ||
| 453 | 0.000443 0.000144 0.002139 0.000036 0.000069 | ||
| 454 | 0.000147 0.000182 0.002188 0.000037 0.000061 | ||
| 455 | 0.000146 0.000138 0.002248 0.000038 0.000067 | ||
| 456 | 0.000147 0.000142 0.002817 0.000039 0.000067 | ||
| 457 | 0.000148 0.000144 0.002230 0.000038 0.000066 | ||
| 458 | 0.000148 0.000142 0.002239 0.000039 0.000067 | ||
| 459 | 0.000149 0.000142 0.002197 0.000038 0.000063 | ||
| 460 | 0.000181 0.000674 0.002170 0.000038 0.000061 | ||
| 461 | 0.000146 0.000195 0.002204 0.000037 0.000061 | ||
| 462 | 0.000146 0.000141 0.002260 0.000039 0.000067 | ||
| 463 | 0.000150 0.000142 0.002193 0.000045 0.000065 | ||
| 464 | 0.000147 0.000140 0.002229 0.000036 0.000066 | ||
| 465 | 0.000146 0.000137 0.002197 0.000037 0.000062 | ||
| 466 | 0.000152 0.000159 0.002187 0.000036 0.000060 | ||
| 467 | 0.000145 0.000139 0.002224 0.000037 0.000064 | ||
| 468 | 0.000149 0.000144 0.002175 0.000038 0.000066 | ||
| 469 | 0.000150 0.000143 0.002187 0.000038 0.000066 | ||
| 470 | 0.000148 0.000141 0.002152 0.000036 0.000061 | ||
| 471 | 0.000185 0.000141 0.002176 0.000036 0.000064 | ||
| 472 | 0.000169 0.000145 0.002483 0.000038 0.000067 | ||
| 473 | 0.000149 0.000141 0.002225 0.000036 0.000064 | ||
| 474 | 0.000244 0.000149 0.002538 0.000038 0.000065 | ||
| 475 | 0.000156 0.000143 0.002317 0.000039 0.000297 | ||
| 476 | 0.000228 0.000172 0.002222 0.000039 0.000300 | ||
| 477 | 0.000149 0.000145 0.002173 0.000040 0.000066 | ||
| 478 | 0.000154 0.000145 0.002155 0.000038 0.000093 | ||
| 479 | 0.000161 0.000145 0.002178 0.000039 0.000063 | ||
| 480 | 0.000147 0.000170 0.002299 0.000039 0.000066 | ||
| 481 | 0.000149 0.000142 0.003494 0.000040 0.000066 | ||
| 482 | 0.000149 0.000178 0.002237 0.000038 0.000062 | ||
| 483 | 0.000148 0.000143 0.002150 0.000037 0.000064 | ||
| 484 | 0.000146 0.000139 0.002315 0.000038 0.000065 | ||
| 485 | 0.000147 0.000141 0.002269 0.000039 0.000067 | ||
| 486 | 0.000173 0.000145 0.002191 0.000037 0.000065 | ||
| 487 | 0.000166 0.000144 0.002247 0.000038 0.000061 | ||
| 488 | 0.000146 0.000140 0.002551 0.000038 0.000065 | ||
| 489 | 0.000148 0.000175 0.002202 0.000037 0.000064 | ||
| 490 | 0.000145 0.000141 0.002217 0.000038 0.000063 | ||
| 491 | 0.000146 0.000138 0.002164 0.000132 0.000547 | ||
| 492 | 0.000148 0.000144 0.008140 0.000160 0.000893 | ||
| 493 | 0.000311 0.000221 0.004526 0.000058 0.000109 | ||
| 494 | 0.000238 0.000225 0.003475 0.000044 0.000094 | ||
| 495 | 0.000178 0.000177 0.002537 0.000041 0.000087 | ||
| 496 | 0.000172 0.000161 0.002194 0.000048 0.000084 | ||
| 497 | 0.000172 0.000163 0.002177 0.000040 0.000084 | ||
| 498 | 0.001177 0.000156 0.002351 0.000041 0.000325 | ||
| 499 | 0.000167 0.000163 0.002273 0.000040 0.000088 | ||
| 500 | 0.000170 0.000151 0.002245 0.000040 0.000077 | ||
| 501 | 0.000172 0.000896 0.002181 0.000038 0.000080 | ||
| 502 | 0.000202 0.000164 0.002449 0.000038 0.000076 | ||
| 503 | 0.000162 0.000161 0.002188 0.000037 0.000078 | ||
| 504 | 0.000165 0.000154 0.002440 0.000074 0.000091 | ||
| 505 | 0.000167 0.000149 0.002185 0.000039 0.000081 | ||
| 506 | 0.000176 0.000154 0.002427 0.000040 0.000093 | ||
| 507 | 0.000168 0.000154 0.002304 0.000038 0.000105 | ||
| 508 | 0.000672 0.000160 0.002260 0.000038 0.000088 | ||
| 509 | 0.000686 0.000159 0.002207 0.000038 0.000084 | ||
| 510 | 0.000163 0.000154 0.002186 0.000037 0.000077 | ||
| 511 | 0.000173 0.000153 0.002399 0.000038 0.000082 | ||
| 512 | 0.000166 0.000157 0.002709 0.000039 0.000077 | ||
| 513 | 0.000155 0.000149 0.002143 0.000038 0.000097 | ||
| 514 | 0.000166 0.000154 0.003454 0.000051 0.000106 | ||
| 515 | 0.000166 0.000160 0.002539 0.000039 0.000128 | ||
| 516 | 0.000169 0.000149 0.002307 0.000039 0.000085 | ||
| 517 | 0.000170 0.000158 0.002225 0.000040 0.000088 | ||
| 518 | 0.000170 0.000180 0.002165 0.000036 0.000103 | ||
| 519 | 0.000203 0.000160 0.002345 0.000039 0.000075 | ||
| 520 | 0.000173 0.000191 0.002160 0.000038 0.000074 | ||
| 521 | 0.000165 0.000156 0.002243 0.000039 0.000085 | ||
| 522 | 0.000172 0.000154 0.002260 0.000040 0.000090 | ||
| 523 | 0.000163 0.000164 0.002258 0.000040 0.000085 | ||
| 524 | 0.000168 0.000143 0.002755 0.000039 0.000086 | ||
| 525 | 0.000178 0.000155 0.002202 0.000039 0.000075 | ||
| 526 | 0.000164 0.000153 0.002267 0.000038 0.000081 | ||
| 527 | 0.000161 0.000154 0.002158 0.000036 0.000090 | ||
| 528 | 0.000169 0.000158 0.002454 0.000037 0.000061 | ||
| 529 | 0.000162 0.000154 0.002543 0.000038 0.000091 | ||
| 530 | 0.000170 0.000154 0.002168 0.000037 0.000085 | ||
| 531 | 0.000166 0.000151 0.002852 0.000038 0.000087 | ||
| 532 | 0.000167 0.000165 0.002484 0.000039 0.000089 | ||
| 533 | 0.000374 0.000197 0.002217 0.000038 0.000082 | ||
| 534 | 0.000156 0.000150 0.002213 0.000038 0.000112 | ||
| 535 | 0.000683 0.000155 0.002131 0.000038 0.000077 | ||
| 536 | 0.000162 0.000164 0.002199 0.000038 0.000076 | ||
| 537 | 0.000176 0.000154 0.002345 0.000038 0.000089 | ||
| 538 | 0.000175 0.000150 0.002928 0.000039 0.000082 | ||
| 539 | 0.000161 0.000140 0.002528 0.000039 0.000066 | ||
| 540 | 0.000159 0.000151 0.002256 0.000039 0.000075 | ||
| 541 | 0.000155 0.000156 0.002233 0.000040 0.000066 | ||
| 542 | 0.000171 0.000156 0.002149 0.000066 0.000084 | ||
| 543 | 0.000182 0.000154 0.002233 0.000037 0.000117 | ||
| 544 | 0.000166 0.000160 0.002460 0.000037 0.000088 | ||
| 545 | 0.000159 0.000165 0.002891 0.000043 0.000075 | ||
| 546 | 0.000169 0.000143 0.002383 0.000038 0.000084 | ||
| 547 | 0.000162 0.000149 0.002313 0.000039 0.000078 | ||
| 548 | 0.000166 0.000161 0.003837 0.000041 0.000092 | ||
| 549 | 0.000166 0.000144 0.002389 0.000038 0.000078 | ||
| 550 | 0.000185 0.000153 0.002548 0.000040 0.000090 | ||
| 551 | 0.000166 0.000152 0.002943 0.000037 0.000063 | ||
| 552 | 0.000147 0.000140 0.002284 0.000038 0.000066 | ||
| 553 | 0.000145 0.000141 0.002555 0.000038 0.000071 | ||
| 554 | 0.000189 0.000143 0.002235 0.000038 0.000359 | ||
| 555 | 0.000149 0.000140 0.002779 0.000053 0.000089 | ||
| 556 | 0.000211 0.000206 0.002744 0.000040 0.000067 | ||
| 557 | 0.000150 0.000144 0.002471 0.000039 0.000065 | ||
| 558 | 0.000151 0.000140 0.002563 0.000040 0.000064 | ||
| 559 | 0.000148 0.000138 0.002305 0.000039 0.000066 | ||
| 560 | 0.000148 0.000141 0.002162 0.000036 0.000060 | ||
| 561 | 0.000182 0.000145 0.002403 0.000042 0.000063 | ||
| 562 | 0.000152 0.000141 0.002311 0.000039 0.000065 | ||
| 563 | 0.000148 0.000180 0.002192 0.000038 0.000065 | ||
| 564 | 0.000149 0.000141 0.002516 0.000039 0.000066 | ||
| 565 | 0.000147 0.000142 0.002193 0.000040 0.000064 | ||
| 566 | 0.000146 0.000138 0.002194 0.000036 0.000060 | ||
| 567 | 0.000197 0.000142 0.002291 0.000038 0.000063 | ||
| 568 | 0.000148 0.000142 0.002440 0.000039 0.000066 | ||
| 569 | 0.000148 0.000143 0.002228 0.000039 0.000066 | ||
| 570 | 0.000149 0.000140 0.002216 0.000038 0.000067 | ||
| 571 | 0.000148 0.000145 0.002196 0.000038 0.000066 | ||
| 572 | 0.000148 0.000141 0.002157 0.000036 0.000061 | ||
| 573 | 0.000144 0.000175 0.002491 0.000039 0.000063 | ||
| 574 | 0.000147 0.000141 0.002290 0.000039 0.000066 | ||
| 575 | 0.000149 0.000143 0.002508 0.000039 0.000067 | ||
| 576 | 0.000149 0.000142 0.002536 0.000039 0.000067 | ||
| 577 | 0.000150 0.000141 0.003132 0.000046 0.000070 | ||
| 578 | 0.000153 0.000145 0.002202 0.000039 0.000067 | ||
| 579 | 0.000149 0.000143 0.002102 0.000037 0.000067 | ||
| 580 | 0.000989 0.000142 0.002188 0.000063 0.000068 | ||
| 581 | 0.000151 0.000142 0.002229 0.000038 0.000068 | ||
| 582 | 0.001481 0.000141 0.002238 0.000039 0.000070 | ||
| 583 | 0.000148 0.000142 0.002204 0.000037 0.000093 | ||
| 584 | 0.000160 0.000141 0.002138 0.000038 0.000062 | ||
| 585 | 0.000145 0.000141 0.002708 0.000039 0.000065 | ||
| 586 | 0.000147 0.000142 0.002218 0.000039 0.000067 | ||
| 587 | 0.000148 0.000140 0.002759 0.000038 0.000066 | ||
| 588 | 0.000148 0.000139 0.003156 0.000037 0.000067 | ||
| 589 | 0.000185 0.000141 0.002259 0.000040 0.000066 | ||
| 590 | 0.000148 0.000142 0.002226 0.000047 0.000068 | ||
| 591 | 0.000148 0.000142 0.002305 0.000040 0.000090 | ||
| 592 | 0.001000 0.000155 0.002217 0.000064 0.000068 | ||
| 593 | 0.000154 0.000144 0.002554 0.000038 0.000065 | ||
| 594 | 0.000148 0.000141 0.002151 0.000038 0.000066 | ||
| 595 | 0.000146 0.000181 0.003031 0.000039 0.000062 | ||
| 596 | 0.000146 0.000180 0.002254 0.000039 0.000061 | ||
| 597 | 0.000147 0.000143 0.002188 0.000039 0.000065 | ||
| 598 | 0.000147 0.000140 0.002259 0.000039 0.000063 | ||
| 599 | 0.000146 0.000141 0.002238 0.000038 0.000076 | ||
| 600 | 0.000148 0.000141 0.002163 0.000038 0.000061 | ||
| 601 | 0.000153 0.000143 0.002195 0.000043 0.000072 | ||
| 602 | 0.000149 0.000177 0.003291 0.000039 0.000063 | ||
| 603 | 0.000258 0.000153 0.002150 0.000039 0.000066 | ||
| 604 | 0.000157 0.000144 0.002155 0.000037 0.000060 | ||
| 605 | 0.000160 0.001194 0.002269 0.000040 0.000100 | ||
| 606 | 0.000164 0.000151 0.002162 0.000038 0.000078 | ||
| 607 | 0.000163 0.000424 0.002178 0.000036 0.000069 | ||
| 608 | 0.001333 0.000389 0.002249 0.000039 0.000066 | ||
| 609 | 0.000175 0.000142 0.002208 0.000037 0.000102 | ||
| 610 | 0.000443 0.000156 0.002249 0.000040 0.000062 | ||
| 611 | 0.000244 0.001562 0.003049 0.000041 0.000083 | ||
| 612 | 0.000208 0.000183 0.002483 0.000040 0.000068 | ||
| 613 | 0.000164 0.000156 0.002220 0.000040 0.000078 | ||
| 614 | 0.000169 0.000142 0.002694 0.000040 0.000083 | ||
| 615 | 0.000162 0.000152 0.002453 0.000038 0.000077 | ||
| 616 | 0.000157 0.000189 0.002306 0.000040 0.000077 | ||
| 617 | 0.000162 0.000151 0.002200 0.000039 0.000325 | ||
| 618 | 0.000150 0.000142 0.002251 0.000039 0.000066 | ||
| 619 | 0.000172 0.000157 0.002184 0.000039 0.000073 | ||
| 620 | 0.000160 0.000150 0.002678 0.000038 0.000326 | ||
| 621 | 0.000165 0.000151 0.002292 0.000038 0.000094 | ||
| 622 | 0.000162 0.000156 0.002203 0.000037 0.000083 | ||
| 623 | 0.000170 0.000141 0.002175 0.000037 0.000074 | ||
| 624 | 0.000149 0.000166 0.002235 0.000039 0.000071 | ||
| 625 | 0.000161 0.000143 0.002423 0.000036 0.000180 | ||
| 626 | 0.000164 0.000152 0.003095 0.000039 0.000076 | ||
| 627 | 0.000172 0.000153 0.002466 0.000039 0.000115 | ||
| 628 | 0.000151 0.000153 0.002274 0.000039 0.000066 | ||
| 629 | 0.000150 0.000142 0.003179 0.000040 0.000080 | ||
| 630 | 0.000172 0.000159 0.002421 0.000039 0.000083 | ||
| 631 | 0.000159 0.000142 0.002165 0.000037 0.000068 | ||
| 632 | 0.000155 0.000150 0.002233 0.000041 0.000123 | ||
| 633 | 0.000153 0.000158 0.002253 0.000039 0.000571 | ||
| 634 | 0.000203 0.000145 0.002269 0.000041 0.000077 | ||
| 635 | 0.000164 0.000158 0.002176 0.000038 0.000086 | ||
| 636 | 0.000197 0.000144 0.002220 0.000041 0.000080 | ||
| 637 | 0.000174 0.000403 0.002224 0.000039 0.000063 | ||
| 638 | 0.000218 0.000144 0.002150 0.000036 0.000069 | ||
| 639 | 0.000149 0.000141 0.002479 0.000040 0.000079 | ||
| 640 | 0.000163 0.000145 0.002664 0.000039 0.000082 | ||
| 641 | 0.000150 0.000152 0.002446 0.000040 0.000069 | ||
| 642 | 0.000203 0.000154 0.002205 0.000043 0.000077 | ||
| 643 | 0.000160 0.000143 0.002210 0.000039 0.000087 | ||
| 644 | 0.000194 0.000145 0.002167 0.000038 0.000069 | ||
| 645 | 0.000151 0.000154 0.002137 0.000036 0.000079 | ||
| 646 | 0.000162 0.000140 0.002697 0.000037 0.000085 | ||
| 647 | 0.000162 0.000143 0.002233 0.000039 0.000076 | ||
| 648 | 0.000148 0.000144 0.002210 0.000039 0.000065 | ||
| 649 | 0.000151 0.000152 0.003015 0.000041 0.000084 | ||
| 650 | 0.000158 0.000156 0.002730 0.000039 0.000079 | ||
| 651 | 0.000312 0.000165 0.002207 0.000038 0.000076 | ||
| 652 | 0.000167 0.000139 0.002297 0.000040 0.000065 | ||
| 653 | 0.000172 0.000154 0.002205 0.000037 0.000080 | ||
| 654 | 0.000146 0.000149 0.002286 0.000039 0.000076 | ||
| 655 | 0.000164 0.000151 0.002214 0.000038 0.000073 | ||
| 656 | 0.000162 0.000169 0.003110 0.000038 0.000067 | ||
| 657 | 0.000293 0.000144 0.002182 0.000038 0.000060 | ||
| 658 | 0.000157 0.000153 0.003778 0.000049 0.000095 | ||
| 659 | 0.001735 0.000210 0.004360 0.000050 0.000083 | ||
| 660 | 0.000297 0.000198 0.002532 0.000039 0.000072 | ||
| 661 | 0.000185 0.000163 0.002173 0.000039 0.000070 | ||
| 662 | 0.000183 0.000142 0.002122 0.000038 0.000062 | ||
| 663 | 0.000147 0.000145 0.002443 0.000039 0.000066 | ||
| 664 | 0.000149 0.000144 0.002473 0.000040 0.000066 | ||
| 665 | 0.000147 0.000139 0.002949 0.000038 0.000063 | ||
| 666 | 0.000147 0.000139 0.002737 0.000039 0.000066 | ||
| 667 | 0.000199 0.000142 0.002927 0.000038 0.000066 | ||
| 668 | 0.000149 0.000141 0.002188 0.000038 0.000065 | ||
| 669 | 0.000147 0.000144 0.002203 0.000038 0.000066 | ||
| 670 | 0.000149 0.000141 0.002154 0.000037 0.000062 | ||
| 671 | 0.000144 0.000137 0.003526 0.000037 0.000066 | ||
| 672 | 0.000151 0.000153 0.002150 0.000036 0.000060 | ||
| 673 | 0.000145 0.000138 0.002202 0.000037 0.000065 | ||
| 674 | 0.000272 0.000187 0.002477 0.000038 0.000306 | ||
| 675 | 0.000148 0.000141 0.002421 0.000038 0.000067 | ||
| 676 | 0.000147 0.000141 0.002252 0.000039 0.000065 | ||
| 677 | 0.000150 0.000140 0.002144 0.000037 0.000061 | ||
| 678 | 0.000191 0.000144 0.002229 0.000038 0.000060 | ||
| 679 | 0.000145 0.000145 0.002202 0.000038 0.000061 | ||
| 680 | 0.000146 0.000142 0.002418 0.000038 0.000065 | ||
| 681 | 0.000189 0.000171 0.002568 0.000040 0.000066 | ||
| 682 | 0.000150 0.000141 0.002300 0.000039 0.000067 | ||
| 683 | 0.000151 0.000141 0.002199 0.000038 0.000347 | ||
| 684 | 0.000147 0.000140 0.002165 0.000035 0.000061 | ||
| 685 | 0.000151 0.000646 0.002310 0.000040 0.000062 | ||
| 686 | 0.000161 0.000410 0.002195 0.000038 0.000061 | ||
| 687 | 0.000147 0.000141 0.002466 0.000039 0.000066 | ||
| 688 | 0.000147 0.000141 0.003026 0.000038 0.000066 | ||
| 689 | 0.000148 0.000142 0.002223 0.000038 0.000065 | ||
| 690 | 0.000147 0.000142 0.002196 0.000038 0.000067 | ||
| 691 | 0.000147 0.000141 0.002155 0.000044 0.000064 | ||
| 692 | 0.000146 0.000140 0.002354 0.000039 0.000067 | ||
| 693 | 0.000149 0.000143 0.002186 0.000037 0.000062 | ||
| 694 | 0.000150 0.000144 0.002498 0.000040 0.000063 | ||
| 695 | 0.000178 0.000212 0.002453 0.000039 0.000062 | ||
| 696 | 0.000149 0.000177 0.002463 0.000038 0.000063 | ||
| 697 | 0.000147 0.000142 0.002507 0.000038 0.000067 | ||
| 698 | 0.000149 0.000142 0.002717 0.000038 0.000066 | ||
| 699 | 0.000148 0.000141 0.002452 0.000037 0.000065 | ||
| 700 | 0.000147 0.000140 0.002266 0.000039 0.000066 | ||
| 701 | 0.000149 0.000141 0.002183 0.000037 0.000066 | ||
| 702 | 0.000153 0.000142 0.002203 0.000039 0.000067 | ||
| 703 | 0.000152 0.000419 0.002245 0.000040 0.000062 | ||
| 704 | 0.000149 0.000181 0.002181 0.000038 0.000063 | ||
| 705 | 0.000147 0.000142 0.002224 0.000039 0.000066 | ||
| 706 | 0.000147 0.000142 0.002204 0.000038 0.000066 | ||
| 707 | 0.000146 0.000141 0.002250 0.000038 0.000065 | ||
| 708 | 0.000148 0.000141 0.002142 0.000038 0.000063 | ||
| 709 | 0.000156 0.000139 0.002176 0.000036 0.000060 | ||
| 710 | 0.000243 0.000148 0.002768 0.000039 0.000069 | ||
| 711 | 0.000146 0.000204 0.002194 0.000037 0.000065 | ||
| 712 | 0.000147 0.000143 0.003071 0.000039 0.000066 | ||
| 713 | 0.000148 0.000144 0.003489 0.000042 0.000073 | ||
| 714 | 0.000151 0.000151 0.002173 0.000039 0.000064 | ||
| 715 | 0.000146 0.000140 0.003509 0.000038 0.000067 | ||
| 716 | 0.000148 0.000142 0.002191 0.000038 0.000064 | ||
| 717 | 0.000146 0.000139 0.002441 0.000039 0.000117 | ||
| 718 | 0.000174 0.000141 0.002133 0.000038 0.000065 | ||
| 719 | 0.000151 0.000142 0.002257 0.000039 0.000073 | ||
| 720 | 0.000163 0.000147 0.002187 0.000038 0.000061 | ||
| 721 | 0.000146 0.000222 0.002193 0.000038 0.000062 | ||
| 722 | 0.000145 0.000143 0.002434 0.000037 0.000064 | ||
| 723 | 0.000145 0.000139 0.002933 0.000041 0.000066 | ||
| 724 | 0.000146 0.000140 0.002680 0.000037 0.000065 | ||
| 725 | 0.000143 0.000139 0.002217 0.001029 0.000065 | ||
| 726 | 0.000145 0.000139 0.002361 0.000039 0.000067 | ||
| 727 | 0.000150 0.000143 0.002186 0.000068 0.000066 | ||
| 728 | 0.000148 0.000142 0.002149 0.000037 0.000061 | ||
| 729 | 0.000147 0.000181 0.002183 0.000037 0.000061 | ||
| 730 | 0.000146 0.000455 0.002305 0.000038 0.000074 | ||
| 731 | 0.000148 0.000143 0.002223 0.000038 0.000066 | ||
| 732 | 0.000148 0.000141 0.002547 0.000038 0.000066 | ||
| 733 | 0.000148 0.000143 0.002180 0.000038 0.000336 | ||
| 734 | 0.000146 0.000141 0.002102 0.000037 0.000063 | ||
| 735 | 0.000150 0.000145 0.002170 0.000037 0.000067 | ||
| 736 | 0.000152 0.000138 0.002982 0.000038 0.000067 | ||
| 737 | 0.000149 0.000143 0.002419 0.000037 0.000064 | ||
| 738 | 0.000145 0.000195 0.002228 0.000040 0.000067 | ||
| 739 | 0.000148 0.000143 0.002193 0.000038 0.000064 | ||
| 740 | 0.000155 0.000141 0.002166 0.000067 0.000066 | ||
| 741 | 0.000454 0.000176 0.002193 0.000038 0.000063 | ||
| 742 | 0.000186 0.000142 0.002165 0.000035 0.000066 | ||
| 743 | 0.000144 0.000138 0.002542 0.000038 0.000066 | ||
| 744 | 0.000148 0.000143 0.002733 0.000039 0.000066 | ||
| 745 | 0.000147 0.000141 0.002227 0.000038 0.000067 | ||
| 746 | 0.000145 0.000142 0.002764 0.000037 0.000064 | ||
| 747 | 0.000144 0.000138 0.002207 0.000037 0.000065 | ||
| 748 | 0.000147 0.000185 0.002262 0.000038 0.000062 | ||
| 749 | 0.000154 0.000160 0.002163 0.000038 0.000063 | ||
| 750 | 0.000150 0.000145 0.002719 0.000038 0.000065 | ||
| 751 | 0.000145 0.000139 0.002226 0.000037 0.000074 | ||
| 752 | 0.000148 0.000140 0.002517 0.000038 0.000067 | ||
| 753 | 0.000148 0.000142 0.003734 0.000039 0.000067 | ||
| 754 | 0.000147 0.000143 0.002508 0.000039 0.000067 | ||
| 755 | 0.000146 0.000143 0.002288 0.000038 0.000067 | ||
| 756 | 0.000149 0.000143 0.002899 0.000039 0.000067 | ||
| 757 | 0.000150 0.000145 0.002232 0.000037 0.000065 | ||
| 758 | 0.000148 0.000142 0.002169 0.000039 0.000067 | ||
| 759 | 0.000161 0.000141 0.002196 0.000036 0.000060 | ||
| 760 | 0.000145 0.000137 0.002467 0.000040 0.000064 | ||
| 761 | 0.000147 0.000141 0.002168 0.000037 0.000063 | ||
| 762 | 0.000147 0.000139 0.002165 0.000037 0.000064 | ||
| 763 | 0.000146 0.000138 0.002167 0.000036 0.000060 | ||
| 764 | 0.000150 0.000141 0.002326 0.000039 0.000063 | ||
| 765 | 0.000149 0.000179 0.002197 0.000039 0.000063 | ||
| 766 | 0.000148 0.000142 0.002538 0.000039 0.000067 | ||
| 767 | 0.000148 0.000148 0.002555 0.000039 0.000067 | ||
| 768 | 0.000150 0.000144 0.002180 0.000038 0.000066 | ||
| 769 | 0.000245 0.000152 0.002203 0.000038 0.000065 | ||
| 770 | 0.000146 0.000142 0.002118 0.000036 0.000091 | ||
| 771 | 0.000648 0.000141 0.002173 0.000035 0.000058 | ||
| 772 | 0.000142 0.000149 0.002137 0.000037 0.000059 | ||
| 773 | 0.000144 0.000138 0.002191 0.000037 0.000063 | ||
| 774 | 0.000143 0.000137 0.002795 0.000039 0.000065 | ||
| 775 | 0.000147 0.000256 0.002250 0.000038 0.000064 | ||
| 776 | 0.000148 0.000142 0.002231 0.000040 0.000075 | ||
| 777 | 0.000149 0.000143 0.002174 0.000038 0.000061 | ||
| 778 | 0.000182 0.000708 0.002255 0.000038 0.000061 | ||
| 779 | 0.000181 0.000170 0.002222 0.000038 0.000060 | ||
| 780 | 0.000148 0.000141 0.002177 0.000038 0.000065 | ||
| 781 | 0.000147 0.000141 0.002478 0.000039 0.000065 | ||
| 782 | 0.000148 0.000141 0.002191 0.000039 0.000065 | ||
| 783 | 0.000146 0.000139 0.002161 0.000067 0.000063 | ||
| 784 | 0.000157 0.000138 0.002174 0.000036 0.000059 | ||
| 785 | 0.000143 0.000165 0.002396 0.000040 0.000067 | ||
| 786 | 0.000148 0.000141 0.002302 0.000044 0.000067 | ||
| 787 | 0.000148 0.000142 0.002226 0.000043 0.000065 | ||
| 788 | 0.000149 0.000142 0.002198 0.000038 0.000087 | ||
| 789 | 0.000147 0.000143 0.002221 0.000039 0.000066 | ||
| 790 | 0.000146 0.000142 0.002376 0.000065 0.000063 | ||
| 791 | 0.000152 0.000154 0.002201 0.000038 0.000062 | ||
| 792 | 0.000150 0.000142 0.002705 0.000039 0.000067 | ||
| 793 | 0.000149 0.000142 0.002267 0.000039 0.000067 | ||
| 794 | 0.000194 0.000149 0.002347 0.000039 0.000066 | ||
| 795 | 0.000155 0.000141 0.002594 0.000038 0.000066 | ||
| 796 | 0.000148 0.000141 0.002189 0.000038 0.000064 | ||
| 797 | 0.000202 0.000142 0.002155 0.000039 0.000062 | ||
| 798 | 0.000182 0.000146 0.002204 0.000037 0.000061 | ||
| 799 | 0.000146 0.000139 0.002466 0.000037 0.000065 | ||
| 800 | 0.000146 0.000140 0.002463 0.000036 0.000065 | ||
| 801 | 0.000146 0.000139 0.002209 0.000037 0.000063 | ||
| 802 | 0.000145 0.000138 0.002146 0.000036 0.000060 | ||
| 803 | 0.000181 0.000142 0.003356 0.000038 0.000068 | ||
| 804 | 0.000161 0.000142 0.002169 0.000038 0.000062 | ||
| 805 | 0.000146 0.000175 0.002538 0.000039 0.000061 | ||
| 806 | 0.000148 0.000141 0.002482 0.000039 0.000067 | ||
| 807 | 0.000148 0.000144 0.002450 0.000040 0.000066 | ||
| 808 | 0.000149 0.000143 0.002466 0.000043 0.000068 | ||
| 809 | 0.000148 0.000144 0.003551 0.000038 0.000068 | ||
| 810 | 0.000149 0.000142 0.002482 0.000039 0.000066 | ||
| 811 | 0.000149 0.000142 0.002220 0.000039 0.000066 | ||
| 812 | 0.000151 0.000140 0.002199 0.000038 0.000064 | ||
| 813 | 0.000148 0.000184 0.002185 0.000038 0.000066 | ||
| 814 | 0.000145 0.000140 0.002158 0.000036 0.000092 | ||
| 815 | 0.000158 0.000140 0.002262 0.000038 0.000062 | ||
| 816 | 0.000148 0.000143 0.002674 0.000039 0.000066 | ||
| 817 | 0.000148 0.000140 0.002421 0.000039 0.000066 | ||
| 818 | 0.000149 0.000149 0.002433 0.000038 0.000065 | ||
| 819 | 0.000146 0.000172 0.002187 0.000038 0.000065 | ||
| 820 | 0.000146 0.000140 0.002311 0.000039 0.000323 | ||
| 821 | 0.000149 0.000142 0.002180 0.000038 0.000091 | ||
| 822 | 0.000420 0.000143 0.002483 0.000038 0.000063 | ||
| 823 | 0.000685 0.000145 0.002136 0.000035 0.000064 | ||
| 824 | 0.000146 0.000145 0.002433 0.000038 0.000062 | ||
| 825 | 0.000146 0.000139 0.002496 0.000039 0.000066 | ||
| 826 | 0.000149 0.000139 0.003626 0.000041 0.000068 | ||
| 827 | 0.000153 0.000147 0.002272 0.000042 0.000067 | ||
| 828 | 0.000248 0.000155 0.002208 0.000038 0.000063 | ||
| 829 | 0.000146 0.000138 0.002524 0.000038 0.000068 | ||
| 830 | 0.000147 0.000140 0.002176 0.000210 0.000065 | ||
| 831 | 0.000147 0.000140 0.002166 0.000036 0.000060 | ||
| 832 | 0.000144 0.000146 0.002169 0.000036 0.000057 | ||
| 833 | 0.000144 0.000138 0.002207 0.000037 0.000063 | ||
| 834 | 0.000145 0.000138 0.002183 0.000037 0.000062 | ||
| 835 | 0.000145 0.000137 0.002167 0.000036 0.000059 | ||
| 836 | 0.000148 0.000453 0.002310 0.000038 0.000061 | ||
| 837 | 0.000183 0.000855 0.002326 0.000037 0.000061 | ||
| 838 | 0.000146 0.000175 0.002672 0.000036 0.000060 | ||
| 839 | 0.000143 0.000140 0.002238 0.000039 0.000065 | ||
| 840 | 0.000146 0.000139 0.002473 0.000037 0.000064 | ||
| 841 | 0.000146 0.000139 0.002196 0.000039 0.000065 | ||
| 842 | 0.000145 0.000139 0.002141 0.000036 0.000061 | ||
| 843 | 0.000174 0.000397 0.002175 0.000036 0.000059 | ||
| 844 | 0.000143 0.000139 0.002647 0.000037 0.000065 | ||
| 845 | 0.000147 0.000138 0.002196 0.000037 0.000064 | ||
| 846 | 0.000146 0.000138 0.002199 0.000037 0.000063 | ||
| 847 | 0.000146 0.000138 0.002167 0.000036 0.000066 | ||
| 848 | 0.000169 0.000141 0.002156 0.000036 0.000060 | ||
| 849 | 0.000143 0.000139 0.002180 0.000037 0.000065 | ||
| 850 | 0.000144 0.000136 0.002756 0.000039 0.000066 | ||
| 851 | 0.000150 0.000141 0.002919 0.000039 0.000066 | ||
| 852 | 0.000147 0.000140 0.002184 0.000036 0.000065 | ||
| 853 | 0.000145 0.000138 0.002168 0.000036 0.000091 | ||
| 854 | 0.000156 0.000139 0.002169 0.000036 0.000059 | ||
| 855 | 0.000143 0.000139 0.002741 0.000038 0.000065 | ||
| 856 | 0.000147 0.000140 0.002429 0.000037 0.000063 | ||
| 857 | 0.000145 0.000139 0.002226 0.000037 0.000064 | ||
| 858 | 0.000145 0.000139 0.003381 0.000040 0.000066 | ||
| 859 | 0.000153 0.000141 0.002262 0.000038 0.000064 | ||
| 860 | 0.000145 0.000140 0.002137 0.000036 0.000062 | ||
| 861 | 0.000154 0.000650 0.002217 0.000038 0.000063 | ||
| 862 | 0.000184 0.000143 0.002209 0.000038 0.000062 | ||
| 863 | 0.000153 0.000142 0.002907 0.000039 0.000066 | ||
| 864 | 0.000147 0.000142 0.002158 0.000038 0.000064 | ||
| 865 | 0.000146 0.000140 0.002953 0.000039 0.000068 | ||
| 866 | 0.000148 0.000143 0.002208 0.000039 0.000065 | ||
| 867 | 0.000149 0.000139 0.002187 0.000036 0.000065 | ||
| 868 | 0.000144 0.000139 0.002157 0.000036 0.000061 | ||
| 869 | 0.000154 0.000926 0.002139 0.000036 0.000059 | ||
| 870 | 0.000183 0.000140 0.002526 0.000038 0.000062 | ||
| 871 | 0.000148 0.000142 0.002207 0.000038 0.000066 | ||
| 872 | 0.000147 0.000139 0.002790 0.000039 0.000069 | ||
| 873 | 0.000149 0.000144 0.002251 0.000038 0.000066 | ||
| 874 | 0.000151 0.000140 0.002220 0.000039 0.000066 | ||
| 875 | 0.000148 0.000142 0.002523 0.000038 0.000064 | ||
| 876 | 0.000151 0.000138 0.002151 0.000037 0.000065 | ||
| 877 | 0.000147 0.000140 0.002251 0.000037 0.000062 | ||
| 878 | 0.000149 0.000139 0.002607 0.000037 0.000065 | ||
| 879 | 0.000147 0.000141 0.003380 0.000037 0.000066 | ||
| 880 | 0.000147 0.000139 0.002285 0.000069 0.000066 | ||
| 881 | 0.000149 0.000142 0.002566 0.000038 0.000067 | ||
| 882 | 0.000147 0.000142 0.002523 0.000038 0.000067 | ||
| 883 | 0.000152 0.000143 0.002215 0.000038 0.000067 | ||
| 884 | 0.000150 0.000144 0.002243 0.000038 0.000075 | ||
| 885 | 0.000149 0.000141 0.002148 0.000036 0.000063 | ||
| 886 | 0.000182 0.000144 0.002167 0.000036 0.000062 | ||
| 887 | 0.000278 0.000155 0.002631 0.000036 0.000061 | ||
| 888 | 0.000149 0.000139 0.003175 0.000040 0.000066 | ||
| 889 | 0.000156 0.000140 0.002660 0.000038 0.000065 | ||
| 890 | 0.000148 0.000141 0.006171 0.000067 0.000069 | ||
| 891 | 0.000164 0.000142 0.002713 0.000038 0.000064 | ||
| 892 | 0.000161 0.000150 0.002270 0.000038 0.000081 | ||
| 893 | 0.000160 0.000283 0.002276 0.000038 0.000083 | ||
| 894 | 0.000168 0.000150 0.002207 0.000037 0.000072 | ||
| 895 | 0.000151 0.000669 0.002160 0.000038 0.000062 | ||
| 896 | 0.000196 0.000156 0.002363 0.000036 0.000061 | ||
| 897 | 0.000162 0.000141 0.002160 0.000037 0.000077 | ||
| 898 | 0.000147 0.000141 0.002676 0.000038 0.000096 | ||
| 899 | 0.000162 0.000143 0.002263 0.000037 0.000065 | ||
| 900 | 0.000162 0.000141 0.002206 0.000036 0.000080 | ||
| 901 | 0.000146 0.000139 0.002149 0.000036 0.000060 | ||
| 902 | 0.000169 0.000884 0.002163 0.000036 0.000076 | ||
| 903 | 0.000187 0.000140 0.002222 0.000036 0.000061 | ||
| 904 | 0.000145 0.000140 0.002192 0.000037 0.000084 | ||
| 905 | 0.000145 0.000138 0.002619 0.000039 0.000116 | ||
| 906 | 0.000158 0.000149 0.002213 0.000038 0.000089 | ||
| 907 | 0.000145 0.000183 0.002154 0.000038 0.000089 | ||
| 908 | 0.000162 0.000142 0.002142 0.000037 0.000061 | ||
| 909 | 0.000146 0.000178 0.002401 0.000038 0.000062 | ||
| 910 | 0.000145 0.000150 0.002741 0.000037 0.000081 | ||
| 911 | 0.000147 0.000139 0.002360 0.000040 0.000067 | ||
| 912 | 0.000151 0.000153 0.002459 0.000039 0.000075 | ||
| 913 | 0.000148 0.000155 0.002459 0.000037 0.000091 | ||
| 914 | 0.000153 0.000152 0.002174 0.000036 0.000064 | ||
| 915 | 0.000424 0.000149 0.002116 0.000036 0.000068 | ||
| 916 | 0.000166 0.000168 0.002625 0.000038 0.000076 | ||
| 917 | 0.000146 0.000141 0.002957 0.000038 0.000067 | ||
| 918 | 0.000160 0.000142 0.002501 0.000039 0.000079 | ||
| 919 | 0.000147 0.000143 0.002219 0.000038 0.000066 | ||
| 920 | 0.000160 0.000143 0.002771 0.000040 0.000079 | ||
| 921 | 0.000148 0.000150 0.002426 0.000037 0.000082 | ||
| 922 | 0.000146 0.000138 0.002134 0.000036 0.000103 | ||
| 923 | 0.000659 0.000143 0.002197 0.000036 0.000073 | ||
| 924 | 0.000179 0.000153 0.002301 0.000038 0.000074 | ||
| 925 | 0.000147 0.000142 0.002258 0.000038 0.000066 | ||
| 926 | 0.000146 0.000141 0.002210 0.000038 0.000066 | ||
| 927 | 0.000161 0.000141 0.002235 0.000038 0.000084 | ||
| 928 | 0.000145 0.000138 0.002131 0.000036 0.000060 | ||
| 929 | 0.000151 0.000211 0.002265 0.000038 0.000062 | ||
| 930 | 0.000147 0.000142 0.002254 0.000038 0.000067 | ||
| 931 | 0.000148 0.000143 0.002217 0.000038 0.000079 | ||
| 932 | 0.000160 0.000155 0.002229 0.000038 0.000066 | ||
| 933 | 0.000145 0.000142 0.002129 0.000038 0.000065 | ||
| 934 | 0.000165 0.000140 0.002140 0.000036 0.000076 | ||
| 935 | 0.000162 0.000142 0.002452 0.000039 0.000079 | ||
| 936 | 0.000148 0.000143 0.002253 0.000059 0.000068 | ||
| 937 | 0.000164 0.000142 0.003378 0.000039 0.000096 | ||
| 938 | 0.000150 0.000194 0.002192 0.000039 0.000067 | ||
| 939 | 0.000161 0.000152 0.002202 0.000037 0.000077 | ||
| 940 | 0.000160 0.000141 0.002258 0.000039 0.000067 | ||
| 941 | 0.000167 0.000143 0.002706 0.000039 0.000067 | ||
| 942 | 0.000149 0.000155 0.002280 0.000037 0.000100 | ||
| 943 | 0.000174 0.000144 0.002134 0.000037 0.000090 | ||
| 944 | 0.001167 0.000154 0.002224 0.000038 0.000067 | ||
| 945 | 0.000162 0.000155 0.002181 0.000035 0.000065 | ||
| 946 | 0.000773 0.000153 0.002145 0.000036 0.000060 | ||
| 947 | 0.000149 0.000161 0.002160 0.000036 0.000071 | ||
| 948 | 0.000208 0.000144 0.002164 0.000035 0.000060 | ||
| 949 | 0.000143 0.000138 0.002156 0.000036 0.000064 | ||
| 950 | 0.000143 0.000138 0.002225 0.000055 0.000066 | ||
| 951 | 0.000147 0.000141 0.002734 0.000038 0.000065 | ||
| 952 | 0.000145 0.000147 0.002173 0.000037 0.000064 | ||
| 953 | 0.000146 0.000139 0.002112 0.000037 0.000060 | ||
| 954 | 0.000144 0.000137 0.002708 0.000038 0.000064 | ||
| 955 | 0.000144 0.000139 0.002421 0.000037 0.000064 | ||
| 956 | 0.000145 0.000140 0.002449 0.000037 0.000063 | ||
| 957 | 0.000143 0.000138 0.002278 0.000038 0.000064 | ||
| 958 | 0.000145 0.000140 0.002427 0.000040 0.000130 | ||
| 959 | 0.000151 0.000142 0.002155 0.000036 0.000064 | ||
| 960 | 0.000181 0.000139 0.002435 0.000036 0.000060 | ||
| 961 | 0.000145 0.000138 0.003527 0.000038 0.000065 | ||
| 962 | 0.000146 0.000178 0.002178 0.000036 0.000060 | ||
| 963 | 0.000145 0.000138 0.002139 0.000037 0.000065 | ||
| 964 | 0.000145 0.000137 0.003006 0.000037 0.000064 | ||
| 965 | 0.000146 0.000139 0.002204 0.000037 0.000065 | ||
| 966 | 0.000145 0.000139 0.002211 0.000038 0.000062 | ||
| 967 | 0.000182 0.000140 0.002221 0.000036 0.000061 | ||
| 968 | 0.000145 0.000139 0.003169 0.000038 0.000068 | ||
| 969 | 0.000149 0.000174 0.002414 0.000038 0.000066 | ||
| 970 | 0.000147 0.000142 0.002234 0.000038 0.000066 | ||
| 971 | 0.000149 0.000143 0.002678 0.000038 0.000065 | ||
| 972 | 0.000148 0.000141 0.002886 0.000038 0.000066 | ||
| 973 | 0.000145 0.000140 0.002250 0.000038 0.000065 | ||
| 974 | 0.000148 0.000139 0.002181 0.000035 0.000065 | ||
| 975 | 0.000718 0.000142 0.002141 0.000035 0.000059 | ||
| 976 | 0.000189 0.000140 0.002383 0.000036 0.000059 | ||
| 977 | 0.000145 0.000139 0.002206 0.000039 0.000065 | ||
| 978 | 0.000154 0.000186 0.002457 0.000038 0.000066 | ||
| 979 | 0.000190 0.000141 0.002224 0.000038 0.000066 | ||
| 980 | 0.000149 0.000141 0.002151 0.000037 0.000066 | ||
| 981 | 0.000215 0.000143 0.002151 0.000035 0.000061 | ||
| 982 | 0.000144 0.000138 0.002822 0.000039 0.000065 | ||
| 983 | 0.000147 0.000139 0.002275 0.000038 0.000065 | ||
| 984 | 0.000148 0.000141 0.002211 0.000036 0.000064 | ||
| 985 | 0.000146 0.000138 0.002201 0.000037 0.000066 | ||
| 986 | 0.000148 0.000140 0.002273 0.000038 0.000068 | ||
| 987 | 0.000150 0.000144 0.002188 0.000037 0.000063 | ||
| 988 | 0.000152 0.000151 0.002190 0.000037 0.000062 | ||
| 989 | 0.000146 0.000142 0.003145 0.000039 0.000067 | ||
| 990 | 0.000151 0.000139 0.002218 0.000037 0.000065 | ||
| 991 | 0.000145 0.000138 0.002264 0.000037 0.000066 | ||
| 992 | 0.000148 0.000142 0.003011 0.000039 0.000067 | ||
| 993 | 0.000149 0.000141 0.002196 0.000038 0.000065 | ||
| 994 | 0.000146 0.000141 0.002188 0.000036 0.000060 | ||
| 995 | 0.000149 0.000140 0.002190 0.000035 0.000060 | ||
| 996 | 0.000144 0.000137 0.002641 0.000038 0.000064 | ||
| 997 | 0.000146 0.000138 0.002182 0.000043 0.000065 | ||
| 998 | 0.000146 0.000141 0.002216 0.000036 0.000064 | ||
| 999 | 0.000147 0.000139 0.002294 0.000039 0.000068 | ||
| 1000 | 0.000657 0.000145 0.002143 0.000037 0.000062 | ||
| 1001 | 0.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 | |||
| 31 | class 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 | |||
| 96 | class 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 | |||
| 211 | registerProcessor('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 | |||
| 2 | var Godot = (() => { | ||
| 3 | var _scriptDir = typeof document !== 'undefined' && document.currentScript ? document.currentScript.src : undefined; | ||
| 4 | |||
| 5 | return ( | ||
| 6 | function(Godot) { | ||
| 7 | Godot = Godot || {}; | ||
| 8 | |||
| 9 | var 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 | })(); | ||
| 16 | if (typeof exports === 'object' && typeof module === 'object') | ||
| 17 | module.exports = Godot; | ||
| 18 | else if (typeof define === 'function' && define['amd']) | ||
| 19 | define([], function() { return Godot; }); | ||
| 20 | else if (typeof exports === 'object') | ||
| 21 | exports["Godot"] = Godot; | ||
| 22 | |||
| 23 | const 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 | */ | ||
| 168 | const EngineConfig = {}; // eslint-disable-line no-unused-vars | ||
| 169 | |||
| 170 | /** | ||
| 171 | * @struct | ||
| 172 | * @constructor | ||
| 173 | * @ignore | ||
| 174 | */ | ||
| 175 | const 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 | */ | ||
| 526 | const 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 | }()); | ||
| 794 | if (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="<mxfile userAgent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36" version="7.1.3" editor="www.draw.io" type="google"><diagram id="d1a10cf0-d877-4170-d86f-ec45460d7050" name="Page-1">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</diagram></mxfile>"><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: "Times New Roman"; 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: "Times New Roman"; 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 | ||
| 313 | Hello 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 | ||
| 318 | Hello from Golang | ||
| 319 | Hello from Golang | ||
| 320 | Hello 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 &</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 &</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 &</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 &</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 | |||
| 5 | Title1=Metal | ||
| 6 | File1=http://kathy.torontocast.com:2820/ | ||
| 7 | |||
| 8 | Title2=Technolovers Minimal | ||
| 9 | File2=https://stream.technolovers.fm/minimal | ||
| 10 | |||
| 11 | Title3=Indie Rock | ||
| 12 | File3=http://s5.radio.co/s36d03408d/listen | ||
| 13 | |||
| 14 | Title4=Montreal's Classic Rock | ||
| 15 | File4=http://streams.justclassicrock.com:8000 | ||
| 16 | |||
| 17 | Title5=Raute Metal | ||
| 18 | File5=https://metal-high.rautemusik.fm/?ref | ||
| 19 | |||
| 20 | Title6=NCC 1701a Engine Noise | ||
| 21 | File6=https://files.mitjafelicijan.com/haphazard/ncc-1701-a-engine-noise.ogg | ||
| 22 | |||
| 23 | Title7=Funk & Soul | ||
| 24 | File7=http://streams.80s80s.de/soul/mp3-192/ | ||
| 25 | |||
| 26 | Title8=80's Pop | ||
| 27 | File8=http://streams.fluxfm.de/80er/mp3-320 | ||
| 28 | |||
| 29 | Title9=Roots Legacy Radio Dub | ||
| 30 | File9=http://l.rootslegacy.fr/ | ||
| 31 | |||
| 32 | Title10=Ambiental | ||
| 33 | File10=http://radio.stereoscenic.com/ama-h | ||
| 34 | |||
| 35 | #Title6= | ||
| 36 | #File6= | ||
| 37 | |||
| 38 | Length1=-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 @@ | |||
| 1 | User-agent: * | ||
| 2 | Allow: / | ||
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 | --- | ||
| 2 | title: Personal vault | ||
| 3 | date: 2022-08-27T12:00:00+02:00 | ||
| 4 | url: vault.html | ||
| 5 | type: page | ||
| 6 | draft: false | ||
| 7 | --- | ||
| 8 | |||
| 9 | **Hi traveler!** | ||
| 10 | |||
| 11 | This is a repository of interesting things I have gathered over time and it also | ||
| 12 | stores binaries etc of my personal projects. | ||
| 13 | |||
| 14 | Be 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 @@ | |||
| 1 | import xml.etree.ElementTree as ET | ||
| 2 | import requests | ||
| 3 | |||
| 4 | url = "https://mitjafelicijan.fra1.digitaloceanspaces.com/" | ||
| 5 | |||
| 6 | def 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 | |||
| 12 | response = requests.get(url) | ||
| 13 | if 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) | ||
| 53 | else: | ||
| 54 | print(f"Failed to fetch XML data. Status code: {response.status_code}") | ||
