tag:blogger.com,1999:blog-12713903007991215552024-03-13T08:24:36.875-07:00.planRichardhttp://www.blogger.com/profile/05999356523405056706noreply@blogger.comBlogger181125tag:blogger.com,1999:blog-1271390300799121555.post-80085767782770307382023-11-22T23:27:00.000-08:002023-11-23T01:55:49.943-08:00[Technology] How to "crop" a video in Pitivi<i>Tl;dr: first, go to Render > Advanced > Project Settings ... > Size, and change the width and height of the output video to be rendered. Then go to Clip > Transformation to shift (and scale) the input as needed to fit the cropped output region.</i>
<h1>The problem</h1>
<p>I found the process of trying to crop a video in Pitivi unintuitive, so I thought I would document it. I have a video that is in landscape orientation, and I'd like it in a portrait orientation to make it easier to watch on mobile devices.</p>
<p>Here is a 4s clip from the video:</p>
<div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='640' height='480' src='https://www.blogger.com/video.g?token=AD6v5dwgvf7ycr-E3MFzfkZ5TgnUHg3a15YBBwepQ9Q44LDnNtm2PLWYpcpvXSob0bwxLWTKFYJS1R2sAUBsJNP_Fg' class='b-hbp-video b-uploaded' frameborder='0'></iframe></div>
<p>I'd like to crop it from its original 1440x1080 size to 768×1024, centered.</p>
<p>From this:</p>
<div class="separator" style="clear: both;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjc8ELIjOHu8oeI0k6lXhbVPwC4UjKy_hy8ZPAtpnrmGioIKWVE7xB8AHJVxiisc-Is4ijzaMdTIZQBT_tLM_dkuaHHtuT7VnrUzxSVlvoArZXD-aLwQHRpAYC3ApLtDA54eLwHSZ0KB0xYZ2JT5Z99WuMPS67fxIcHiSqXMDDKHrNgQ0TT1oDd3IXbSYLl/s1440/compare.1.before.Bildschirmfoto%20von%20crop2_4s.mp4.png" style="display: block; padding: 1em 0px; text-align: center;">
<img alt="" border="0" data-original-height="1080" data-original-width="1440" height="480" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjc8ELIjOHu8oeI0k6lXhbVPwC4UjKy_hy8ZPAtpnrmGioIKWVE7xB8AHJVxiisc-Is4ijzaMdTIZQBT_tLM_dkuaHHtuT7VnrUzxSVlvoArZXD-aLwQHRpAYC3ApLtDA54eLwHSZ0KB0xYZ2JT5Z99WuMPS67fxIcHiSqXMDDKHrNgQ0TT1oDd3IXbSYLl/w640-h480/compare.1.before.Bildschirmfoto%20von%20crop2_4s.mp4.png" width="640" />
</a>
</div>
<p>To this:</p>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><img alt="" border="0" data-original-height="1080" data-original-width="1440" height="480" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEzP19mIaxLPYt-tx5QTPFWw5kR34BPDibzNEiZMV7zOAoOswbzkcyf0q5k7TE4l24AYIVFyJEfXRknTqEBJ2YUmroRBCycsPNe6FntQVrLPQwYO4cxe58fKzVJLDkkMGqYppMe4kGKBTcoIymOSmdRWhpZaw1UJb__Hew_eVLWvCE4fP5E2UBBFEJMobo/w640-h480/compare.2.goal.Bildschirmfoto%20von%20crop2_4s.mp4_cropped_target.png" style="margin-left: auto; margin-right: auto;" width="640" /></td></tr><tr><td class="tr-caption" style="text-align: center;">(shaded region showing what will be excluded from the final video)<br /></td></tr></tbody></table><div class="separator" style="clear: both;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhEzP19mIaxLPYt-tx5QTPFWw5kR34BPDibzNEiZMV7zOAoOswbzkcyf0q5k7TE4l24AYIVFyJEfXRknTqEBJ2YUmroRBCycsPNe6FntQVrLPQwYO4cxe58fKzVJLDkkMGqYppMe4kGKBTcoIymOSmdRWhpZaw1UJb__Hew_eVLWvCE4fP5E2UBBFEJMobo/s1440/compare.2.goal.Bildschirmfoto%20von%20crop2_4s.mp4_cropped_target.png" style="display: block; padding: 1em 0px; text-align: center;">
</a>
</div>
<h1>1st attempt: Clip Transformation</h1>
<p>Once you have a Pitivi project started and you've imported your video file into it, there's a promising tab called "Clip" thas has some promising properties: X, Y, Width and Height. There is even a video preview with an adjustable bounding box that you can use to manually select a region! Nice! However, it will not crop the video. X and Y will translate (shift) the input video image, and Width and Height will scale it, but it won't change actually crop the output video. Look at the preview. Now you just get a huge black box around your attempt.</p>
<div class="separator" style="clear: both;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEialN8gu-2RYnyEHnoQ4fiHaCdZJLzDryvXhdjJfkRL3stdQtOaLOPA-xKlC2usVveikSHCoFHB6MiLPoBLcm_dhbfdbmuJ4C9EN7mBLiDwOiXCfcIeKXKb_XfTDHBdUbk6HlQ4TFBKRjIBowLORtKsV3ZL3EwrBWbZOJcQQl-GrwGbCVSoVWuFijudI_hi/s1251/crop3_4s.1.transformation_bad.Bildschirmfoto%20vom%202023-11-22%2022-51-51.png" style="display: block; padding: 1em 0px; text-align: center;">
<img alt="" border="0" data-original-height="432" data-original-width="1251" height="222" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEialN8gu-2RYnyEHnoQ4fiHaCdZJLzDryvXhdjJfkRL3stdQtOaLOPA-xKlC2usVveikSHCoFHB6MiLPoBLcm_dhbfdbmuJ4C9EN7mBLiDwOiXCfcIeKXKb_XfTDHBdUbk6HlQ4TFBKRjIBowLORtKsV3ZL3EwrBWbZOJcQQl-GrwGbCVSoVWuFijudI_hi/w640-h222/crop3_4s.1.transformation_bad.Bildschirmfoto%20vom%202023-11-22%2022-51-51.png" width="640" />
</a>
</div>
<p>Here is the output video: not what we wanted.</p>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='640' height='532' src='https://www.blogger.com/video.g?token=AD6v5dzcWTPkSQJdiQ84bYY9q4xXflxnXujttdoTzyviXl_jk39iw_i50azTOXGbEVXZk0Q1cNM62JL8ftAx1SEcRw' class='b-hbp-video b-uploaded' frameborder='0'></iframe>
</div>
<h1>2nd attempt: Crop effect</h1>
<p>Pitivi has many cool effects you can apply to your video, and one is called 'crop'! A-ha! That must crop the video for us! No, no it does not.</p>
<div class="separator" style="clear: both;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4s09EWGydgsDPAkbREYpRPN5Wm4oOtc6QDxSBWlHyDYJbBR6hBYCSMrnRbKwoQ1OTzR2MR4knHDvDDNxc5-KNNOn0mRCVKd098NQ4zm-m5PmsDmDy0Smf3sE0gfJNH_LrnoTp9BMbM3Kp_V8MjrOkV3VOtoKdpLVn_Pc8cyzlcWIYwtqF4lKxtCUUgSQ_/s1251/crop3_4s.2.crop_bad.Bildschirmfoto%20vom%202023-11-22%2022-51-02.png" style="display: block; padding: 1em 0px; text-align: center;">
<img alt="" border="0" data-original-height="432" data-original-width="1251" height="221" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj4s09EWGydgsDPAkbREYpRPN5Wm4oOtc6QDxSBWlHyDYJbBR6hBYCSMrnRbKwoQ1OTzR2MR4knHDvDDNxc5-KNNOn0mRCVKd098NQ4zm-m5PmsDmDy0Smf3sE0gfJNH_LrnoTp9BMbM3Kp_V8MjrOkV3VOtoKdpLVn_Pc8cyzlcWIYwtqF4lKxtCUUgSQ_/w640-h221/crop3_4s.2.crop_bad.Bildschirmfoto%20vom%202023-11-22%2022-51-02.png" width="640" />
</a>
</div>
<p>Here is the output video: still not what we wanted.</p>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='640' height='532' src='https://www.blogger.com/video.g?token=AD6v5dzvfrZqt8-eD13Mj7AjG6UF_BEp-IxBYTVsk4iHyXyP5Os1nd7cvsvgNYEx2u8_R-LjhbMpIXjC_2Lu2AyaWQ' class='b-hbp-video b-uploaded' frameborder='0'></iframe>
</div>
<h1>Final attempt: Project Settings output resolution + Clip transformation</h1>
<p>This probably makes sense to video editor people, but to actually crop a video such that the output is actually cropped, you have to dig through a few menus to find settings for the resolution of your output video, rather than acting upon the video that you're editing itself. To do this, go to Render > Advanced > Project Settings ... > Size and change the values to your desired output width and height.</p>
<p>Go to 'Render'</p>
<div class="separator" style="clear: both;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiF4fBLphrUM_dh09hnBUCsEKwlIxNT87kMeAPa2uz9xGMhxJ_oNroRSfh3UdU2pQLfttTq8YiwcsYKv1NvRAstC3hQzMz49gOKRna0oJ6g1-fa3y0P-aKK-POcqZHltVIX3dHMoyeEPbLbwLRCaj9MpyfLFPgSLCa5uV78-PUihEY_x0lZQWlrHTF3sWkR/s347/crop3_4s.3.1.Render%20button.Bildschirmfoto%20vom%202023-11-22%2022-55-55.png" style="display: block; padding: 1em 0px; text-align: center;">
<img alt="" border="0" data-original-height="207" data-original-width="347" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiF4fBLphrUM_dh09hnBUCsEKwlIxNT87kMeAPa2uz9xGMhxJ_oNroRSfh3UdU2pQLfttTq8YiwcsYKv1NvRAstC3hQzMz49gOKRna0oJ6g1-fa3y0P-aKK-POcqZHltVIX3dHMoyeEPbLbwLRCaj9MpyfLFPgSLCa5uV78-PUihEY_x0lZQWlrHTF3sWkR/s16000/crop3_4s.3.1.Render%20button.Bildschirmfoto%20vom%202023-11-22%2022-55-55.png" />
</a>
</div>
<p>Expand 'Advanced' and go to 'Project Settings'</p>
<div class="separator" style="clear: both;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqUT6DmXUwELUAH8dVdZEGMFCUOgaE2bk42BG7dW1rEmBYqOD7DvKaAZGyNY8fv9pz0COwjmYOEELHD5nhSr-5YW1_wk4gySfRe65WWn4bIPqORWXghYhUGiXwjIcg0UGrpyqDXboCpKmIAGKPl_8IBGgpdaqo1P9R-JEXifWI1c4BMdB9ItAETDqeEyBt/s949/crop3_4s.3.2.Advanced%20settings.Bildschirmfoto%20vom%202023-11-22%2022-56-04.png" style="display: block; padding: 1em 0px; text-align: center;">
<img alt="" border="0" data-original-height="827" data-original-width="949" height="557" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiqUT6DmXUwELUAH8dVdZEGMFCUOgaE2bk42BG7dW1rEmBYqOD7DvKaAZGyNY8fv9pz0COwjmYOEELHD5nhSr-5YW1_wk4gySfRe65WWn4bIPqORWXghYhUGiXwjIcg0UGrpyqDXboCpKmIAGKPl_8IBGgpdaqo1P9R-JEXifWI1c4BMdB9ItAETDqeEyBt/w640-h557/crop3_4s.3.2.Advanced%20settings.Bildschirmfoto%20vom%202023-11-22%2022-56-04.png" width="640" />
</a>
</div>
<p>Once in 'Project Settings', go to 'Size' and update the output Width and Height as desired.</p>
<div class="separator" style="clear: both;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinr15Iohir28qKBMaESLjgG9IeSzIBvXiTsVa9Pyw2YMCh5nYyifx-lEYM6waQqbV-UyxLUgVaBzO4SknYMlLirTRrRRSyJs92ubYsoEVSYJztOqAkyPY5sIPbuXRgqhOHtdeqV0hp18Xc_65ykVOyrgtgPE9i9HDffdcAY6387wAIrvXnDHVrrQSpoGQB/s768/crop3_4s.3.3.Project%20settings.Bildschirmfoto%20vom%202023-11-22%2022-56-22.png" style="display: block; padding: 1em 0px; text-align: center;">
<img alt="" border="0" data-original-height="561" data-original-width="768" height="467" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEinr15Iohir28qKBMaESLjgG9IeSzIBvXiTsVa9Pyw2YMCh5nYyifx-lEYM6waQqbV-UyxLUgVaBzO4SknYMlLirTRrRRSyJs92ubYsoEVSYJztOqAkyPY5sIPbuXRgqhOHtdeqV0hp18Xc_65ykVOyrgtgPE9i9HDffdcAY6387wAIrvXnDHVrrQSpoGQB/w640-h467/crop3_4s.3.3.Project%20settings.Bildschirmfoto%20vom%202023-11-22%2022-56-22.png" width="640" />
</a>
</div>
<p>
NOW we can go to <b>Clip Transformation</b> from earlier and adjust <b>X</b> and <b>Y</b> to shift our desired
region over to where it should be. Since cropping via the Render Project
Settings is anchored to the top-left corner, we'll use <b>negative</b> X and Y values
to shift the image region left and up towards that anchor. Width and Height for
Clip Transformation should continue to match the <i>input</i> video's
dimensions, or we'll squish things up and ruin the crop.
</p>
<div class="separator" style="clear: both;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhX7aftfyyBCTGUdd_RHb_0iHWHxyGSUCZ7pQGvXkIqVxSf5fauMlG3HtsBHHP3KLH6kN9xsKaYeWiN5BcOUsi93Sgw7ZUyqP_aejf0Mf17KLePxKxWCiKH8Pz2aJ8d_xFSAl2qRTERNYDq-_JGqkFYS2eB3MR-Q9zJxMlBvfVjo1yheogyBFQ0li_pk6-h/s1272/crop3_4s.3.4.Clip%20transformation.Bildschirmfoto%20vom%202023-11-22%2023-21-36.png" style="display: block; padding: 1em 0px; text-align: center;">
<img alt="" border="0" data-original-height="435" data-original-width="1272" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhX7aftfyyBCTGUdd_RHb_0iHWHxyGSUCZ7pQGvXkIqVxSf5fauMlG3HtsBHHP3KLH6kN9xsKaYeWiN5BcOUsi93Sgw7ZUyqP_aejf0Mf17KLePxKxWCiKH8Pz2aJ8d_xFSAl2qRTERNYDq-_JGqkFYS2eB3MR-Q9zJxMlBvfVjo1yheogyBFQ0li_pk6-h/s600/crop3_4s.3.4.Clip%20transformation.Bildschirmfoto%20vom%202023-11-22%2023-21-36.png" width="600" />
</a>
</div>
<p>And here is the final output, properly cropped. (Blogger's thumbnail is misleading; but the video itself is correct.)<br /></p>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen='allowfullscreen' webkitallowfullscreen='webkitallowfullscreen' mozallowfullscreen='mozallowfullscreen' width='480' height='640' src='https://www.blogger.com/video.g?token=AD6v5dwU7n9mD4c8zij1RVvA7HbMZJpqQ9uY-kTd7EBtqR8JXmxF1_6Xp8u_LfyAAxVyMk56Zogr3xTaC7PW58HttA' class='b-hbp-video b-uploaded' frameborder='0'></iframe> </div><div class="separator" style="clear: both; text-align: center;"> </div><h2 style="text-align: left;">Issue</h2><p>There's some discussion on making it easier in the future here:</p><ul style="text-align: left;"><li><a href="https://gitlab.gnome.org/GNOME/pitivi/-/issues/2360 ">https://gitlab.gnome.org/GNOME/pitivi/-/issues/2360 </a></li></ul>Richardhttp://www.blogger.com/profile/05999356523405056706noreply@blogger.com0tag:blogger.com,1999:blog-1271390300799121555.post-505838214092548822023-11-22T04:31:00.000-08:002023-11-22T04:31:49.598-08:00[Technology] Nextcloud on a Raspberry Pi: the easy way<p><i>Note: nextcloudpi, while easy, is actually going away! But you can do a similar approach with <a href="https://github.com/nextcloud/all-in-one">Nextcloud All-in-One</a> which I will try to play with soon.</i></p>
<p>In <a href="/2023/11/technology-nextcloud-on-raspberry-pi.html">my previous post</a>, I talked about setting up Nextcloud from source, including configuring a web server, a database, and PHP, based on Nextcloud's detailed guide.</p>
<p>In comparison, deploying it from a container is <i>much</i> simpler. E.g. using the (recently deprecated :|) <a href="https://github.com/nextcloud/nextcloudpi">ownyourbits' NextcloudPi project</a>:
</p><pre># <i># let's make sure our system is up-to-date first :)</i>
# apt update
# apt upgrade <i># don't forget to reboot periodically!</i>
#
# <i># Use docker's handy install script to get it on your Raspberry Pi</i>
# curl -fsSL https://get.docker.com -o get-docker.sh
# bash get-docker.sh <i># adds 1.6GB</i>
#
# <i># pull nextcloudpi from ownyourbits and run it! (adjust ports to avoid collisions with any existing web servers as necessary)</i>
# docker pull docker.io/ownyourbits/nextcloudpi:latest
# docker run --detach \
--publish 4443:4443 \
--publish 443:443 \
--publish 80:80 \
--volume ncdata:/data \
--name nextcloudpi \
ownyourbits/nextcloudpi <i style="color: red;">YourPisHostName</i>
</pre>
<p>Then visit https://<i style="color: red;">YourPisHostName</i>/ and follow steps for configuration. It will give provide you with administrative and user credentials, defaulting to the username 'ncp'. There will be some administrative configuration on port 4443 and regular user/admin experience on 443. Stored data will end up in /var/lib/docker/volumes/<b>ncdata</b> (based on the volume label given above in the <code>docker run</code> command). If you'd like to enter the container while it's running to adjust something, you can use</p>
<pre>sudo docker exec -it nextcloudpi bash</pre>
<p>I had to install vim once inside to have an editor. :) A useful tool for administering nextcloudpi from the command-line is <code>ncp-config</code>.</p><p></p>Richardhttp://www.blogger.com/profile/05999356523405056706noreply@blogger.com0tag:blogger.com,1999:blog-1271390300799121555.post-78555391225621338892023-11-22T00:43:00.000-08:002023-11-22T16:52:49.828-08:00[Technology] Nextcloud on a Raspberry Pi: setting up a web server, a database, PHP and Nextcloud itself <p>Installing Nextcloud on a Raspberry Pi can be fun, or "fun". Run your own suite of open source web services for greater control, customization, independence, and whatever. I'll share my process for installing it from a tarball on a Raspberry Pi (4) running Raspberry Pi OS (bookworm). Let's hope I don't skip any steps.</p><p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgY7Aps5nVKV7WefNgGnqugBa8GBQt78skPAQF5SFLNgHseaQ5OerOqQ200F5opm_j6C7Ed7F4X7mIShBns_hrkOUFq1q6ltlyVwJp63RlfZi2DObtlyU63hIv4LMGnT6iiZjCgfwHr1rd8S9w19kbElmc48h2LLBulzVDj_5cqY-CyW8DYxP0dFRviOEeX/s1317/raspberrypi.PXL_20220101_012056559.MP.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="988" data-original-width="1317" height="240" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgY7Aps5nVKV7WefNgGnqugBa8GBQt78skPAQF5SFLNgHseaQ5OerOqQ200F5opm_j6C7Ed7F4X7mIShBns_hrkOUFq1q6ltlyVwJp63RlfZi2DObtlyU63hIv4LMGnT6iiZjCgfwHr1rd8S9w19kbElmc48h2LLBulzVDj_5cqY-CyW8DYxP0dFRviOEeX/s320/raspberrypi.PXL_20220101_012056559.MP.jpg" width="320" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">My Pi, luxuriating on the soft bedding it deserves<br /></td></tr></tbody></table> <br />Nextcloud's website offers a lot of options, and you can run Nextcloud in containers, install it from snaps, from Fedora's RPM repositories, etc. One benefit of installing it from a simple tarball, from its source, is that you can better understand a lot of its dependencies and the configuration needs. I used their extensive directions found here:</p>
<ul>
<li>
<a href="https://docs.nextcloud.com/server/latest/admin_manual/installation/source_installation.html">https://docs.nextcloud.com/server/latest/admin_manual/installation/source_installation.html</a>
</li>
</ul>
<p>Honestly, they're comprehensive enough that you can follow that instead of
the below, but hopefully in the end I'll have a streamlined guide, at least
for myself.</p>
<p>Regarding storage, going through this on my Raspberry Pi (already in use
for other things) used 3.5GB of disk space. Going through it on the
docker.io/library/debian:latest container image, I used 4.8GB of disk space
(starting from a minimal 172MB!). And this is before user data gets
accumulated. So if you want to store a lot, you will likely want to get a
larger microSD card for your Pi or use some external USB storage.</p>
<p>Regarding performance, I've had some mixed results. During a demo to a
group of friends on a local network using the nextcloudpi docker container,
many features were quite slow. However, testing at home recently, using
either the container or the source installation described below, those same
features were now fast with very low latency!</p>
<h1>Environment</h1>
<p>My environment:</p>
<ul>
<li>Hardware:</li>
<ul>
<li>Raspberry Pi 4 Model B Rev 1.4</li>
<li>Storage: 29GB</li>
</ul>
<li>OS: </li>
<ul>
<li>Raspberry Pi OS (Debian GNU/Linux 12 (bookworm))</li>
<li>image: 2023-10-10-raspios-bookworm-arm64-lite.img</li>
</ul>
<li>Nextcloud</li>
<ul>
<li>version: 27.1.3</li>
<li>build: 2023-10-26T17:25:16+00:00 565dc36226d08d071c30d8ad4fd54126dfa4be79</li>
</ul>
</ul>
<p>Nextcloud can work with a variety of databases and web servers, and the choices can be overwhelming. For this process, I'm going with their recommendations in their install guide and making some boring, conventional choices. </p>
<p>Software choices:</p>
<ul>
<li>web server: Apache</li>
<ul>
<li>apache2-2.4.57-2</li>
</ul>
<li>database: MariaDB (mysql)</li>
<ul>
<li>mariadb-server-1:10.11.4-1~deb12u1</li>
</ul>
</ul>
<p>If you would like to follow along but don't have a Raspberry Pi to play with, you can get a very similar set-up experience using a standard Debian GNU/Linux 12 (bookworm) installation. If you like containers, docker.io/library/debian:latest is currently bookworm. I used that with podman to do testing along the way.</p>
<p>Another note is that I generally use systemd but feel free to use your favourite service manager/init system.</p>
<h1>1. Set-up Environment</h1>
<pre># <i># update the base system</i>
# apt update
# apt upgrade
# <i># install some useful tools</i>
# apt install vim
# apt install less
# apt install wget
# <i># install some tools that Nextcloud requires</i>
# apt install bzip2
</pre>
<h1>2. Database</h1>
<p>As noted above, I'm using MariaDB, a MySQL-compatible derivative. You'll create an empty database, as well as a username and a password, for Nextcloud. Nextcloud will handle table creation on its own. Don't forget to replace <i>username</i> and <i>password</i> with your own unique values below.</p>
<pre># apt install mariadb-server <i># 18.3MB download, 197MB installed</i>
# systemctl enable --now mariadb
# mysql -u root
> CREATE USER '<i style="color: red;">username</i>'@'localhost' IDENTIFIED BY '<i style="color: red;">password</i>';
> CREATE DATABASE IF NOT EXISTS nextcloud CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;
> GRANT ALL PRIVILEGES ON nextcloud.* TO '<i style="color: red;">username</i>'@'localhost';
> FLUSH PRIVILEGES;
</pre>
<p>Next, we need to add some configuration to MariaDB/MySQL in
<code>/etc/mysql/my.cnf</code> (which maps to
<code>/etc/mysql/mariadb.cnf</code> for me). The installation guide suggests
the following settings. I'll note that my default config already has a similar [client-server] section,
so I excluded I only added the other ones that weren't present. The <i>transaction_isolation</i>
and <i>binlog_format</i> settings are particularly important.</p>
<pre>[server]
skip_name_resolve = 1
innodb_buffer_pool_size = 128M
innodb_buffer_pool_instances = 1
innodb_flush_log_at_trx_commit = 2
innodb_log_buffer_size = 32M
innodb_max_dirty_pages_pct = 90
query_cache_type = 1
query_cache_limit = 2M
query_cache_min_res_unit = 2k
query_cache_size = 64M
tmp_table_size= 64M
max_heap_table_size= 64M
slow_query_log = 1
slow_query_log_file = /var/log/mysql/slow.log
long_query_time = 1
[client-server]
!includedir /etc/mysql/conf.d/
!includedir /etc/mysql/mariadb.conf.d/
[client]
default-character-set = utf8mb4
[mysqld]
character_set_server = utf8mb4
collation_server = utf8mb4_general_ci
transaction_isolation = READ-COMMITTED
binlog_format = ROW
innodb_large_prefix=on
innodb_file_format=barracuda
innodb_file_per_table=1
</pre>
<p>Later on, when configuring Nextcloud itself, you'll provide it with the database name, username, password and host (in this case, localhost). You can manually configure it or use the web installation wizard (which I'll do for in post.)</p>
<h1>3. PHP</h1>
<p>Nextcloud requires a bunch of PHP modules, some of which were already installed on my system, and some not.
Below I only show install commands for those that I were not already there. You can view Nextcloud's
<a href="https://docs.nextcloud.com/server/latest/admin_manual/installation/php_configuration.html#php-modules">documentation</a>
to see all the modules they require and recommend, including some optional ones that I am skipping.</p>
<pre># apt install php
#
# <i># install required modules</i>
# apt install php-curl
# apt install php-gd
# apt install php-json
# apt install php-mbstring
# apt install php-xml <i># SimpleXML, XMLReader, XMLWriter</i>
# apt install php-zip
# apt install php-mysql <i># for DB since I use MariaDB</i>
#
# <i># install recommended modules</i>
# apt install php-bz2 <i># for installing packages</i>
# apt install php-intl <i># faster language translation performance (I run it in German)</i>
# apt install php-redis <i># cache for faster performance; alt: php-acpu, php-memcached</i>
# apt install redis-server <i># see <a href="https://docs.nextcloud.com/server/latest/admin_manual/configuration_server/caching_configuration.html#id2">notes</a></i>
# systemctl enable --now redis-server <i># or redis-server</i>
#
# <i># file preview generation</i>
# apt install php-imagick <i># image preview generation (22.4MB down, 84.0MB installed)</i>
# apt install ffmpeg <i># video preview generation; alt: avconv; (127MB down, 415MB installed)</i>
# apt install libreoffice <i># (318MB down, 1,235MB installed)</i>
</pre>
<p>You may want to <a href="https://docs.nextcloud.com/server/latest/admin_manual/installation/php_configuration.html#ini-values">review suggested configuration changes</a> to see which ones you need.</p>
<h1>4. Web server</h1>
<p>As noted above, I'm using Apache 2. We will enable some modules; several that Nextcloud want were enabled by default but I'm listing them anyway.</p>
<p>It's 2023, so of course we will encrypt our connections and traffic. In this case, we are going to use a default self-signed certificate, but if you are actually going to deploy it, at least use Let's Encrypt to get a certificate for your actual domain.</p>
<pre># apt install apache2
# systemctl enable --now apache2
#
# <i># required modules, for at least pretty urls :)</i>
# a2enmod rewrite
# <i># recommended modules</i>
# a2enmod headers
# a2enmod env <i># already enabled for me</i>
# a2enmod dir <i># already enabled for me</i>
# a2enmod mime <i># already enabled for me</i>
#
# <i># SSL</i>
# a2enmod ssl
# a2ensite default-ssl
#
# <i># use php-fpm, Nextcloud recommends it over mod_php</i>
# apt install php-fpm
# a2enmod proxy_fcgi
# a2enmod setenvif <i># already enabled for me</i>
# a2enconf php8.2-fpm
# systemctl enable --now php8.2-fpm
#
# systemctl restart apache2
# systemctl reload apache2
</pre>
<p>Next, we'll configure our Nextcloud site in Apache. You can set it up as either a sub-directory or a subdomain on your host. I picked sub-directory. More details <a href="https://docs.nextcloud.com/server/latest/admin_manual/installation/source_installation.html#additional-apache-configurations">here</a>. Note that it disables mod_dav, as Nextcloud uses SabreDAV.</p>
<h4>Nextcloud Apache Configuration</h4>
<p>Create this file <code>/etc/apache2/sites-available/nextcloud.conf</code> with the following content:</p>
<pre>Alias /nextcloud "/var/www/nextcloud/"
<Directory /var/www/nextcloud/>
Require all granted
AllowOverride All
Options FollowSymLinks MultiViews
<IfModule mod_dav.c>
Dav off
</IfModule>
</Directory>
</pre>
<p>Afterwards, run this:</p>
<pre> a2ensite nextcloud.conf
systemctl reload apache2
</pre>
<p>We will actually create and populate the /var/www/nextcloud directory when we finally get to installing Nextcloud itself from its tarball.</p>
<h1>5. Nextcloud</h1>
<p>Now that we have our web server, database, and PHP configured, we can finally install Nextcloud itself. As noted above, I am installing it from their latest source tarball. You can find it by going to their Install page > Community Projects > Archive, or just follow this direct link: <a href="https://download.nextcloud.com/server/releases/latest.tar.bz2">https://download.nextcloud.com/server/releases/latest.tar.bz2</a>.</p>
<pre># cd /var/www
# wget https://download.nextcloud.com/server/releases/latest.tar.bz2 <i># 172MB download, 607MB unpacked</i>
# tar -xf latest.tar.bz2 <i># this unpacks 'nextcloud/' here at '/var/www/nextcloud'</i>
# chown -R www-data:www-data /var/www/nextcloud/
#
# <i># verify that necessary services are running</i>
# systemctl status mariadb
# systemctl status php8.2-fpm
# systemctl status apache2
</pre>
<p>Now, if everything went smoothly, you should be able to pop open https://<i>yourpihostname</i>:443/ and be greeted with the initial configuration page!</p>
<ul>
<li>create an admin account</li>
<li>configure database settings (back from step #2 up above)</li>
<li>install recommended apps</li>
</ul>
<p>Now you can have some fun playing around. Some features require extra configuration, like using Nextcloud Office with Collabora Online (Development Edition, CODE), and I may update this in the future with some more nuance.</p>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;">
<tbody>
<tr>
<td style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipR2m_QHn2_0cjH7bbGY1Fks_9zJG0vnfS4ij7cF5sOC1oyh0-leCmUr6X4TC9w6LRapWrH_-_IL_SbRIQbZmK_suPzjY2J4dsbSCNjFHzbM-blGSy1Rn-u24uP4H0J9DdhyCVDtHmLgkOntnvEnM0Zx5Jw3gDbQ1jw-BudCfGZd1hMWzUfSc0gPlb7tJG/s1080/Bildschirmfoto%20vom%202023-11-22%2003-28-48.png" style="margin-left: auto; margin-right: auto;">
<img border="0" data-original-height="1080" data-original-width="623" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipR2m_QHn2_0cjH7bbGY1Fks_9zJG0vnfS4ij7cF5sOC1oyh0-leCmUr6X4TC9w6LRapWrH_-_IL_SbRIQbZmK_suPzjY2J4dsbSCNjFHzbM-blGSy1Rn-u24uP4H0J9DdhyCVDtHmLgkOntnvEnM0Zx5Jw3gDbQ1jw-BudCfGZd1hMWzUfSc0gPlb7tJG/w370-h640/Bildschirmfoto%20vom%202023-11-22%2003-28-48.png" width="370" />
</a>
</td>
</tr>
<tr>
<td class="tr-caption" style="text-align: center;">Admin user and DB set-up screen<br /><br /></td>
<td class="tr-caption" style="text-align: center;">
<br />
</td>
</tr>
</tbody>
</table>
<table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;">
<tbody>
<tr>
<td style="text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTmHJ2C2AuZpNvLkhiJM4acPjGcT4MH1_szMXVxIAwcsPjCvNy01OYhw1g3tmF2zw4wpWYnCDV1jdVA_aaQW4t8Cei37mGSaF9GnjqJoKMi7pUlZT92z-y67YCjxRgsaxlmL2gkZvlr_bKKSX0o0SZOo5sYSRjw5FuH4C939TTU5LAW9h9oDzlJmW6ohdM/s1194/Nextcloud%202023-11-22.Bildschirmfoto%20am%202023-11-22%20um%2004.58.03-fullpage.png" style="margin-left: auto; margin-right: auto;">
<img border="0" data-original-height="1080" data-original-width="1194" height="578" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiTmHJ2C2AuZpNvLkhiJM4acPjGcT4MH1_szMXVxIAwcsPjCvNy01OYhw1g3tmF2zw4wpWYnCDV1jdVA_aaQW4t8Cei37mGSaF9GnjqJoKMi7pUlZT92z-y67YCjxRgsaxlmL2gkZvlr_bKKSX0o0SZOo5sYSRjw5FuH4C939TTU5LAW9h9oDzlJmW6ohdM/w640-h578/Nextcloud%202023-11-22.Bildschirmfoto%20am%202023-11-22%20um%2004.58.03-fullpage.png" width="640" />
</a>
</td>
</tr>
<tr>
<td class="tr-caption" style="text-align: center;">User dashboard with some test data added<br />
</td>
</tr>
</tbody>
</table>
<h1>Next steps</h1>
<p>In a future post, I may discuss setting up a Google Docs-like experience with
Nextcloud Office using Collabora Online office, as well as explore more of the options
and configuration settings. I will also discuss the much-simpler ways of
installing and running Nextcloud (e.g. from VM or container images!)</p>
<p><i>Update: just wrote up the very quick-to-start-but-deprecated <b><a href="/2023/11/technology-nextcloud-on-raspberry-pi_22.html">nextcloudpi</a></b></i><b> </b><i>container image</i>.</p>
Richardhttp://www.blogger.com/profile/05999356523405056706noreply@blogger.com0tag:blogger.com,1999:blog-1271390300799121555.post-70261668637311869212023-11-04T02:09:00.010-07:002023-11-04T02:13:25.180-07:00[Technology] IDEs, Emacs and LSP: Python and TypeScript<p>Back in my day, we had a text editor, a compiler and a Makefile, and we liked
it like that. Maybe we didn't really like it like that. But it let
you write and compile code.</p>
<p>I got attached to Emacs early on (sorry vi) and over the years have
accumulated a number of additional packages and lisp code to make development
easier and more efficient. More "recently," Language Server Protocol (LSP)
<a href="https://en.wikipedia.org/wiki/Language_Server_Protocol">[wiki]</a>
<a href="https://github.com/Microsoft/language-server-protocol">[git]</a> was
born, initially targeting Microsoft's VSCode, which has allowed the creation
of Language Servers that are independent of any specific editor, and made
editors more agnostic to which languages they support, by facilitating a
standardized interface between the two facilitating the helpful features
wanted in Integrated Development Environments (IDEs).</p>
<p>Some common features include:</p>
<ul style="text-align: left;">
<li>code completion</li>
<li>syntax highlighting</li>
<li>in-line error/warning indicators</li>
<li>refactoring support</li>
<li>code navigation to definitions and references</li>
<li>in-line API documentation for function signatures and variable typing</li>
</ul>
<p>With Emacs, many of these features have been available through a variety of
internal and external packages independently for a while. Modes
for languages (c-mode, python-mode, web-mode, etc.) have enabled syntax
highlighting and code formatting assistance. <i>company</i> has
supported code completion. <i>flymake</i> has supported syntax checking
and error/warning indicators. Etc.</p>
<p>I decided to update my environment, though, to benefit from the existence of
LSP language servers and hopefully simplify my configuration and
approach. With Emacs often comes a lot of choice and some custom
configuration. That can be great to achieve an ideal environment for
yourself, but it can also require a lot of time and attention to figure out
what that ideal environment should look like, and just how to glue interacting
packages together. So, I'll share my process.</p>
<h2>LSP client modes in Emacs</h2>
<p>There are now two prominent options in Emacs</p>
<ul>
<li>
<b>lsp-mode</b>
<a href="https://emacs-lsp.github.io/lsp-mode/">[github.io]</a>
</li>
<li>Eglot
<a href="https://www.gnu.org/software/emacs/manual/html_mono/eglot.html">[gnu]</a>
<a href="https://github.com/joaotavora/eglot">[git]</a>
</li>
</ul>
<p>Eglot has recently been merged into core GNU Emacs v29. According to
"the Internet", lsp-mode is more featureful. I want to try both, but
Fedora 38 only ships GNU Emacs v28.3, so I have tried lsp-mode
first! I'll try Eglot once I upgrade to Fedora 39 next
week. </p>
<h2>Language Servers for Python</h2>
<p>I'm decided to try two different languages, first Python and then
TypeScript. However, both have multiple language servers available.
The pain of making choices!</p>
<p>lsp-mode's
<a href="https://emacs-lsp.github.io/lsp-mode/page/languages/">language server page</a> lists several options for Python already
</p>
<ul>
<li>Pylsp / python-lsp-server <a href="https://github.com/python-lsp/python-lsp-server">[git]</a></li>
<li>Jedi Language Server <a href="https://github.com/pappasam/jedi-language-server">[git]</a></li>
<li><del>Palantir Python Language Server <a href="https://github.com/palantir/python-language-server">[git]</a></del> (deprecated)</li>
<li>Microsoft's <b>Pyright</b> <a href="https://github.com/microsoft/pyright">[git]</a></li>
<li><del>Microsoft Python Language Server <a href="https://github.com/Microsoft/python-language-server">[git]</a></del> (superseded by Pyright)</li>
<li>Ruff <a href="https://github.com/astral-sh/ruff-lsp">[git]</a></li>
</ul>
<p>So many nice options. Which to pick? Well, an interviewer once
recommended Pyright so there I go to start.</p>
<h2> Language Servers for TypeScript/JavaScript</h2>
<p>Again, options!</p>
<ul>
<li>Deno <a href="https://deno.land/">[site]</a></li>
<li><del>Sourcegraph's javascript-typescript-langserver <a href="https://github.com/sourcegraph/javascript-typescript-langserver">[git]</a></del> (unmaintained)</li>
<li><b>TypeScript Language Server</b> <a href="https://github.com/typescript-language-server/typescript-language-server">[git]</a> (formerly theia-ide by TypeFox)</li>
</ul>
<p>This time I went with TypeScript Language Server because lsp-mode's page for it explicitly marks it as recommended.</p>
<h2>Additional packages</h2>
<p>One issue with IDEs is that all of their features can make an interface
busy/noisy and slow. Sometimes similar information will be redundantly
surfaced at multiple points on screen. lsp-mode is delightful in that
it's very modular and (like many IDEs) you can toggle features on and off as
you need them. They even offer
<a href="https://emacs-lsp.github.io/lsp-mode/tutorials/how-to-turn-off/">a handy visual guide to disabling features</a>. </p>
<p>lsp-mode also leverages a lot of other packages, some internal and some
external, to offer a lot of its functionality. They list these as some
of them: <i><b>lsp-ui</b>, <b>company</b>, <b>flycheck</b>, flymake, projectile, imenu, xref,
lsp-treemacs, dap-mode, lsp-helm, lsp-ivy, consult-lsp, which-key, dired,
iedit, emacs-tree-sitter.</i></p>
<p>Some of these will also leverage other packages and external tools,
too. E.g. <i>flycheck</i>which runs syntax checkers can also call <i>pylint</i>, <i>mypy</i>, etc. from outside emacs, to surface errors and warnings on screen. :) The bolded ones will be included in my set-up steps below.<br /></p>
<h2>My configuration: lsp-mode, pyright, pylint</h2>
<p>After configuring my system, I reproduced it in a minimal container image (<i>registry.fedoraproject.org/fedora</i>) via podman </p>
<p>Install emacs and (for pyright) npm.</p>
<pre> $ sudo dnf install emacs
$ sudo dnf install npm # for pyright, which is written in typescript
</pre>
<p>Make sure you have the MELPA package archive configured in your <b>~/.emacs</b></p>
<pre> ;; ---- Package Management (package.el, melpa) ----
(require 'package)
(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
(package-initialize)
</pre>
<p style="text-align: left;">Next, you can start emacs and run these commands:<br /></p><pre> M-x package-refresh-contents<br /> M-x package-install use-package
<br /> ;; install a few minimal packages we'll use for LSP/IDE features
M-x package-install lsp-mode
M-x package-install lsp-ui
M-x package-install flycheck ;; show errors and warnings from pyright
M-x package-install company ;; auto-complete<br /><br /> ;; now to install language support (servers + mode)
M-x package-install lsp-pyright<br /> M-x package-install typescript-mode
M-x lsp-install-server pyright-tramp<br /> M-x lsp-install-server typescript-language-server
</pre>
<p>Additional .emacs configuration for newly added LSP/IDE packages:</p>
<pre>;; From https://emacs-lsp.github.io/lsp-mode/page/installation/
(use-package lsp-mode<br /> :init<br /> ;; set prefix for lsp-command-keymap (few alternatives - "C-l", "C-c l")<br /> (setq lsp-keymap-prefix "s-l")<br /> :hook ((python-mode . lsp-deferred))<br /> :hook ((typescript-mode . lsp-deferred))<br /> :commands (lsp lsp-deferred))<br /> <br />
(use-package lsp-ui :commands lsp-ui-mode)
(setq lsp-ui-doc-show-with-cursor t)
;; From https://emacs-lsp.github.io/lsp-pyright/
(use-package lsp-pyright
:ensure t
:hook (python-mode . (lambda ()
(require 'lsp-pyright)
(lsp-deferred))))</pre>
Show some additional API documentation on screen for symbols!
<pre>M-x lsp-ui-sideline-toggle-symbols-info</pre>
<h3 style="text-align: left;">"flycheck isn't working?!" <br /></h3><p>One issue that stumped me for a while was lsp failing to show errors/warnings from flycheck when flycheck was configured to use "lsp" as its syntax checker. It turns out that because I often use symlinks from my home directory to my current active projects, I ran into lsp-ui's <a href="https://github.com/emacs-lsp/lsp-ui/issues/119">previously-resolved issue #119</a> (or potentially a new, similar one). So, if lsp-ui doesn't indicate warnings/errors from flycheck (or flymake), make sure your path isn't via a symlink. Oops.<br /></p><h2 style="text-align: left;">Handy Keybindings</h2><p style="text-align: left;">Here are some of my most-used/commands keybindings:</p><ul style="text-align: left;"><li style="text-align: left;"><i>s-l r r - </i>refactor > rename a symbol</li><li style="text-align: left;"><i>s-l g g</i> - go to definition</li><li style="text-align: left;"><i>s-l g r</i> - list references<br /></li><li style="text-align: left;"><i>C-x</i> ` - go to next error (flycheck)</li><li style="text-align: left;"><i>M-x lsp-format-region</i></li><li style="text-align: left;"><i>M-x lsp-format-buffer</i></li></ul><p>Here is a list of others: <a href="https://emacs-lsp.github.io/lsp-mode/page/keybindings/">https://emacs-lsp.github.io/lsp-mode/page/keybindings/</a></p><p>I don't see "s-" often as a prefix, but it's for the <i>Super</i> key (e.g. Windows key). On my system (Fedora 38 with GNOME), <i>s-l</i> locks my screen, but holding <i>shift</i> along with <i>super </i>works for Emacs too, e.g. "<i><shift>+<super>+l r r"</i> to rename a symbol.<br /></p><h2 style="text-align: left;">Conclusion</h2><p style="text-align: left;">Something I appreciate most about IDEs and their fancy features is the early detection of problems and API guidance as you code. I still will add linting/syntax checking/test steps to my build process to guard against bad code entering my repositories. I will say that I think there is some benefit to being able to code without the guidance of an IDE (e.g. code completion) as it can encourage you to better learn an API in the first place. But there comes a point when you can focus more on being productive (with the help of tools!) than on exercising your API memorization for a hundredth time. :)<br /></p>Richardhttp://www.blogger.com/profile/05999356523405056706noreply@blogger.com0tag:blogger.com,1999:blog-1271390300799121555.post-65628911949660432042023-10-06T19:43:00.011-07:002023-10-06T20:46:42.774-07:00[Technology] Element and Signal crashing on notification closure :(: novel-edition<style type="text/css">
h4 { text-decoration: underline; }
</style>
<p>
I run Fedora and have messaging app Element (and Signal) installed via Flatpak. Last week, I upgraded to versions that upped their base dependencies on its runtime org.freedesktop.Platform and base image org.electronjs.Electron2.BaseApp from 22.08 to 23.08. Since, clicking on notifications have made Element go kaboom :(
</p>
<p> I decided to see if I could identify the problem and submit a fix. (Spoiler: someone else has solved it first, but I learned a lot along the way).</p>
<p><i> tl;dr: filed some issues, and learned new things about Flatpak</i></p><h3 style="text-align: left;">0. tl;dr #2<br /></h3><p style="text-align: left;">In the general case, following debugging instructions from these two resources has been sufficient in the past:<br /></p><ul style="text-align: left;"><li style="text-align: left;"><a href="https://docs.flatpak.org/en/latest/debugging.html">https://docs.flatpak.org/en/latest/debugging.html</a><br />"Debugging"<br /></li><li style="text-align: left;"><a href="https://blogs.gnome.org/mclasen/2017/01/20/debugging-a-flatpak-application/">https://blogs.gnome.org/mclasen/2017/01/20/debugging-a-flatpak-application/</a><br />"Debugging a Flatpak application by mclasen" from 2017-01-20</li></ul><p>Basically, for im.riot.Riot, I would normally want to:<br /></p><ul style="text-align: left;"><li>$ flatpak install im.riot.Riot.Debug # <i>install .Debug extension</i><br /></li><li>$ flatpak run --devel --command=sh im.riot.Riot # <i>run a shell in devel mode for debug info and tools like 'gdb' </i><br /></li></ul><p>In this case, that was insufficient because the debugging information was in the Electron base layer, so I ultimately rebuilt Element locally, specifying the electron .Debug extension in Element's YAML file's "base-extensions:" list, and spent too much time figuring out how to install my locally-built Flatpak's own .Debug extension from my build directory. (See "Detour 2.1" below for details.)</p><p>Here are all my steps in case that helps someone else:<br /></p>
<h3>1. Investigate</h3>
<h4>Check for existing bug reports</h4>
<p>
First I wanted to look to see if another user/developer had already noticed/identified the issue. I thought the problem might be specific to the its Flatpak package, given the constraints on how it can interact with the host system (e.g portals). So my first stop was Flathub, going to Element (im.riot.Riot)'s app page:
</p>
<ul style="text-align: left;"><li>
<a href="https://flathub.org/apps/im.riot.Riot">https://flathub.org/apps/im.riot.Riot</a>
</li></ul>
<h4>
Detour 1: broken app pages
</h4>
<ul style="text-align: left;"><li>
<a href="https://github.com/flathub/website/issues/2045">https://github.com/flathub/website/issues/2045</a> "App pages broken"
</li></ul>
<p>
That led to the above issue getting filed, as visiting Element's app page . No one directly replied but I was flattered to see it referenced in the #flathub:matrix.org chat:
</p>
<p>
<img alt="" height="246" src="data:image/png;base64,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" width="640" />
</p>
<h4>
Check for existing bug reports, take 2
</h4>
<p>
So for now I just googled and found that Flathub Flatpaks have their package repos stored under Flathub's github like:
</p>
<ul>
<li>
<a href="https://github.com/flathub/im.riot.Riot">https://github.com/flathub/im.riot.Riot</a>
</li>
</ul>
<p>
There wasn't an existing issue created for this, so I made one!
</p>
<ul>
<li>
<a href="https://github.com/flathub/im.riot.Riot/issues/406">https://github.com/flathub/im.riot.Riot/issues/406</a><br />'Notifications cause Element to crash after commit 6d9d107 "Use newer freedesktop platform 23.08"'
</li>
</ul>
<h4>Finding the change that broke things</h4>
<p>
First I had to see if I could find the version/change that introduced the problem. I referred to Flatpak's
<a href="https://docs.flatpak.org/en/latest/tips-and-tricks.html#bisecting-regressions-in-application-builds">bisect documentation</a> but for reasons that I will investigate later, `flatpak bisect` didn't actually work for me, so I went the classic route of ... clone the package repo and bisect it myself!
</p>
<h4>Building locally</h4>
<p>
I referred to more documentation (<a href="https://docs.flatpak.org/en/latest/first-build.html">Building your first Flatpak</a> (even though this is like my third!))
</p>
<pre>~$ git clone https://github.com/flathub/im.riot.Riot.git
[~]$ cd im.riot.Riot/
[im.riot.Riot]$ git clone https://github.com/flathub/shared-modules.git
[im.riot.Riot]$ flatpak-builder build-dir im.riot.Riot.yaml
error: org.freedesktop.Sdk/x86_64/23.08 not installed
Failed to init: Unable to find sdk org.freedesktop.Sdk version 23.08</pre>
<p>
:( Let's install our prerequisites:
</p>
<pre>$ flatpak remote-add --user --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
$ flatpak install --user --no-related org.freedesktop.Sdk/x86_64/23.08
$ flatpak install --user --no-related org.freedesktop.Platform/x86_64/23.08
$ flatpak install --user --no-related org.electronjs.Electron2.BaseApp/x86_64/23.08</pre>
<p>
Notes:
</p>
<ul>
<li>
remote-add: for my test environment, flathub exists already for the system, but I just want to test this locally, so adding it for user.
</li>
<li>
--no-related: I use this to skip Locale extensions that are very large and likely unnecessary for testing (in this case, they're going to get installed anyway, ah well)
</li>
</ul>
<p>
Now it basically builds!<br />
</p>
<h4>
Manually bisecting
</h4>
<p>
I added a branch tag to im.riot.Riot.yaml to mark it as my debugging version:
</p>
<pre>app-id: im.riot.Riot
<b>branch: dbg</b>
base: org.electronjs.Electron2.BaseApp
...</pre>
<p>
Repeat this a few times:
</p>
<pre>$ git log # view changes and commit IDs
$ git checkout <COMMIT_ID> # test a commit
$ flatpak-builder --user --install --force-clean build-dir im.riot.Riot.yaml
$ flatpak run im.riot.Riot/x86_64/dbg # run my dbg branch to test</pre>
<p>
Testing in this case saw me messaging one of my Matrix accounts from another to generate the notification, clicking, and seeing if it crashed.
</p>
<p>
This quickly narrowed it down to this:
</p>
<ul>
<li>
<a href="https://github.com/flathub/im.riot.Riot/commit/6d9d107941143997e40649192116d93eefe38796">https://github.com/flathub/im.riot.Riot/commit/6d9d107941143997e40649192116d93eefe38796</a><br />"Use newer freedesktop platform 23.08"
</li>
</ul>
<p>
While the commit name references the org.freedesktop.Platform runtime change, spoiler: the issue is more related to the org.electronjs.Electron2.BaseApp base image change to 23.08.
</p>
<p>
This led to issue 406 (above) being filed,
<b>but</b> while working on this, a friend sent me a message via Signal (also based on Electron) and that crashed when I clicked its notification! Uh oh.
</p>
<h4>
Check for existing bug reports, Signal-edition
</h4>
<p>
In Signal's case, someone had already filed an issue:
</p>
<ul>
<li>
<a href="https://github.com/flathub/org.signal.Signal/issues/521">https://github.com/flathub/org.signal.Signal/issues/521</a><br />"libnotify crash"
</li>
</ul>
<p>
They had identified the issue as existing in libnotify (rather than specifically how the Flatpak used it), and had already filed an issue there:
<br />
</p>
<ul>
<li>
<a href="https://gitlab.gnome.org/GNOME/libnotify/-/issues/34" rel="nofollow">https://gitlab.gnome.org/GNOME/libnotify/-/issues/34</a><br />"Signal crashes in flatpak when notification is dismissed"
</li>
</ul>
<h3>2. Debug
<br />
</h3>
<h4>Finding the change that broke things, part 2: libnotify edition</h4>
<p> So from there I decided to try to debug the source of the crash. First I tried installing the debug info for Element (im.riot.Riot) and running it in devel mode, so I could use gdb to catch the crash and look at the backtrace:
<br />
</p>
<p>
</p><pre>$ flatpak install --user im.riot.Riot.Debug
$ flatpak run --user --devel --command=sh --devel im.riot.Riot
[📦 im.riot.Riot ~]$ cd /app/bin
[📦 im.riot.Riot bin]$ ./element &
[📦 im.riot.Riot bin]$ gdb --pid=<PID>
<span style="color: #999999;">...
Enable debuginfod for this session? (y or [n]) y
...</span>
(gdb) continue
<span style="color: #999999;">...
Downloading separate debug info for /app/lib/libnotify.so.4
(element-desktop:6): libnotify-WARNING **: 18:22:08.633: Running in confined mode, using Portal notifications. Some features and hints won't be supported
Thread 1 "element-desktop" received signal SIGSEGV, Segmentation fault.</span>
<b>0x00007f945f8d1418 in ?? () from /app/lib/libnotify.so.4</b>
(gdb) bt
<b>#0 0x00007f945f8d1418 in () at /app/lib/libnotify.so.4</b>
#1 0x00007f946f4fb4ea in g_closure_invoke (closure=0x173001ee90b0, return_value=0x0, n_param_values=4, param_values=0x7ffd598a9cb0, invocation_hint=0x7ffd598a9c30) at ../gobject/gclosure.c:832
...</pre>
<p>
Huh, despite installing the .Devel extension for Element, running it using --devel, and even having gdb try to download debug info for libnotify.so.4, there are no symbols.
</p>
<p>I took a peek inside my Flatpak to see that running with --devel meant /app/lib/debug/
<b>did </b>have debug info for various libraries and packages, but not libnotify.
<br />
</p>
<p>Note:</p>
<ul>
<li>for PID above, element launches multiple element-desktop processes, but the one I want is the following invocation, which abrt was kind enough to identify when I first encountered this problem:
<br />
</li>
<ul>
<li>/app/Element/element-desktop --enable-wayland-ime --ozone-platform-hint=auto --enable-features=WaylandWindowDecorations,WebRTCPipeWireCapturer </li>
</ul>
</ul>
<h4>Detour 2.0: the quest for libnotify debugging symbols</h4>
<p>So I tried a variety of things and did a lot of reading.</p>
<p>Looking around, I saw that libnotify wasn't directly included in im.riot.Riot but in its base layer, org.electronjs.Electron2.BaseApp:</p>
<ul>
<li>https://github.com/flathub/org.electronjs.Electron2.BaseApp/</li>
</ul>
<p>I went back to #flatpak:matrix.org and asked around and barthalion helpedfully noted that apps using Electron usually didn't retain their debugging symbols.
<br />
</p>
<p>I tried to build a local version of that under my own dbg branch, and then rebuilt my local dbg build of im.riot.Riot using that dbg branch of Electron2, but they were still missing. Hmm.</p>
<h4>Detour 2.1: successfully including debugging symbols from a base image</h4>
<p>After some more reading, I found this
<b>very helpful</b> blog post by Redhat's Stefan Hajnoczi, and a helpful digging deeper into Flatpak builder docs:
<br />
</p>
<ul>
<li>
<a href="http://blog.vmsplice.net/2022/04/debugging-flatpak-applications.html" rel="nofollow noreferrer noopener" target="_blank">http://blog.vmsplice.net/2022/04/debugging-flatpak-applications.html</a>"Debugging Flatpak applications" by Stefan Hajnoczi
<br />
</li>
<li>
<a href="https://docs.flatpak.org/en/latest/flatpak-builder-command-reference.html">https://docs.flatpak.org/en/latest/flatpak-builder-command-reference.html</a>"Flatpak Builder Command Reference" on base-extensions</li>
</ul>
<p>So I was finally able to test Element with libnotify debugging info by:</p>
<ol>
<li>Adding the following to my im.riot.Riot.yaml, telling it to actually use the Debug extension for org.electronjs.Electron2.BaseApp (using the flathub version, rather than my dbg build):
<br />
<pre>base-extensions:
app-id: im.riot.Riot
<b>branch: dbg</b>
base: org.electronjs.Electron2.BaseApp
base-version: '23.08'
<b>base-extensions:
- org.electronjs.Electron2.BaseApp.Debug
</b>runtime: org.freedesktop.Platform
...</pre>
</li>
<li>actually locally installing the Debug extension of my locally-built dbg build (thanks to Stefan Hajnoczi's blog post above!). From my local git repo,
<br />
<pre>[im.riot.Riot]$ flatpak install --user im.riot.Riot.Debug
[im.riot.Riot]$ flatpak install --user --reinstall --assumeyes "$(pwd)/.flatpak-builder/cache" im.riot.Riot.Debug</pre>
</li>
</ol>
<p>Repeating earlier steps to run gdb and catch the crash, I got to:
<br />
</p><pre>...
<span style="color: #999999;">[New Thread 0x7f61bff1b6c0 (LWP 184)]
(element-desktop:4): libnotify-WARNING **: 18:20:44.116: Running in confined mode, using Portal notifications. Some features and hints won't be supported
</span>Thread 1 "element-desktop" received signal SIGSEGV, Segmentation fault.
0x00007f61b33cb418 in close_notification (reason=NOTIFY_CLOSED_REASON_DISMISSED, notification=0x25d801795f20) at ../libnotify/notification.c:708
<b>708 if (notification->priv->closed_reason != NOTIFY_CLOSED_REASON_UNSET ||
</b>(gdb) bt
#0 0x00007f61b33cb418 in close_notification (reason=NOTIFY_CLOSED_REASON_DISMISSED, notification=0x25d801795f20) at ../libnotify/notification.c:708
<span style="color: #999999;">#1 proxy_g_signal_cb (proxy=<optimized out>, sender_name=<optimized out>, signal_name=<optimized out>, parameters=0x25d8002ae990, notification=0x25d801795f20) at ../libnotify/notification.c:795
#2 0x00007f61c2f154ea in g_closure_invoke (closure=0x25d8002d1150, return_value=0x0, n_param_values=4, param_values=0x7ffc29493d70, invocation_hint=0x7ffc29493cf0) at ../gobject/gclosure.c:832
...</span></pre>
<p></p>
<p>The notification wasn't valid by the time we got to close_notification. Likely, it was unref'd prematurely, possibly by Electron. From there, I spent some time reading source code, setting break points, etc. However, I ultimately ran out of time before Maximiliano beat me to it!
<br />
</p>
<h3>3. Resolution</h3>
<p>As you can see in the
<a href="https://gitlab.gnome.org/GNOME/libnotify/-/issues/34">libnotify issue #34</a> previously noted above, Maximiliano (@msandova) was hard at work today on libnotify's
<a href="https://gitlab.gnome.org/msandova/libnotify/-/commits/fix-electron">fix-electron branch</a> working on a fix.
<br />
</p>
<p>
<img alt="" src="data:image/png;base64,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" /> </p><p>I rebuilt Electron's BaseApp using a gitlab-generated .tar.gz from the fix-electron branch, and rebuilt Element atop that, and that resolved the problem! <br /></p>
<p>While I have to switch to other projects in life now, and I didn't really help solve the actual problem, it's been fun learning more about Flatpak and hopefully these notes will prove useful when debugging Flatpak issues in the future. <br /></p><h3>Thank yous</h3><p>Thank you to the following very-helpful people:</p><ul><li>Maximiliano (@msandova) </li><li>Stefan Hajnoczi</li><li>barthalion</li></ul>
<p></p>
Richardhttp://www.blogger.com/profile/05999356523405056706noreply@blogger.com0tag:blogger.com,1999:blog-1271390300799121555.post-24765811575396073552023-09-25T13:42:00.022-07:002023-09-25T15:49:35.305-07:00[Technology] docker.io/library/node container image size<p>As seen in my last post, the node image on docker is over 1GB. I was curious what contributed to that, so I ran and attached myself to a shell in it.</p>
<style type="text/css">
div.post-body {
text-align: left;
}
div.post-body p {
text-align: justify;
}
</style>
<pre>$ podman run -dt node bash
$ podman attach -l
root@...:/#</pre>
<p>A quick query of installed packages and their sizes gave me these top 30 packages:</p>
<code>dpkg-query -Wf '${Installed-Size}\t${Package}\n' | sort -nr | head -n 30</code>
<br />
<br />
<style type="text/css">
table#node-pkg-size tr td:nth-child(1),
table#node-pkg-size tr td:nth-child(3) {
text-align: right;
}
</style>
<div class="overflow">
<table id="node-pkg-size" class="kosmo-table rotate-header" border="1">
<thead>
<tr>
<th><div>Size (kB)</div></th>
<th><div>Deb Package</div></th>
<th><div>% (of installed packages)</div></th>
</tr>
</thead>
<tbody>
<tr><td>68,236</td><td>gcc-12</td><td>7.65</td></tr>
<tr><td>47,784</td><td>libicu-dev</td><td>5.36</td></tr>
<tr><td>44,477</td><td>git</td><td>4.99</td></tr>
<tr><td>36,170</td><td>libicu72</td><td>4.05</td></tr>
<tr><td>36,161</td><td>g++-12</td><td>4.05</td></tr>
<tr><td>33,848</td><td>cpp-12</td><td>3.79</td></tr>
<tr><td>28,862</td><td>libperl5.36</td><td>3.23</td></tr>
<tr><td>19,446</td><td>libstdc++-12-dev</td><td>2.18</td></tr>
<tr><td>18,062</td><td>coreutils</td><td>2.02</td></tr>
<tr><td>17,816</td><td>perl-modules-5.36</td><td>1.99</td></tr>
<tr><td>16,203</td><td>libx265-199</td><td>1.81</td></tr>
<tr><td>15,021</td><td>binutils-common</td><td>1.68</td></tr>
<tr><td>14,577</td><td>mercurial-common</td><td>1.63</td></tr>
<tr><td>14,284</td><td>libgcc-12-dev</td><td>1.60</td></tr>
<tr><td>12,986</td><td>libc6</td><td>1.45</td></tr>
<tr><td>12,303</td><td>libssl-dev</td><td>1.38</td></tr>
<tr><td>11,957</td><td>libc6-dev</td><td>1.34</td></tr>
<tr><td>11,428</td><td>binutils-x86-64-linux-gnu</td><td>1.28</td></tr>
<tr><td>10,909</td><td>librsvg2-2</td><td>1.22</td></tr>
<tr><td>10,076</td><td>sq</td><td>1.13</td></tr>
<tr><td>10,075</td><td>libglib2.0-dev</td><td>1.13</td></tr>
<tr><td>9,404</td><td>libglib2.0-data</td><td>1.05</td></tr>
<tr><td>8,323</td><td>libpython3.11-stdlib</td><td>0.93</td></tr>
<tr><td>8,130</td><td>libmagic-mgc</td><td>0.91</td></tr>
<tr><td>8,017</td><td>libasan8</td><td>0.89</td></tr>
<tr><td>7,815</td><td>libtsan2</td><td>0.87</td></tr>
<tr><td>7,638</td><td>perl-base</td><td>0.85</td></tr>
<tr><td>7,164</td><td>bash</td><td>0.80</td></tr>
<tr><td>6,761</td><td>python3.11-minimal</td><td>0.75</td></tr>
<tr><td>6,589</td><td>linux-libc-dev</td><td>0.73</td></tr>
</tbody>
</table>
</div>
<p>
Surprisingly, no packages for nodejs/npm are listed! I calculated the sum of the size of all installed packages, and got 891,320 kB, but overall disk usage in the image's final file system is 1,139,008 kB. That's a discrepancy of 247,688 kB!
Poking around to find some evidence of it, I see that npm is installed at <code>/usr/local/bin/npm</code>. All of <code>/usr/local</code> takes up 167,728 kB in the final image. Let's poke around and see which layer added that.
</p>
<pre>$ podman image tree node
Image ID: 386e0be86bde
Tags: [docker.io/library/node:latest]
Size: 1.122GB
Image Layers
├── ID: 7c85cfa30cb1 Size: 121.3MB
├── ID: a9af9831483f Size: 49.56MB
├── ID: 68731f6c1e1e Size: 181.4MB
├── ID: d396cdbdc3ad Size: 596.9MB
├── ID: 02f1f39c8ec9 Size: 22.53kB
├── ID: 4709b21dad1d Size: 164.8MB
├── ID: 24d9598c79a8 Size: 7.626MB
└── ID: 19ba6ee0c874 Size: 3.584kB Top Layer of: [docker.io/library/node:latest]
$ podman history node
ID CREATED CREATED BY SIZE COMMENT
386e0be86bde 4 days ago /bin/sh -c #(nop) CMD ["node"] 0B
<missing> 4 days ago /bin/sh -c #(nop) ENTRYPOINT ["docker-ent... 0B
<missing> 4 days ago /bin/sh -c #(nop) COPY file:4d192565a7220e... 3.58kB
<missing> 4 days ago /bin/sh -c set -ex && for key in 6A0... 7.63MB
<missing> 4 days ago /bin/sh -c #(nop) ENV YARN_VERSION=1.22.19 0B
<missing> 4 days ago /bin/sh -c ARCH= && dpkgArch="$(dpkg --pri... 165MB
<missing> 4 days ago /bin/sh -c #(nop) ENV NODE_VERSION=20.7.0 0B
<missing> 4 days ago /bin/sh -c groupadd --gid 1000 node && u... 22.5kB
<missing> 5 days ago /bin/sh -c set -ex; apt-get update; apt-... 597MB
<missing> 5 days ago /bin/sh -c apt-get update && apt-get insta... 181MB
<missing> 5 days ago /bin/sh -c set -eux; apt-get update; apt... 49.6MB
<missing> 5 days ago /bin/sh -c #(nop) CMD ["bash"] 0B
<missing> 5 days ago /bin/sh -c #(nop) ADD file:ce04d6a354feaef... 0B
</pre>
<p>Taking a peak in <code>~/.local/share/containers/storage/overlay</code> and doing a find against each of the layer IDs, looking for the npm binary, I get this:</p>
<pre>./4709b21dad1d5d5cb88803c9c598c81fd9a94de38398ad002ec569cff33445c7/diff/usr/local/bin/npm
./4709b21dad1d5d5cb88803c9c598c81fd9a94de38398ad002ec569cff33445c7/diff/usr/local/lib/node_modules/corepack/shims/nodewin/npm
./4709b21dad1d5d5cb88803c9c598c81fd9a94de38398ad002ec569cff33445c7/diff/usr/local/lib/node_modules/corepack/shims/npm
./4709b21dad1d5d5cb88803c9c598c81fd9a94de38398ad002ec569cff33445c7/diff/usr/local/lib/node_modules/npm
./4709b21dad1d5d5cb88803c9c598c81fd9a94de38398ad002ec569cff33445c7/diff/usr/local/lib/node_modules/npm/bin/npm</pre>
<p>Peaking at its directory structure, I see that that layer is 167,712 kB and accounts for all of <code>/usr/local</code>, and its entirely node files. Some of the most notable disk usage is as follows:</p>
<style type="text/css">
table#node-usr-local-sizes tr td:nth-child(1) {
text-align: right;
}
table#node-usr-local-sizes tr td:nth-child(2) {
font-family: monospace;
}
</style>
<div class="overflow">
<table id="node-usr-local-sizes" class="kosmo-table rotate-header" border="1">
<thead>
<tr><th><div>Size (kB)</div></th><th><div>Path</div></th><th><div>Comment</div></th></tr>
</thead>
<tbody>
<tr><td>93,524</td><td>usr/local/bin/node</td><td>The binary itself.</td></tr>
<tr><td>53,004</td><td>usr/local/include/node/openssl/</td><td>Most of this in its archs/ subdirectory, with 21 architectures' .h files.</td></tr>
<tr><td>19,208</td><td>usr/local/lib/node_modules/</td><td></td></tr>
<tr><td>17,456</td><td>usr/local/lib/node_modules/npm</td><td></td></tr>
<tr><td>14,308</td><td>usr/local/lib/node_modules/npm/node_modules</td><td>Contains 196 modules, the largest as node-gyp at 3716 kB.</td></tr>
</tbody>
</table>
</div>
<p>So, there you have it. The node image is so large mostly because it contains a tonne of development .deb packages, and node-specific files take up ~164 MB, about 14% of the final image.</p>Richardhttp://www.blogger.com/profile/05999356523405056706noreply@blogger.com0tag:blogger.com,1999:blog-1271390300799121555.post-6387288576642754892023-09-24T15:07:00.019-07:002023-09-25T14:38:29.680-07:00[Technology] Galton Boards and OCI Containers<div class="separator">
<p style="clear: right; float: right; margin-bottom: 1em; margin-left: 1em;">
<img alt="" src="data:image/png;base64,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" /><br />
</p>
</div>
<p>
A friendly recently showed me a Galton Board. Think binomial distributions and maybe even Plinko. (<a href="https://en.wikipedia.org/wiki/Galton_board" target="_blank">Wiki</a>, and a <a href="https://www.compadre.org/osp/EJSS/3965/109.htm" target="_blank">simulation</a> by Wolfgang Christian.)<br />
</p>
<p>
I ended up implementing one of my own using <a href="https://www.typescriptlang.org/" target="_blank">TypeScript</a> and as an excuse to play more with <a href="https://podman.io" target="_blank">podman</a> (an OCI container manager like Docker).
</p>
<p>
You can find the source code on <a href="https://gitlab.com/aquarichy/kosmo-galton/">gitlab</a> and run it there, too: <a href="https://aquarichy.gitlab.io/kosmo-galton">https://aquarichy.gitlab.io/kosmo-galton</a>
</p>
<p>Here are some random notes from the effort:</p>
<ul style="text-align: left;">
<li>Gitlab pipelines for to deploy pages only work on the default branch. I tried to work on my .gitlab-ci.yml file in a side branch and that didn't work. Oops.</li>
<li>
I had a path hard-coded in my Makefile that I didn't really want to expose, so I had some in git fun branching to its commit, editing, rebasing, and then clearing my reflog and doing some gc. :D<br />
</li>
<li>
Since typescript is available for npm, using the node:lts image that gitlab likes to suggest is great. Just need to do "npm install -g typescript" first.<br />
</li>
<li>Podman images: I played with a variety of Containerfile approaches to look at resulting image size. See below.</li>
</ul>
<h2 style="text-align: left;">
Containers<br />
</h2>
<p>I played around with single and two-stage Containerfiles. The point of two stage was to have typescript's tsc available to compile the code within a container, without needing to carry nodejs in the final image. In general I used Apache's httpd. </p><p>I appreciate that images are stored as layers and common layers are reused, so making use of, say, a 1GB container image (node) in 3 images of my own doesn't result in 3GB of additional disk space used. Still, I find it valuable to be conscious of space and memory usage, and minimizing unnecessary files when preparing and deploying software.</p>
<p>
Also, while I may "save space" by using smaller images, in this case, that results in extra network I/O and CPU time as I now end up needing to use dnf/microdnf/apk/npm to install nodejs/npm/typescript (depending on combination).<br />
</p>
<p>
Single-stage: <br />
</p>
<ol style="text-align: left;">
<li>
<b>httpd</b>: Pre-transcompile .ts into .js outside of the image; then use docker's httpd image and just add my HTML/JS/CSS files to it.
</li>
</ol>
<p>
Two stage (first compile ts; second deploy in Apache)<br />
</p>
<ol start="2" style="text-align: left;">
<li>
<b>fedora-minimal>httpd: First stage</b>, start with the <b>fedora-minimal</b> image from registry.fedoraproject.org, install its <i>typescript</i> using microdnf (pulls in node), transcompile .ts; second stage, start with httpd again and copy over transcompiled .js, and add HTML/CSS from outside of the image.
</li>
<li>
<b>node>httpd:</b> First stage, start with <b>node</b> image from docker, install <i>typescript</i> using <b>npm</b>, add and transcompile .ts; second stage like #2.
</li>
<li>
<b>alpine>httpd:</b> First stage, start with tiny <b>alpine </b>image from docker, add <i>npm</i> using <b>apk</b>, then install <i>typescript </i>with <b>npm.</b> The rest like #2 and #3.
</li>
<li>
<b>alpine>alpine:</b> First stage, same as #4 using alpine; stage two, start with <b>alpine</b> again, add <b>apache2</b> with <b>apk</b>, copy in HTML/CSS/JS as before, and add <b>CMD</b> to store httpd in the foreground (warning: dumb, simple configuration; not appropriate for real usage as is)
</li>
</ol>
<p style="text-align: left;">For base image sizes:</p>
<ul style="text-align: left;">
<li style="text-align: left;">docker.io/library/alpine: 7.63MB</li><li style="text-align: left;">registry.fedoraproject.org/library/fedora-minimal: 97.8MB</li>
<li style="text-align: left;">
registry.fedoraproject.org/library/fedora: 196MB<br />
</li>
<li style="text-align: left;">docker.io/library/httpd: 173MB</li><li style="text-align: left;">docker.io/library/node: 1.12GB</li>
</ul>
<p> For my intermediary and final images, I end up with:</p>
<style type="text/css">
table#oci_image_sizes tr td:nth-child(1),
table#oci_image_sizes tr td:nth-child(2),
table#oci_image_sizes tr td:nth-child(4),
table#oci_image_sizes tr td:nth-child(5) {
text-align: right;
}
</style>
<div class="overflow" >
<table id="oci_image_sizes" class="kosmo-table rotate-header" border="1" >
<thead>
<tr>
<th><div>Approach</div></th>
<th><div>Stage</div></th>
<th><div>Image description</div></th>
<th><div>Modified image size</div></th>
<th><div>Base image size</div></th>
<th><div>Note</div></th>
</tr>
</thead>
<tbody>
<tr><td>1</td><td>(n/a)</td><td>httpd</td><td>173 MB</td><td>173 MB</td><td>No notable change!</td></tr>
<tr><td>2</td><td>1</td><td>fedora-minimal + nodejs, typescript</td><td><b>332 MB</b></td><td>97 MB</td><td>nodejs + typescript add a lot</td></tr>
<tr><td>3</td><td>1</td><td>node + typescript</td><td>1.18 GB</td><td>1.12 GB</td><td>node image starts off big</td></tr>
<tr><td>4</td><td>1</td><td>alpine + npm, typescript</td><td><b>133 MB</b></td><td>7.63 MB</td><td>nodejs, npm and typescript adding a lot again</td></tr>
<tr><td>5</td><td>2</td><td>alpine + httpd</td><td>13.5 MB</td><td>7.63 MB</td><td>so tiny vs. the 173 MB httpd image!</td></tr>
</tbody>
</table>
</div>
<p>
This makes it worthwhile to tag and have a container with TypeScript set-up already. :) <br />
</p>
Richardhttp://www.blogger.com/profile/05999356523405056706noreply@blogger.com0tag:blogger.com,1999:blog-1271390300799121555.post-8984114214586675452023-09-05T20:17:00.002-07:002023-09-05T20:17:18.625-07:00[Technology] systemd timers and service files in place of cron<p>I keep a daily journal in an <a href="https://orgmode.org/">Emacs org-mode file</a>. Sometimes due to clumsy keypresses in Emacs, I have temporarily deleted (!) lines or sections (!). I think I have always caught these mistakes, but to be safe, I decided to create a git repository for it and do a daily commit.</p><p>In the past, I'd have used a cron job, but in recent years I've tried to make more and more use of systemd and timers. Is one better than the other? I'm going to ignore that question and proceed. :D<br /></p><p>For this task, which I'm calling "log_git_committer" (very uninspired), I have four files:<br /></p><ul style="text-align: left;"><li>log_git_committer.sh - a Bash script that handles actually committing changes</li><li>log_git_committer.service - a systemd service file that references the .sh file</li><li>log_git_committer.timer - a systemd timer file that implicitly references .service unit and describes the interval</li><li>Makefile - a simple make file to install and uninstall my files as I work on it</li></ul><p>Below are some of the more interesting notes from working on it, and the systemd files. <br /></p><h2 style="text-align: left;">Notes<br /></h2><p>Some notable pieces that came up:</p><ul style="text-align: left;"><li><b>.service: <br /></b></li><ul><li><b>Type=oneshot:</b> since I'm running this from a timer, I just want this service unit to be a "oneshot"<b>,</b> as it's not actually a service that would keep running in the background.<b><br /></b></li><li><b>ExecStart= and %h</b>: I'm installing the shell script locall in my ~/.local/bin directory. ExecStart in a .service won't accept ~/ or $HOME/ in a path, preferring absolute paths. However, systemd has some <a href="https://www.freedesktop.org/software/systemd/man/systemd.unit.html#Specifiers">specifiers</a> like %h that will substitute in a user's path when a service unit is run with --user. </li></ul><li><b>.timer:</b></li><ul><li><b>OnCalendar=:</b> it has a lot of options that are similar to cron. Neat. </li><li><b>retroactively running missed timers?</b> Yes, if I set a timer to run at 3AM but I put my computer to sleep at 1AM and turn it back on at 8AM, the timer will then execute. If I end up in Narnia and my computer is asleep for 3 days while I'm away (a lifetime there), it will then run the service just once to catch up. Nice.<br /></li></ul><li><b>Makefile: <br /></b></li><ul><li><b>unit file syntax checking: </b>systemd provides a command that lets you analyze your unit files to check for correctness. E.g.<br /><div style="margin-left: 40px;"><span style="font-family: courier;">systemd-analyze verify log_git_committer.timer<br />systemd-analyze verify log_git_committer.service</span><br /></div>so I added that to a target.<br /></li><li><b>systemd install directory: </b>for non-root user services and timers, the install directory is <b>~/.config/systemd/user/</b><br />Some other locations on my Fedora 38 system for systemd unit files include:</li><ul><li>/usr/lib/systemd/user/</li><li>/usr/lib/systemd/service/</li><li>/etc/systemd/user/</li><li>/etc/systemd/system/<br /></li></ul><li><b>systemd and reloading updated .service files: </b>if I make a change to a .service file, systemd would like me to reload the new one from disk. So, in my Makefile, after I copy .service and .timer files into their install directory, I call:<br /><div style="margin-left: 40px;"><span style="font-family: courier;">systemctl --user daemon-reload</span></div></li></ul></ul><h2 style="text-align: left;">log_git_committer.sh</h2><p>If there's interest, I can share this, but it's pretty simple and straight forward.</p><h2 style="text-align: left;">log_git_committer.service<br /></h2><p></p><blockquote><span style="font-family: courier;">[Unit]<br />Description=Commit changes to a log file<br /><br />[Service]<br />Type=oneshot<br />ExecStart=%h/.local/bin/log_git_committer.sh<br /><br />[Install]<br />WantedBy=multi-user.target</span><br /></blockquote><h2 style="text-align: left;"> log_git_committer.timer</h2><blockquote><p><span style="font-family: courier;">[Unit]<br />Description=Do a daily commit of the log file.<br /><br />[Timer]<br />OnCalendar=3:00:00<br />Persistent=true<br /><br />[Install]<br />WantedBy=timers.target</span><br /></p></blockquote><h2 style="text-align: left;"> Resources</h2><ul style="text-align: left;"><li style="text-align: left;"><a href="https://www.freedesktop.org/software/systemd/man/systemd.service.html">https://www.freedesktop.org/software/systemd/man/systemd.service.html</a></li><li style="text-align: left;"><a href="https://wiki.archlinux.org/title/systemd">https://wiki.archlinux.org/title/systemd</a></li><li style="text-align: left;"><a href="https://wiki.archlinux.org/title/systemd/Timers">https://wiki.archlinux.org/title/systemd/Timers</a></li><li style="text-align: left;"><a href="https://wiki.archlinux.org/title/Systemd/User#Basic_setup">https://wiki.archlinux.org/title/Systemd/User#Basic_setup</a></li><li style="text-align: left;"><a href="https://documentation.suse.com/smart/systems-management/html/systemd-working-with-timers/index.html">https://documentation.suse.com/smart/systems-management/html/systemd-working-with-timers/index.html</a></li></ul><p style="text-align: left;"> <br /></p><p></p>Richardhttp://www.blogger.com/profile/05999356523405056706noreply@blogger.com0tag:blogger.com,1999:blog-1271390300799121555.post-82201902722369607692023-09-05T19:00:00.002-07:002023-09-05T19:00:07.816-07:00[Technology] web development: TypeScript!<p>I used to be a snob about various technologies. Two decades ago, I hated doing web development with JavaScript, dealing with browser quirks and what felt like deficiencies in the base standard and browser client libraries. It felt like you couldn't write simple, safe and predictable code, especially without relying on a third party framework or library.</p><p>However, much has changed and I genuinely enjoy it now. I still often prefer to write code without third-party libraries or frameworks if I can afford to, but I have increasingly come to rely on <a href="https://www.typescriptlang.org/">TypeScript</a>. I value type checking <b>a lot</b>, especially as projects grow and APIs evolve. Managing types explicitly entails more work earlier on, but it also helps spare me from silly bugs and saves me time during refactoring or when revisiting code I wrote a while ago. </p><p>TypeScript works by transcompiling TypeScript (in .ts files) into pure JavaScript. Some of my favourite features include:</p><ul style="text-align: left;"><li>getting to set language standard targets in configuration. E.g. setting your target to "es2016" will mean the generated JavaScript will down-compile newer syntax into syntax that exists in ECMAScript 2016. (Note: this doesn't polyfill API functionality!)</li><li>easily defining interface types for simple objects with fixed property names<br /></li></ul><p>There's some effort to promote a native static type system in future ECMAScript, like this proposal: <a href="https://github.com/tc39/proposal-type-annotations">https://github.com/tc39/proposal-type-annotations</a>. I hope for this friendlier future.<br /></p>Richardhttp://www.blogger.com/profile/05999356523405056706noreply@blogger.com0tag:blogger.com,1999:blog-1271390300799121555.post-87949347986228079072023-09-03T16:04:00.003-07:002023-09-03T16:04:16.107-07:00[Technology] firejail: sandboxing with Linux namespaces<p>I am generally fairly wary of the amount of access software has on my computer. Consequently, I like to use <a href="https://firejail.wordpress.com/">firejail</a> on Linux to sandbox a lot of applications. E.g. am I playing a single-player game from <a href="http://itch.io">itch.io</a>? It doesn't need access to my mount points, my home directory (beyond the game's own directory for the program, game files and save data) or to the network. Sometimes I am stunned by how much trust I put into random software back in 1998<br /></p><p>It uses <a href="https://en.wikipedia.org/wiki/Linux_namespaces">Linux namespace</a> and <a href="https://en.wikipedia.org/wiki/Seccomp">seccomp-bfp</a>.</p><p>An example command of what I might use would be:</p><p></p><blockquote>$ firejail --net=none --disable-mnt --whitelist=/home/<span style="color: #800180;">myuser</span>/files/games/<span style="color: #800180;">game_title</span>/ ./<span style="color: #800180;">game</span>.sh</blockquote>Some common programs have pre-existing profiles defined by firejail, like firefox, and those can be found in /etc/firejail. In the case of firefox, one notable change is access to your home directory: it gets restricted to just your downloads folder!<br /><p></p>Richardhttp://www.blogger.com/profile/05999356523405056706noreply@blogger.com0tag:blogger.com,1999:blog-1271390300799121555.post-46515000179613248352023-04-24T16:33:00.006-07:002023-04-25T16:33:12.645-07:00[Technology] Blogger template: add back the edit button<div class="separator"><p style="margin-left: auto; margin-right: auto;"><img alt="" src="data:image/png;base64,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" /> <br /></p></div><p>Like poor Blogger user <i>User 7100044714607836407</i>, I have missed the <a href="https://support.google.com/blogger/thread/163404296/how-do-i-get-my-quick-edit-button-back">quick edit button</a> on newer Blogger templates. So I wrote a little snippet of JavaScript to bring it back.</p>
<h3>Differences:</h3>
<ul>
<li>Appears in the title instead of at the bottom.</li>
<li>Does not appear until you press ctrl-e.</li>
<li>In theory will show even when readers press ctrl-e, but of course they would still need to log in as you to actually get to the edit page.</li>
<li>Just uses the blog and post IDs already viewable on the page.</li></ul><ul>
</ul>
<h3>Code</h3>
<pre> window.addEventListener ("keydown", function (ev) {
if (ev.code == "KeyE" && ev.ctrlKey == true) {
let posts = document.querySelectorAll ("DIV.post-outer:not(.edit_link_added)") ?? [];
for (let post of posts) {
const blog_id = post.querySelector("meta[itemprop='blogId']").getAttribute ("content");
const post_id = post.querySelector("meta[itemprop='postId']").getAttribute ("content");
const post_title_h3 = post.querySelector (".post-title");
let edit_a = document.createElement ("A");
edit_a.href = `https://www.blogger.com/post-edit.g?blogID=${blog_id}&postID=${post_id}&from=pencil`;
edit_a.target = "_blank";
edit_a.innerText = "[✏]";
post_title_h3.appendChild (edit_a);
post.classList.add ("edit_link_added");
}
}
});</pre>Richardhttp://www.blogger.com/profile/05999356523405056706noreply@blogger.com0tag:blogger.com,1999:blog-1271390300799121555.post-17529595071594809002023-04-01T17:31:00.000-07:002023-04-25T16:38:15.572-07:00[Technology] Memento: estate possession distribution<p><a href="https://gitlab.com/aquarichy/kosmomemento/">gitlab.com/aquarichy/kosmomemento</a></p><p>A while ago, I lost a dear family member. It was a very challenging time, and a very important and heavy activity was helping box up their life, room by room. There were a lot of memories tied to the physical possessions, and it was hard to make decisions for them at the time, so off they went to storage.</p><p>It's been long enough that the beneficiaries need to make collective decisions as to the disposal and distribution of the possessions (storage isn't cheap!) So, as a fun personal project and an exercise in simple web development, I wrote Memento, which generates tables from a catalogue of photos to allow a group of people to vote on actions for each item. </p><p> As an example, imagine the beneficiaries are the characters from Scott Pilgrim vs. the World and the possessions are heirloom doughnuts that had been scattered across a couple cities (rather than rooms):<br /></p><p></p><p><a href="https://gitlab.com/aquarichy/kosmomemento/-/raw/master/doc/dark%20room%202.png"><img alt="https://gitlab.com/aquarichy/kosmomemento/-/raw/master/doc/dark%20room%202.png" class="shrinkToFit transparent" src="https://gitlab.com/aquarichy/kosmomemento/-/raw/master/doc/dark%20room%202.png" style="width: 518px; height: 640px;" /></a> </p><p>If you find this and find it useful, or are interesting in using it and need some help setting it up, let me know.<br /></p>Richardhttp://www.blogger.com/profile/05999356523405056706noreply@blogger.com0tag:blogger.com,1999:blog-1271390300799121555.post-76268620365593508272022-11-17T05:05:00.000-08:002023-04-19T02:47:47.959-07:00 [GNOME] GNOME Files and custom file icons: setting a cute 2x2 image preview for photo albums<p>Update: credit to David in the comments of my previous post, there's a much fancier implementation of this here: <a href="https://github.com/flozz/cover-thumbnailer">https://github.com/flozz/cover-thumbnailer</a></p><p>Going further in my delight at belatedly discovering the "metadata::custom-icon" GVFS attribute used by Nautilus, I extended beyond <a href="/2022/11/gnome-gnome-files-and-custom-file-icons.html">just music album covers</a> to write a script that did a fun 2x2 grid for photo album covers. <br /></p><p>From this:<br /> <br /> <img src="https://kosmokaryote.org/images/GNOME Files custom icon photo album.1.before.jpg" /><br /> </p><p>To this:</p> <img src="https://kosmokaryote.org/images/GNOME Files custom icon photo album.2.after.jpg" /><br /> <br /> <hr /><br /> This script is uglier, so maybe write your own, but you can have a look-see to see what I did. I learned some new syntax for ImageMagick in the process (using ^ when scaling to treat the geometry as a minimum rather than a maximum, using "-gravity center" to crop from the center, etc.), <br /> <br /> <pre>#!/bin/sh
# Run in a directory containing photo album folders. Will generate 2x2 grid thumbnail images of photos within, and set them as the
# folder icon. (Recurses down through all subfolders.)
# set GVFS attribute "metadata::custom-icon"
# e.g. gio set /path/to/album/dir "metadata::custom-icon" "file:///home/USER/files/music/ARTIST NAME/ALBUM NAME/cover.jpg"
# to reset it:
# gio set /path/to/album/dir "metadata::custom-icon" -d
function crop {
FILE="${1}";
DIM="${2}"; # e.g. "200x200"
# scale so that the min-dimension is 200 (we'll crop out whatever exceeds it in the max dimension)
# so if we're given an 400x1000 photo here, we'll scale it to 200x500, thanks to ^
convert "${FILE}" -scale "${DIM}+0+0^" "${FILE}.scaled";
# crop a 200x200 square from the center, so if we have a 200x500, we'll lose the top and bottom 50
convert "${FILE}.scaled" -gravity center -crop "${DIM}+0+0" "${FILE}.cropped"
# now we have a nice 200x200 version, centered
# emit the name of the newly cropped file
echo "${FILE}.cropped";
}
# provide a '-f' option to regenerate existing photo album covers; by default, it skips dirs where one already exists
if [ "${1}" == -f ]; then
FORCE=1
else
FORCE=0
fi
find ./ -type d |
while read DIR; do
# skip . hidden directories
if basename "${DIR}" | grep "^\."; then
continue;
fi
echo "${DIR}...";
# check if a generated photo album already exists and skip redoing it (unless -f set)
if [ -f "${DIR}/.npac_cover.jpg" ] && [ "${FORCE}" -eq 0 ]; then
echo " Already generated, skipping (use -f to force regeneration)";
continue;
fi
# create a temporary directory to do image cropping and stitching in
TMPDIR="$(mktemp -d)";
# find 4 images below dir for potential thumbnailing; use 'sort -R' to randomize the list
find "${DIR}" -regextype egrep -iregex ".*\.(jpg|jpeg|png|webp)$" |
sort -R |
while read COVER_PART; do
# because I sometimes have duplicate files for various reasons, and
# I don't want an image repeated, I work with them using their hash
HASH="$(md5sum "${COVER_PART}" | cut -b 1-32)";
if ! [ -f "${TMPDIR}/${HASH}" ]; then
echo " ${COVER_PART}";
cp "${COVER_PART}" "${TMPDIR}/${HASH}.part"
fi
if [ "$(ls "${TMPDIR}" | wc -l)" -ge 4 ]; then
break;
fi
done;
# lets create a 2x2 grid of 4 images, but also support fewer if necessary
(
cd "${TMPDIR}";
NUM_PARTS="$(ls | wc -l)";
P1="$(ls | head -n 1 | tail -n 1)";
P2="$(ls | head -n 2 | tail -n 1)";
P3="$(ls | head -n 3 | tail -n 1)";
P4="$(ls | head -n 4 | tail -n 1)";
if [ "${NUM_PARTS}" -ge 3 ]; then
# stitch the first two together side-by-side for the top half of a 3 or 4 grid
convert "$(crop "${P1}" 200x200)" "$(crop "${P2}" 200x200)" -background black +append "top.jpg"
if [ "${NUM_PARTS}" -ge 4 ]; then
# stitch two together for the bottom, then stitch top and bottom together for the grid, yay
convert "$(crop "${P3}" 200x200)" "$(crop "${P4}" 200x200)" -background black +append "bottom.jpg"
convert "top.jpg" "bottom.jpg" -background black -append "grid.jpg"
elif [ "${NUM_PARTS}" -eq 3 ]; then
# only have 3 images, so make the 3rd one take up the whole bottom
convert "top.jpg" "$(crop "${P3}" 400x200)" -background black -append "grid.jpg"
fi
elif [ "${NUM_PARTS}" -eq 2 ]; then
# only have two, so stack them vertically
convert "$(crop "${P1}" 400x200)" "$(crop "${P2}" 400x200)" -background black -append "grid.jpg"
elif [ "${NUM_PARTS}" -eq 1 ]; then
# only have one, so it'll be the whole grid!
cp "$(crop "${P1}" 400x400)" grid.jpg
else
echo "WARNING: nautilus_photo_album_cover.sh: no images found for dir '${DIR}' in tmpdir '${TMPDIR}'.";
fi
)
# if we successfully generated a grid of images, copy it to the photo album dir as a
# hidden thumbnail image (.npac_cover.jpg), set "metadata::custom-icon" in GVFS, and then remove the temp dir
if [ -f "${TMPDIR}/grid.jpg" ]; then
cp "${TMPDIR}/grid.jpg" "${DIR}/.npac_cover.jpg"
gio set "${DIR}" metadata::custom-icon "file://$(realpath "${DIR}/.npac_cover.jpg")";
rm -rf "${TMPDIR}"
fi
done
<br /> </pre><br /> <br /> <hr /><br /> <p>To do:</p> <ul><li>Add a cute folder emblem to the bottom right of the 2x2 icons, and maybe put a border around it, to make it more obviously still a folder!</li> <li>It fails on some folders for some reason, look into it :D</li> <li>Correct orientation issues</li><br /> </ul><br /> Richardhttp://www.blogger.com/profile/05999356523405056706noreply@blogger.com0tag:blogger.com,1999:blog-1271390300799121555.post-86633098571225886092022-11-16T21:48:00.000-08:002023-04-25T16:38:35.916-07:00[GNOME] GNOME Files and custom file icons: setting album art on directories!<p>Update: credit to David in the comments, there's a much fancier implementation of this here: <a href="https://github.com/flozz/cover-thumbnailer">https://github.com/flozz/cover-thumbnailer</a></p> <p>While playing with GNOME 43 on my recent upgrade to Fedora 37, I saw that nautilus aka GNOME Files lets me set arbitrary images as a custom icon for files and folders, replacing the default icon/thumbnail. (The support for "metadata::custom-icon" has apparently been around for a while already.)<br /></p><p>I quickly hopped into my music folder and wrote a small script to replace all of the (legally purchased) folders of albums of music's icons with images of their album art if an image was already present.</p><p> My Camera Obscura band's folder of albums went from this:<br /></p><p><img alt="" src="https://www.kosmokaryote.org/images/GNOME Files.custom icons.Camera Obscura albums.1.before.png" style="width: 640px;" /></p> <p>to this</p><img alt="" src="https://www.kosmokaryote.org/images/GNOME Files.custom icons.Camera Obscura albums.2.after.png" style="width: 640px;" /><br /> Cool! <hr /><br /> The quick code:<br /> <br /> <pre>#!/bin/sh
find ./ -type d |
while read DIR; do
if basename "${DIR}" | grep "^\."; then
# skip . directories
continue;
fi
echo "${DIR}...";
touch /tmp/.naa.coversearch
# ranked cover options by preference, as some dirs have multiple;
# break after we find highest one
echo "front.(jpg|png)
cover.(jpg|png)
[Ff]older.(jpg|png)
box.jpg
album\-[0-9a-f]+\-[0-9a-f]+\.jpeg" |
while read COVER_PATTERN; do
# echo " ${COVER_PATTERN}...";
find "${DIR}" -regextype egrep -regex ".*/${COVER_PATTERN}$" |
head -n 1 | # grab first and go
while read COVER_RELPATH; do
rm /tmp/.naa.coversearch # we found a cover, end search
echo " found cover ${COVER_RELPATH}!";
COVER_ABSPATH="$(realpath "${COVER_RELPATH}")";
gio set "${DIR}" metadata::custom-icon "file://${COVER_ABSPATH}"
done
# if we're not still searching, skip other patterns and go to next dir
test -f /tmp/.naa.coversearch || break
done
done </pre><br /> <hr /><br /> For the curious, I purchased a lot of legally-licensed, DRM-free music through eMusic back in the day, before streaming took over everything. I still purchase CDs as merch at shows sometimes, and then extract those to OGG Vorbis (sorry, not FLAC). Sometimes, I still open up Rhythmbox and play actual files, ooo.<br /> <h4>To do:</h4> <ul><li>corner folder icons: Generate album folder thumbnails that have a little folder icon in the bottom corner still, so I can tell that it's still a folder</li> <li>artist custom icons as potential grids: My folder structure is artist/album/track.ogg. So right now, the artist folder also acquires the first album cover it finds. If an artist has multiple album covers available, I want to do a small grid of up to 2x2.</li> <li>photo albums: do something similar for photo albums folders.</li></ul> Richardhttp://www.blogger.com/profile/05999356523405056706noreply@blogger.com0tag:blogger.com,1999:blog-1271390300799121555.post-19057214278051179162021-06-22T02:43:00.000-07:002023-04-19T00:17:52.697-07:00[Technology] Issues I have with the web<p>Following my last post, I'll highlight some issues I have:</p><ul style="text-align: left;"><li>infinite scroll and chunking<br /></li><li>see once and disappear</li><li>approximate, imprecise linking (e.g. Facebook comment highlights)</li><li>inefficient web design (facebook's emphasis on big images in posts)</li><li>transient content (considerations for privacy, vs. value of permanence)</li><li>opaque and obscure web structure</li><li>sharing information via screenshot</li><li>copyright holder abuse of fandom (Sailor Moon Says)</li><li>cyclic reinvention; e.g. messaging + voice/video</li><li>search-first over organization, and low discoverability <br /></li><li>poor support for attribution (Pinterest is the devil)</li><li>dynamic articles <br /></li><li>infinite privacy leaks and lacklustre permission control</li><li>challenges managing large volumes of information and making a profit</li><li>the stupid disorganization of ecommerce <br /></li></ul><h4 style="text-align: left;">infinite scroll and chunking</h4><p style="text-align: left;">The example that annoyed me most recently was opening the comment section of a Facebook post in my mobile web browser. There were several hundred comments. I did indeed want to load The Whole Comment Section. Instead, they just allowed me to load like 20 comments at a time. This really wastes my time and gives me a very fragile context. It doesn't take much to lose your context on mobile devices; e.g. a message comes in, so you switch to that messenger to reply, and you have like a 50/50 chance of your app/web browser's state being preserved (yay) so you can resume where you left off, or of having it reset (aggressive efforts to conserve memory, I guess), and losing your context (potentially "irretrievably"). </p><p style="text-align: left;">This is part of what annoys me about infinite scroll. If I'm interrupted, and my app/page has its state reset, I've totally lost the context in which I was, and my new context is likely different (with new content appearing and old viewed content disappearing). </p><p style="text-align: left;">Some sites are better at this than others. reddit breaks things up by pages and encodes references to anchor where you are in a collection of posts. Twitter is awful; once I've passed a tweet, there's a good chance I'll never find it again.</p><p style="text-align: left;"><b>see once and disappear</b></p><p style="text-align: left;">I noted Twitter above, but I use Facebook more and this is a huge pain point for me. Once I've viewed something, if I lose context, it might be gone forever. A common problem is a friend will share a link when I'm viewing on mobile; I open the link and read a decent article and by the time I'm done, I don't recall who shared it. When I switch back to Facebook, it has now reloaded the app/browser tab! I have no idea who shared it now! My workaround is to pre-emptively like posts, so that at least I can go to the buried Activity History in settings (my interface is in German, so I'm not sure what it's called in English), and see what posts I last liked. Ideally, there'd be some section that showed you which posts you had read chronologically, so you can always go back a bit. </p><h4 style="text-align: left;">approximate, imprecise linking (e.g. Facebook comment highlights)</h4><p>This baffles me slightly. Facebook's feed will often highlight a post and in particular a comment made by a friend on the post. In theory, I should be able to click on the comment they've surfaced, and it should take me to the comment section for that post <i>opened</i> <i>to that comment. </i>Perhaps that now works on the app, though I no longer use the app. It used to not, and it still does not on the mobile website, which is very frustrating. </p><p>Rather than taking me to the indicated comment, it just takes me to the top of the comment section. For a busy post with hundreds of comments, combined with Facebook's inability to actually load all the comments for me in a direct manner (thanks, chunking), means that it can be nearly impossible for me to actually interact with my friend's activity on the post.</p><h4 style="text-align: left;">inefficient web design (facebook's emphasis on big images in posts) </h4><p style="text-align: left;">Presumably this somehow helps keep users engaged? I find it disrespectful to my time and just an unpleasant experience. I would appreciate a <i>much more</i> compact interface, so I can easily browse recent activity, choose what I want to interact with, and then drill down into that. Instead, on my phone, each post in my feed now takes up almost my full screen. If someone has shared a link, they always find some image to use a preview that I don't want. On my laptop, I can often see 2 posts. Also, I'm unsure, but it feels like Facebook might be more likely to promote lengthier posts or posts with images/links in my feed, than more concise posts, which is very unfortunate, as I often care more about actual updates/questions by friends.</p><p style="text-align: left;">My inability to use Facebook and some similar sites efficiently is one of the main reasons why I don't use them much anymore. It just feels overwhelming and frustrating to use. <br /></p><h4 style="text-align: left;">transient content (considerations for privacy, vs. value of permanence)</h4><p style="text-align: left;">This is really killing me recently. I think Instagram's app now defaults new posts to be stories. I hate stories. Stories disappear after 24 hours. I hate this because it disrespects me and my time. It bullies and pressures me into using the app at least twice a day if I'm interested in actually keeping up with my friends' activity. </p><p style="text-align: left;">Some of the possible benefits to Instagram are having to store less information (but I think they might actually store them beyond 24 hours, visible to just the original poster?), possible increase in privacy (less easy to be haunted by your old activity if it's mostly ephemeral), possibly encourage people to interact with the app more (besides bullying people into using it at least once a day to not miss content, perhaps the limited time that your content is up encourages people to then add new content often, and encourage them to share fleeting thoughts and content that they never would consider giving a permanent home to?). </p><p style="text-align: left;">A more controversial view on it relates to activism over transient social media (so including Snapchat and Facebook Stories and Instagram Stories). For some reason, when issues get attention like Wet'suwet'en, BLM, Palestine, etc., people love to post important content ... in a format that will just disappear in 24 hours? I sometimes wonder if a platform encouraging transience in group discourse like that is a strategy to limit politicization of the platform. E.g. a number of friends of mine quit using Facebook because the dominant content grew too depressing for them, and they moved to Instagram/Snapchat/Tiktok.</p><p style="text-align: left;">A decade ago, I feel like it was common to say "nothing truly is gone once it's online". But now I think it's the opposite. Things rarely persist online. Even the general web. 5 years ago, I feel like I used to be able to search certain topics like ICON computers used in Ontario in the 1990s, and I could find hundreds of references. 10 years ago I could google my old elementary school (since demolished) and still find photos of it online. Now I actually can't! Platforms like GeoCities have gone away. Google Cache is just not available for a lot of sites anymore. Efforts like the Wayback Machine are woefully incomplete - almost every time I turn to it, I am disappointed. Sigh.</p><p style="text-align: left;">Somewhat disturbingly is the intentionality behind part of it. In Europe, some people advance a "right to be forgotten" which I find disturbing as it gets used by some bad actors in society to cover up their misdeeds and escape accountability. I am actually in favour of obliging content creators and hosts to correct inaccurate information (e.g. if I was falsely accused of a heinous crime and was cleared, I'd like to oblige hosts to correct that; but I wouldn't want to actually entirely erase the whole affair; it would be worthwhile that the original false accusations were still a matter of record). <br /></p><h4 style="text-align: left;">opaque and obscure web structure</h4><p style="text-align: left;">This kills me, and it's a somewhat niche problem. As a computer programmer, I have opportunities to improve my user experience by making my own modifications to the sites I use. I can write custom style sheets, GreaseMonkey scripts, bookmarklets and extensions to adapt a website's presentation and functionality to better suit my needs.</p><p style="text-align: left;">However, for various reasons, websites make it increasingly hard to work with their websites in interesting ways. Few websites have what I'd consider a stable "API" or even a human-friendly unstable one. In particular, CSS classes are all unsemantic, obfuscated nonsense on the user's end, making it a challenge to properly select elements to do interesting manipulations to a page, like converting all dates to a sane Y-M-D format. </p><p style="text-align: left;">As an example: Since I fell in love with my favourite T.V. show ever, She-Ra and the Princesses of Power (Netflix 2018), I've started collecting a lot of media related to it. It's really important to me when collecting that, or memes, or just whatever, that I be able to accurately attribute authorship, the source (e.g. platform), the date-time it was created/found, etc. Consequently, if I'm going to save a piece of fan art or fan fiction, I like to have a bookmarklet to pop up the key info (e.g. creator username, date-time posted, platform) so I can include it in the saved filename. However, each website makes it a pain to identify the elements holding those. </p><p style="text-align: left;">Authorship attribution in general is a failure of the modern web that makes me very sad, given the power we have to do better. Pinterest and reddit are good examples of failures there.<br /></p><h4 style="text-align: left;">sharing information via screenshot</h4><p style="text-align: left;">This kills me as well. The dominant way people seem to share textual information around me now is by screenshot. I can see some appeal to that; it appears literally exactly as the person first encountered, possibly exactly as the author had hoped it would appear. However, it also makes it nearly impossible to work with. You can't easily translate it (though machine translation tools actually are working fairly well with image text; but even on Android with the amazing Google Lens, it's still extra steps and more friction and a new, unnecessary risk for error). You can't easily cut/copy/paste. You can't easily <b>search</b> it. It wastes space and bandwidth (an image of text is often many more bytes than just the text itself). </p><p style="text-align: left;">It's doubly bad because this intersects with transient sharing. So many Instagram stories of interest: if I want to preserve what I'm seeing, I have to screenshot it! I can't copy/paste it anymore. I can't save a permalink to the story (since it will just disappear shortly). I end up with dozens/hundreds/thousands of poorly-organized screenshots of interesting/important stuff in a folder on my phone. It's hard to follow-up on, and it's infuriating. </p><p style="text-align: left;">It feels as time goes on and the Internet "evolves", information is becoming less accessible and more opaque. I guess there are some benefits to that, but that depresses me.</p><h4 style="text-align: left;">copyright holder abuse of fandom (Sailor Moon Says)</h4><p style="text-align: left;">An on-going issue with the web is the abuse by copyright holders of fair usage by fans. What kills me about this is when a copyright holder attacks an activity that directly benefits the copyright holder.</p><p style="text-align: left;">I'm quite enjoy the Sailor Moon anime, despite the variety of issues it carries. I think it's very reasonable for the copyright holders to go after streaming sites that host entire episodes online, when the copyright holder has ensured there is a "reasonable" means to access the content legally. But in this example, there has been a very popular YouTube channel called Sailor Moon Says that has hosted hundreds of amazing, amusing, entertaining short clips from the series. This has been an amazing resource for fans to revel in the show that they love and commiserate over so many great moments. However, last week YouTube removed the channel due to alleged copyright violations. </p><p style="text-align: left;">Part of my complaint is how easily unfair complaints make it through a platform's reporting process to unfairly penalize fan activity (I wish YouTube had the capacity to give better review and had a greater interest in defending users), but the other part of my complaint is the readiness with which companies attack their customers and fans. Like, please stop undermining your own communities. <br /></p><h4 style="text-align: left;">cyclic reinvention; e.g. messaging + voice/video</h4><p style="text-align: left;">This makes me feel dead inside. It's another failed promise of technology and its evolution. I'm going to pick on messaging + voice/video chat. NetMeeting, MSN Messenger, Windows Live Messenger, Skype, Teams. Google Talk, Gmail Chat, Google Hangouts, Google Duo, Google Allo, Google Chat + Meet. iMessage, Facebook Messenger, WhatsApp, Instagram Direct/Chat, Telegram, Snapchat, Signal, etc. I'm fine with multiple approaches competing against each other, especially from different vendors. But what feels stupid is the repeated reinvention of the same tools, and re-living the growing pains each time. </p><p style="text-align: left;">I'm sure there's value in it. Older approaches had limitations and newer approaches hope to avoid those (while discovering new ones). It's just exhausting, because each time a new approach starts and matures, users have to relive the the associated growing pains. And we end up with a ecosystem of dozens of "solutions" that don't interoperate, forcing us to split ourselves and our attention across multiple platforms, complicating the management of our lives and communications.<br /></p><p style="text-align: left;">I am so grateful for e-mail. A standard format that different providers all (mostly) interoperate well with. Shame on those who seek to replace it. Especially with proprietary, closed solutions.</p><p style="text-align: left;">I really loved communications technology, back when the big question was XMPP/Jabber vs. SIP. I had so much hope and optimism when most of the leading chat networks were switching to XMPP, including facebook Messenger, Google Talk, maybe AIM? What killed that? I remember a lot of fuss over adding voice/video on top. Maybe that was the problem? Jingle. SIP. Eventually people were trying to add their own proprietary extensions. Next they just gave up and went with their own private protocols. Was it just depressing business decisions, "why interoperate when we can try to lock people into our platform?!"<br /></p><p style="text-align: left;">Perhaps the open solutions at the time were just ultimately inadequate to enable the rich experiences communications providers strived for. The fact that friends keep pressing me to install creepy apps that overreach for access on my phone, though, will continue depressing me. </p><p style="text-align: left;">I really wish I just had one app with an interface that suited me.</p><h4 style="text-align: left;">search-first over organization, and low discoverability</h4><p style="text-align: left;">I'm going to pick on Windows and modern messengers for this one. Back in my day, it felt easy for me to browse and discover my operating system to understand what it was capable of, in part because of an imposed organization. I could go to the Start Menu, and programs were pre-sorted into categories! It was amazing. Now on operating systems or my phone, if I pop open the list of available apps, it's a disorganized grid, often sorted alphabetically or (for better or worse) recency (where I lose positional context as things keep shifting around as I use them). Windows settings and configuration experience feels like a mess; there are often multiple views into the same settings, and the different views have different capabilities. Control Panel/Settings feels like a war between the old paradigm (kept around to keep older users happy and for eternal backwards compatibility) and a desire to have a "fresh new approach" which centres search. </p><p style="text-align: left;">My issue with search-first is that you need to already know something exists or might exist to know to search for it! If you're not aware that something is possible or may exist, you can only find it via search by dumb luck. When things are categorized, and potentially with a hierarchy, you now have a space in which you can browse and explore and discover what's possible. I'm pretty happy with my settings on, say, Fedora Linux, and how they're organized in GNOME's control centre. I'm a bit less happy with the settings on Android and Firefox - in part because of that earlier problem of cyclic reinvention. Re-designing your settings and re-arranging where they're found is incredibly painful when you're forcing users to relearn how to use their devices every 2 years. Firefox's settings in particular are also becoming very space inefficient, which is making them exhausting to navigate. </p><p style="text-align: left;">The other area where I'm really hating search is in messaging apps. When they have it. Back in my day, a lot of chat histories/logs were well-organized by date. In some messaging programs, I was able to easily navigate by year, month, day. I could also do an actual, proper search against the text. Facebook Messenger, despite having hundreds of millions of users, is abysmal at this. My two ways of accessing old messages are: infinite scroll (which is horrible, as incoming messages will kick me back down to the bottom, and which suffers from that small chunking problem from before), plain incomplete search results, and no way of selecting by an actual date/range. </p><p style="text-align: left;">I actually will use the Facebook Download tool to export my messaging history to my computer, and then just use grep to locate what I need. This can take some more time, but is reliable and successful. I am still stunned that I can search for keywords that are <b>definitively</b> present in a conversation's history, and Facebook just simply doesn't find them. <br /></p><h4 style="text-align: left;">poor support for attribution (Pinterest is the devil)</h4><p style="text-align: left;">I am so depressed by this. Earlier I cited my keen enthusiasm for the new She-Ra. I'm a member of several online communities for it. One of the most frustrating things is that people will post fan art they like to Facebook groups or their Instagrams, <i>without actually attributing the artist</i>. Sometimes it also creates an implication that the poster is the actual creator, when they're not. Thanks to Google Image Search, I can do a reverse search and often track down the original and identify the artist to give them credit in a comment. A lot of users are reluctant to put in effort to identify and credit an artist, despite appreciating their work, which feels pretty disrespectful to me. </p><p style="text-align: left;">In the header, I specifically pick on pinterest. This is in part because when I do a reverse Google Image Search on an image, I invariably find 90% pinterest hits of people who have all saved the same image to their pinterest, and 99% of them have added no context at all. This is much worse than on other platforms that have common attribution issues like Facebook and Instagram. For She-Ra, reddit's SPOP community is actually fairly decent at crediting the artist (wow, given how horrible the rest of reddit is at attribution). Tumblr and Twitter actually come out on top, in part because of how their platforms work, with reblogging and retweeting and quote retweeting actually linking directly to the original post (yay). </p><p style="text-align: left;">Besides having pinterest burn to the ground, something I'd love to see is better, more durable embedding of authorship metadata. I know some creators actually <i>don't</i> really want identifying information of theirs to be associated with their works. I guess I wish all image/content creation tools more prominently emphasised addition of metadata to images/content (e.g. like how metadata is an important part of music files), and that image/content viewers more prominently displayed it (and not just hiding it behind some properties panel). I also wish the image transformation tools were more biased towards to preserving metadata (e.g. when cropping/resizing an image and exporting to JPEG, I'd love it if the original authorship metadata carried over by default). I also wish that when saving media from websites, web browsers would embed the originating URL into the image metadata (!), possibly along with a timestamp (!). </p><p style="text-align: left;">My craziest desire connects to my problem above with the use of screenshots to share information. I kind of wish that a screenshot process was intelligent enough to identify the elements on screen that had metadata, that the screenshot would <i>aggregate</i> that metadata and associate it to their relevant region of the screenshot (!). I see risks to privacy with this, but as an example: if you took a screenshot of several overlapping windows open, one with a photo, one with a piece of fan art, one with a Word document, one with a PDF, and one with a song playing), I'd want the screenshot to have multiple metadata records for each of those items it captured. I want to be able to look at a screenshot and hover the piece of partially fan art captured in it, and be able to tell who its author was, and the datetime the fan art was created (as recorded in the original image). Similarly with the author and title of the Word document, etc. There's a definite problem of people inadvertently capturing information they don't want to share, though, so this isn't that simple of a solution. </p><p style="text-align: left;">I'd also really like it if some of the larger web companies actually supported content registries, where creators could register content they had produced as theirs, similar to how Content ID works in YouTube. As an artist, I'd like to be able to upload copies of my work registered to me. Then, a user could encounter some of my work (perhaps a screenshot of it, or a re-compressed version, that isn't bit-identical), and the registry would ideally work in such a way that it could identify close matches. This somewhat bypasses the data-heavy approach I dream of with metadata, putting the onus on, say, the web browser or image viewer to maybe generate a representative digest of the media I'm curious about and match it in a registry. </p><p style="text-align: left;">Regarding reddit in particular, there's a large incentive somehow for people to farm karma with others content. People will knowingly repost content that was never there's, and sometimes wilfully conflate themselves with the original artist. I'd really enjoy it if reddit posts actually had a feature to add a link back to a source and an author. Also, to deny a poster the benefit of karma accrued on a post if it is not their content. E.g. if they're reposting someone else's original post from 2 years ago, I would like upvotes on the new post to go to the original user's profile if still active.</p><h4 style="text-align: left;">dynamic articles</h4><p style="text-align: left;">This isn't actually a great way to describe them. However, I'll try to explain. When you click on an article at a site, and reach the bottom, and suddenly you're scrolling to a new article, endlessly. Or you're in an article, and a lot of sections unrelated to article proper dynamically interweave themselves into it, similar to advertisements but actually just content from the same site. E.g. you go to read a story about a new video game and after two paragraphs down there's a video ... not for that video game, but from a feature story on some other game or even a film. This happens with general news sites a lot, too. I guess it's an attempt to grab the reader to keep them pulled in. They're reading one story, and you want to keep their attention so you keep highlighting other stories too. </p><p style="text-align: left;">I hate this. It's so disruptive and aggravating. I avoid entire websites due to these practises. I used to really love Kotaku. Besides decent coverage on actual news, they also spent a lot of time adding value to their reporting by considering human and social impact atop the facts. Now it is unreadable. Pages load painfully. The dynamic content (videos from other featured stories, partially loading comment sections, other article pages connecting when I scroll past the end) including the abusive volume of advertisements, creates jerky pages where content keeps shifting as I scroll. Perhaps their greatest sin is splitting up lists like this</p><ul style="text-align: left;"><li>list item header 1<br /></li><li>big advertisement</li><li>list item content 1<br /></li><li>list item header 2</li><li>big advertisement</li><li>list item content 2</li><li>...</li></ul><p>The humane way of interleaving advertisements would be to be between list items, not breaking up an item between its header and content. Presumably they feel like having ads humanely placed would just make it easy for a reader to subconsciously ignore the ads, and just look at the space in between. But now they've annoyed me so much and made trying to read it so hard, that I just avoid their site and don't look at any of their ads at all. The "ads breaking up content" is doubly frustrating when the content is actually images, so if you basically have an image caption (the header) separate from the image itself, by another, unrelated image (the ad), and the cognitive dissonance in trying to associate the header/caption with which image is supposed to be the content gives me a headache.</p><h4 style="text-align: left;">infinite privacy leaks and lacklustre permission control</h4><p style="text-align: left;">My mind is blown by the state of privacy, security, and application distribution. Privacy abuses by app developers are rampant. Systems like Android provide APIs that help reveal the type of access that an app intends on having, which is kind of nice. You can review it. But if you don't like it, there's little you can do about it. Why does this GPS-powered compass need access to my network connection and microphone?! There is some limited ability to control these, but it's laughably limited. At one point I remember having the option to revoke some permission only after I would install an app - so the app once installed would happily have several/dozens of seconds from installation to when I could "successfully" revoke permissions, to siphon my precious private data off to their servers. Huh?</p><p style="text-align: left;">Really, the model I want is a) for an app to access any information or context outside of itself, to go through a controlled API, and b) to be able to - at the time of installation - choose whether I want to allow it real access to that service/information, a limited/virtual access, or no access. E.g. an app to backup texts requests access to external storage and network connections. I may want to say yes to the former and no the latter. I'd rather have an app potentially crash from unexpectedly getting no/fake access to a network, then to have to implicitly trust it.</p><p style="text-align: left;">I'm sometimes stunned that desktop/laptop computer OSes went so long with such poor control over resource access. It blows my mind how trivial it has always been for a simple "benign" utility to get installed, and instantly pop open a network connection to receive remote commands or exfiltrate sensitive data. I rely on a network of trust on Fedora Linux, where I have to hope that the volunteer community of packagers and open source projects maintainers are sufficiently trustworthy, helped in part by the open source nature of their work. There are still regular failures (e.g. an open source application, Node.js dependency, or browser extension gets "bought" by a bad actor who then adds malicious code :\), but it's still somewhat better than the closed source "hip new camera filter app" on the app store gaining 100,000 downloads with ridiculously unsavoury permission requirements. </p><p style="text-align: left;">I'm grateful that Flatpak and Firejail are trying to do a better job of isolating programs from resources to control risk, but there's still a long way to go.<br /></p><h4 style="text-align: left;">challenges managing large volumes of information and making a profit<br /></h4><p style="text-align: left;">I understand that a lot of what I hate about modern web design is driven by the challenges of managing large volumes of information that people <i>mostly </i>just want to consume briefly and move on. But these choices still make using a lot of services nearly miserable and present a continuingly failed promise.</p><p style="text-align: left;">I also understand that service providers have real costs, and have real aspirations to grow and evolve, and to do so in our capitalist society, they need to generate a meaningful profit. Which generally means advertising. I'm not fully opposed to being advertised too, nor am I opposed to personalized advertising. In fact, I am very grateful when I see advertisements that actually pertain to my interests, rather than generic ones that are sometimes downright offensive. (The web should know well enough I'm a vegan by now, so please stop advertising meaty dishes at restaurants to me.)</p><p style="text-align: left;">I do wish advertising networks also just gave me more direct control. I would really love to be able to actually register some of my interests with them, and some of my disinterests. Also, advertising fails in a big way with tunnel vision. I do a single search for a record player, and suddenly I see ads for that same record player all week everywhere I go. What they're getting wrong: if I already bought that record player, I do not want to see more ads for it. Advertising something I've already bought to me is wasted advertising opportunity. If I have not already bought it, then there are two likely reasons: I didn't like the price, or I didn't like that specific product though I wanted something in its class. I'd really appreciate it if advertisements would focus on trying to actually match me with a better deal (I'm looking at you, 2TB SSDs), or a better version of that product (it took me a long time of searching myself to find the air conditioner I wanted, with advertisers missing out by just showing me ones I'd already looked at and passed on already). </p><h4 style="text-align: left;">the stupid disorganization of e-commerce</h4><p style="text-align: left;"><span style="font-weight: normal;">How does anyone ever manage to successfully buy anything from Amazon? For such a massively successful company, I remain perplexed by how unusable it is almost every time I go to use it. Some common issue:</span></p><ul style="text-align: left;"><li><span style="font-weight: normal;">I go to search for an item on amazon.com and find it but they do not ship to Canada</span></li><li><span style="font-weight: normal;">I search for it on amazon.ca but they do not have it (it's only on amazon.com)</span></li><li><span style="font-weight: normal;">I find it on amazon.ca, but it's at a Much Worse Price than amazon.com. </span></li><li><span style="font-weight: normal;">My specific, explicit search terms pull irrelevant results (HOW?!)</span></li><ul><li><span style="font-weight: normal;">e.g. I search for a "2TB SSD" and the results are muddled with irrelevant results for 2TB HDDs (where the product page doesn't reference SSD at all) or 1TB SSDs (where the product page doesn't reference 2TB at all). I'm guessing some sellers are somehow stuffing references in somehow to appear inappropriately in more searches? Or Amazon is trying to do some "clever" approximate matching, assuming I don't actually know what I'm looking for? </span></li></ul><li><span style="font-weight: normal;">I search for something specific with necessarily ambiguous words (e.g. "bike rack", hoping for a rack for bikes to carry saddle bags, and instead get racks for cars to carry a bike), and have no way to filter what cluster of "bike rack" meanings I mean. </span></li><li><span style="font-weight: normal;">sometimes-available, sometimes-mutually-exclusive filters? This one makes my head almost explode. I may be on a site like BestBuy, and I want to look at computers, and they provide me with a variety of filters on the left-hand side, for processor speed, RAM amount, SSD capacity, etc. I set one of them, and then some of the other filter options disappear (?!). </span></li><li><span style="font-weight: normal;">poorly-structured and inconsistent product information: I'll pick on BestBuy again. One of the main things they sell are computers. There are many key specs of a computer that people are interested in when searching and comparing. And they manage to encode them ambiguously or incorrectly into their product records. E.g. some HDDs will have their speed in RPM listed, and others won't! The level of detail on two monitors will differ, as well as the presentation/format of that data, making it hard to effectively compare multiple monitors' on contrast ratio, without having to search each of the product's pages on their manufacturer's websites. (Don't get me started on the uselessness of Home Depot's website when it comes to shopping for shower heads...) </span></li><li><span style="font-weight: normal;">Oh, and sizing on clothing O_O And the stupid disproportionate amount of packaging (e.g. too lightly packed fragile stuff; ridiculously overpacked tiny stuff), oh and and and...<br /></span></li></ul><p style="text-align: left;">Ultimately, I accept that there must be something wrong with me here, as many people seem to successfully do a lot of shopping on-line, and e-commerce companies make billions. I just feel so depressed because it's easy to visualize what an actually-easy and frictionless experience <i>should</i> be, and see the gap between that and what we have. What we have is in some ways more flexible and agile; there's less explicit, specific support coded and maintained for each different type of product, yay? I am a big fan of actually paying to do the work needed to get an optimal outcome, though. I want utopia, damn it.<br /></p><p style="text-align: left;"><b>thank you</b> <br /></p><p style="text-align: left;">If you actually read this rant, wow. Thanks. Sorry for the typos. Please leave a comment just so I know you exist.</p><p style="text-align: left;">I miss the predominance of blogs, once upon a time, outside the social media silos. I'm old now, I guess.<br /></p>Richardhttp://www.blogger.com/profile/05999356523405056706noreply@blogger.com0tag:blogger.com,1999:blog-1271390300799121555.post-86979979988016104402021-06-22T00:12:00.000-07:002023-04-19T00:17:52.932-07:00[Technology] Complaints<p>I sometimes feel like most of my thoughts on technology in the past several years are too negative. I mostly focus on deficiencies and frustrations. I end up not wanting to share those, as they don't often feel constructive. I think that's because it's easy to express them as a value judgement. </p><p>I dislike criticising a technological choice while implying some sort of inferiority in the developers that made that choice. People make bad choices, and so do I, but also many choices that appear "bad" are actually very reasonable given the context, and it's hard to know what that was. So I don't like squawking about it.</p><p>That said, I think it might be worthwhile to sometimes express my issues with technology, as those are often the points I'm interested in trying to improve. So I'll try to do some posts about that in the future.<br /></p>Richardhttp://www.blogger.com/profile/05999356523405056706noreply@blogger.com0tag:blogger.com,1999:blog-1271390300799121555.post-36845276085580323542021-03-13T11:49:00.000-08:002023-04-24T19:25:14.488-07:00[Technology] "Add to Home Screen" broken by PWA's "start_url"<h2 style="text-align: left;">Problem</h2> <p>This has been driving me mad. At some point, I was increasingly unable to add direct links to web pages on my home screen on my phone. E.g. to specific Twitter accounts, or to Instagram's Chat page. I would go through the usual steps of visiting the specific page, going to the menu and choosing "Zum Startbildschirm zufügen" (aka. "Add to Home Screen"), but the shortcut would only go to the main page for the site instead, twitter.com or instagram.com, making it somewhat useless.</p> <p>Today I tried to investigate the problem:<br /></p> <p><a href="https://android.stackexchange.com/questions/225002/chrome-and-firefox-cannot-add-specific-url-to-home-screen">https://android.stackexchange.com/questions/225002/chrome-and-firefox-cannot-add-specific-url-to-home-screen</a></p> <p>The problem is that these sites are acting as Progressive Web Application (PWA). In their Manifest file, they can specify a value "start_url", which then overrides the actual URL I'm trying when adding to my home screen. </p><p>It's pretty infuriating and undermines my control over my device and experience, and impairs me from accomplishing my goals.</p><p>The site lists some workarounds. One of them is to use 3rd party apps to create the short-cut. One of my qualms with 3rd party apps on Linux is that so many request excess permissions beyond what they need for their purpose, and despite having some limited control over that, it's rarely enough to feel safe. :\</p><h2 style="text-align: left;">Solution I'm Using</h2><div style="text-align: left;"><a href="https://android.stackexchange.com/questions/146169/how-to-add-desktop-shortcut-for-url-ignoring-web-app-manifest">https://android.stackexchange.com/questions/146169/how-to-add-desktop-shortcut-for-url-ignoring-web-app-manifest</a><br /><br /></div><div style="text-align: left;"><pre>javascript:{
if (meta=document.querySelector('meta[name="mobile-web-app-capable"]')) {
meta.parentNode.removeChild(meta);
}
if (mani=document.querySelector('link[rel="manifest"]')) {
mani.parentNode.removeChild(mani);
}
void(0);
}</pre></div> <p>The user that suggested this, "user185038", notes that Chrome seems to strip "javascript:" away if you just copy and paste that in, so they paste something slightly different (javascriptx:) for that protocol bit, and then just edit to be what's intended.</p> And it worked!<br /> Richardhttp://www.blogger.com/profile/05999356523405056706noreply@blogger.com0tag:blogger.com,1999:blog-1271390300799121555.post-25231829264268315112020-11-27T23:39:00.000-08:002023-04-19T00:17:53.366-07:00[Technology] signal-desktop and WaylandSignal will open on Wayland on Fedora again. Oh happy day!<br />Richardhttp://www.blogger.com/profile/05999356523405056706noreply@blogger.com0tag:blogger.com,1999:blog-1271390300799121555.post-36145829465572692732020-05-26T14:31:00.000-07:002023-04-19T00:17:53.582-07:00[Technology] Data Debt: part 3<div>While in school, and for a period after, I neglected my systems of organization. I continued to accumulate information, but without spending effort to manage it. This has resulted in a large data debt. <br /></div><div><br /></div><div>I have<br /></div><ul><li> years of e-mail, chat and text logs in various formats that I want to de-duplicate and consolidate.</li><li> thousands of screenshots and saved images of memes and wallpapers and artwork from some of my favourite video games and media sitting in massive folders.</li><li> years of photos grouped just by date taken (surprisingly useful) with no indication of people present (actually not a huge problem given Google Photos)</li><li> thousands of To Do items spread across various formats and systems, that have no priority, they just end up in an endless queue that only ever grows.</li><li>old websites, blogs, accounts that are redundant or obsolete.</li><li>projects that need starting, video games that need completing.</li></ul><div>Part of my problem is hope. I have hope. Hope that this can all be managed. Hope because I have the skills necessary.<br /></div><div><br /></div><div>Part of my problem is that I am late. There are good opportunities, especially at the time of transitioning from one process to another, or at the time I acquire a record, to act then and keep-up. They were missed. And now I have debt<br /></div><div><br /></div><div>I just need the time. So here I am, stealing an hour here, an hour there, out of my busy days, not dealing with problems of today, but dealing with a self-created problem of years past, for a goal that, like my dad's, may be pointless.</div><div><br /></div><div>How many photos do I ever review?</div><div>How many e-mails will I ever re-read?</div><div>How many ToDo items do I ever expect to complete?</div><div><br /></div><div>My alternative is recency. Focus on what is recent and applicable to me today. But I know I can do it, and I know that, like my father sifting through his decades of paper data, there are gems to be found. Memories to recall. People that I do not want to lose as the unfrequented connections in my brain fade to make room for more recent experience.</div><div><br /></div><div>I have created a large data debt, one that might be manageable with the programming skills I have, and maybe more manageable as AI continues to improve. But does it matter? Probably not. Just my vanity.<br /></div>Richardhttp://www.blogger.com/profile/05999356523405056706noreply@blogger.com0tag:blogger.com,1999:blog-1271390300799121555.post-53782203300663547722020-05-26T14:19:00.000-07:002023-04-19T00:17:53.800-07:00[Technology] Data Debt: part 2<div>As just noted, my father managed to accumulate quite a bit of information in physical form that he now spends time sorting through and discarding what has no value after all, which is most of it.</div><div><br /></div><div>I think about that in relation to the data I keep, mostly digital. Files upon files upon files. Photos upon photos. A vain effort to preserve every text message and e-mail forever. A vain war against data loss, against entropy, against chaos. Vain, my vanity.</div><div><br /></div><div>I am not a fan of the paradigm of search first. I love being able to meaningfully search my information. I do not believe, at present, or perhaps ever, that search will be capable of being able to completely and comprehensively report back to me the information I seek. I can only search for what I know exists. Artificial intelligence has made search much more useful than ever before; e.g. I can search for "cake" in Google Photos and I get hundreds of photos, mostly actually of cake! But I also know many more photos that I have taken of cake are missing, and there are photos not of cake present. Precision, accuracy and recall are not at 100%, yet, and given the indefinite nature of some definitions, can they ever be.</div><div><br /></div><div>Organize. A dead motto. Another vanity project. Just as I do not expect search to be able to accurately identify all of the most relevant results for me, I do not believe that I can adequately and exhaustively categorize all of my information in a complete way.</div><div><br /></div><div>But between the two, I still prefer organizing over searching. I still prefer a reasonable hierarchy of folders and some futile "tags". It scales a bit better. Perhaps I cannot granularly categorize every record I have, but I can at least definitely categorize them into broad groups that I can add specificity to as needed.</div><div><br /></div><div>What is the major obstacle that I have? Volume of information. I collect too much information. And I am generally unwilling to let any detail go. Storage is cheap. I have a 1TB SSD that I purchased for 80CAD, and it stores tens of thousands of photos and millions of lines of text from the past decade, in a small block that can fit into the palm of my hand.</div><div><br /></div><div>And my flexible approach to organizing it all works fine... if I can keep up. But my data debt grows faster than I can spend my daily available time to manage it.<br /></div>Richardhttp://www.blogger.com/profile/05999356523405056706noreply@blogger.com0tag:blogger.com,1999:blog-1271390300799121555.post-46970364757321650922020-05-26T14:07:00.000-07:002023-04-19T00:17:54.019-07:00[Technology] Data Debt: part 1<div>Technical debt. Time debt. <br /></div><div><br /></div><div>My father is a bit older now, and he has been going through his Stuff. Not just big physical Stuff like objects and thingy things. But also informational Stuff, like receipts, letters, newspaper clippings, magazines, mileage notebooks. Stuff he read or took notes on over the past several decades that have accumulated into quite a many boxes (formerly of shoes)or Piles or Stacks. Sometimes, bags.</div><div><br /></div><div>He's looking at all of this informational Stuff, and wondering, what was the point? He definitely found value in some of it. One of his joys in the past few years has been surfacing a memory of some event, of something he read or did, and then searching through his many records to find the Evidence of it. I can understand the thrill. Finding that newspaper clipping of something he did in our small town, once, or a letter from a friend from 2003, and hey, maybe Richard can find the phone number of the sender now, and hey, I did, and now my dad has renewed contact after a decade and a 1/2.</div><div><br /></div><div>But there's a lot that he will never need, and never really did need in the end. He has been meticulous in recording how many kilometres he has driven between gas refills, how much gas he added, and how much it cost. It has given him a good sense of his spending in that regard, and of his cars performance. It is all jotted in tiny notebooks. Nothing digital. Nothing that he can load easily into a spreadsheet now, and review larger trends. And, honestly, numbers that he has not needed for three decades.</div><div><br /></div><div>I love this history that he has collected, these peeks into his life and mind and priorities over the past several decades. I do not get to enjoy them so directly, though. I am reluctant to dig through his Stuff, it feels like an invasion of privacy. He is shredding or recycling stuff now that he does not expect to need after all, which is most of it. Saving information for rainy days that mostly never came.</div><div><br /></div><div>I find it interesting that his approach is to review it all. It definitely has had merit. He finds random points of interest and it creates conversation topics for us. It used to be something he could show his friends at the coffee shop, back when coffee shops were places where you could sit with friends. But there is so much, and so much he finds is of no value to him. I am pretty sure this year he will give up in the face of the sheer volume of information he has collected in the past several decades and just say good bye to it all. It was never that useful anyway.</div>Richardhttp://www.blogger.com/profile/05999356523405056706noreply@blogger.com0tag:blogger.com,1999:blog-1271390300799121555.post-64236312870846940442020-04-20T22:54:00.000-07:002023-04-19T00:17:54.238-07:00[Technology] JavaScript's querySelector () is one of my favourite APIsI don't mind traversing a DOM or using XPath, but CSS selectors work so nicely.<br />Richardhttp://www.blogger.com/profile/05999356523405056706noreply@blogger.com0tag:blogger.com,1999:blog-1271390300799121555.post-66027546509823389132020-04-11T12:13:00.000-07:002023-04-19T00:17:54.456-07:00[Technology] Messaging and the Flow of Time<br /> <p><br /> Something fairly depressing in the realm of technology is the lack of monotonic progress messaging has made in the last 30 years.<br /> </p><br /> <br /> <p><br /> Recently, Instagram <a href="https://www.theverge.com/2020/4/10/21215449/instagram-dm-web-browser-update-direct-message">finally started supporting messaging from the web</a> (theverge.com). It still doesn't allow me to organize messages by archiving them, though.<br /> </p><br /> <br /> <p><br /> Facebook Messenger lets me archive them and message from the web or my phone (yay), but it's horrible trying to actually read their history; trying to search or browse back in time is incredibly painful. That was something that used to be so easy a decade ago.<br /> </p><br /> <br /> <p><br /> Every few years, a new messaging platform rises up, and with it a classic set of limitations. How many times have I been compelled to use a new platform to find that, once again, group messaging or video chat aren't available? Or that there isn't end-to-end encryption?<br /> </p><br /> <br /> <p><br /> I briefly had hope a decade ago when it looked like XMPP was going to help standardize messaging protocols and that I'd finally be able to interoperably chat with friends across networks. Now they're more siloed than ever before. I almost hope for Facebook to integrate Messenger, Instagram Direct and WhatsApp so that people will stop pestering me to install yet-another-privacy-violating application.<br /> </p><br /> <br /> <p><br /> On a positive note, I really enjoy per-message reactions that a few services like Facebook Messenger and Signal now support.<br /> </p><br /> Richardhttp://www.blogger.com/profile/05999356523405056706noreply@blogger.com0tag:blogger.com,1999:blog-1271390300799121555.post-69910569548006342042020-02-28T18:11:00.000-08:002023-04-19T00:17:54.670-07:00[Technology] Java 13, switch and text blocks, yahoo!From <br /><br /> <a href="https://blog.jetbrains.com/idea/2019/07/intellij-idea-2019-2-java-13-preview-features-profiling-tools-services-tool-window-and-more/">https://blog.jetbrains.com/idea/2019/07/intellij-idea-2019-2-java-13-preview-features-profiling-tools-services-tool-window-and-more/</a> <br /><br /> <blockquote class="tr_bq"><br /> Java 13 is coming out in September, and, as usual, IntelliJ IDEA is <br /> ready for it. The IDE provides support for the Switch Expressions <br /> preview feature (<a href="https://openjdk.java.net/jeps/354">JEP 354</a>) and its new syntax, and for the Text Blocks preview feature (<a href="https://openjdk.java.net/jeps/355">JEP 355</a>).</blockquote><br /> Yes, Java will soon support multi-line String literals and more compact and versatile switch statements/expressions. Wahoo! <br /> Richardhttp://www.blogger.com/profile/05999356523405056706noreply@blogger.com0tag:blogger.com,1999:blog-1271390300799121555.post-49136954181213511332020-02-23T11:11:00.000-08:002023-04-19T02:52:48.777-07:00[Technology] Let's Encrypt!For a while, this blog's appearance was a bit broken, because of issues with a mix of unencrypted HTTP and encrypted HTTPS content. Eek.<br /><br /> <div> I finally went about using <a href="https://draft.blogger.com/letsencrypt.org">Let's Encrypt</a> to get some signed certificates for my domains to help improve the privacy of your browsing session here. Enjoy.</div><br /> Richardhttp://www.blogger.com/profile/05999356523405056706noreply@blogger.com0