<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="https://starbeamrainbowlabs.com/blog/feed.xslt"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title type="html">Stardust | Starbeamrainbowlabs' Blog</title>
  <link rel="alternate" href="https://starbeamrainbowlabs.com/blog/"/>
  <link rel="self" href="https://starbeamrainbowlabs.com/blog/feed.php"/>
  <updated>2026-04-17T07:07:36+01:00</updated>
  <generator uri="https://starbeamrainbowlabs.com/code/phpatomgenerator/" version="0.3">atom.gen.php - A Simple PHP Atom Feed Generator</generator>
  <author>
    <name>Starbeamrainbowlabs</name>
    <email>sbrl@starbeamrainbowlabs.com</email>
    <uri>https://starbeamrainbowlabs.com</uri>
  </author>
  <id>https://starbeamrainbowlabs.com/blog/</id>
  <entry>
    <title type="html">.desktop files: Launcher icons on Linux</title>
    <link href="https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F545-desktop-files.html"/>
    <id>https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F545-desktop-files.html</id>
    <updated>2024-04-24T09:02:15+01:00</updated>
    <rights type="html">CC-BY-SA</rights>
    <content type="html">&lt;article class='post' data-post-title='.desktop files: Launcher icons on Linux' itemscope itemtype='http://schema.org/BlogPosting'&gt;
			&lt;a id='posts%2F545-desktop-files.html'&gt;&lt;/a&gt;
&lt;div itemprop='articleBody'&gt;&lt;!--
Release on  | 24th April 2024 at 9:00am
Author      | Starbeamrainbowlabs
Tags        | Linux, Tutorial
--&gt;
&lt;p&gt;Heya! Just thought I'd write a quick reminder post for myself on the topic of &lt;code&gt;.desktop&lt;/code&gt; files. In most Linux distributions, launcher icons for things are dictated by files with the file extension &lt;code&gt;.desktop&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Of course, most programs these days come with a &lt;code&gt;.desktop&lt;/code&gt; file automatically, but if you for example download an &lt;a href="https://appimage.org/"&gt;AppImage&lt;/a&gt;, then you might not get an auto-generated one. You might also be packaging something for your distro's package manager (go you!) - something I do semi-regularly when apt repos for software I need isn't updated (see &lt;a href="http://apt.starbeamrainbowlabs.com/"&gt;my apt repository&lt;/a&gt;!).&lt;/p&gt;
&lt;p&gt;They can live either locally to your user account (&lt;code&gt;~/.local/share/applications&lt;/code&gt;) or globally (&lt;code&gt;/usr/share/applications&lt;/code&gt;), and they follow the &lt;a href="https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html"&gt;XDG desktop entry specification&lt;/a&gt; (see also the &lt;a href="https://wiki.archlinux.org/title/Desktop_entries"&gt;Arch Linux docs page&lt;/a&gt;, which is fabulous as usual ✨). It's basically a fancy &lt;code&gt;.ini&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-ini"&gt;[Desktop Entry]
Encoding=UTF-8
Type=Application
Name=Krita
Comment=Krita: Professional painting and digital art creation program
Version=1.0
Terminal=false
Exec=/usr/local/bin/krita
Icon=/usr/share/icons/krita.png&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Basically, leave the first line, the &lt;code&gt;Type&lt;/code&gt;, the &lt;code&gt;Version&lt;/code&gt;, the &lt;code&gt;Terminal&lt;/code&gt;, and the &lt;code&gt;Encoding&lt;/code&gt; directives alone, but the others you'll want to customise:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Name&lt;/code&gt;:&lt;/strong&gt; The name of the application to be displayed in the launcher&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Comment&lt;/code&gt;:&lt;/strong&gt; The short 1-line description. Some distros display this as the tooltip on hover, others display it in other ways.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Exec&lt;/code&gt;:&lt;/strong&gt; Path to the binary to execute. Prepend with &lt;code&gt;env Foo=bar&lt;/code&gt; etc if you need to set some environment variables (e.g. &lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F436-running-application-on-nvidia.html"&gt;running on a discrete card&lt;/a&gt; - 27K views? wow O.o)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;Icon&lt;/code&gt;:&lt;/strong&gt; Path to the icon to display as the launcher icon. For global &lt;code&gt;.desktop&lt;/code&gt; files, this should be located somewhere in &lt;code&gt;/usr/share/icon&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is just the basics. There are many other directives you can include - like the &lt;code&gt;Category&lt;/code&gt; directive, which describes - if your launcher supports categories - what categories a given launch icon should appear under.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Troubleshooting:&lt;/strong&gt; It took me &lt;em&gt;waaay&lt;/em&gt; too long to realise this, but if you have put your &lt;code&gt;.desktop&lt;/code&gt; file in the right place and it isn't appearing - even after a relog - then the &lt;code&gt;desktop-file-validate&lt;/code&gt; command could come in handy:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;desktop-file-validate path/to/file.desktop&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It validates the content of a given &lt;code&gt;.desktop&lt;/code&gt; file. If it contains any errors, then it will complain about them for you - unlike your desktop environment which just ignores &lt;code&gt;.desktop&lt;/code&gt; files that are invalid.&lt;/p&gt;
&lt;p&gt;If you found this useful, please do leave a comment below about what you're creating launcher icons for! &lt;/p&gt;
&lt;h3&gt;Sources and further reading&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://wiki.archlinux.org/title/Desktop_entries"&gt;Desktop entries - ArchWiki&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html"&gt;XDG desktop entry specification&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;span style='display: none;' itemprop='image' itemscope itemtype='https://schema.org/ImageObject'&gt;&lt;meta itemprop='url' content='http://starbeamrainbowlabs.com/favicon.png' /&gt;&lt;meta itemprop='width' content='256' /&gt;&lt;meta itemprop='height' content='256' /&gt;&lt;/span&gt;
&lt;/div&gt;&lt;meta itemprop='commentCount' content='3' /&gt;&lt;meta itemprop='datePublished' content='2024-04-24T09:00:00+01:00' /&gt;&lt;meta itemprop='dateModified' content='2024-04-24T09:02:15+01:00' /&gt;&lt;hr /&gt;
			&lt;footer class='small-panel centretext'&gt;
				by &lt;span itemprop='author publisher' itemscope itemtype='http://schema.org/Person'&gt;&lt;span itemprop='name'&gt;Starbeamrainbowlabs&lt;/span&gt;&lt;meta itemprop='image' content='https://starbeamrainbowlabs.com/favicon-small.png' /&gt;&lt;/span&gt; | &lt;span class='oi' data-glyph='clock' title='Published on' aria-hidden='true'&gt;&lt;/span&gt;
			&lt;span title='Wednesday 24th of April 2024 at 09:00am BST' style='cursor:help;'&gt;24-4-2024 at 09:00 am&lt;/span&gt; | &lt;span class='oi' data-glyph='tag' title='Tags' aria-hidden='true'&gt;&lt;/span&gt;&lt;a href='//starbeamrainbowlabs.com/blog/?tags=Linux'&gt;Linux&lt;/a&gt;, &lt;a href='//starbeamrainbowlabs.com/blog/?tags=Tutorial'&gt;Tutorial&lt;/a&gt; | &lt;a itemprop='url' href='https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F545-desktop-files.html'&gt;&lt;span class='oi' data-glyph='link-intact' title='Permanent Link' aria-hidden='true'&gt;&lt;/span&gt;Permanent Link&lt;/a&gt; | &lt;span class='oi' data-glyph='monitor' title='Views'&gt;&lt;/span&gt;3492 views&lt;img class='icon nomargin' data-src='https://starbeamrainbowlabs.com/blog/viewtracker.php?action=record&amp;format=image&amp;post-id=posts%2F545-desktop-files.html' alt='View tracking image. Download it to increment the view counter!' /&gt; | &lt;a href='https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F545-desktop-files.html#comments' itemprop='discussionUrl'&gt;&lt;span class='oi' data-glyph='comment-square' title='Comments' aria-hidden='true'&gt;&lt;/span&gt;3 comments&lt;/a&gt; | &lt;span class='oi' data-glyph='people' title='Share' aria-hidden='true'&gt;&lt;/span&gt;Share via:
&lt;a href='https://starbeamrainbowlabs.com/share2fediverse/#text=.desktop%20files%3A%20Launcher%20icons%20on%20Linux%20-%20Blog%20post%0Ahttps%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F545-desktop-files.html' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/fediverse.svg' class='icon' title='Share on the Fediverse' alt='Share this post on the Fediverse' /&gt;&lt;/a&gt;
&lt;a href='https://twitter.com/share?url=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F545-desktop-files.html&amp;text=.desktop%20files%3A%20Launcher%20icons%20on%20Linux%20-%20Blog%20post&amp;via=SBRLabs' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/twitter.svg' class='icon' title='Share via Twitter' alt='Share this post via Twitter' /&gt;&lt;/a&gt;
&lt;a href='https://facebook.com/sharer/sharer.php?u=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F545-desktop-files.html' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/facebook.svg' class='icon' title='Share via Facebook' alt='Share this post via Facebook' /&gt;&lt;/a&gt;
&lt;a href='http://www.addtoany.com/add_to/evernote?linkurl=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F545-desktop-files.html&amp;title=.desktop%20files%3A%20Launcher%20icons%20on%20Linux' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/evernote.svg' class='icon' title='Share via Evernote' alt='Share this article via Evernote' /&gt;&lt;/a&gt;
&lt;a href='mailto:?Subject=Stardust%20Blog%20Post%3A%20.desktop%20files%3A%20Launcher%20icons%20on%20Linux&amp;#38;Body=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F545-desktop-files.html'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/mail.svg' class='icon' title='Share by Email' alt='Share by Email' /&gt;&lt;/a&gt;			&lt;/footer&gt;
		&lt;/article&gt;
</content>
    <category term="linux" label="Linux"/>
    <category term="tutorial" label="Tutorial"/>
    <author>
      <name>Starbeamrainbowlabs</name>
      <email>sbrl@starbeamrainbowlabs.com</email>
      <uri>https://starbeamrainbowlabs.com</uri>
    </author>
    <published>2024-04-24T09:00:00+01:00</published>
  </entry>
  <entry>
    <title type="html">PhD Update 18: The end and the beginning</title>
    <link href="https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F546-phd-update-18.html"/>
    <id>https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F546-phd-update-18.html</id>
    <updated>2024-05-27T03:19:14+01:00</updated>
    <rights type="html">CC-BY-SA</rights>
    <content type="html">&lt;article class='post' data-post-title='PhD Update 18: The end and the beginning' itemscope itemtype='http://schema.org/BlogPosting'&gt;
			&lt;a id='posts%2F546-phd-update-18.html'&gt;&lt;/a&gt;
&lt;div itemprop='articleBody'&gt;&lt;!--
Release on  | 23rd May 2024 at 4:15pm
Author      | Starbeamrainbowlabs
Tags        | PhD, University, Update, Announcement
--&gt;
&lt;p&gt;Hello! It has been a while. Things have been most certainly happening, and I'm sorry I haven't had the energy to update my blog here as often as I'd like. Most notably, I submitted my thesis last week (gasp!)! This does not mean the end of this series though - see below.&lt;/p&gt;
&lt;p&gt;Before we continue, here's our traditional list of past posts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/388-phd-update-1-directions.html"&gt;PhD Update 1: Directions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/397-phd-2-experiments.html"&gt;PhD Update 2: The experiment, the data, and the supercomputers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/404-phd-3-simulating-simulations.html"&gt;PhD Update 3: Simulating simulations with some success&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/417-phd-4-gimornous-data.html"&gt;PhD Update 4: Ginormous Data&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/430-phd-update-5-hyper-optimisations-and-frustrations.html"&gt;PhD Update 5: Hyper optimisation and frustration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F438-phd-update-6-the-road-ahead.html"&gt;PhD Update 6: The road ahead&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/452-phd-update-7.html"&gt;PhD Update 7: Just out of reach&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/463-phd-update-8-eggs-baskets.html"&gt;PhD Update 8: Eggs in Baskets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/471-phd-update-9.html"&gt;PhD Update 9: Results?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/476-phd-update-10.html"&gt;PhD Update 10: Sharing with the world&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/485-phd-update-11-answers.html"&gt;PhD Update 11: Answers to our questions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/493-phd-12-enough.html"&gt;PhD Update 12: Is it enough?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/501-PhD-Update-13-a-half-complete.html"&gt;PhD Update 13: A half complete&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/512-phd-update-14.html"&gt;PhD Update 14: An old enemy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/sources/520-phd-update-15.md"&gt;PhD Update 15: Finding what works when&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/528-phd-update-16.html"&gt;PhD Update 16: Realising the possibilities of the past&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/539-phd-update-17.html"&gt;PhD Update 17: Light at the end of the tunnel&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Since last time, that detecting persuasive tactic challenge has ended too, and we have a paper going through at the moment: &lt;a href="https://bda-hull.github.io/publications/[PRE-CAMERIA%20READY]%20Detection%20of%20Persuasion%20in%20Memes%20Across%20Languages%20with%20Ensemble%20Learning%20and%20External%20Knowledge.pdf"&gt;BDA at SemEval-2024 Task 4: Detection of Persuasion in Memes Across Languages with Ensemble Learning and External Knowledge&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Theeeeeeeeeeeeesis&lt;/h3&gt;
&lt;p&gt;Hi! A wild thesis appeared! Final counts are 35,417 words, 443 separate sources, 167 pages, and 50 pages of bibliography - making that 217 pages in total. No wonder it took so long to write! I submitted at 2:35pm BST on Friday 10th May 2024.&lt;/p&gt;
&lt;p&gt;I. can. finally. rest.&lt;/p&gt;
&lt;p&gt;It has been such a long process, and taken a lot of energy to complete it, especially since large amounts of formal academic writing isn't usually my thing. I would like to extend a heartfelt thanks especially to my supervisor for being there from beginning to end and beyond to support me through this endeavour - and everyone else who has helped out in one way or another (you know who you are).&lt;/p&gt;
&lt;p&gt;Next step is the viva, which will be some time in July. I know who my examiners are going to be, but I'm unsure whether it would be wise to say here. Between now and then, I want to &lt;del&gt;stalk&lt;/del&gt; investigate my examiners' research histories, which should give me an insight into their perspective on my research.&lt;/p&gt;
&lt;p&gt;Once the viva is done, I expect to have a bunch of corrections to do. Once &lt;em&gt;those&lt;/em&gt; are completed, I will to the best of my ability be releasing my thesis for all to read for free. I still need to talk to people to figure out how to do that, but rest assured that if you can't get enough of my research via the papers I've written for some reason, then my thesis will not be far behind.&lt;/p&gt;
&lt;p&gt;Coming to the end of my PhD and submitting my thesis has been surprisingly emotionally demanding, so I thank everyone who is still here for sticking around and being patient as I navigate these unfamiliar events.&lt;/p&gt;
&lt;h3&gt;Researchy things&lt;/h3&gt;
&lt;p&gt;While my PhD may be coming to a close (I still can't believe this is happening), I have confirmed that I will have dedicated time for research-related activities. Yay!&lt;/p&gt;
&lt;p&gt;This means, of course, that as one ending draws near, a new beginning is also starting. Today's task after writing this post is to readificate around my chosen idea to figure out where there's a gap in existing research for me to make a meaningful contribution. In a very real way, it's almost like I am searching for directions as I did in my &lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/388-phd-update-1-directions.html"&gt;very first post in this series&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;My idea is connected to the &lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/527-cageo-smjournal.html"&gt;social media research&lt;/a&gt; that I did previously on multimodal natural language processing of flooding tweets and images with respect to sentiment analysis (it sounded better in my head).&lt;/p&gt;
&lt;p&gt;Specifically, I think I can do better than just sentiment analysis. Imagine an image of a street that's partially underwater. Is there a rescue team on a boat rescuing someone? What about the person on the roof waving for help? Perhaps it's a bridge that's about to be swept away, or a tree that has fallen down? Can we both identify these things in images and map them to physical locations?&lt;/p&gt;
&lt;p&gt;Existing approaches to e.g. detect where the water is in the image are prone to misidentifying water that is infact where it should be for once, such as in rivers and lakes. To this end, I propose looking for the people and things in the water rather than the water itself and go for a people-centred approach to flood information management.&lt;/p&gt;
&lt;p&gt;I imagine that while I'll probably use data from social media I already have (getting a hold of new data from social media is very difficult at the moment) - filtered for memes and misinformation this time - if you know of any relevant sources of data or datasets, I'm absolutely interested and please get in touch. It would be helpful but not required if it's related to a specific natural disaster event (I'm currently looking at floods, branching out to others is absolutely possible and on the cards but I will need to submit a new ethics form for that before touching any data).&lt;/p&gt;
&lt;p&gt;Another challenge I anticipate is that of unlabelled data. It is often the case that large volumes of data are generated during an unfolding natural disaster, and processing it all can be a challenge. To this end, somehow I want my approach here to make sense of unlabelled images. Of course, generalist foundational models like &lt;a href="https://github.com/openai/CLIP"&gt;CLIP&lt;/a&gt; are great, but lack the ability to be specific and accurate enough with natural disaster images.&lt;/p&gt;
&lt;p&gt;I also intend that this idea would be applicable to images from a range of sources, and not just with respect to social media. I don't know what those sources could be just yet, but if you have some ideas, please let me know.&lt;/p&gt;
&lt;p&gt;Finally, I am particularly interested if you or someone you know are in any way involved in natural disaster management. What kinds of challenges do you face? Would this be in any way useful? Please do get in touch either in the comments below or sending me an email (my email address is on the homepage of this website).&lt;/p&gt;
&lt;h3&gt;Persuasive tactics challenge&lt;/h3&gt;
&lt;p&gt;The research group I'm part of were successful in completing the &lt;a href="https://propaganda.math.unipd.it/semeval2024task4/index.html"&gt;SemEval Task 4: Multilingual Detection of Persuasion Techniques in Memes&lt;/a&gt;! I implemented the 'late fusion engine', which is a fancy name for an algorithm that uses in basic probability to combine categorical predictions from multiple different models depending on how accurate each model was on a per-category basis.&lt;/p&gt;
&lt;p&gt;I'm unsure of the status of the paper, but I think it's been through peer-review so you can find that here: &lt;a href="https://bda-hull.github.io/publications/[PRE-CAMERIA%20READY]%20Detection%20of%20Persuasion%20in%20Memes%20Across%20Languages%20with%20Ensemble%20Learning%20and%20External%20Knowledge.pdf"&gt;BDA at SemEval-2024 Task 4: Detection of Persuasion in Memes Across Languages with Ensemble Learning and External Knowledge&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I wasn't the lead on that challenge, but I believe the lead person (a friend of mine, if you are reading this and want me to link to somewhere here get in touch) on that project will be going to mexico to present it.&lt;/p&gt;
&lt;h3&gt;Teaching&lt;/h3&gt;
&lt;p&gt;I'm still not sure what I can say and what I can't, but starting in september I have been asked to teach a module on basic system administration skills. It's a rather daunting prospect, but I have a bunch of people much more experienced than me to guide me through the process. At the moment the plan is for 21 lecture-ish things, 9 labs, and the assessment stuff, so I'm rather nervous about preparing all of this content.&lt;/p&gt;
&lt;p&gt;Of course, as a disclaimer nothing written in this section should be taken as absolute. (Hopefully) more information at some point, though unfortunately I doubt that I would be allowed to share the content created given it's University course material.&lt;/p&gt;
&lt;p&gt;As always though, if there's a specific topic that lies anywhere within my expertise that you'd like explaining, I'm happy to write a blog post about it (in my own time, of course).&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;We've taken a little look at what is been going on since I last posted, and while this post has been rather talky (will try for some kewl graphics next time!), nonetheless I hope this has been an interesting read. I've submitted my thesis, started initial readificating for my next research project - which we've explored the ideas here, helped out a group research challenge project thingy, and been invited to do some teaching!&lt;/p&gt;
&lt;p&gt;Hopefully the next post in this series will come out on time - long-term the plan is to absolutely continue blogging about the research I'm doing.&lt;/p&gt;
&lt;p&gt;Until next time, the journey continues!&lt;/p&gt;
&lt;p&gt;(Oh yeah! and finally finally, to the person who asked a question by email about &lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/156-Autoupdate-CSharp.html"&gt;this old post&lt;/a&gt; (I think?), I'm sorry for the delay and I'll try to get back to you soon.)&lt;/p&gt;&lt;span style='display: none;' itemprop='image' itemscope itemtype='https://schema.org/ImageObject'&gt;&lt;meta itemprop='url' content='http://starbeamrainbowlabs.com/favicon.png' /&gt;&lt;meta itemprop='width' content='256' /&gt;&lt;meta itemprop='height' content='256' /&gt;&lt;/span&gt;
&lt;/div&gt;&lt;meta itemprop='commentCount' content='0' /&gt;&lt;meta itemprop='datePublished' content='2024-05-23T16:15:00+01:00' /&gt;&lt;meta itemprop='dateModified' content='2024-05-27T03:19:14+01:00' /&gt;&lt;hr /&gt;
			&lt;footer class='small-panel centretext'&gt;
				by &lt;span itemprop='author publisher' itemscope itemtype='http://schema.org/Person'&gt;&lt;span itemprop='name'&gt;Starbeamrainbowlabs&lt;/span&gt;&lt;meta itemprop='image' content='https://starbeamrainbowlabs.com/favicon-small.png' /&gt;&lt;/span&gt; | &lt;span class='oi' data-glyph='clock' title='Published on' aria-hidden='true'&gt;&lt;/span&gt;
			&lt;span title='Thursday 23rd of May 2024 at 04:15pm BST' style='cursor:help;'&gt;23-5-2024 at 04:15 pm&lt;/span&gt; | &lt;span class='oi' data-glyph='tag' title='Tags' aria-hidden='true'&gt;&lt;/span&gt;&lt;a href='//starbeamrainbowlabs.com/blog/?tags=PhD'&gt;PhD&lt;/a&gt;, &lt;a href='//starbeamrainbowlabs.com/blog/?tags=University'&gt;University&lt;/a&gt;, &lt;a href='//starbeamrainbowlabs.com/blog/?tags=Update'&gt;Update&lt;/a&gt;, &lt;a href='//starbeamrainbowlabs.com/blog/?tags=Announcement'&gt;Announcement&lt;/a&gt; | &lt;a itemprop='url' href='https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F546-phd-update-18.html'&gt;&lt;span class='oi' data-glyph='link-intact' title='Permanent Link' aria-hidden='true'&gt;&lt;/span&gt;Permanent Link&lt;/a&gt; | &lt;span class='oi' data-glyph='monitor' title='Views'&gt;&lt;/span&gt;372 views&lt;img class='icon nomargin' data-src='https://starbeamrainbowlabs.com/blog/viewtracker.php?action=record&amp;format=image&amp;post-id=posts%2F546-phd-update-18.html' alt='View tracking image. Download it to increment the view counter!' /&gt; | &lt;a href='https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F546-phd-update-18.html#comments' itemprop='discussionUrl'&gt;&lt;span class='oi' data-glyph='comment-square' title='Comments' aria-hidden='true'&gt;&lt;/span&gt;0 comments&lt;/a&gt; | &lt;span class='oi' data-glyph='people' title='Share' aria-hidden='true'&gt;&lt;/span&gt;Share via:
&lt;a href='https://starbeamrainbowlabs.com/share2fediverse/#text=PhD%20Update%2018%3A%20The%20end%20and%20the%20beginning%20-%20Blog%20post%0Ahttps%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F546-phd-update-18.html' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/fediverse.svg' class='icon' title='Share on the Fediverse' alt='Share this post on the Fediverse' /&gt;&lt;/a&gt;
&lt;a href='https://twitter.com/share?url=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F546-phd-update-18.html&amp;text=PhD%20Update%2018%3A%20The%20end%20and%20the%20beginning%20-%20Blog%20post&amp;via=SBRLabs' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/twitter.svg' class='icon' title='Share via Twitter' alt='Share this post via Twitter' /&gt;&lt;/a&gt;
&lt;a href='https://facebook.com/sharer/sharer.php?u=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F546-phd-update-18.html' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/facebook.svg' class='icon' title='Share via Facebook' alt='Share this post via Facebook' /&gt;&lt;/a&gt;
&lt;a href='http://www.addtoany.com/add_to/evernote?linkurl=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F546-phd-update-18.html&amp;title=PhD%20Update%2018%3A%20The%20end%20and%20the%20beginning' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/evernote.svg' class='icon' title='Share via Evernote' alt='Share this article via Evernote' /&gt;&lt;/a&gt;
&lt;a href='mailto:?Subject=Stardust%20Blog%20Post%3A%20PhD%20Update%2018%3A%20The%20end%20and%20the%20beginning&amp;#38;Body=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F546-phd-update-18.html'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/mail.svg' class='icon' title='Share by Email' alt='Share by Email' /&gt;&lt;/a&gt;			&lt;/footer&gt;
		&lt;/article&gt;
</content>
    <category term="phd" label="PhD"/>
    <category term="university" label="University"/>
    <category term="update" label="Update"/>
    <category term="announcement" label="Announcement"/>
    <author>
      <name>Starbeamrainbowlabs</name>
      <email>sbrl@starbeamrainbowlabs.com</email>
      <uri>https://starbeamrainbowlabs.com</uri>
    </author>
    <published>2024-05-23T16:15:00+01:00</published>
  </entry>
  <entry>
    <title type="html">Defining AI: Sequenced models || LSTMs and Transformers</title>
    <link href="https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F547-defining-ai-sequenced-data.html"/>
    <id>https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F547-defining-ai-sequenced-data.html</id>
    <updated>2024-06-01T09:09:40+01:00</updated>
    <rights type="html">CC-BY-SA</rights>
    <content type="html">&lt;article class='post' data-post-title='Defining AI: Sequenced models || LSTMs and Transformers' itemscope itemtype='http://schema.org/BlogPosting'&gt;
			&lt;a id='posts%2F547-defining-ai-sequenced-data.html'&gt;&lt;/a&gt;
&lt;div itemprop='articleBody'&gt;&lt;!--
Release on  | 1st June 2024 at 9:00am
Author      | Starbeamrainbowlabs
Tags        | Artificial Intelligence, Tutorial, Defining AI
--&gt;
&lt;p&gt;Hi again! I'm back for more, and I hope you are too! First we looked at &lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/543-defining-ai-word-embeddings.html"&gt;word embeddings&lt;/a&gt;, and then &lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/544-defining-ai-image-segmentation.html"&gt;image embeddings&lt;/a&gt;. Another common way of framing tasks for AI models is handling sequenced data, which I'll talk about briefly today.&lt;/p&gt;
&lt;picture&gt;
    &lt;source srcset="https://starbeamrainbowlabs.com/blog/images/defining-ai.avif" type="image/avif"&gt;&lt;/source&gt;
    &lt;source srcset="https://starbeamrainbowlabs.com/blog/images/defining-ai.webp" type="image/webp"&gt;&lt;/source&gt;
    &lt;img itemprop="image" src="https://starbeamrainbowlabs.com/blog/images/defining-ai.png" alt="Banner showing the text 'Defining AI' on top on translucent white vertical stripes against a voronoi diagram in white against a pink/purple background. 3 progressively larger circles are present on the right-hand side."&gt;
&lt;/picture&gt;
&lt;p&gt;Sequenced data can mean a lot of things. Most commonly that's natural language, which we can split up into words (tokenisation) and then bung through some &lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/543-defining-ai-word-embeddings.html"&gt;word embeddings&lt;/a&gt; before dropping it through some model.&lt;/p&gt;
&lt;p&gt;That model is usually specially designed for processing sequenced data, such as an &lt;a href="https://towardsdatascience.com/illustrated-guide-to-lstms-and-gru-s-a-step-by-step-explanation-44e9eb85bf21"&gt;LSTM&lt;/a&gt; (or it's little cousin the GRU, see that same link). An LSTM is part of a class of models called Recurrent Neural Networks, or RNNs. These models work by feeding their output back in to themselves again along with the next element of input, thereby processing a sequence of items. The output bit that feeds back in is basically the memory of the thing that remembers stuff across multiple items in the sequence. The model can decide to add or remove things from this memory at each iteration, which is how it learns.&lt;/p&gt;
&lt;p&gt;The problem with this class of model is twofold: firstly, it processes everything serially which means we can't compute it in parallel, and secondly if the sequence of data it processes is long enough it will forget things from earlier in the sequence.&lt;/p&gt;
&lt;p&gt;In 2017 a model was invented that solves at least 1 of these issues: the &lt;a href="https://jalammar.github.io/illustrated-transformer/"&gt;Transformer&lt;/a&gt;. Instead of working like a recurrent network, a Transformer processes an entire sequence at once, and encodes a time signal (the 'positional embedding') into the input so it can keep track of what was where in the sequence - a downside to processing in parallel means you don't know which element of the sequence was where.&lt;/p&gt;
&lt;p&gt;The transformer model also brought with it the concept of 'attention', which is where the model can decide what parts of the input data are important at each step. This helps the transformer to focus on the bits of the data that are relevant to the task at hand.&lt;/p&gt;
&lt;p&gt;Since 2017, the number of variants of the original transformer &lt;a href="http://arxiv.org/pdf/2302.07730"&gt;has exploded&lt;/a&gt;, which stands testament to the popularity of this model architecture.&lt;/p&gt;
&lt;p&gt;Regarding inputs and outputs, most transformers will take an input in the same shape as the word embeddings in the first post in this series, and will spit it out in the same shape - just potentially with a different shape to the embedding dimension:&lt;/p&gt;
&lt;p&gt;&lt;img itemprop="image" src="https://starbeamrainbowlabs.com/blog/images/20240523-transformer.png" alt="A diagram explaining how a transformer works. A series of sine waves are added as a positional embedding to the data before it goes in." /&gt;&lt;/p&gt;
&lt;p&gt;In this fashion, transformers are only limited by memory requirements and computational expense with respect to sequence lengths, which has been exploited in some model designs to convince a transformer-style model to learn to handle some significantly long sequences.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;This is just a little look at sequenced data modelling with LSTMs and Transformers. I seem to have my ordering a bit backwards here, so in the next few posts we'll get down to basics and explain some concepts like Tensors and shapes, loss functions and backpropagation, attention, and how AI models are put together.&lt;/p&gt;
&lt;p&gt;Are there any AI-related concepts or questions you would like answering? Leave a comment below and I'll write another post in this series to answer your question.&lt;/p&gt;
&lt;h3&gt;Sources and further reading&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://jalammar.github.io/illustrated-transformer/"&gt;The Illustrated Transformer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://towardsdatascience.com/illustrated-guide-to-lstms-and-gru-s-a-step-by-step-explanation-44e9eb85bf21"&gt;Illustrated Guide to LSTMs and GRUs: A step by step explanation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://arxiv.org/pdf/1706.03762"&gt;Attention is All You Need&lt;/a&gt; - the original paper about the transformer model architecture&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.bioinf.jku.at/publications/older/2604.pdf"&gt;Long Short-Term Memory&lt;/a&gt; - the original paper about the LSTM&lt;/li&gt;
&lt;li&gt;&lt;a href="http://arxiv.org/pdf/2302.07730"&gt;Transformer models: an introduction and catalog&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://karpathy.github.io/2015/05/21/rnn-effectiveness/"&gt;The Unreasonable Effectiveness of Recurrent Neural Networks&lt;/a&gt; - older post from 2015 but a very cool earlier character-based text generation model. The hallucination by that model is a great example of why modern Transformer-based text generation models (a topic for another time) like ChatGPT have a similar issue.&lt;/li&gt;
&lt;/ul&gt;&lt;span style='display: none;' itemprop='image' itemscope itemtype='https://schema.org/ImageObject'&gt;&lt;meta itemprop='url' content='https://starbeamrainbowlabs.com/blog/images/defining-ai.png' /&gt;&lt;meta itemprop='width' content='1920' /&gt;&lt;meta itemprop='height' content='600' /&gt;&lt;/span&gt;
&lt;/div&gt;&lt;meta itemprop='commentCount' content='0' /&gt;&lt;meta itemprop='datePublished' content='2024-06-01T09:00:00+01:00' /&gt;&lt;meta itemprop='dateModified' content='2024-06-01T09:09:40+01:00' /&gt;&lt;hr /&gt;
			&lt;footer class='small-panel centretext'&gt;
				by &lt;span itemprop='author publisher' itemscope itemtype='http://schema.org/Person'&gt;&lt;span itemprop='name'&gt;Starbeamrainbowlabs&lt;/span&gt;&lt;meta itemprop='image' content='https://starbeamrainbowlabs.com/favicon-small.png' /&gt;&lt;/span&gt; | &lt;span class='oi' data-glyph='clock' title='Published on' aria-hidden='true'&gt;&lt;/span&gt;
			&lt;span title='Saturday 1st of June 2024 at 09:00am BST' style='cursor:help;'&gt;1-6-2024 at 09:00 am&lt;/span&gt; | &lt;span class='oi' data-glyph='tag' title='Tags' aria-hidden='true'&gt;&lt;/span&gt;&lt;a href='//starbeamrainbowlabs.com/blog/?tags=Artificial%20Intelligence'&gt;Artificial Intelligence&lt;/a&gt;, &lt;a href='//starbeamrainbowlabs.com/blog/?tags=Tutorial'&gt;Tutorial&lt;/a&gt;, &lt;a href='//starbeamrainbowlabs.com/blog/?tags=Defining%20AI'&gt;Defining AI&lt;/a&gt; | &lt;a itemprop='url' href='https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F547-defining-ai-sequenced-data.html'&gt;&lt;span class='oi' data-glyph='link-intact' title='Permanent Link' aria-hidden='true'&gt;&lt;/span&gt;Permanent Link&lt;/a&gt; | &lt;span class='oi' data-glyph='monitor' title='Views'&gt;&lt;/span&gt;350 views&lt;img class='icon nomargin' data-src='https://starbeamrainbowlabs.com/blog/viewtracker.php?action=record&amp;format=image&amp;post-id=posts%2F547-defining-ai-sequenced-data.html' alt='View tracking image. Download it to increment the view counter!' /&gt; | &lt;a href='https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F547-defining-ai-sequenced-data.html#comments' itemprop='discussionUrl'&gt;&lt;span class='oi' data-glyph='comment-square' title='Comments' aria-hidden='true'&gt;&lt;/span&gt;0 comments&lt;/a&gt; | &lt;span class='oi' data-glyph='people' title='Share' aria-hidden='true'&gt;&lt;/span&gt;Share via:
&lt;a href='https://starbeamrainbowlabs.com/share2fediverse/#text=Defining%20AI%3A%20Sequenced%20models%20%7C%7C%20LSTMs%20and%20Transformers%20-%20Blog%20post%0Ahttps%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F547-defining-ai-sequenced-data.html' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/fediverse.svg' class='icon' title='Share on the Fediverse' alt='Share this post on the Fediverse' /&gt;&lt;/a&gt;
&lt;a href='https://twitter.com/share?url=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F547-defining-ai-sequenced-data.html&amp;text=Defining%20AI%3A%20Sequenced%20models%20%7C%7C%20LSTMs%20and%20Transformers%20-%20Blog%20post&amp;via=SBRLabs' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/twitter.svg' class='icon' title='Share via Twitter' alt='Share this post via Twitter' /&gt;&lt;/a&gt;
&lt;a href='https://facebook.com/sharer/sharer.php?u=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F547-defining-ai-sequenced-data.html' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/facebook.svg' class='icon' title='Share via Facebook' alt='Share this post via Facebook' /&gt;&lt;/a&gt;
&lt;a href='http://www.addtoany.com/add_to/evernote?linkurl=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F547-defining-ai-sequenced-data.html&amp;title=Defining%20AI%3A%20Sequenced%20models%20%7C%7C%20LSTMs%20and%20Transformers' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/evernote.svg' class='icon' title='Share via Evernote' alt='Share this article via Evernote' /&gt;&lt;/a&gt;
&lt;a href='mailto:?Subject=Stardust%20Blog%20Post%3A%20Defining%20AI%3A%20Sequenced%20models%20%7C%7C%20LSTMs%20and%20Transformers&amp;#38;Body=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F547-defining-ai-sequenced-data.html'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/mail.svg' class='icon' title='Share by Email' alt='Share by Email' /&gt;&lt;/a&gt;			&lt;/footer&gt;
		&lt;/article&gt;
</content>
    <category term="artificial-intelligence" label="Artificial Intelligence"/>
    <category term="tutorial" label="Tutorial"/>
    <category term="defining-ai" label="Defining AI"/>
    <author>
      <name>Starbeamrainbowlabs</name>
      <email>sbrl@starbeamrainbowlabs.com</email>
      <uri>https://starbeamrainbowlabs.com</uri>
    </author>
    <published>2024-06-01T09:00:00+01:00</published>
  </entry>
  <entry>
    <title type="html">Encrypting and formatting a disk with LUKS + Btrfs</title>
    <link href="https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F548-crypt-btrfs-setup.html"/>
    <id>https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F548-crypt-btrfs-setup.html</id>
    <updated>2024-06-08T09:03:33+01:00</updated>
    <rights type="html">CC-BY-SA</rights>
    <content type="html">&lt;article class='post' data-post-title='Encrypting and formatting a disk with LUKS + Btrfs' itemscope itemtype='http://schema.org/BlogPosting'&gt;
			&lt;a id='posts%2F548-crypt-btrfs-setup.html'&gt;&lt;/a&gt;
&lt;div itemprop='articleBody'&gt;&lt;!--
Release on  | 8th June 2024 at 9:00am
Author      | Starbeamrainbowlabs
Tags        | Guide, Linux, Bash, Terminal, Security
--&gt;
&lt;p&gt;Hey there, a wild tutorial appeared! This is just a quick one for self-reference, but I hope it helps others too.&lt;/p&gt;
&lt;p&gt;The problem at hand is that of formatting a &lt;em&gt;data&lt;/em&gt; disk (if you want to format your root &lt;code&gt;/&lt;/code&gt; disk please look elsewhere - it usually has to be done before or during installation unless you like fiddling around in a live environment) with Btrfs.... but also encrypting the disk, &lt;a href="https://wiki.archlinux.org/title/Btrfs#Encryption"&gt;which isn't something that Btrfs natively supports&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I'm copying over some data to my new lab PC, and I've decided to up the security on the data disk I store my research data on.&lt;/p&gt;
&lt;p&gt;Unfortunately, both &lt;em&gt;GParted&lt;/em&gt; and &lt;em&gt;KDE Partition Manager&lt;/em&gt; were unable to help me (the former not supporting LUKS, and the latter crashing with a strange error), so I ended up looking through more posts that should be reasonable to find a solution that didn't involve encrypting either &lt;code&gt;/&lt;/code&gt; or &lt;code&gt;/boot&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;It's actually quite simple. First, find your disk's name via &lt;code&gt;lsblk&lt;/code&gt;, and ensure you have created the partition in question. You can format it with anything (e.g. using the above) since we'll be overwriting it anyway.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; You may need to reboot after creating the partition (or after some of the below) if you encounter errors, as Linux sometimes doesn't like new partitions appearing out of the blue with names that were used previously on that boot very much.&lt;/p&gt;
&lt;p&gt;Then, format it with LUKS, the most common encryption scheme on Linux:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;sudo cryptsetup luksFormat /dev/nvmeXnYpZ&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;...then, formatting with Btrfs is a 2-step process. First we hafta unlock the LUKS encrypted partition:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;sudo cryptsetup luksOpen /dev/nvme0n1p1 SOME_MAPPER_NAME&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;...this creates a virtual 'mapper' block device we can hit like any other normal (physical) partition. Change &lt;code&gt;SOME_MAPPER_NAME&lt;/code&gt; to anything you like so long as it doesn't match anything else in &lt;code&gt;lsblk&lt;/code&gt;/&lt;code&gt;df -h&lt;/code&gt; and also doesn't contain spaces. Avoid unicode/special characters too, just to be safe.&lt;/p&gt;
&lt;p&gt;Then, format it with Btrfs:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;sudo mkfs.btrfs --metadata single --data single --label "SOME_LABEL" /dev/mapper/SOME_MAPPER_NAME&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;...replacing &lt;code&gt;SOME_MAPPER_NAME&lt;/code&gt; (same value you chose earlier) and &lt;code&gt;SOME_LABEL&lt;/code&gt; as appropriate. If you have multiple disks, rinse and repeat the above steps for them, and then bung them on the end:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;sudo mkfs.btrfs --metadata raid1 --data raid1 --label "SOME_LABEL" /dev/mapper/MAPPER_NAME_A /dev/mapper/MAPPER_NAME_B ... /dev/mapper/MAPPER_NAME_N&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Note the change from &lt;code&gt;single&lt;/code&gt; to &lt;code&gt;raid1&lt;/code&gt;. &lt;code&gt;raid1&lt;/code&gt; stores at least 2 copies on different disks - it's a bit of a misnomer as &lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/472-nas-backups-part-2-btrfs-send-recieve.html"&gt;I've talked about before&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now that you have a kewl Btrfs-formatted partition, mount it as normal:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;sudo mount /dev/mapper/SOME_MAPPER_NAME /absolute/path/to/mount/point&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For Btrfs filesystems with multiple disks, it shouldn't matter which source partition you pick here as Btrfs should pick up on the other disks.&lt;/p&gt;
&lt;h3&gt;Automation&lt;/h3&gt;
&lt;p&gt;Now that we have it formatted, we don't want to hafta keep typing all those commands again. The simple solution to this is to create a shell script and put it somewhere in our &lt;code&gt;$PATH&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;To do this, we should ensure we have a robust name for the disk instead of &lt;code&gt;/dev/nvme&lt;/code&gt;, which could point to a different disk in future if your motherboard or kernel decides to present them in a different order for a giggle. That's easy by looking over the output of &lt;code&gt;blkid&lt;/code&gt; and cross-referencing it with &lt;code&gt;lsblk&lt;/code&gt; and/or &lt;code&gt;df -h&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;sudo lsblk
sudo df -h
sudo blkid # → UUID&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The number you're after should be in the &lt;code&gt;UUID=""&lt;/code&gt; field. The shell script I came up with is short and sweet:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;#!/usr/bin/env bash
disk_id="ID_FROM_BLKID";
mapper_name="SOME_NAME";
mount_path="/absolute/path/to/mount/dir";

sudo cryptsetup luksOpen "/dev/disk/by-uuid/${disk_id}" "${mapper_name}";
sudo mount "/dev/mapper/${mapper_name}" "${mount_path}"&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Fill in the values as appropriate:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;disk_id&lt;/code&gt;:&lt;/strong&gt; The UUID of the disk in question from &lt;code&gt;blkid&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;mapper_name&lt;/code&gt;:&lt;/strong&gt; A name of your choosing that doesn't clash with anything else in &lt;code&gt;/dev/mapper&lt;/code&gt; on your system&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;mount_path&lt;/code&gt;:&lt;/strong&gt; The absolute path to the directory that you want to mount into - usually in &lt;code&gt;/mnt&lt;/code&gt; or &lt;code&gt;/media&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Put this script in e.g. &lt;code&gt;$HOME/.local/bin&lt;/code&gt; or somewhere else in &lt;code&gt;$PATH&lt;/code&gt; that suits you and your setup. Don't forget to run &lt;code&gt;chmod +x path/to/script&lt;/code&gt;!&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;We've formatted an existing partition with LUKS and Btrfs, and written a quick-and-dirty shell script to semi-automate the process of mounting it here.&lt;/p&gt;
&lt;p&gt;If this has been useful or if you have any suggestions, please do leave a comment below!&lt;/p&gt;
&lt;h3&gt;Sources and further reading&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Another guide that I have somehow lost that reminded me about &lt;code&gt;cryptsetup luksFormat&lt;/code&gt; and &lt;code&gt;cryptsetup luksOpen&lt;/code&gt; - if you find it again please leave a comment below! I think it was a GitHub Gist or repo somewhere&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bbs.archlinux.org/viewtopic.php?id=262656"&gt;cryptsetup - device-mapper: reload ioctl on failed: No such file or / Newbie Corner / Arch Linux Forums&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://unix.stackexchange.com/q/658/64687"&gt;linux: How can I view all UUIDs for all available disks on my system? - Unix &amp;#38; Linux Stack Exchange&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;span style='display: none;' itemprop='image' itemscope itemtype='https://schema.org/ImageObject'&gt;&lt;meta itemprop='url' content='http://starbeamrainbowlabs.com/favicon.png' /&gt;&lt;meta itemprop='width' content='256' /&gt;&lt;meta itemprop='height' content='256' /&gt;&lt;/span&gt;
&lt;/div&gt;&lt;meta itemprop='commentCount' content='0' /&gt;&lt;meta itemprop='datePublished' content='2024-06-08T09:00:00+01:00' /&gt;&lt;meta itemprop='dateModified' content='2024-06-08T09:03:33+01:00' /&gt;&lt;hr /&gt;
			&lt;footer class='small-panel centretext'&gt;
				by &lt;span itemprop='author publisher' itemscope itemtype='http://schema.org/Person'&gt;&lt;span itemprop='name'&gt;Starbeamrainbowlabs&lt;/span&gt;&lt;meta itemprop='image' content='https://starbeamrainbowlabs.com/favicon-small.png' /&gt;&lt;/span&gt; | &lt;span class='oi' data-glyph='clock' title='Published on' aria-hidden='true'&gt;&lt;/span&gt;
			&lt;span title='Saturday 8th of June 2024 at 09:00am BST' style='cursor:help;'&gt;8-6-2024 at 09:00 am&lt;/span&gt; | &lt;span class='oi' data-glyph='tag' title='Tags' aria-hidden='true'&gt;&lt;/span&gt;&lt;a href='//starbeamrainbowlabs.com/blog/?tags=Guide'&gt;Guide&lt;/a&gt;, &lt;a href='//starbeamrainbowlabs.com/blog/?tags=Linux'&gt;Linux&lt;/a&gt;, &lt;a href='//starbeamrainbowlabs.com/blog/?tags=Bash'&gt;Bash&lt;/a&gt;, &lt;a href='//starbeamrainbowlabs.com/blog/?tags=Terminal'&gt;Terminal&lt;/a&gt;, &lt;a href='//starbeamrainbowlabs.com/blog/?tags=Security'&gt;Security&lt;/a&gt; | &lt;a itemprop='url' href='https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F548-crypt-btrfs-setup.html'&gt;&lt;span class='oi' data-glyph='link-intact' title='Permanent Link' aria-hidden='true'&gt;&lt;/span&gt;Permanent Link&lt;/a&gt; | &lt;span class='oi' data-glyph='monitor' title='Views'&gt;&lt;/span&gt;4188 views&lt;img class='icon nomargin' data-src='https://starbeamrainbowlabs.com/blog/viewtracker.php?action=record&amp;format=image&amp;post-id=posts%2F548-crypt-btrfs-setup.html' alt='View tracking image. Download it to increment the view counter!' /&gt; | &lt;a href='https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F548-crypt-btrfs-setup.html#comments' itemprop='discussionUrl'&gt;&lt;span class='oi' data-glyph='comment-square' title='Comments' aria-hidden='true'&gt;&lt;/span&gt;0 comments&lt;/a&gt; | &lt;span class='oi' data-glyph='people' title='Share' aria-hidden='true'&gt;&lt;/span&gt;Share via:
&lt;a href='https://starbeamrainbowlabs.com/share2fediverse/#text=Encrypting%20and%20formatting%20a%20disk%20with%20LUKS%20%2B%20Btrfs%20-%20Blog%20post%0Ahttps%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F548-crypt-btrfs-setup.html' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/fediverse.svg' class='icon' title='Share on the Fediverse' alt='Share this post on the Fediverse' /&gt;&lt;/a&gt;
&lt;a href='https://twitter.com/share?url=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F548-crypt-btrfs-setup.html&amp;text=Encrypting%20and%20formatting%20a%20disk%20with%20LUKS%20%2B%20Btrfs%20-%20Blog%20post&amp;via=SBRLabs' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/twitter.svg' class='icon' title='Share via Twitter' alt='Share this post via Twitter' /&gt;&lt;/a&gt;
&lt;a href='https://facebook.com/sharer/sharer.php?u=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F548-crypt-btrfs-setup.html' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/facebook.svg' class='icon' title='Share via Facebook' alt='Share this post via Facebook' /&gt;&lt;/a&gt;
&lt;a href='http://www.addtoany.com/add_to/evernote?linkurl=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F548-crypt-btrfs-setup.html&amp;title=Encrypting%20and%20formatting%20a%20disk%20with%20LUKS%20%2B%20Btrfs' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/evernote.svg' class='icon' title='Share via Evernote' alt='Share this article via Evernote' /&gt;&lt;/a&gt;
&lt;a href='mailto:?Subject=Stardust%20Blog%20Post%3A%20Encrypting%20and%20formatting%20a%20disk%20with%20LUKS%20%2B%20Btrfs&amp;#38;Body=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F548-crypt-btrfs-setup.html'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/mail.svg' class='icon' title='Share by Email' alt='Share by Email' /&gt;&lt;/a&gt;			&lt;/footer&gt;
		&lt;/article&gt;
</content>
    <category term="guide" label="Guide"/>
    <category term="linux" label="Linux"/>
    <category term="bash" label="Bash"/>
    <category term="terminal" label="Terminal"/>
    <category term="security" label="Security"/>
    <author>
      <name>Starbeamrainbowlabs</name>
      <email>sbrl@starbeamrainbowlabs.com</email>
      <uri>https://starbeamrainbowlabs.com</uri>
    </author>
    <published>2024-06-08T09:00:00+01:00</published>
  </entry>
  <entry>
    <title type="html">Inter-process communication between Javascript and Python</title>
    <link href="https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F549-js-python-ipc.html"/>
    <id>https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F549-js-python-ipc.html</id>
    <updated>2024-06-15T09:07:10+01:00</updated>
    <rights type="html">CC-BY-SA</rights>
    <content type="html">&lt;article class='post' data-post-title='Inter-process communication between Javascript and Python' itemscope itemtype='http://schema.org/BlogPosting'&gt;
			&lt;a id='posts%2F549-js-python-ipc.html'&gt;&lt;/a&gt;
&lt;div itemprop='articleBody'&gt;&lt;!--
Release on  | 15th June 2024 at 9:00am
Author      | Starbeamrainbowlabs
Tags        | Javascript, Python, Tutorial 
--&gt;
&lt;p&gt;Often, different programming languages are good at different things. To this end, it is sometimes desirable to write different parts of a program in different languages. In no situation is this more apparent than with an application implementing some kind of (ethical, I hope) AI-based feature.&lt;/p&gt;
&lt;p&gt;I'm currently kinda-sort-mayenbe thinking of implementing a lightweight web interface backed by an AI model (more details if the idea comes to fruition), and while I like writing web servers in Javascript (it really shines with asynchronous input/output), AI models generally don't like being run in Javascript very much - as I have mentioned before, &lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/470-tensorflow-in-review.html"&gt;Tensorflow.js has a number of bugs that mean it isn't practically useful for doing anything serious with AI&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Naturally, the solution then is to run the AI stuff in Python (yeah, Python sucks - believe me I know) since it has the libraries for it, and get Javascript/Node.js to talk to the Python subprocess via inter-process communication, or IPC.&lt;/p&gt;
&lt;p&gt;While Node.js has a fanceh message-passing system it calls IPC, this doesn't really work when communicating with processes that don't also run Javascript/Node.js. To this end, the solution is to use the standard input (stdin) and standard output (stdout) of the child process to communicate:&lt;/p&gt;
&lt;p&gt;&lt;img itemprop="image" src="https://starbeamrainbowlabs.com/blog/images/20240613-IPC-diagram.webp" alt="A colourful diagram of the IPC setup implemented in this post. Node.js, Python, and Terminal are 3 different coloured boxes. Python talks to Node.js via stdin and stdout as input and output respectively. Python&amp;#039;s stderr interacts direct with the terminal, as does Node.js&amp;#039; stdin, stdout, stderr." /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(Above: A diagram of how the IPC setup we're going for works. &lt;a href="https://starbeamrainbowlabs.com/blog/images/20240613-IPC-diagram.ora"&gt;Editing file&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This of course turned out to be more nuanced and complicated than I expected, so I thought I'd document it here - especially since the Internet was very unhelpful on the matter.&lt;/p&gt;
&lt;p&gt;Let's start by writing the parent Node.js script. First, we need to spawn that Python subprocess, so let's do that:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-js"&gt;import { spawn } from 'child_process';
const python = spawn("path/to/child.py", {
    stdio: [ "pipe", "pipe", "inherit" ]
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;...where we set stdin and stdout to &lt;code&gt;pipe&lt;/code&gt; mode - which let's us interact with the streams - and the standard error (stderr) to &lt;code&gt;inherit&lt;/code&gt; mode, which allows it to share the parent process' stderr. That way errors in the child process propagate upwards and end up in the same log file that the parent process sends its output to.&lt;/p&gt;
&lt;p&gt;If you need to send the Python subprocess some data to start with, you have to wait until it is initialised to send it something:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-js"&gt;python.on(`spawn`, () =&amp;#62; {
    console.log(`[node:data:out] Sending initial data packet`);
    python.stdin.write(`start\n`);
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;...an easier alternative than message passing for small amounts of data would be to set an environment variable when you call &lt;code&gt;child_process.spawn&lt;/code&gt; - i.e. &lt;code&gt;env: { key: "value" }&lt;/code&gt; in the options object above.&lt;/p&gt;
&lt;p&gt;Next, we need to read the response from the Python script. Let's do that next:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-js"&gt;import nexline from 'nexline'; // Put this import at the top of the file

const reader = nexline({
    input: python.stdout,
})

for await(const line of reader) {
    console.log(`[node:data:in] ${line}`)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The simplest way to do this would be to listen for the &lt;code&gt;data&lt;/code&gt; event on &lt;code&gt;python.stdout&lt;/code&gt;, but this does not guarantee that each chunk that arrives is &lt;em&gt;actually&lt;/em&gt; a line of data, since data between processes is not line-buffered like it is when displaying content in the terminal.&lt;/p&gt;
&lt;p&gt;To fix this, I suggest using one of my favourite npm packages: &lt;a href="https://npmjs.com/package/nexline"&gt;&lt;code&gt;nexline&lt;/code&gt;&lt;/a&gt;. Believe it or not, handling this issue efficiently with minimal buffering is a lot more difficult than it sounds, so it's just easier to pull in a package to do it for you.&lt;/p&gt;
&lt;p&gt;With a nice little &lt;code&gt;for await..of&lt;/code&gt; loop, we can efficiently read the responses from the Python child process.&lt;/p&gt;
&lt;p&gt;If you were doing this for real, I would suggest wrapping this in an &lt;a href="https://devdocs.io/node/events#class-eventemitter"&gt;&lt;code&gt;EventEmitter&lt;/code&gt;&lt;/a&gt; (Node.js) / &lt;a href="https://devdocs.io/dom/eventtarget"&gt;&lt;code&gt;EventTarget&lt;/code&gt;&lt;/a&gt; (&lt;a href="https://dom.spec.whatwg.org/#interface-eventtarget"&gt;WHAT WG&lt;/a&gt; browser spec, also available in Node.js).&lt;/p&gt;
&lt;h3&gt;Python child process&lt;/h3&gt;
&lt;p&gt;That's basically it for the child process, but what does the Python script look like? It's really quite easy actually:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-python"&gt;import sys

sys.stderr.write(f"[python] hai\n")
sys.stderr.flush()

count = 0
for line in sys.stdin:
    sys.stdout.write(f"boop" + str(count) + "\n")
    sys.stdout.flush()
    count += 1&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Easy! We can simply iterate &lt;code&gt;sys.stdin&lt;/code&gt; to read from the parent Node.js process.&lt;/p&gt;
&lt;p&gt;We can write to &lt;code&gt;sys.stdout&lt;/code&gt; to send data back to the parent process, but &lt;strong&gt;it's important to call &lt;code&gt;sys.stdout.flush()&lt;/code&gt;!&lt;/strong&gt; Node.js doesn't have an equivalent 'cause it's smart, but in Python it may not actually send the response until who-know-when (if at all) unless you call &lt;code&gt;.flush()&lt;/code&gt; to force it to. Think of it as batching graphics draw calls to increase efficiency, but in this case it doesn't work in our favour.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;This is just a quick little tutorial on how to implement Javascript/Node.js &amp;#60;--&amp;#62; Python IPC. We deal im plain-text messages here, but I would recommend using JSON - &lt;code&gt;JSON.stringify()&lt;/code&gt;/&lt;code&gt;JSON.parse()&lt;/code&gt; (Javascript) | &lt;code&gt;json.dumps()&lt;/code&gt; / &lt;code&gt;json.loads&lt;/code&gt; (Python) - to serialise / deserialise messages to ensure robustness. JSON by default contains no newline characters and escapes any present into &lt;code&gt;\n&lt;/code&gt;, so it should be safe in this instance.&lt;/p&gt;
&lt;p&gt;See also &lt;a href="https://jsonlines.org/"&gt;JSON Lines&lt;/a&gt;, a related specification.&lt;/p&gt;
&lt;p&gt;Until next time!&lt;/p&gt;
&lt;h3&gt;Code&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;index.mjs&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-js"&gt;#!/usr/bin/env node
"use strict";

import { spawn } from 'child_process';
import nexline from 'nexline';

///
// Spawn subprocess
///
const python = spawn("/tmp/x/child.py", {
    env: {  // Erases the parent process' environment variables
        "TEST": "value"
    },
    stdio: [ "pipe", "pipe", "inherit" ]
});

python.on(`spawn`, () =&amp;#62; {
    console.log(`[node:data:out] start`);
    python.stdin.write(`start\n`);
});

///
// Send stuff on loop - example
///
let count = 0;
setInterval(() =&amp;#62; {
    python.stdin.write(`interval ${count}\n`);
    console.log(`[node:data:out] interval ${count}`);
    count++;
}, 1000);


///
// Read responses
///
const reader = nexline({
    input: python.stdout,
})

for await(const line of reader) {
    console.log(`[node:data:in] ${line}`)
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;child.py&lt;/code&gt;:&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-python"&gt;#!/usr/bin/env python3
import sys

sys.stderr.write(f"[python] hai\n")
sys.stderr.flush()

count = 0
for line in sys.stdin:
    # sys.stderr.write(f"[python:data:in] {line}\n")
    # sys.stderr.flush()

    sys.stdout.write(f"boop" + str(count) + "\n")
    sys.stdout.flush()
    count += 1
&lt;/code&gt;&lt;/pre&gt;&lt;span style='display: none;' itemprop='image' itemscope itemtype='https://schema.org/ImageObject'&gt;&lt;meta itemprop='url' content='https://starbeamrainbowlabs.com/blog/images/20240613-IPC-diagram.webp' /&gt;&lt;meta itemprop='width' content='3840' /&gt;&lt;meta itemprop='height' content='2160' /&gt;&lt;/span&gt;
&lt;/div&gt;&lt;meta itemprop='commentCount' content='0' /&gt;&lt;meta itemprop='datePublished' content='2024-06-15T09:00:00+01:00' /&gt;&lt;meta itemprop='dateModified' content='2024-06-15T09:07:10+01:00' /&gt;&lt;hr /&gt;
			&lt;footer class='small-panel centretext'&gt;
				by &lt;span itemprop='author publisher' itemscope itemtype='http://schema.org/Person'&gt;&lt;span itemprop='name'&gt;Starbeamrainbowlabs&lt;/span&gt;&lt;meta itemprop='image' content='https://starbeamrainbowlabs.com/favicon-small.png' /&gt;&lt;/span&gt; | &lt;span class='oi' data-glyph='clock' title='Published on' aria-hidden='true'&gt;&lt;/span&gt;
			&lt;span title='Saturday 15th of June 2024 at 09:00am BST' style='cursor:help;'&gt;15-6-2024 at 09:00 am&lt;/span&gt; | &lt;span class='oi' data-glyph='tag' title='Tags' aria-hidden='true'&gt;&lt;/span&gt;&lt;a href='//starbeamrainbowlabs.com/blog/?tags=Javascript'&gt;Javascript&lt;/a&gt;, &lt;a href='//starbeamrainbowlabs.com/blog/?tags=Python'&gt;Python&lt;/a&gt;, &lt;a href='//starbeamrainbowlabs.com/blog/?tags=Tutorial'&gt;Tutorial&lt;/a&gt; | &lt;a itemprop='url' href='https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F549-js-python-ipc.html'&gt;&lt;span class='oi' data-glyph='link-intact' title='Permanent Link' aria-hidden='true'&gt;&lt;/span&gt;Permanent Link&lt;/a&gt; | &lt;span class='oi' data-glyph='monitor' title='Views'&gt;&lt;/span&gt;1614 views&lt;img class='icon nomargin' data-src='https://starbeamrainbowlabs.com/blog/viewtracker.php?action=record&amp;format=image&amp;post-id=posts%2F549-js-python-ipc.html' alt='View tracking image. Download it to increment the view counter!' /&gt; | &lt;a href='https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F549-js-python-ipc.html#comments' itemprop='discussionUrl'&gt;&lt;span class='oi' data-glyph='comment-square' title='Comments' aria-hidden='true'&gt;&lt;/span&gt;0 comments&lt;/a&gt; | &lt;span class='oi' data-glyph='people' title='Share' aria-hidden='true'&gt;&lt;/span&gt;Share via:
&lt;a href='https://starbeamrainbowlabs.com/share2fediverse/#text=Inter-process%20communication%20between%20Javascript%20and%20Python%20-%20Blog%20post%0Ahttps%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F549-js-python-ipc.html' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/fediverse.svg' class='icon' title='Share on the Fediverse' alt='Share this post on the Fediverse' /&gt;&lt;/a&gt;
&lt;a href='https://twitter.com/share?url=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F549-js-python-ipc.html&amp;text=Inter-process%20communication%20between%20Javascript%20and%20Python%20-%20Blog%20post&amp;via=SBRLabs' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/twitter.svg' class='icon' title='Share via Twitter' alt='Share this post via Twitter' /&gt;&lt;/a&gt;
&lt;a href='https://facebook.com/sharer/sharer.php?u=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F549-js-python-ipc.html' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/facebook.svg' class='icon' title='Share via Facebook' alt='Share this post via Facebook' /&gt;&lt;/a&gt;
&lt;a href='http://www.addtoany.com/add_to/evernote?linkurl=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F549-js-python-ipc.html&amp;title=Inter-process%20communication%20between%20Javascript%20and%20Python' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/evernote.svg' class='icon' title='Share via Evernote' alt='Share this article via Evernote' /&gt;&lt;/a&gt;
&lt;a href='mailto:?Subject=Stardust%20Blog%20Post%3A%20Inter-process%20communication%20between%20Javascript%20and%20Python&amp;#38;Body=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F549-js-python-ipc.html'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/mail.svg' class='icon' title='Share by Email' alt='Share by Email' /&gt;&lt;/a&gt;			&lt;/footer&gt;
		&lt;/article&gt;
</content>
    <category term="javascript" label="Javascript"/>
    <category term="python" label="Python"/>
    <category term="tutorial" label="Tutorial"/>
    <author>
      <name>Starbeamrainbowlabs</name>
      <email>sbrl@starbeamrainbowlabs.com</email>
      <uri>https://starbeamrainbowlabs.com</uri>
    </author>
    <published>2024-06-15T09:00:00+01:00</published>
  </entry>
  <entry>
    <title type="html">A memory tester for the days of UEFI</title>
    <link href="https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F550-memtest86.html"/>
    <id>https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F550-memtest86.html</id>
    <updated>2024-06-22T09:03:04+01:00</updated>
    <rights type="html">CC-BY-SA</rights>
    <content type="html">&lt;article class='post' data-post-title='A memory tester for the days of UEFI' itemscope itemtype='http://schema.org/BlogPosting'&gt;
			&lt;a id='posts%2F550-memtest86.html'&gt;&lt;/a&gt;
&lt;div itemprop='articleBody'&gt;&lt;!--
Release on  | 22nd June 2024 at 9:00am
Author      | Starbeamrainbowlabs
Tags        | Linux, Hardware, Tool, Problem Solving
--&gt;
&lt;p&gt;For the longest time, &lt;a href="https://memtest.org/"&gt;&lt;code&gt;memtest86+&lt;/code&gt;&lt;/a&gt; was a standard for testing sticks of RAM that one suspects may be faulty. I haven't used it in a while, but when I do use it I find that an OS-independent tool (i.e. one that you boot into instead of your normal operating system) is the most reliable way to identify faults with RAM.&lt;/p&gt;
&lt;p&gt;It may surprise you, but I've had this post mostly written up for about 2 years...! I remembered about this post recently, and decided to rework some of it and post it here. &lt;/p&gt;
&lt;p&gt;Since UEFI was invented (Unified Extensible Firmware Interface) and replaced the traditional BIOS for booting systems around the world, booting memtest86+ suddenly became more challenging, as it is not currently compatible with UEFI. Now, it has been updated to support UEFI though, so I thought I'd write a blog post about it - mainly because there are very rarely guides on booting images like memtest86+ from a multiboot flash drive, like the one &lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/389-multiboot-2.html"&gt;I have blogged about before&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Before we begin, worthy of note is &lt;a href="https://memtest86.com/"&gt;memtest86&lt;/a&gt;. While it has a very similar name, it is a variant of memtest86+ that is not open source. I have tried it though, and it works well too - brief instructions can be found for it at the end of this blog post.&lt;/p&gt;
&lt;p&gt;I will assume that you have already followed my previous guide on setting up a multiboot flash drive. You can find that guide here:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/389-multiboot-2.html"&gt;Multi-boot + data + multi-partition = octopus flash drive 2.0?&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Alternatively, anywhere you can find a grub config file you can probably follow this guide. I have yet to find an actually decent reference for the grub configuration file language, but if you know of one, please do post it in the comments.&lt;/p&gt;
&lt;h3&gt;Memtest86+ (the open source one)&lt;/h3&gt;
&lt;p&gt;Personally, I recommend the open-source &lt;a href="https://memtest.org/"&gt;Memtest86+&lt;/a&gt;. Since the update to version 7.0, it is now compatible with both BIOS and UEFI-based systems without any additional configuration, which is nice. See the above link to one of my previous blog posts if you would like a flash drive that boots both BIOS and UEFI grub at the same time.&lt;/p&gt;
&lt;p&gt;To start, visit &lt;a href="https://memtest.org/"&gt;the official website&lt;/a&gt;, and scroll down to the download section. From here, you want to download the "Binary Files (.bin/.efi) For PXE and chainloading" version. Unzip the file you download, and you should see the following files:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;memtest32.bin
memtest32.efi
memtest64.bin
memtest64.efi&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;....discard the files with the &lt;code&gt;.efi&lt;/code&gt; file extension - these are for booting directly instead of being chainloaded by grub. As the names suggest, the ones with &lt;code&gt;64&lt;/code&gt; in the filename are the ones for 64-bit systems, which includes most systems today. Copy these to the device of your choice, and the open up your relevant &lt;code&gt;grub.cfg&lt;/code&gt; (or equivalent grub configuration file - &lt;code&gt;/etc/default/grub&lt;/code&gt; on an already-installed system) for editing. Then, somewhere in there add the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-grub"&gt;submenu "Memtest86+" {
    if loadfont unicode ; then
        set gfxmode=1024x768,800x600,auto
        set gfxpayload=800x600,1024x768
        terminal_output gfxterm
    fi

    insmod linux

    menuentry "[amd64] Start Memtest86+, use built-in support for USB keyboards" {
        linux /images/memtest86/memtest64.bin keyboard=both
    }
    menuentry "[amd64] Start Memtest86+, use BIOS legacy emulation for USB keyboards" {
        linux /images/memtest86/memtest64.bin keyboard=legacy
    }
    menuentry "[amd64] Start Memtest86+, disable SMP and memory identification" {
        linux /images/memtest86/memtest64.bin nosmp nosm nobench
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;!-- &lt;TODO LIFT FROM FLASH DRIVE...... and take a backup copy of that disk at some point. Seriously. --&gt;
&lt;p&gt;...replace &lt;code&gt;/images/memtest86/memtest64.bin&lt;/code&gt; with the path to the &lt;code&gt;memtest64.bin&lt;/code&gt; (or &lt;code&gt;memtest32.bin&lt;/code&gt;) file, relative to your &lt;code&gt;grub.cfg&lt;/code&gt; file. I forget where I took the above config file from, but I can't find it in my history.&lt;/p&gt;
&lt;p&gt;If you are doing this on an installed OS instead of a USB flash drive, then things get a little more complicated. You will need to dig around and find what your version of grub considers paths to be relative to, and put your &lt;code&gt;memtest64.bin&lt;/code&gt; file somewhere nearby. If you have experience with this, then please do leave a comment below.&lt;/p&gt;
&lt;p&gt;This should be all you need. For those using a grub setup for an already-installed OS (e.g. via &lt;code&gt;/etc/default/grub&lt;/code&gt;), then you will need to run a command for your changes to take effect:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;sudo update-grub&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Adding shutdown/reboot/reboot to bios setup/firmware options&lt;/h3&gt;
&lt;p&gt;Another thing I discovered recently is how to add options to my grub menu to reboot, shutdown, and reboot into firmware settings. rEFInd (an alternative bootloader to grub that I like very much, but I haven't yet explored for booting multiple ISOs on a flash drive) has these in its menus by default, but grub doesn't - so since I discovered how to do it recently I thought I'd include the config here for reference.&lt;/p&gt;
&lt;p&gt;Simply add the following somewhere in your grub configuration file:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-grub"&gt;menuentry "Reboot" {
    reboot
}

menuentry "Shut Down" {
    halt
}

menuentry "UEFI Firmware / BIOS Settings" {
    fwsetup
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Bonus: Memtest86 (non open-source)&lt;/h3&gt;
&lt;p&gt;I followed [&lt;a href="https://www.yosoygames.com.ar/wp/2020/03/installing-memtest86-on-uefi-grub2-ubuntu/"&gt;https://www.yosoygames.com.ar/wp/2020/03/installing-memtest86-on-uefi-grub2-ubuntu/&lt;/a&gt;] this guide, but ended up changing a few things, so I'll outline the process here. Again, I'll assume you &lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/389-multiboot-2.html"&gt;alreaady have a multiboot flash drive&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Firstly, download &lt;a href="https://www.memtest86.com/downloads/memtest86-usb.zip"&gt;&lt;code&gt;memtest86-usb.zip&lt;/code&gt;&lt;/a&gt; and extract the contents. Then, find the &lt;code&gt;memtest86-usb.img&lt;/code&gt; file and find the offset of the partition that contains the actual EFI image that is the memtest86 program:&lt;/p&gt;
&lt;pre class="language-bash command-line" data-user="sbrl" data-host="somehost" data-output="2-12" data-line="12"&gt;&lt;code&gt;
fdisk -lu memtest86-usb.img

Disk memtest86-usb.img: 500 MiB, 524288000 bytes, 1024000 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: gpt
Disk identifier: 68264C0F-858A-49F0-B692-195B64BE4DD7

Device              Start     End Sectors  Size Type
memtest86-usb.img1   2048  512000  509953  249M Microsoft basic data
memtest86-usb.img2 514048 1023966  509919  249M EFI System
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, take the start position of the second partition (the last line that is highlighted), and multiply it by &lt;code&gt;512&lt;/code&gt;, the sector size. In my case, the number is &lt;code&gt;263192576&lt;/code&gt;. Then, mount the partition into a directory you have already created:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;sudo mount -o loop,offset=263192576 memtest86-usb.img /absolute/path/to/dir&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, browse the contents of the mounted partition and copy the &lt;code&gt;EFI/BOOT&lt;/code&gt; directory off to your flash drive, and rename it to &lt;code&gt;memtest86&lt;/code&gt; or something.&lt;/p&gt;
&lt;p&gt;Now, update your &lt;code&gt;grub.cfg&lt;/code&gt; and add the following:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;menuentry "memtest86" {
    chainloader /images/memtest/BOOTX64.efi
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;....replacing &lt;code&gt;/images/memtest/BOOTX64.efi&lt;/code&gt; with the path to the &lt;code&gt;BOOTX64.efi&lt;/code&gt; file that should be directly in the &lt;code&gt;BOOT&lt;/code&gt; directory you copied off.&lt;/p&gt;
&lt;p&gt;Finally, you should be able to try it out! Boot into your multiboot flash drive as normal, and then select the &lt;code&gt;memtest86&lt;/code&gt; option from the grub menu.&lt;/p&gt;
&lt;h3&gt;Extra note: booting from hard drives&lt;/h3&gt;
&lt;p&gt;This post is really turning into a random grab-bag of items in my grub config file, isn't it? Anyway, An option I don't use all that often (but is very useful when I do need it), are options to boot from the different hard drives in a machine. Since you can't get grub to figure out how many there are in advance, you have to statically define them ahead of time:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-grub"&gt;

submenu "Boot from Hard Drive" {
    menuentry "Hard Drive 0" {
        set root=(hd0)
        chainloader +1
    }
    menuentry "Hard Drive 1" {
        set root=(hd1)
        chainloader +1
    }
    menuentry "Hard Drive 2" {
        set root=(hd2)
        chainloader +1
    }
    menuentry "Hard Drive 3" {
        set root=(hd3)
        chainloader +1
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;....chainloading (aka calling another bootloader) is a wonderful thing :P&lt;/p&gt;
&lt;p&gt;Of course, expand this as much as you like. I believe this approach also works with specific partitions with the syntax &lt;code&gt;(hd0,X)&lt;/code&gt;, where &lt;code&gt;X&lt;/code&gt; is the partition number &lt;strong&gt;starting from 0.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Again, add to your &lt;code&gt;grub.cfg&lt;/code&gt; file and update as above.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;This post is more chaotic and disorganised than I expected, but I thought it would be useful to document some of the tweaks I've made to my multiboot flash drive setup over the years - something that has more proven its worth many many times since I first set it up.&lt;/p&gt;
&lt;p&gt;We've added a memory (RAM) tester to our setup, using the open-source &lt;a href="https://memtest.org/"&gt;Memtest86+&lt;/a&gt;, and the alternative non-open-source version. We've also added options to reboot, shutdown, and enter the bios/uefi firmware settings.&lt;/p&gt;
&lt;p&gt;Finally, we took a quick look at adding options to boot from different hard drives and partitions. If anyone knows how to add a menu item that could allow one to distinguish between different hard disks, partitions, their sizes, and their content more easily, please do leave a comment below.&lt;/p&gt;
&lt;h3&gt;Sources and further reading&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Answer to &lt;a href="https://superuser.com/a/535953"&gt;Linux on UEFI - how to reboot to the UEFI setup screen like Windows 8 can?&lt;/a&gt; on SuperUser, part of the Stack Exchange network&lt;/li&gt;
&lt;li&gt;Answer to &lt;a href="https://askubuntu.com/a/1440254/139735"&gt;How to turn off the computer from the GRUB screen in dual boot&lt;/a&gt; on Ask Ubuntu, part of the Stack Exchange network&lt;/li&gt;
&lt;li&gt;&lt;a href="https://memtest.org/"&gt;memtest86+&lt;/a&gt; (open source version)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://memtest86.com/"&gt;memtest86&lt;/a&gt; (not open source)&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.yosoygames.com.ar/wp/2020/03/installing-memtest86-on-uefi-grub2-ubuntu/"&gt;Installing memtest86 on UEFI Grub2 Ubuntu&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/389-multiboot-2.html"&gt;Multi-boot + data + multi-partition = octopus flash drive 2.0?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;span style='display: none;' itemprop='image' itemscope itemtype='https://schema.org/ImageObject'&gt;&lt;meta itemprop='url' content='http://starbeamrainbowlabs.com/favicon.png' /&gt;&lt;meta itemprop='width' content='256' /&gt;&lt;meta itemprop='height' content='256' /&gt;&lt;/span&gt;
&lt;/div&gt;&lt;meta itemprop='commentCount' content='1' /&gt;&lt;meta itemprop='datePublished' content='2024-06-22T09:00:00+01:00' /&gt;&lt;meta itemprop='dateModified' content='2024-06-22T09:03:04+01:00' /&gt;&lt;hr /&gt;
			&lt;footer class='small-panel centretext'&gt;
				by &lt;span itemprop='author publisher' itemscope itemtype='http://schema.org/Person'&gt;&lt;span itemprop='name'&gt;Starbeamrainbowlabs&lt;/span&gt;&lt;meta itemprop='image' content='https://starbeamrainbowlabs.com/favicon-small.png' /&gt;&lt;/span&gt; | &lt;span class='oi' data-glyph='clock' title='Published on' aria-hidden='true'&gt;&lt;/span&gt;
			&lt;span title='Saturday 22nd of June 2024 at 09:00am BST' style='cursor:help;'&gt;22-6-2024 at 09:00 am&lt;/span&gt; | &lt;span class='oi' data-glyph='tag' title='Tags' aria-hidden='true'&gt;&lt;/span&gt;&lt;a href='//starbeamrainbowlabs.com/blog/?tags=Linux'&gt;Linux&lt;/a&gt;, &lt;a href='//starbeamrainbowlabs.com/blog/?tags=Hardware'&gt;Hardware&lt;/a&gt;, &lt;a href='//starbeamrainbowlabs.com/blog/?tags=Tool'&gt;Tool&lt;/a&gt;, &lt;a href='//starbeamrainbowlabs.com/blog/?tags=Problem%20Solving'&gt;Problem Solving&lt;/a&gt; | &lt;a itemprop='url' href='https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F550-memtest86.html'&gt;&lt;span class='oi' data-glyph='link-intact' title='Permanent Link' aria-hidden='true'&gt;&lt;/span&gt;Permanent Link&lt;/a&gt; | &lt;span class='oi' data-glyph='monitor' title='Views'&gt;&lt;/span&gt;1011 views&lt;img class='icon nomargin' data-src='https://starbeamrainbowlabs.com/blog/viewtracker.php?action=record&amp;format=image&amp;post-id=posts%2F550-memtest86.html' alt='View tracking image. Download it to increment the view counter!' /&gt; | &lt;a href='https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F550-memtest86.html#comments' itemprop='discussionUrl'&gt;&lt;span class='oi' data-glyph='comment-square' title='Comments' aria-hidden='true'&gt;&lt;/span&gt;1 comment&lt;/a&gt; | &lt;span class='oi' data-glyph='people' title='Share' aria-hidden='true'&gt;&lt;/span&gt;Share via:
&lt;a href='https://starbeamrainbowlabs.com/share2fediverse/#text=A%20memory%20tester%20for%20the%20days%20of%20UEFI%20-%20Blog%20post%0Ahttps%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F550-memtest86.html' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/fediverse.svg' class='icon' title='Share on the Fediverse' alt='Share this post on the Fediverse' /&gt;&lt;/a&gt;
&lt;a href='https://twitter.com/share?url=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F550-memtest86.html&amp;text=A%20memory%20tester%20for%20the%20days%20of%20UEFI%20-%20Blog%20post&amp;via=SBRLabs' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/twitter.svg' class='icon' title='Share via Twitter' alt='Share this post via Twitter' /&gt;&lt;/a&gt;
&lt;a href='https://facebook.com/sharer/sharer.php?u=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F550-memtest86.html' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/facebook.svg' class='icon' title='Share via Facebook' alt='Share this post via Facebook' /&gt;&lt;/a&gt;
&lt;a href='http://www.addtoany.com/add_to/evernote?linkurl=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F550-memtest86.html&amp;title=A%20memory%20tester%20for%20the%20days%20of%20UEFI' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/evernote.svg' class='icon' title='Share via Evernote' alt='Share this article via Evernote' /&gt;&lt;/a&gt;
&lt;a href='mailto:?Subject=Stardust%20Blog%20Post%3A%20A%20memory%20tester%20for%20the%20days%20of%20UEFI&amp;#38;Body=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F550-memtest86.html'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/mail.svg' class='icon' title='Share by Email' alt='Share by Email' /&gt;&lt;/a&gt;			&lt;/footer&gt;
		&lt;/article&gt;
</content>
    <category term="linux" label="Linux"/>
    <category term="hardware" label="Hardware"/>
    <category term="tool" label="Tool"/>
    <category term="problem-solving" label="Problem Solving"/>
    <author>
      <name>Starbeamrainbowlabs</name>
      <email>sbrl@starbeamrainbowlabs.com</email>
      <uri>https://starbeamrainbowlabs.com</uri>
    </author>
    <published>2024-06-22T09:00:00+01:00</published>
  </entry>
  <entry>
    <title type="html">Ubuntu 24.04 upgrade report</title>
    <link href="https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F551-ubuntu2404-update.html"/>
    <id>https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F551-ubuntu2404-update.html</id>
    <updated>2024-07-21T21:39:48+01:00</updated>
    <rights type="html">CC-BY-SA</rights>
    <content type="html">&lt;article class='post' data-post-title='Ubuntu 24.04 upgrade report' itemscope itemtype='http://schema.org/BlogPosting'&gt;
			&lt;a id='posts%2F551-ubuntu2404-update.html'&gt;&lt;/a&gt;
&lt;div itemprop='articleBody'&gt;&lt;!--
Release on  | 20th July 2024 at 5:40pm
Author      | Starbeamrainbowlabs
Tags        | Linux, Upgrade
--&gt;
&lt;p&gt;Heya! I just upgraded to from Ubuntu 23.10 to Ubuntu 24.04 today, so I thought I'd publish a quick blog post on my experience. There are a number of issues to watch out for on this one.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;tldr:&lt;/strong&gt; Do &lt;strong&gt;not&lt;/strong&gt; upgrade a machine to which you do not have physical access to 24.04 until the first point-release comes out!&lt;/p&gt;
&lt;p&gt;While the &lt;code&gt;do-release-upgrade&lt;/code&gt; itself went relatively well, I encountered a number of problematic issues that significantly affected the stability of my system afterwards, which I describe below, along with the fixes and workarounds that I applied.&lt;/p&gt;
&lt;p&gt;&lt;img itemprop="image" src="https://starbeamrainbowlabs.com/blog/images/20240720-numbat-slice.jpg" alt="Illustration of a striped numbat, looking up at fireflies against a pink and purple gradient background with light rays coming from the top corners" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(Above: One of the &lt;a href="https://news.itsfoss.com/ubuntu-24-04-lts-wallpapers/"&gt;official wallpapers&lt;/a&gt; for Ubuntu 24.04 Noble Numbat entitled "Little numbat boy", drawn by &lt;a href="https://discourse.ubuntu.com/u/azskalt/summary"&gt;azskalt&lt;/a&gt; in &lt;a href="https://krita.org/"&gt;Krita&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;
&lt;h3&gt;apt sources&lt;/h3&gt;
&lt;p&gt;Of course, any &lt;code&gt;do-release-upgrade&lt;/code&gt; you run is going to disable third-party sources. But this time there's a new mysterious format for apt sources that looks a bit like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Enabled: yes
Signed-By: /etc/apt/trusted.gpg.d/sbrl.asc
Types: deb
URIs: https://apt.starbeamrainbowlabs.com/
Suites: ./
Components: &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;....pretty strange, right? As it turns out, Ubuntu 24.04 has decided to switch to this new "DEB822" apt sources format by default, though I believe the existing format that looks like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;deb [signed-by=/etc/apt/trusted.gpg.d/sbrl.asc] https://apt.starbeamrainbowlabs.com/ ./ # apt.starbeamrainbowlabs.com&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;....should still work. Something else to note: the &lt;code&gt;signed-by&lt;/code&gt; there is now required, and sources won't work without it.&lt;/p&gt;
&lt;p&gt;For more information, see steeldriver's Ask Ubuntu Answer here:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://askubuntu.com/a/1518203/139735"&gt;Where is the documentation for the new apt sources format used in 24.04? - Ask Ubuntu&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Boot failure: plymouth and the splash screen&lt;/h3&gt;
&lt;p&gt;Another issue I encountered was this bug:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://askubuntu.com/a/1515197/139735"&gt;boot - Kubuntu 24.04 Black Screen / Not Booting After Upgrade - Ask Ubuntu&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;...basically, there's a problem with the splash screen which crashes the system because it tries to load an image before the graphics drivers load. The solution here is to disable the &lt;code&gt;splash&lt;/code&gt; option in the grub settings.&lt;/p&gt;
&lt;p&gt;This can be done either before you reboot into 24.04, or if you have already rebooted into 24.04, in the grub menu you can simply hit &lt;code&gt;e&lt;/code&gt; on the default Ubuntu entry in your grub menu and then remove the word &lt;code&gt;splash&lt;/code&gt; from the boot line there.&lt;/p&gt;
&lt;p&gt;If you are lucky enough to see this post before you reboot, then simply edit &lt;code&gt;/etc/default/grub&lt;/code&gt; and change &lt;code&gt;quiet splash&lt;/code&gt; under &lt;code&gt;GRUB_CMDLINE_LINUX_DEFAULT&lt;/code&gt; to be an empty string:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;GRUB_CMDLINE_LINUX_DEFAULT=""&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;...and then update grub like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;sudo update-grub&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Boot failure: unable to even reach grub&lt;/h3&gt;
&lt;p&gt;A strange one I encountered was an inability to even reach grub, even if I manually select the &lt;code&gt;grub.efi&lt;/code&gt; as a boot target via my UEFI firmware settings (I'm on an entroware laptop so that's F2, but your key will vary).&lt;/p&gt;
&lt;p&gt;This one kinda stumped me, so I found this page:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://help.ubuntu.com/community/Boot-Repair"&gt;Boot-Repair - Community Help Wiki&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;...which suggests a boot repair tool. Essentially it reinstalls grub and fixes a number of other common issues, such as a missing nvram entry for grub (UEFI systems need bootloaders registering against them), missing packages - I suspect this was the issue this time - and other common issues.&lt;/p&gt;
&lt;p&gt;It did claim that my nvram was locked, but it still seems to have resolved the issue anyway. I do recommend booting into the live Ubuntu session with the &lt;code&gt;toram&lt;/code&gt; kernel parameter (press &lt;code&gt;e&lt;/code&gt; in the grub menu → add kernel parameter → press ctrl + x) and them removing your flash drive before running this tool, just to avoid it getting confused and messing with the bootloader on your flash drive - thus rendering it unusable - by accident.&lt;/p&gt;
&lt;p&gt;Essentially, boot into a live environment, connect to the Internet, and run then these commands:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;sudo add-apt-repository ppa:yannubuntu/boot-repair &amp;#38;&amp;#38; sudo apt update
sudo apt install -y boot-repair
boot-repair&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;sudo&lt;/code&gt; is not required for some strange reason.&lt;/p&gt;
&lt;h3&gt;indicator-keyboard-service memory leak&lt;/h3&gt;
&lt;p&gt;Finally, there is a significant memory leak in &lt;code&gt;indicator-keyboard-service&lt;/code&gt; - which I assume provides the media/function key functionality, which I only noticed because I have a system resource monitor running in my system tray (&lt;code&gt;indicator-multiload&lt;/code&gt;; &lt;code&gt;multiload-ng&lt;/code&gt; is an alternative version that may work if you have issues with the former). &lt;/p&gt;
&lt;p&gt;The workaround I implemented was to move the offending binary aside and install a stub script in its place:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;cd /usr/libexec/indicator-keyboard
sudo mv indicator-keyboard-service indicator-keyboard-service.bak
sudo nano indicator-keyboard-service&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the text editor for the replacement for &lt;code&gt;indicator-keyboard-service&lt;/code&gt;, paste the following content:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;#!/usr/bin/env sh
exit 0&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;...save and exit. Then, &lt;code&gt;chmod +x&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;sudo chmod +x indicator-keyboard-service&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;....this should at least workaround the issue so that you can regain system stability.&lt;/p&gt;
&lt;p&gt;I run the Unity desktop, but this will likely affect the GNOME desktop and others too. There's already a bug report on Launchpad here:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://bugs.launchpad.net/ubuntu/+source/indicator-keyboard/+bug/2055388"&gt;Bug #2055388 "suspected memory leak with indicator-keyboard (causing gnome-session-flashback to freeze after startup)" : Bugs : indicator-keyboard package : Ubuntu&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;...if this issue affects you, do make sure to go and click the green text at this top-ish of the page to say so. The more people that say it affects them, the higher it will be on the priority list to fix.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;A number of significant issues currently plague the upgrade process to 24.04:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Memory leaks from &lt;code&gt;indicator-keyboard-service&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Multiple issues preventing systems from booting by default&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;...I recommend that upgrading to 24.04 is done cautiously at this time. If you do not have physical access to a given system or do not have the time/energy to fix issues that prevent your system from booting successfully, I strongly recommend waiting for the first or second point release (i.e. 24.04.1 / 24.04.2) before upgrading.&lt;/p&gt;
&lt;p&gt;If you haven't already, I also strongly recommend configuring &lt;a href="https://github.com/linuxmint/timeshift"&gt;timeshift&lt;/a&gt; to take automated snapshots of your system so that you can easily roll back in case of a failure.&lt;/p&gt;
&lt;p&gt;Finally, I also recommend upgrading via the command line with this command:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;sudo do-release-upgrade&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;...and carefully monitoring the logs as the upgrade process is running. Then, do not reboot as it asks you to until you have checked and resolved all of the above issues.&lt;/p&gt;
&lt;p&gt;That's all I have at the moment for upgrading Ubuntu. I have 3 other systems to upgrade from 22.04, but I'll be waiting for the first point release before attempting that. I'll make another post (or a comment on this one) to let everyone know how it went when I do begin the process of upgrading them.&lt;/p&gt;
&lt;p&gt;If you've encountered any issues in the upgrade process to 24.04 (or have any further insight into the issues I describe here), please do leave a comment below!&lt;/p&gt;&lt;span style='display: none;' itemprop='image' itemscope itemtype='https://schema.org/ImageObject'&gt;&lt;meta itemprop='url' content='https://starbeamrainbowlabs.com/blog/images/20240720-numbat-slice.jpg' /&gt;&lt;meta itemprop='width' content='1920' /&gt;&lt;meta itemprop='height' content='592' /&gt;&lt;/span&gt;
&lt;/div&gt;&lt;meta itemprop='commentCount' content='1' /&gt;&lt;meta itemprop='datePublished' content='2024-07-20T17:40:00+01:00' /&gt;&lt;meta itemprop='dateModified' content='2024-07-21T21:39:48+01:00' /&gt;&lt;hr /&gt;
			&lt;footer class='small-panel centretext'&gt;
				by &lt;span itemprop='author publisher' itemscope itemtype='http://schema.org/Person'&gt;&lt;span itemprop='name'&gt;Starbeamrainbowlabs&lt;/span&gt;&lt;meta itemprop='image' content='https://starbeamrainbowlabs.com/favicon-small.png' /&gt;&lt;/span&gt; | &lt;span class='oi' data-glyph='clock' title='Published on' aria-hidden='true'&gt;&lt;/span&gt;
			&lt;span title='Saturday 20th of July 2024 at 05:40pm BST' style='cursor:help;'&gt;20-7-2024 at 05:40 pm&lt;/span&gt; | &lt;span class='oi' data-glyph='tag' title='Tags' aria-hidden='true'&gt;&lt;/span&gt;&lt;a href='//starbeamrainbowlabs.com/blog/?tags=Linux'&gt;Linux&lt;/a&gt;, &lt;a href='//starbeamrainbowlabs.com/blog/?tags=Upgrade'&gt;Upgrade&lt;/a&gt; | &lt;a itemprop='url' href='https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F551-ubuntu2404-update.html'&gt;&lt;span class='oi' data-glyph='link-intact' title='Permanent Link' aria-hidden='true'&gt;&lt;/span&gt;Permanent Link&lt;/a&gt; | &lt;span class='oi' data-glyph='monitor' title='Views'&gt;&lt;/span&gt;826 views&lt;img class='icon nomargin' data-src='https://starbeamrainbowlabs.com/blog/viewtracker.php?action=record&amp;format=image&amp;post-id=posts%2F551-ubuntu2404-update.html' alt='View tracking image. Download it to increment the view counter!' /&gt; | &lt;a href='https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F551-ubuntu2404-update.html#comments' itemprop='discussionUrl'&gt;&lt;span class='oi' data-glyph='comment-square' title='Comments' aria-hidden='true'&gt;&lt;/span&gt;1 comment&lt;/a&gt; | &lt;span class='oi' data-glyph='people' title='Share' aria-hidden='true'&gt;&lt;/span&gt;Share via:
&lt;a href='https://starbeamrainbowlabs.com/share2fediverse/#text=Ubuntu%2024.04%20upgrade%20report%20-%20Blog%20post%0Ahttps%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F551-ubuntu2404-update.html' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/fediverse.svg' class='icon' title='Share on the Fediverse' alt='Share this post on the Fediverse' /&gt;&lt;/a&gt;
&lt;a href='https://twitter.com/share?url=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F551-ubuntu2404-update.html&amp;text=Ubuntu%2024.04%20upgrade%20report%20-%20Blog%20post&amp;via=SBRLabs' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/twitter.svg' class='icon' title='Share via Twitter' alt='Share this post via Twitter' /&gt;&lt;/a&gt;
&lt;a href='https://facebook.com/sharer/sharer.php?u=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F551-ubuntu2404-update.html' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/facebook.svg' class='icon' title='Share via Facebook' alt='Share this post via Facebook' /&gt;&lt;/a&gt;
&lt;a href='http://www.addtoany.com/add_to/evernote?linkurl=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F551-ubuntu2404-update.html&amp;title=Ubuntu%2024.04%20upgrade%20report' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/evernote.svg' class='icon' title='Share via Evernote' alt='Share this article via Evernote' /&gt;&lt;/a&gt;
&lt;a href='mailto:?Subject=Stardust%20Blog%20Post%3A%20Ubuntu%2024.04%20upgrade%20report&amp;#38;Body=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F551-ubuntu2404-update.html'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/mail.svg' class='icon' title='Share by Email' alt='Share by Email' /&gt;&lt;/a&gt;			&lt;/footer&gt;
		&lt;/article&gt;
</content>
    <category term="linux" label="Linux"/>
    <category term="upgrade" label="Upgrade"/>
    <author>
      <name>Starbeamrainbowlabs</name>
      <email>sbrl@starbeamrainbowlabs.com</email>
      <uri>https://starbeamrainbowlabs.com</uri>
    </author>
    <published>2024-07-20T17:40:00+01:00</published>
  </entry>
  <entry>
    <title type="html">PhD Update 19: The Reckoning</title>
    <link href="https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F552-phd-update-19-reckoning.html"/>
    <id>https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F552-phd-update-19-reckoning.html</id>
    <updated>2024-08-12T15:19:59+01:00</updated>
    <rights type="html">CC-BY-SA</rights>
    <content type="html">&lt;article class='post' data-post-title='PhD Update 19: The Reckoning' itemscope itemtype='http://schema.org/BlogPosting'&gt;
			&lt;a id='posts%2F552-phd-update-19-reckoning.html'&gt;&lt;/a&gt;
&lt;div itemprop='articleBody'&gt;&lt;!--
Release on  | 11th August 2024 at 5:05pm
Author      | Starbeamrainbowlabs
Tags        | University, PhD, Update, Announcement
--&gt;
&lt;p&gt;The inevitability of all PhDs. At first it seems distant and ephemeral, but it is also the inescapable and unavoidable destination for all on the epic journey of the PhD.&lt;/p&gt;
&lt;p&gt;Sit down and listen as I tell my own tale of the event I speak of.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/388-phd-update-1-directions.html"&gt;PhD Update 1: Directions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/397-phd-2-experiments.html"&gt;PhD Update 2: The experiment, the data, and the supercomputers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/404-phd-3-simulating-simulations.html"&gt;PhD Update 3: Simulating simulations with some success&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/417-phd-4-gimornous-data.html"&gt;PhD Update 4: Ginormous Data&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/430-phd-update-5-hyper-optimisations-and-frustrations.html"&gt;PhD Update 5: Hyper optimisation and frustration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F438-phd-update-6-the-road-ahead.html"&gt;PhD Update 6: The road ahead&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/452-phd-update-7.html"&gt;PhD Update 7: Just out of reach&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/463-phd-update-8-eggs-baskets.html"&gt;PhD Update 8: Eggs in Baskets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/471-phd-update-9.html"&gt;PhD Update 9: Results?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/476-phd-update-10.html"&gt;PhD Update 10: Sharing with the world&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/485-phd-update-11-answers.html"&gt;PhD Update 11: Answers to our questions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/493-phd-12-enough.html"&gt;PhD Update 12: Is it enough?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/501-PhD-Update-13-a-half-complete.html"&gt;PhD Update 13: A half complete&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/512-phd-update-14.html"&gt;PhD Update 14: An old enemy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/sources/520-phd-update-15.md"&gt;PhD Update 15: Finding what works when&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/528-phd-update-16.html"&gt;PhD Update 16: Realising the possibilities of the past&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/539-phd-update-17.html"&gt;PhD Update 17: Light at the end of the tunnel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/546-phd-update-18.html"&gt;PhD Update 18: The end and the beginning&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I am, of course, talking about the PhD Viva. It differs from country to country, but here in the UK the viva is an "exam" that happens a few months after you have submitted your thesis (&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/546-phd-update-18.html"&gt;PhD Update 18: The end and the beginning&lt;/a&gt;). Unlike across the pond in the US, in the UK vivas are a much more private affair, with only you, the chair, and your internal and external examiners normally attending. &lt;/p&gt;
&lt;p&gt;In my case, that was 2 externals (as I am also staff, ref &lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/525-eo.html"&gt;Achievement get: Experimental Officer Position!&lt;/a&gt;), an internal, and of course the chair. I won't name them as I'm unsure of policy there, but they were experts in the field and very kind people.&lt;/p&gt;
&lt;p&gt;I write this a few weeks removed from the actual event (see also &lt;a href="https://fediscience.org/@sbrl/112849554932147946"&gt;my post on Fediscience at the time&lt;/a&gt;), and I thought that my viva itself deserved a special entry in this series dedicated to it.&lt;/p&gt;
&lt;p&gt;My purpose in this post is to talk about my experience as honestly and candidly as I can, and offer some helpful advice from someone who has now been through the process.&lt;/p&gt;
&lt;h3&gt;The Structure&lt;/h3&gt;
&lt;p&gt;The viva itself took about 4 hours. It's actually a pretty complicated affair: all your examiners (both internal and external) have to read your thesis and come up with a list of questions (hidden from you of course). Then, on the day but before you enter the room they have to debate who is going to ask what to avoid duplication.&lt;/p&gt;
&lt;p&gt;In practice this usually means that the examiners will meet in the morning to discuss, before having lunch and then convening for the &lt;em&gt;actual&lt;/em&gt; viva bit where they ask the questions. In my case, I entered the room to meet the examiners and say hi, before leaving again for them to sort out who was going to ask what.&lt;/p&gt;
&lt;p&gt;Then, the main part of the viva simply consists of you answering all the questions that they have for you. Once all the questions are answered, then the viva is done.&lt;/p&gt;
&lt;p&gt;You are usually allowed a copy of your thesis in one form or another to assist you while answering their questions. The exact form this will take varies from institution to institution, so I recommended always checking this with someone in charge (e.g. the &lt;em&gt;Doctoral College&lt;/em&gt; in my case) well in advance - you don't want to be hit with paperwork and confusion minutes before your viva is scheduled to start!&lt;/p&gt;
&lt;p&gt;After the questions, you leave the room again for the examiners to deliberate over what the outcome will be, before calling you back into the room to give you the news.&lt;/p&gt;
&lt;p&gt;Once they have done this: the whole thing is over and you can go sleep (trust me, you will not want to do anything else).&lt;/p&gt;
&lt;h3&gt;My experience&lt;/h3&gt;
&lt;p&gt;As I alluded to in the aforementioned post on fediscience (a node in &lt;a href="https://fedi.tips/"&gt;the fediverse&lt;/a&gt;), I found the viva a significantly intense experience - and one I'm not keen on repeating any time soon. I strongly recommend having someone nearby as emotional support for after the viva and during those periods when you have to step out of the room. I am not ashamed to admit that there were tears after the exam had ended.&lt;/p&gt;
&lt;p&gt;More of the questions than I expected focused on the 'big picture' kinda stuff, like how my research questions linked in with the rest of the thesis, and how the thesis flowed. I was prepared for technical questions -- and there were some technical questions -- but the 'fluffy stuff' kinda questions caught me a little off guard. For example, there were some questions about my introduction and how while I introduced the subject matter well, the jump into the technical stuff with the research questions was quite jarring, with concepts mentioned that weren't introduced beforehand.&lt;/p&gt;
&lt;p&gt;To this end, I can recommend looking over the 'big picture' stuff beforehand so that you are prepared for questions that quiz you on your motivations for doing your research in the first place and question different aspects research questions.&lt;/p&gt;
&lt;p&gt;It can also feel quite demoralising, being questioned for hours on what has been your entire life for multiple years. It can feel like all you have done is pointless, and you need to start over. While it is sure that you could improve upon your methods if you started from scratch, remember that you have worked hard to get to this point! You have discovered things that were not known to the world before your research began, and that is a significant accomplishment!&lt;/p&gt;
&lt;p&gt;Try not to think too hard about the corrections you will need to make once the viva is done. Institutions differ, but in my case it is the job of the chair to compile the list of corrections and then send them to you (in one form or another). The list of corrections - even if they are explained to you verbally when you go back in to receive the result - may surprise you.&lt;/p&gt;
&lt;h3&gt;Outcome&lt;/h3&gt;
&lt;p&gt;As I am sure that most of you reading this are wondering, what was my result?! Before I tell you, I will preface the answer to your burning question with a list of the possible outcomes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Pass with no corrections (extremely rare)&lt;/li&gt;
&lt;li&gt;Pass with X months corrections (common, where X is a multiple of 3)&lt;/li&gt;
&lt;li&gt;Fail (also extremely rare)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In my case, I &lt;strong&gt;passed with corrections&lt;/strong&gt;!&lt;/p&gt;
&lt;p&gt;It is complicated by the fact that while the panel decided that I had 6 months of corrections to do, I am not able to spend 100% of my time doing them. To this end, it is currently undefined how long I will have to do them - paperwork is still being sorted out.&lt;/p&gt;
&lt;p&gt;The reasons for this are many, but chief among them is that I will be doing some teaching in September - more to come on my experience doing that in a separate post (series?) just as soon as I have clarified what I can talk about and what I can't.&lt;/p&gt;
&lt;p&gt;I have yet to recieve a list of the corrections themselves (although I have not checked my email recently as I'm on holiday now as I write this), but it is likely that the corrections will include re-running some experiments - a process I have begun already.&lt;/p&gt;
&lt;h3&gt;Looking ahead&lt;/h3&gt;
&lt;p&gt;So here we are. I have passed my viva with corrections! This is &lt;strong&gt;not the end of this series&lt;/strong&gt; - I will keep everyone updated in future posts as I work through the corrections.&lt;/p&gt;
&lt;p&gt;I also intend to write a post or two about my experience learning to teach - a (side)quest that I am currently persuing in my capacity as Experimental Officer (research is still my focus - don't worry!)&lt;/p&gt;
&lt;p&gt;Hopefully this post has provided some helpful insight into the process of the PhD viva - and my experience in mine.&lt;/p&gt;
&lt;p&gt;The viva is not a destination: only a waypoint on a longer journey.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;If you have any questions, I am happy to anwser them in the comments, and chat on &lt;a href="https://fediscience.org/@sbrl"&gt;the fediverse&lt;/a&gt; and via other related channels.&lt;/em&gt;&lt;/p&gt;&lt;span style='display: none;' itemprop='image' itemscope itemtype='https://schema.org/ImageObject'&gt;&lt;meta itemprop='url' content='http://starbeamrainbowlabs.com/favicon.png' /&gt;&lt;meta itemprop='width' content='256' /&gt;&lt;meta itemprop='height' content='256' /&gt;&lt;/span&gt;
&lt;/div&gt;&lt;meta itemprop='commentCount' content='0' /&gt;&lt;meta itemprop='datePublished' content='2024-08-11T17:05:00+01:00' /&gt;&lt;meta itemprop='dateModified' content='2024-08-12T15:19:59+01:00' /&gt;&lt;hr /&gt;
			&lt;footer class='small-panel centretext'&gt;
				by &lt;span itemprop='author publisher' itemscope itemtype='http://schema.org/Person'&gt;&lt;span itemprop='name'&gt;Starbeamrainbowlabs&lt;/span&gt;&lt;meta itemprop='image' content='https://starbeamrainbowlabs.com/favicon-small.png' /&gt;&lt;/span&gt; | &lt;span class='oi' data-glyph='clock' title='Published on' aria-hidden='true'&gt;&lt;/span&gt;
			&lt;span title='Sunday 11th of August 2024 at 05:05pm BST' style='cursor:help;'&gt;11-8-2024 at 05:05 pm&lt;/span&gt; | &lt;span class='oi' data-glyph='tag' title='Tags' aria-hidden='true'&gt;&lt;/span&gt;&lt;a href='//starbeamrainbowlabs.com/blog/?tags=University'&gt;University&lt;/a&gt;, &lt;a href='//starbeamrainbowlabs.com/blog/?tags=PhD'&gt;PhD&lt;/a&gt;, &lt;a href='//starbeamrainbowlabs.com/blog/?tags=Update'&gt;Update&lt;/a&gt;, &lt;a href='//starbeamrainbowlabs.com/blog/?tags=Announcement'&gt;Announcement&lt;/a&gt; | &lt;a itemprop='url' href='https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F552-phd-update-19-reckoning.html'&gt;&lt;span class='oi' data-glyph='link-intact' title='Permanent Link' aria-hidden='true'&gt;&lt;/span&gt;Permanent Link&lt;/a&gt; | &lt;span class='oi' data-glyph='monitor' title='Views'&gt;&lt;/span&gt;523 views&lt;img class='icon nomargin' data-src='https://starbeamrainbowlabs.com/blog/viewtracker.php?action=record&amp;format=image&amp;post-id=posts%2F552-phd-update-19-reckoning.html' alt='View tracking image. Download it to increment the view counter!' /&gt; | &lt;a href='https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F552-phd-update-19-reckoning.html#comments' itemprop='discussionUrl'&gt;&lt;span class='oi' data-glyph='comment-square' title='Comments' aria-hidden='true'&gt;&lt;/span&gt;0 comments&lt;/a&gt; | &lt;span class='oi' data-glyph='people' title='Share' aria-hidden='true'&gt;&lt;/span&gt;Share via:
&lt;a href='https://starbeamrainbowlabs.com/share2fediverse/#text=PhD%20Update%2019%3A%20The%20Reckoning%20-%20Blog%20post%0Ahttps%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F552-phd-update-19-reckoning.html' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/fediverse.svg' class='icon' title='Share on the Fediverse' alt='Share this post on the Fediverse' /&gt;&lt;/a&gt;
&lt;a href='https://twitter.com/share?url=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F552-phd-update-19-reckoning.html&amp;text=PhD%20Update%2019%3A%20The%20Reckoning%20-%20Blog%20post&amp;via=SBRLabs' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/twitter.svg' class='icon' title='Share via Twitter' alt='Share this post via Twitter' /&gt;&lt;/a&gt;
&lt;a href='https://facebook.com/sharer/sharer.php?u=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F552-phd-update-19-reckoning.html' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/facebook.svg' class='icon' title='Share via Facebook' alt='Share this post via Facebook' /&gt;&lt;/a&gt;
&lt;a href='http://www.addtoany.com/add_to/evernote?linkurl=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F552-phd-update-19-reckoning.html&amp;title=PhD%20Update%2019%3A%20The%20Reckoning' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/evernote.svg' class='icon' title='Share via Evernote' alt='Share this article via Evernote' /&gt;&lt;/a&gt;
&lt;a href='mailto:?Subject=Stardust%20Blog%20Post%3A%20PhD%20Update%2019%3A%20The%20Reckoning&amp;#38;Body=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F552-phd-update-19-reckoning.html'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/mail.svg' class='icon' title='Share by Email' alt='Share by Email' /&gt;&lt;/a&gt;			&lt;/footer&gt;
		&lt;/article&gt;
</content>
    <category term="university" label="University"/>
    <category term="phd" label="PhD"/>
    <category term="update" label="Update"/>
    <category term="announcement" label="Announcement"/>
    <author>
      <name>Starbeamrainbowlabs</name>
      <email>sbrl@starbeamrainbowlabs.com</email>
      <uri>https://starbeamrainbowlabs.com</uri>
    </author>
    <published>2024-08-11T17:05:00+01:00</published>
  </entry>
  <entry>
    <title type="html">Teaching this September</title>
    <link href="https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F553-ificating.html"/>
    <id>https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F553-ificating.html</id>
    <updated>2024-09-17T19:18:11+01:00</updated>
    <rights type="html">CC-BY-SA</rights>
    <content type="html">&lt;article class='post' data-post-title='Teaching this September' itemscope itemtype='http://schema.org/BlogPosting'&gt;
			&lt;a id='posts%2F553-ificating.html'&gt;&lt;/a&gt;
&lt;div itemprop='articleBody'&gt;&lt;!--
Release on  | 17th September 2024 at 9:00am
Author      | Starbeamrainbowlabs
Tags        | Update, University
--&gt;
&lt;p&gt;&lt;img itemprop="image" src="https://starbeamrainbowlabs.com/blog/images/20180816-Banner-B.png" alt="A banner from a game long lost. Maybe I&amp;#039;ll remake it and finish it someday." /&gt;&lt;/p&gt;
&lt;p&gt;Hello!&lt;/p&gt;
&lt;p&gt;Believe it or not, I'm going to be teachificatinating a thing at University this semester, which starts at the end of this month and lasts until around December-ish time (yeah, I'm surprised too).&lt;/p&gt;
&lt;p&gt;It's called &lt;em&gt;Secure Digital Infrastructure&lt;/em&gt;, and I'll be teaching Linux and system administration skills, so that includes the following sorta-areas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bash (&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/242-Learn-Your-Terminal.html"&gt;Learn your terminal (or command line)&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Linux file and account permissions (no posts I could find yet - plenty of resources online tho)&lt;/li&gt;
&lt;li&gt;Practical networking and web server configuration (see also &lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/514-dns-nsd.html"&gt;The NSD Authoritative DNS Server: What, why, and how&lt;/a&gt; and &lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/515-dynamic-dns.html"&gt;part 2&lt;/a&gt;, &lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/291-DNS-Epic-Journey.html"&gt;An epic journey awaits: The hows and whys of DNS (and why DNS privacy is important)&lt;/a&gt;, &lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/047-Linux-Security-Part-1.html"&gt;Securing a Linux Server Part 1: Firewall&lt;/a&gt;, and others)&lt;/li&gt;
&lt;li&gt;Docker (see also &lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/445-cluster-10-dockerfiles.html"&gt;Cluster, Part 10: Dockerisification | Writing Dockerfiles&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Clustering - at least the theory (see also &lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/486-cluster-series-list.html"&gt;Cluster Series List&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/314-Proxies-What-is-the-difference.html"&gt;Reverse proxies&lt;/a&gt; (see also related posts: &lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/477-reverse-proxy-security.html"&gt;Securing your port-forwarded reverse proxy&lt;/a&gt; and the unreasonably popular &lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/237-WebDav-Nginx-Setup.html"&gt;How to set up a WebDav share with Nginx&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;(related posts aren't necessarily the exact content I'm going to cover, but are related)&lt;/p&gt;
&lt;p&gt;To this end, it is quite stressful and is taking significantly more energy than I expected to prepare for this.&lt;/p&gt;
&lt;p&gt;I definitely want to talk about it here, but that will likely happen after the fact - probably some time in January or February.&lt;/p&gt;
&lt;p&gt;Please be patient with me as I navigate this new and unexpected experience :-)&lt;/p&gt;
&lt;p&gt;--Starbeamrainbowlabs&lt;/p&gt;
&lt;p&gt;&lt;img itemprop="image" src="https://starbeamrainbowlabs.com/blog/images/20180816-Banner-A.png" alt="A banner from a game long lost. Maybe I&amp;#039;ll remake it and finish it someday." /&gt;&lt;/p&gt;&lt;span style='display: none;' itemprop='image' itemscope itemtype='https://schema.org/ImageObject'&gt;&lt;meta itemprop='url' content='https://starbeamrainbowlabs.com/blog/images/20180816-Banner-B.png' /&gt;&lt;meta itemprop='width' content='1248' /&gt;&lt;meta itemprop='height' content='404' /&gt;&lt;/span&gt;
&lt;/div&gt;&lt;meta itemprop='commentCount' content='0' /&gt;&lt;meta itemprop='datePublished' content='2024-09-17T09:00:00+01:00' /&gt;&lt;meta itemprop='dateModified' content='2024-09-17T19:18:11+01:00' /&gt;&lt;hr /&gt;
			&lt;footer class='small-panel centretext'&gt;
				by &lt;span itemprop='author publisher' itemscope itemtype='http://schema.org/Person'&gt;&lt;span itemprop='name'&gt;Starbeamrainbowlabs&lt;/span&gt;&lt;meta itemprop='image' content='https://starbeamrainbowlabs.com/favicon-small.png' /&gt;&lt;/span&gt; | &lt;span class='oi' data-glyph='clock' title='Published on' aria-hidden='true'&gt;&lt;/span&gt;
			&lt;span title='Tuesday 17th of September 2024 at 09:00am BST' style='cursor:help;'&gt;17-9-2024 at 09:00 am&lt;/span&gt; | &lt;span class='oi' data-glyph='tag' title='Tags' aria-hidden='true'&gt;&lt;/span&gt;&lt;a href='//starbeamrainbowlabs.com/blog/?tags=Update'&gt;Update&lt;/a&gt;, &lt;a href='//starbeamrainbowlabs.com/blog/?tags=University'&gt;University&lt;/a&gt; | &lt;a itemprop='url' href='https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F553-ificating.html'&gt;&lt;span class='oi' data-glyph='link-intact' title='Permanent Link' aria-hidden='true'&gt;&lt;/span&gt;Permanent Link&lt;/a&gt; | &lt;span class='oi' data-glyph='monitor' title='Views'&gt;&lt;/span&gt;579 views&lt;img class='icon nomargin' data-src='https://starbeamrainbowlabs.com/blog/viewtracker.php?action=record&amp;format=image&amp;post-id=posts%2F553-ificating.html' alt='View tracking image. Download it to increment the view counter!' /&gt; | &lt;a href='https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F553-ificating.html#comments' itemprop='discussionUrl'&gt;&lt;span class='oi' data-glyph='comment-square' title='Comments' aria-hidden='true'&gt;&lt;/span&gt;0 comments&lt;/a&gt; | &lt;span class='oi' data-glyph='people' title='Share' aria-hidden='true'&gt;&lt;/span&gt;Share via:
&lt;a href='https://starbeamrainbowlabs.com/share2fediverse/#text=Teaching%20this%20September%20-%20Blog%20post%0Ahttps%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F553-ificating.html' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/fediverse.svg' class='icon' title='Share on the Fediverse' alt='Share this post on the Fediverse' /&gt;&lt;/a&gt;
&lt;a href='https://twitter.com/share?url=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F553-ificating.html&amp;text=Teaching%20this%20September%20-%20Blog%20post&amp;via=SBRLabs' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/twitter.svg' class='icon' title='Share via Twitter' alt='Share this post via Twitter' /&gt;&lt;/a&gt;
&lt;a href='https://facebook.com/sharer/sharer.php?u=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F553-ificating.html' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/facebook.svg' class='icon' title='Share via Facebook' alt='Share this post via Facebook' /&gt;&lt;/a&gt;
&lt;a href='http://www.addtoany.com/add_to/evernote?linkurl=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F553-ificating.html&amp;title=Teaching%20this%20September' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/evernote.svg' class='icon' title='Share via Evernote' alt='Share this article via Evernote' /&gt;&lt;/a&gt;
&lt;a href='mailto:?Subject=Stardust%20Blog%20Post%3A%20Teaching%20this%20September&amp;#38;Body=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F553-ificating.html'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/mail.svg' class='icon' title='Share by Email' alt='Share by Email' /&gt;&lt;/a&gt;			&lt;/footer&gt;
		&lt;/article&gt;
</content>
    <category term="update" label="Update"/>
    <category term="university" label="University"/>
    <author>
      <name>Starbeamrainbowlabs</name>
      <email>sbrl@starbeamrainbowlabs.com</email>
      <uri>https://starbeamrainbowlabs.com</uri>
    </author>
    <published>2024-09-17T09:00:00+01:00</published>
  </entry>
  <entry>
    <title type="html">Ducks</title>
    <link href="https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F554-ducks.html"/>
    <id>https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F554-ducks.html</id>
    <updated>2024-11-01T10:03:46+00:00</updated>
    <rights type="html">CC-BY-SA</rights>
    <content type="html">&lt;article class='post' data-post-title='Ducks' itemscope itemtype='http://schema.org/BlogPosting'&gt;
			&lt;a id='posts%2F554-ducks.html'&gt;&lt;/a&gt;
&lt;div itemprop='articleBody'&gt;&lt;!--
Release on  | 1st November 2024 at 10:00am
Author      | Starbeamrainbowlabs
Tags        | Update
--&gt;
&lt;p&gt;Heya!&lt;/p&gt;
&lt;p&gt;I like ducks. Have some ducks:&lt;/p&gt;
&lt;p&gt;&lt;img itemprop="image" src="https://starbeamrainbowlabs.com/blog/images/20241030-ducks.png" alt="Some duck wallpaper" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(Source: Unknown. If you're the creator and can prove it, comment below and I'll attribute properly)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;....teaching is not easy, and I don't like preparing content week-by-week (i.e. preparing content to teach the next week) very much at all.&lt;/p&gt;
&lt;p&gt;I recognise this is the longest break in blog posts there has been since I began this on 29th June 2014 (wow, it has been 10 years here already?!). Both energy and time are extraordinarily low at the moment (I have not had even a moment to work on my PhD corrections in over a month at this point).&lt;/p&gt;
&lt;p&gt;However, there is hope that this is not a permanent state of affairs (and if I have anything to say about it, it won't be).&lt;/p&gt;
&lt;p&gt;Hopefully in a few weeks things should improve to the point that I have energy to work on my PhD and post here again.&lt;/p&gt;
&lt;p&gt;I've got several cool ideas for posts that I want to write:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Most obviously, I want to write a blog post about my experiences teaching&lt;/li&gt;
&lt;li&gt;I've found a really neat solution to a 3-way split of a dataset in Tensorflow&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And others that are a thing in the background.&lt;/p&gt;
&lt;p&gt;Just a short check in to let everyone know that while I am very exhausted I am also very determined to keep this blog going as a permanent thing.&lt;/p&gt;
&lt;p&gt;It's not much of a 10 year celebration, but if you've been reading here for a while I thank you SO MUCH for continuing to stick around, even if you don't comment.&lt;/p&gt;
&lt;p&gt;There is &lt;em&gt;always&lt;/em&gt; hope.&lt;/p&gt;
&lt;p&gt;--Starbeamrainbowlabs&lt;/p&gt;&lt;span style='display: none;' itemprop='image' itemscope itemtype='https://schema.org/ImageObject'&gt;&lt;meta itemprop='url' content='https://starbeamrainbowlabs.com/blog/images/20241030-ducks.png' /&gt;&lt;meta itemprop='width' content='1000' /&gt;&lt;meta itemprop='height' content='1000' /&gt;&lt;/span&gt;
&lt;/div&gt;&lt;meta itemprop='commentCount' content='0' /&gt;&lt;meta itemprop='datePublished' content='2024-11-01T10:00:00+00:00' /&gt;&lt;meta itemprop='dateModified' content='2024-11-01T10:03:46+00:00' /&gt;&lt;hr /&gt;
			&lt;footer class='small-panel centretext'&gt;
				by &lt;span itemprop='author publisher' itemscope itemtype='http://schema.org/Person'&gt;&lt;span itemprop='name'&gt;Starbeamrainbowlabs&lt;/span&gt;&lt;meta itemprop='image' content='https://starbeamrainbowlabs.com/favicon-small.png' /&gt;&lt;/span&gt; | &lt;span class='oi' data-glyph='clock' title='Published on' aria-hidden='true'&gt;&lt;/span&gt;
			&lt;span title='Friday 1st of November 2024 at 10:00am GMT' style='cursor:help;'&gt;1-11-2024 at 10:00 am&lt;/span&gt; | &lt;span class='oi' data-glyph='tag' title='Tags' aria-hidden='true'&gt;&lt;/span&gt;&lt;a href='//starbeamrainbowlabs.com/blog/?tags=Update'&gt;Update&lt;/a&gt; | &lt;a itemprop='url' href='https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F554-ducks.html'&gt;&lt;span class='oi' data-glyph='link-intact' title='Permanent Link' aria-hidden='true'&gt;&lt;/span&gt;Permanent Link&lt;/a&gt; | &lt;span class='oi' data-glyph='monitor' title='Views'&gt;&lt;/span&gt;360 views&lt;img class='icon nomargin' data-src='https://starbeamrainbowlabs.com/blog/viewtracker.php?action=record&amp;format=image&amp;post-id=posts%2F554-ducks.html' alt='View tracking image. Download it to increment the view counter!' /&gt; | &lt;a href='https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F554-ducks.html#comments' itemprop='discussionUrl'&gt;&lt;span class='oi' data-glyph='comment-square' title='Comments' aria-hidden='true'&gt;&lt;/span&gt;0 comments&lt;/a&gt; | &lt;span class='oi' data-glyph='people' title='Share' aria-hidden='true'&gt;&lt;/span&gt;Share via:
&lt;a href='https://starbeamrainbowlabs.com/share2fediverse/#text=Ducks%20-%20Blog%20post%0Ahttps%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F554-ducks.html' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/fediverse.svg' class='icon' title='Share on the Fediverse' alt='Share this post on the Fediverse' /&gt;&lt;/a&gt;
&lt;a href='https://twitter.com/share?url=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F554-ducks.html&amp;text=Ducks%20-%20Blog%20post&amp;via=SBRLabs' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/twitter.svg' class='icon' title='Share via Twitter' alt='Share this post via Twitter' /&gt;&lt;/a&gt;
&lt;a href='https://facebook.com/sharer/sharer.php?u=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F554-ducks.html' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/facebook.svg' class='icon' title='Share via Facebook' alt='Share this post via Facebook' /&gt;&lt;/a&gt;
&lt;a href='http://www.addtoany.com/add_to/evernote?linkurl=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F554-ducks.html&amp;title=Ducks' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/evernote.svg' class='icon' title='Share via Evernote' alt='Share this article via Evernote' /&gt;&lt;/a&gt;
&lt;a href='mailto:?Subject=Stardust%20Blog%20Post%3A%20Ducks&amp;#38;Body=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F554-ducks.html'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/mail.svg' class='icon' title='Share by Email' alt='Share by Email' /&gt;&lt;/a&gt;			&lt;/footer&gt;
		&lt;/article&gt;
</content>
    <category term="update" label="Update"/>
    <author>
      <name>Starbeamrainbowlabs</name>
      <email>sbrl@starbeamrainbowlabs.com</email>
      <uri>https://starbeamrainbowlabs.com</uri>
    </author>
    <published>2024-11-01T10:00:00+00:00</published>
  </entry>
  <entry>
    <title type="html">Compiling the wacom driver from source to fix tilt &amp;amp; rotation support</title>
    <link href="https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F555-install-wacom-driver-tilt-rotation-support.html"/>
    <id>https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F555-install-wacom-driver-tilt-rotation-support.html</id>
    <updated>2024-11-27T00:57:59+00:00</updated>
    <rights type="html">CC-BY-SA</rights>
    <content type="html">&lt;article class='post' data-post-title='Compiling the wacom driver from source to fix tilt &amp;#38; rotation support' itemscope itemtype='http://schema.org/BlogPosting'&gt;
			&lt;a id='posts%2F555-install-wacom-driver-tilt-rotation-support.html'&gt;&lt;/a&gt;
&lt;div itemprop='articleBody'&gt;&lt;!--
Release on  | 22nd November 2024 at 9:00am
Author      | Starbeamrainbowlabs
Tags        | Linux, Terminal, Tutorial, Graphics, Hardware
--&gt;
&lt;p&gt;I was all sat down and setup to do some digital drawing the other day, and then I finally snapped. My graphics tablet (a secondhand Wacom Intuos Pro S from Vinted) - which supports &lt;a href="https://support.wacom.com/hc/en-us/articles/1500006270201-What-is-Tilt"&gt;pen tilt&lt;/a&gt; - was not functioning correctly. Due to &lt;a href="https://github.com/linuxwacom/input-wacom/issues/445"&gt;a bug&lt;/a&gt; that has yet to be patched, the tilt X/Y coordinates were being wrongly interpreted as unsigned integers (i.e. &lt;code&gt;uint32&lt;/code&gt;) instead of signed integers (e.g. &lt;code&gt;int32&lt;/code&gt;). This had the effect of causing the rotational calculation to jump around randomly, making it difficult when drawing.&lt;/p&gt;
&lt;p&gt;So, given that someone had kindly posted a source patch, I set about compiling the driver from source. For some reason that is currently unclear to me, it is not being merged into the main wacom tablet driver repository. This leaves compiling from source with the patch the only option here that is currently available.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/linuxwacom/input-wacom/issues/445#issuecomment-2484100012"&gt;It worked!&lt;/a&gt; I was so ecstatic. I had tilt functionality for the first time!&lt;/p&gt;
&lt;p&gt;Fast-forward to yesterday....... and it broke again, and I first noticed because I am left-handed and I have &lt;a href="https://gitlab.com/sbrl/bin/-/blob/master/scripts/setup-intuos-pro-s-listen.py"&gt;a script&lt;/a&gt; that flips the mapping of the pad around so I can use it the opposite way around.&lt;/p&gt;
&lt;p&gt;I have since fixed it, but the entire process took me long enough to figure out that I realised that I was halfway there to writing a blog post as a comment on the aforementioned GitHub issue, so I decided to just go the rest of the way and write this up into a full blog post / tutorially kinda thing and do the drawing I wanted to do in the first place tomorrow.&lt;/p&gt;
&lt;p&gt;In short, there are &lt;strong&gt;2 parts&lt;/strong&gt; to this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;input-wacom&lt;/code&gt;, the kernel driver&lt;/li&gt;
&lt;li&gt;&lt;code&gt;xf86-input-wacom&lt;/code&gt;, the X11 driver that talks to the kernel driver&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;....and they both have to be compiled separately, as I discovered yesterday.&lt;/p&gt;
&lt;h3&gt;Who is this for?&lt;/h3&gt;
&lt;p&gt;If you've got a Wacom Intuos tablet that supports pen tilt / rotation, then this blog post is for you.&lt;/p&gt;
&lt;p&gt;Mine is a Wacom Intuos Pro S PTH-460.&lt;/p&gt;
&lt;p&gt;This tutorial has been written on Ubuntu 24.04, but it should work for other systems too.&lt;/p&gt;
&lt;p&gt;If there's the demand I might put together a package and put it in my &lt;a href="https://apt.starbeamrainbowlabs.com/"&gt;apt repo&lt;/a&gt;, though naturally this will be limited to the versions of Ubuntu I personally use on my laptop - though do tend to upgrade through the 6-monthly updates.&lt;/p&gt;
&lt;p&gt;I could also put together an AUR package, but currently on the devices I run Artix (Arch derivative) I don't usually have a tilt-supporting graphics tablet physically nearby when I'm using them and they run Wayland for unavoidable reasons.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Linux MY_DEVICE_NAME 6.8.0-48-generic #48-Ubuntu SMP PREEMPT_DYNAMIC Fri Sep 27 14:04:52 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Kompiling the kernel module&lt;/h3&gt;
&lt;p&gt;Navigate to a clean directory somewhere persistent, as you may need to get back to it later.&lt;/p&gt;
&lt;p&gt;If you have the kernel driver installed, then uninstall it now.&lt;/p&gt;
&lt;p&gt;On Ubuntu / apt-based systems, they bundle the kernel module and the X11 driver bit all in a single package..... hence the reason why we hafta do all the legwork of compiling and installing both the kernel module and the X11 driver from source :-/&lt;/p&gt;
&lt;p&gt;e.g. on Ubuntu:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;sudo apt remove xserver-xorg-input-wacom&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, clone the git repo and checkout the right branch:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;git clone https://github.com/jigpu/input-wacom.git -b fix-445
cd input-wacom;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;....then, ref the &lt;a href="https://github.com/linuxwacom/input-wacom/wiki/Installing-input-wacom-from-source"&gt;official instructions&lt;/a&gt; install build-time dependencies if required:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;sudo apt-get install build-essential autoconf linux-headers-$(uname -r)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;...check if you have these installed already by replacing &lt;code&gt;apt-get install&lt;/code&gt; with &lt;code&gt;apt-cache policy&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then, build and install all-in-one:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;if test -x ./autogen.sh; then ./autogen.sh; else ./configure; fi &amp;#38;&amp;#38; make &amp;#38;&amp;#38; sudo make install || echo "Build Failed"&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;....this will prompt for a password to install directly into your system. I think they recommend to do it this way to simplify the build process for people.&lt;/p&gt;
&lt;p&gt;This should complete our khecklist for the kernel module, but to activate it you'll need to reboot.&lt;/p&gt;
&lt;p&gt;Don't bother doing that right now though on Ubuntu, since we have the X11 driver to go. For users on systems lucky enough to split the 2 drivers up, then you can just reboot here.&lt;/p&gt;
&lt;p&gt;You can check (&lt;strong&gt;after&lt;/strong&gt; rebooting!) if you've got the right &lt;code&gt;input-wacom&lt;/code&gt; kernel module with this command:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;grep "" /sys/module/wacom*/version&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;....my research suggests you need to have a wacom tablet plugged in for this to work.&lt;/p&gt;
&lt;p&gt;If you get something like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;$ grep "" /sys/module/wacom*/version
v2.00&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;....then you're still using your distribution-provided wacom kernel module. Go uninstall it!&lt;/p&gt;
&lt;p&gt;The output you're looking for should look a bit like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;$ grep "" /sys/module/wacom*/version
v2.00-1.2.0.37.g2c27caa&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Compiling the X11 driver&lt;/h3&gt;
&lt;p&gt;Next up is &lt;code&gt;xf86-input-wacom&lt;/code&gt;, the X11 side of things.&lt;/p&gt;
&lt;p&gt;Instructions for this are partially sourced from &lt;a href="https://github.com/linuxwacom/xf86-input-wacom/wiki/Building-The-Driver#building-with-autotools"&gt;https://github.com/linuxwacom/xf86-input-wacom/wiki/Building-The-Driver#building-with-autotools&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;First, install dependencies:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;sudo apt-get install autoconf pkg-config make xutils-dev libtool xserver-xorg-dev$(dpkg -S $(which Xorg) | grep -Eo -- "-hwe-[^:]*") libx11-dev libxi-dev libxrandr-dev libxinerama-dev libudev-dev&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then, clone the git repository and checkout the latest release:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;git clone https://github.com/linuxwacom/xf86-input-wacom.git
cd "xf86-input-wacom";
git tag; # Pick the latest one from this list
git switch "$(git tag | tail -n1)"; # Basically git switch TAG_NAME&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It should be at the bottom, or at least that's what I found. For me, that was &lt;code&gt;xf86-input-wacom-1.2.3&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Then, to build and install the software from source, run these 2 commands one at a time:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;set -- --prefix="/usr" --libdir="$(readlink -e $(ls -d /usr/lib*/xorg/modules/input/../../../ | head -n1))"
if test -x ./autogen.sh; then ./autogen.sh "$@"; else ./configure "$@"; fi &amp;#38;&amp;#38; make &amp;#38;&amp;#38; sudo make install || echo "Build Failed"&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you should have the X11 side of things installed. In my case that includes &lt;code&gt;xsetwacom&lt;/code&gt;, the (questionably designed) CLI for managing the properties of connected graphics tablets.&lt;/p&gt;
&lt;p&gt;If that is not the case for you, you can extract it from the Ubuntu apt package:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;apt download xserver-xorg-input-wacom
dpkg -x DEB_FILEPATH_HERE .
ar xv DEB_FILEPATH_HERE # or, if you don't have dpkg for some reason&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;....then, go locate the tool and put it somewhere in your &lt;code&gt;PATH&lt;/code&gt;. I recommend somewhere towards the end in case you forget and fiddle with your setup some more later, so it gets overridden automatically. When I was fidddling around, that was &lt;code&gt;/usr/local/games&lt;/code&gt; for me.&lt;/p&gt;
&lt;h3&gt;Making X11 like the kernel Driver&lt;/h3&gt;
&lt;p&gt;Or also known as enabling hotplug support. Or getting the kernel module and X11 to play nicely with each other.&lt;/p&gt;
&lt;p&gt;This is required to make &lt;code&gt;udev&lt;/code&gt; (the daemon that listens for devices to be plugged into the machine and then performs custom actions on them) tell the X server that you've plugged in your graphics tablet, or X11 to recognise that tablet devices are indeed tablet devices, or something else vaguely similar to that effect.&lt;/p&gt;
&lt;p&gt;Thankfully, this just requires the installation of a single configuration file in a directory that may not exist for you yet - especially if you uninstalled your distro's wacom driver package.&lt;/p&gt;
&lt;p&gt;Do it like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;mkdir -p /etc/X11/xorg.conf.d/;
sudo curl -sSv https://raw.githubusercontent.com/linuxwacom/xf86-input-wacom/refs/heads/master/conf/70-wacom.conf -o /etc/X11/xorg.conf.d/70-wacom.conf&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Just case they move things around as I've seen happen in far too many tutorials with broken links before, the direct link to the exact commit of this file I used is:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/linuxwacom/xf86-input-wacom/blob/47552e13e714ab6b8c2dcbce0d7e0bca6d8a8bf0/conf/70-wacom.conf"&gt;https://github.com/linuxwacom/xf86-input-wacom/blob/47552e13e714ab6b8c2dcbce0d7e0bca6d8a8bf0/conf/70-wacom.conf&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Final steps&lt;/h3&gt;
&lt;p&gt;With all that done and out of the way, reboot. This serves 2 purposes:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Reloading the correct kernel module&lt;/li&gt;
&lt;li&gt;Restarting the X11 server so it has the new driver.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Make sure to use the above instructions to check you are indeed running the right version of the &lt;code&gt;input-wacom&lt;/code&gt; kernel module.&lt;/p&gt;
&lt;p&gt;If all goes well, tilt/rotation support should now work in the painting program of your choice.&lt;/p&gt;
&lt;p&gt;For me, that's &lt;a href="https://krita.org/"&gt;Krita&lt;/a&gt;, the AppImage of which I bundle into my apt repository because I like the latest version:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://apt.starbeamrainbowlabs.com/"&gt;https://apt.starbeamrainbowlabs.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img itemprop="image" src="https://starbeamrainbowlabs.com/blog/images/20241121-krita-tilt-working.png" alt="The red text &amp;#34;Look! Negative TX/TY (TiltX / TiltY) numbers!&amp;#34; crudely overlaid using the Shutter screenshotting tool on top of a screenshot of the Krita tablet tester with a red arrow pointing at the TX/TY values highlighted in yellow." /&gt;&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Phew, I have no idea where this blog post has come from. Hopefully it is useful to someone else out there who also owns an tilt-supporting wacom tablet who is encountering a similar kinda issue.&lt;/p&gt;
&lt;p&gt;Ref teaching and the previous post, preparing teaching content is starting to  slwo down now thankfully. Ahead are the uncharted waters of assessment - it is unclear to me how much energy that will take to deal with.&lt;/p&gt;
&lt;p&gt;Hopefully though there will be more PhD time (post on PhD corrections..... eventually) and free energy to spend on writing more blog posts for here! This one was enjoyable to write, if rather unexpected.&lt;/p&gt;
&lt;p&gt;Has this helped you? Are you still stuck? Do report any issues to the authors of the above two packages I've shown in this post!&lt;/p&gt;
&lt;p&gt;Comments below are also appreciated, both large and small.&lt;/p&gt;&lt;span style='display: none;' itemprop='image' itemscope itemtype='https://schema.org/ImageObject'&gt;&lt;meta itemprop='url' content='https://starbeamrainbowlabs.com/blog/images/20241121-krita-tilt-working.png' /&gt;&lt;meta itemprop='width' content='1838' /&gt;&lt;meta itemprop='height' content='1047' /&gt;&lt;/span&gt;
&lt;/div&gt;&lt;meta itemprop='commentCount' content='4' /&gt;&lt;meta itemprop='datePublished' content='2024-11-22T09:00:00+00:00' /&gt;&lt;meta itemprop='dateModified' content='2024-11-27T00:57:59+00:00' /&gt;&lt;hr /&gt;
			&lt;footer class='small-panel centretext'&gt;
				by &lt;span itemprop='author publisher' itemscope itemtype='http://schema.org/Person'&gt;&lt;span itemprop='name'&gt;Starbeamrainbowlabs&lt;/span&gt;&lt;meta itemprop='image' content='https://starbeamrainbowlabs.com/favicon-small.png' /&gt;&lt;/span&gt; | &lt;span class='oi' data-glyph='clock' title='Published on' aria-hidden='true'&gt;&lt;/span&gt;
			&lt;span title='Friday 22nd of November 2024 at 09:00am GMT' style='cursor:help;'&gt;22-11-2024 at 09:00 am&lt;/span&gt; | &lt;span class='oi' data-glyph='tag' title='Tags' aria-hidden='true'&gt;&lt;/span&gt;&lt;a href='//starbeamrainbowlabs.com/blog/?tags=Linux'&gt;Linux&lt;/a&gt;, &lt;a href='//starbeamrainbowlabs.com/blog/?tags=Terminal'&gt;Terminal&lt;/a&gt;, &lt;a href='//starbeamrainbowlabs.com/blog/?tags=Tutorial'&gt;Tutorial&lt;/a&gt;, &lt;a href='//starbeamrainbowlabs.com/blog/?tags=Graphics'&gt;Graphics&lt;/a&gt;, &lt;a href='//starbeamrainbowlabs.com/blog/?tags=Hardware'&gt;Hardware&lt;/a&gt; | &lt;a itemprop='url' href='https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F555-install-wacom-driver-tilt-rotation-support.html'&gt;&lt;span class='oi' data-glyph='link-intact' title='Permanent Link' aria-hidden='true'&gt;&lt;/span&gt;Permanent Link&lt;/a&gt; | &lt;span class='oi' data-glyph='monitor' title='Views'&gt;&lt;/span&gt;608 views&lt;img class='icon nomargin' data-src='https://starbeamrainbowlabs.com/blog/viewtracker.php?action=record&amp;format=image&amp;post-id=posts%2F555-install-wacom-driver-tilt-rotation-support.html' alt='View tracking image. Download it to increment the view counter!' /&gt; | &lt;a href='https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F555-install-wacom-driver-tilt-rotation-support.html#comments' itemprop='discussionUrl'&gt;&lt;span class='oi' data-glyph='comment-square' title='Comments' aria-hidden='true'&gt;&lt;/span&gt;4 comments&lt;/a&gt; | &lt;span class='oi' data-glyph='people' title='Share' aria-hidden='true'&gt;&lt;/span&gt;Share via:
&lt;a href='https://starbeamrainbowlabs.com/share2fediverse/#text=Compiling%20the%20wacom%20driver%20from%20source%20to%20fix%20tilt%20%26amp%3B%20rotation%20support%20-%20Blog%20post%0Ahttps%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F555-install-wacom-driver-tilt-rotation-support.html' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/fediverse.svg' class='icon' title='Share on the Fediverse' alt='Share this post on the Fediverse' /&gt;&lt;/a&gt;
&lt;a href='https://twitter.com/share?url=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F555-install-wacom-driver-tilt-rotation-support.html&amp;text=Compiling%20the%20wacom%20driver%20from%20source%20to%20fix%20tilt%20%26amp%3B%20rotation%20support%20-%20Blog%20post&amp;via=SBRLabs' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/twitter.svg' class='icon' title='Share via Twitter' alt='Share this post via Twitter' /&gt;&lt;/a&gt;
&lt;a href='https://facebook.com/sharer/sharer.php?u=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F555-install-wacom-driver-tilt-rotation-support.html' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/facebook.svg' class='icon' title='Share via Facebook' alt='Share this post via Facebook' /&gt;&lt;/a&gt;
&lt;a href='http://www.addtoany.com/add_to/evernote?linkurl=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F555-install-wacom-driver-tilt-rotation-support.html&amp;title=Compiling%20the%20wacom%20driver%20from%20source%20to%20fix%20tilt%20%26amp%3B%20rotation%20support' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/evernote.svg' class='icon' title='Share via Evernote' alt='Share this article via Evernote' /&gt;&lt;/a&gt;
&lt;a href='mailto:?Subject=Stardust%20Blog%20Post%3A%20Compiling%20the%20wacom%20driver%20from%20source%20to%20fix%20tilt%20%26amp%3B%20rotation%20support&amp;#38;Body=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F555-install-wacom-driver-tilt-rotation-support.html'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/mail.svg' class='icon' title='Share by Email' alt='Share by Email' /&gt;&lt;/a&gt;			&lt;/footer&gt;
		&lt;/article&gt;
</content>
    <category term="linux" label="Linux"/>
    <category term="terminal" label="Terminal"/>
    <category term="tutorial" label="Tutorial"/>
    <category term="graphics" label="Graphics"/>
    <category term="hardware" label="Hardware"/>
    <author>
      <name>Starbeamrainbowlabs</name>
      <email>sbrl@starbeamrainbowlabs.com</email>
      <uri>https://starbeamrainbowlabs.com</uri>
    </author>
    <published>2024-11-22T09:00:00+00:00</published>
  </entry>
  <entry>
    <title type="html">Happy new year 2025! o/</title>
    <link href="https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F556-christmas-2025.html"/>
    <id>https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F556-christmas-2025.html</id>
    <updated>2025-01-10T01:00:30+00:00</updated>
    <rights type="html">CC-BY-SA</rights>
    <content type="html">&lt;article class='post' data-post-title='Happy new year 2025! o/' itemscope itemtype='http://schema.org/BlogPosting'&gt;
			&lt;a id='posts%2F556-christmas-2025.html'&gt;&lt;/a&gt;
&lt;div itemprop='articleBody'&gt;&lt;!--
Release on  | 10th January 2025 at 1:00am
Author      | Starbeamrainbowlabs
Tags        | Holidays, Update
--&gt;
&lt;p&gt;Heya there!&lt;/p&gt;
&lt;p&gt;This is just a short post to say hi, and happy new year! I hope everyone had a great christmas / winter break.&lt;/p&gt;
&lt;p&gt;As I battle a bit of burnout from doing rather too much teaching related tasks in a short space of time (hoping to do a detailed post on my teaching experiences soon), I have actually achieved a lot this past year despite this:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://fediscience.org/@sbrl/112441900707477311"&gt;Submitted my&lt;/a&gt; &lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/546-phd-update-18.html"&gt;thesis&lt;/a&gt; and &lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/552-phd-update-19-reckoning.html"&gt;had my viva&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Completed designed and delivered an entire 20 credit module on Linux + sysadmin from scratch in the span of ~4 months&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/542-nldl2024.html"&gt;Presented at a conference - NLDL-2024 - for the first time&lt;/a&gt; - to a room of 250 people O.o&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/sbrl/applause-cli"&gt;Much&lt;/a&gt; &lt;a href="https://github.com/sbrl/Pepperminty-Wiki"&gt;open&lt;/a&gt; &lt;a href="https://github.com/sbrl/research-smflooding"&gt;source&lt;/a&gt; &lt;a href="https://github.com/sbrl/powahroot"&gt;work&lt;/a&gt; &lt;a href="https://github.com/sbrl/research-rainfallradar"&gt;spread&lt;/a&gt; &lt;a href="https://worldeditadditions.mooncarrot.space/"&gt;across&lt;/a&gt; &lt;a href="https://github.com/sbrl/imgscout"&gt;many&lt;/a&gt; &lt;a href="https://github.com/sbrl/moondoc"&gt;repositories&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 itemprop='headline'&gt;Looking ahead&lt;/h2&gt;
&lt;p&gt;Looking ahead, a significant portion of my energy is going to be spent on getting my corrections done for my PhD. It is requiring the re-running of a bunch of experiments with a grab-bag of new features being added to the codebases, which if you have been following the commit history have been arriving slowly.&lt;/p&gt;
&lt;p&gt;I'll hopefully be at a good enough point soon-ish to write another PhD update blog post about this.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/540-happy-christmas-2023.html"&gt;Last year&lt;/a&gt;, I said that I hoped 2024 would be the year I finally finish my PhD. It was..... kinda sorta maybe okay-not-really. This time I really do want 2025 to be the year I &lt;em&gt;finally&lt;/em&gt; finish this PhD....... I'm ready to just be done with the stupid thing now.&lt;/p&gt;
&lt;p&gt;In 2025 I want to dedicate more time to blogging here. 2024 has not been a great year for this blog, so I want to try and change that this year. I have had lots of ideas for blog posts..... I just haven't had the energy to write them. Hopefully this will mean lots of cool new blog posts about things I've learnt and found!&lt;/p&gt;
&lt;p&gt;If you're interested in keeping up to date with what I've been up to, I can recommend following me &lt;a href="https://fediscience.org/@sbrl"&gt;on the fediverse&lt;/a&gt; (&lt;code&gt;@sbrl@fediscience.org&lt;/code&gt;). I post smaller stuff there that either isn't bug enough for a blog post, or I don't have the energy to blog about at the time.&lt;/p&gt;
&lt;p&gt;Mastodon (the fediverse software used by the instance I'm on) has a built-in RSS feed, if that's your jam: &lt;a href="https://fediscience.org/@sbrl.rss"&gt;https://fediscience.org/@sbrl.rss&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I want to do some incremental improvements to my website here soon - including tidying up and finishing the list of researchy things I've been doing on &lt;a href="https://starbeamrainbowlabs.com/"&gt;my homepage&lt;/a&gt;. Nothing too ground breaking (though I have bigger plans for a better backend to this blog, but I need lotsa time to impleent it)&lt;/p&gt;
&lt;h2 itemprop='headline'&gt;Final thoughts&lt;/h2&gt;
&lt;p&gt;This last year has been rather stressful and emotional in many different ways - including some I have not mentioned here (like people I know very well leaving the University, including my primary supervisor, though I am maintaining regular and normal contact). I hope that 2025 is less stressful than 2024.&lt;/p&gt;
&lt;p&gt;If there's something you'd like me to blog about that I've been doing that I haven't blogged about yet, I've probably forgotten about it. Please get in touch by leaving a comment below!&lt;/p&gt;
&lt;p&gt;&lt;img itemprop="image" src="https://starbeamrainbowlabs.com/blog/images/20250109-bauble-2025.jpg" alt="A cute wooden bauble in the dark on a christmas tree from a few years ago. It has a snowman against the night sky with a postbox with a bird sitting on it and some trees and stuff. The multicoloured christmas lights are turned on and shining brightly. I like this bauble very much." /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(Source: Taken by me. See alt text for detailed description.)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Thanks for &lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/554-ducks.html"&gt;sticking with me&lt;/a&gt; for these last 10 years. There is ALWAYS hope.&lt;/em&gt; Especially &lt;em&gt;when you can't see it.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;--Starbeamrainbowlabs, your friendly but very tired blogger&lt;/p&gt;&lt;span style='display: none;' itemprop='image' itemscope itemtype='https://schema.org/ImageObject'&gt;&lt;meta itemprop='url' content='https://starbeamrainbowlabs.com/blog/images/20250109-bauble-2025.jpg' /&gt;&lt;meta itemprop='width' content='1934' /&gt;&lt;meta itemprop='height' content='910' /&gt;&lt;/span&gt;
&lt;/div&gt;&lt;meta itemprop='commentCount' content='2' /&gt;&lt;meta itemprop='datePublished' content='2025-01-10T01:00:00+00:00' /&gt;&lt;meta itemprop='dateModified' content='2025-01-10T01:00:30+00:00' /&gt;&lt;hr /&gt;
			&lt;footer class='small-panel centretext'&gt;
				by &lt;span itemprop='author publisher' itemscope itemtype='http://schema.org/Person'&gt;&lt;span itemprop='name'&gt;Starbeamrainbowlabs&lt;/span&gt;&lt;meta itemprop='image' content='https://starbeamrainbowlabs.com/favicon-small.png' /&gt;&lt;/span&gt; | &lt;span class='oi' data-glyph='clock' title='Published on' aria-hidden='true'&gt;&lt;/span&gt;
			&lt;span title='Friday 10th of January 2025 at 01:00am GMT' style='cursor:help;'&gt;10-1-2025 at 01:00 am&lt;/span&gt; | &lt;span class='oi' data-glyph='tag' title='Tags' aria-hidden='true'&gt;&lt;/span&gt;&lt;a href='//starbeamrainbowlabs.com/blog/?tags=Holidays'&gt;Holidays&lt;/a&gt;, &lt;a href='//starbeamrainbowlabs.com/blog/?tags=Update'&gt;Update&lt;/a&gt; | &lt;a itemprop='url' href='https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F556-christmas-2025.html'&gt;&lt;span class='oi' data-glyph='link-intact' title='Permanent Link' aria-hidden='true'&gt;&lt;/span&gt;Permanent Link&lt;/a&gt; | &lt;span class='oi' data-glyph='monitor' title='Views'&gt;&lt;/span&gt;392 views&lt;img class='icon nomargin' data-src='https://starbeamrainbowlabs.com/blog/viewtracker.php?action=record&amp;format=image&amp;post-id=posts%2F556-christmas-2025.html' alt='View tracking image. Download it to increment the view counter!' /&gt; | &lt;a href='https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F556-christmas-2025.html#comments' itemprop='discussionUrl'&gt;&lt;span class='oi' data-glyph='comment-square' title='Comments' aria-hidden='true'&gt;&lt;/span&gt;2 comments&lt;/a&gt; | &lt;span class='oi' data-glyph='people' title='Share' aria-hidden='true'&gt;&lt;/span&gt;Share via:
&lt;a href='https://starbeamrainbowlabs.com/share2fediverse/#text=Happy%20new%20year%202025%21%20o%2F%20-%20Blog%20post%0Ahttps%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F556-christmas-2025.html' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/fediverse.svg' class='icon' title='Share on the Fediverse' alt='Share this post on the Fediverse' /&gt;&lt;/a&gt;
&lt;a href='https://twitter.com/share?url=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F556-christmas-2025.html&amp;text=Happy%20new%20year%202025%21%20o%2F%20-%20Blog%20post&amp;via=SBRLabs' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/twitter.svg' class='icon' title='Share via Twitter' alt='Share this post via Twitter' /&gt;&lt;/a&gt;
&lt;a href='https://facebook.com/sharer/sharer.php?u=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F556-christmas-2025.html' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/facebook.svg' class='icon' title='Share via Facebook' alt='Share this post via Facebook' /&gt;&lt;/a&gt;
&lt;a href='http://www.addtoany.com/add_to/evernote?linkurl=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F556-christmas-2025.html&amp;title=Happy%20new%20year%202025%21%20o%2F' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/evernote.svg' class='icon' title='Share via Evernote' alt='Share this article via Evernote' /&gt;&lt;/a&gt;
&lt;a href='mailto:?Subject=Stardust%20Blog%20Post%3A%20Happy%20new%20year%202025%21%20o%2F&amp;#38;Body=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F556-christmas-2025.html'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/mail.svg' class='icon' title='Share by Email' alt='Share by Email' /&gt;&lt;/a&gt;			&lt;/footer&gt;
		&lt;/article&gt;
</content>
    <category term="holidays" label="Holidays"/>
    <category term="update" label="Update"/>
    <author>
      <name>Starbeamrainbowlabs</name>
      <email>sbrl@starbeamrainbowlabs.com</email>
      <uri>https://starbeamrainbowlabs.com</uri>
    </author>
    <published>2025-01-10T01:00:00+00:00</published>
  </entry>
  <entry>
    <title type="html">Doing a 3-way dataset split in Tensorflow // PhD Aside 3</title>
    <link href="https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F557-tensorflow-3-way-dssplit.html"/>
    <id>https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F557-tensorflow-3-way-dssplit.html</id>
    <updated>2025-03-15T17:58:55+00:00</updated>
    <rights type="html">CC-BY-SA</rights>
    <content type="html">&lt;article class='post' data-post-title='Doing a 3-way dataset split in Tensorflow // PhD Aside 3' itemscope itemtype='http://schema.org/BlogPosting'&gt;
			&lt;a id='posts%2F557-tensorflow-3-way-dssplit.html'&gt;&lt;/a&gt;
&lt;div itemprop='articleBody'&gt;&lt;!--
Release on  | 23rd January 2025 at 11:59pm
Author      | Starbeamrainbowlabs
Tags        | PhD, Artificial Intelligence, Python
--&gt;
&lt;p&gt;Heya!&lt;/p&gt;
&lt;p&gt;It's been a while since I talked about my PhD, so I wanna change that today!&lt;/p&gt;
&lt;p&gt;Teaching post coming just as soon as I find the energy to write it.&lt;/p&gt;
&lt;p&gt;Anyway, one of the things I have been asked to do as part of my thesis corrections is to split my dataset into 3 parts and then run some random experiments.&lt;/p&gt;
&lt;p&gt;This seemed like an odd request to me when there are more important things I need to be doing to stablise the models I'm training, but in the process of implementing support for this in a number of my models I hit upon a snag:&lt;/p&gt;
&lt;p&gt;Tensorflow doesn't have native support for 3-way dataset splits!&lt;/p&gt;
&lt;p&gt;If Tensorflow (tf) doesn't have support for it, then clearly it can't be that important :P&lt;/p&gt;
&lt;p&gt;In all seriousness though, it did mean that I needed a solution and after searching around and getting nowhere very quickly (you really don't need to go to &lt;a href="https://stackoverflow.com/a/47738812/1460422"&gt;all this trouble&lt;/a&gt; to solve this one), I decided that something must be done!&lt;/p&gt;
&lt;p&gt;So, I ended up implementing a thing that I thought was rather cool, so I thought I'd share it here.&lt;/p&gt;
&lt;p&gt;Other parts in this PhD aside series:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/509-phd-aside-jupyter-notebook.html"&gt;PhD Aside 2: Jupyter Lab / Notebook First Impressions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/416-multiprocess-line-based-read-nodejs.html"&gt;PhD Aside: Reading a file descriptor line-by-line from multiple Node.js processes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;More coming soon as I get distracted and find cool shiny things while doing my PhD! If you want more PhD-related posts, do check the &lt;a href="https://starbeamrainbowlabs.com/blog/?tags=phd"&gt;PhD tag&lt;/a&gt; here on my blog.&lt;/p&gt;
&lt;h3&gt;Splitting into multiple pieces&lt;/h3&gt;
&lt;p&gt;As a quick reminder, when training an AI we usually split the dataset we're training it on into 2 parts:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Training (usually ~80%)&lt;/li&gt;
&lt;li&gt;Validation (usually ~20%)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;....the model only gets to learn from the &lt;em&gt;training&lt;/em&gt; data, and we hold the validation data back so we can test the model on it later. If it does a lot worse on the validation dataset than on the training dataset, then we can reasonably conclude that the model isn't generalising very well to new data/samples/etc/ it hasn't seen before.&lt;/p&gt;
&lt;p&gt;However, sometimes people decide it's a great idea to split a dataset into 3 parts rather than 2.&lt;/p&gt;
&lt;p&gt;The reasoning behind this - as far as I'm aware, is that while you're working on optimising your model by trying different architectures, hyperparameters, etc, you are in a sense optimising for the model's performance on the validation dataset.&lt;/p&gt;
&lt;p&gt;So, to this end it is suggested that by having a third split - called the &lt;strong&gt;test&lt;/strong&gt; split, one can evaluate the model again and make really really sure how well it's generalising (or not) to new data.&lt;/p&gt;
&lt;p&gt;This is just as much as I know at the moment and it doesn't really make sense in my head, so if you have a better way of explaining it please do leave a comment below.&lt;/p&gt;
&lt;h3&gt;Yeah, Tensorflow sucks&lt;/h3&gt;
&lt;p&gt;.....maybe not really (though CUDA / GPU support does suck very much &amp;#62;_&amp;#60;). The thing to remember about AI model frameworks like Tensorflow is that data loading efficiency is &lt;em&gt;everything&lt;/em&gt;. A tangent for another time perhaps (is your model training slowly? then this is most likely your issue!), but what matters here is that the signature of &lt;code&gt;tf.keras.Model.fit()&lt;/code&gt; (the function that actually trains the shiny new model you've just created / loaded from disk / etc) looks a bit like this:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-python"&gt;model.fit(
    x, # probably either a tf.Tensor or a tf.data.Dataset 
    y, # probably the same as x immediately above
    validation_split=0.0, # Percentage of x to treat as the validation dataset
    validation_data=None, # The validation dataset - see above
    callbacks=None, # A list of functions to call at different times - this will become important later
    # .....
)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;....this is just terrible design, if you ask me. &lt;code&gt;x&lt;/code&gt; and &lt;code&gt;y&lt;/code&gt; here are the input(s) and ground truth labels respectively.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Single letter variable names should not be allowed!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Unfortunately, the only options we have for inputting another dataset to calculate metrics on (e.g. cross-validation, dice coefficient, intersection-over-union - IoU, etc etc etc) is to pass a validation dataset - there's no option to pass e.g. a &lt;code&gt;list()&lt;/code&gt; of datasets to evaluate on, which is a shame as it would almost make sense.&lt;/p&gt;
&lt;h3&gt;Cracking the glass&lt;/h3&gt;
&lt;p&gt;So, we're at a loss right? What to do? We have 3 nice neat &lt;code&gt;tf.data.Dataset&lt;/code&gt;s ready do go and no way to ensure we get metrics calculated reliably on the 3rd one.&lt;/p&gt;
&lt;p&gt;The solution here that I came up with is to write a custom callback that manually iterates over the dataset and calculates the metrics, before then sneakily appending them to TF's main metrics log system so that TF never suspects a thing, and writes them out along with all the other metrics for us :D&lt;/p&gt;
&lt;p&gt;Learning to work &lt;em&gt;within&lt;/em&gt; the framework of your choice is a key part of the process. Don't just try and hack your way around it - most frameworks - TF included - provide many different ways to manipulate tensors etc if you learn how they work.&lt;/p&gt;
&lt;p&gt;In this case, we know that Tensorflow has a callback system, because TF ships with a number of default callbacks like &lt;code&gt;tf.keras.callbacks.CSVLogger&lt;/code&gt; (which can also output as TSV, my favourite file format when I'm not using &lt;a href="https://jsonlines.org/"&gt;jsonl&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Writing a custom callback is a 2 step process:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Write a custom class that inherits from &lt;code&gt;tf.keras.callbacks.Callback&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Instantiate an instance of our new class and pass it to &lt;code&gt;tf.keras.Model.fit()&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Let's go through these 1 by 1.&lt;/p&gt;
&lt;h3&gt;Writing a callback&lt;/h3&gt;
&lt;p&gt;As mentioned, inheriting from &lt;code&gt;tf.keras.callbacks.Callback&lt;/code&gt; is the aim of the game here. We can make it really quite lightweight and do it within 10 lines of code:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-python"&gt;import tensorflow as tf

class CallbackExtraValidation(tf.keras.callbacks.Callback):
    def __init__(self):
        super(CallbackExtraValidation, self).__init__()
        pass

    def on_epoch_end(self, epoch, logs=None):
        pass&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The way callbacks work in TF is that they are a class with a bunch of methods. The main &lt;code&gt;tf.keras.callbacks.Callback&lt;/code&gt; class defines a bunch of empty methods, and then you override the ones you're interested in.&lt;/p&gt;
&lt;p&gt;Some examples of things you can add a callback for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The start/end of training as a whole&lt;/li&gt;
&lt;li&gt;The start/end of every &lt;strong&gt;batch&lt;/strong&gt; (sometimes called a step, but a step cans ometimes mean multiple batches at once)&lt;/li&gt;
&lt;li&gt;The start/end of every &lt;strong&gt;epoch&lt;/strong&gt; (which most of the time but not always is before/after the entire dataset has been seen by the model once)&lt;/li&gt;
&lt;li&gt;The start/end of validation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;....and so on.&lt;/p&gt;
&lt;p&gt;You get the picture: it's a way that you can add simple hooks that let you run custom functions that do &lt;em&gt;stuff&lt;/em&gt; at a time of your choosing.&lt;/p&gt;
&lt;p&gt;In our case, we know that we wanna evaluate our model on an extra dataset at the end of every epoch, so we added a method for that.&lt;/p&gt;
&lt;p&gt;Check the docs for a comprehensive look at the possible functions you can override here:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://devdocs.io/tensorflow~2.9/keras/callbacks/callback"&gt;https://devdocs.io/tensorflow~2.9/keras/callbacks/callback&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Now we have a custom function running when we want it to, it's just a case of grabbing the dataset(s) and evaluating the model with em:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-python"&gt;import tensorflow as tf

class CallbackExtraValidation(tf.keras.callbacks.Callback):
    def __init__(self, datasets, verbose="auto"):
        super(CallbackExtraValidation, self).__init__()
        self.datasets = datasets # Dictionary in the form { string: tf.data.Dataset }, where `string` here is the name of the dataset
        self.verbose = verbose

    def on_epoch_end(self, epoch, logs=None):
        for name, dataset in self.datasets.items():
            metrics = self.model.evaluate(
                dataset,
                verbose=self.verbose,
                return_dict=True
            )&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Excellent! See, we can even throw in enumerating over a list of datasets with minimal effort (I'm looking at you, Tensorflow!).&lt;/p&gt;
&lt;p&gt;Okay, so we have metrics by cheesing the issue and asking TF to evaluate a model. We even have a reference to the model in question provided for us by Tensorflow - how very kind!&lt;/p&gt;
&lt;p&gt;....but how do we hoodwink Tensorflow and slip the extra metrics we've calculated into the main metrics stream without it noticing?&lt;/p&gt;
&lt;p&gt;The solution has actually been provided by Tensorflow itself: The &lt;code&gt;logs&lt;/code&gt; argument that is passed to &lt;code&gt;on_epoch_end&lt;/code&gt; is the metrics log for that current epoch, so we can just update it.&lt;/p&gt;
&lt;p&gt;We don't wanna overwrite any of the existing metrics though, so the solution is just to prepend a static string to the name of each metric as we copy it over:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-python"&gt;for metric_name, metric_value in metrics.items():
    logs[f"{name}_{metric_name}"] = metric_value&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;See? Easy peasy!&lt;/p&gt;
&lt;p&gt;That's all there is to it.&lt;/p&gt;
&lt;p&gt;Of course, a few additional checks need to be added because I'm paranoid and Tensorflow sometimes passes &lt;code&gt;None&lt;/code&gt; instead of the &lt;code&gt;logs&lt;/code&gt; instance for a giggle, but it does work reliably.&lt;/p&gt;
&lt;p&gt;Find the full version of this class with those checks here:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/sbrl/research-rainfallradar/blob/897bfa3/aimodel/src/lib/ai/components/CallbackExtraValidation.py"&gt;https://github.com/sbrl/research-rainfallradar/blob/897bfa3/aimodel/src/lib/ai/components/CallbackExtraValidation.py&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Find the full version with updates (though the link miiight break if I rejig the repo's directory structure or rename the class etc):&lt;/p&gt;
&lt;p&gt;&lt;a href="https://github.com/sbrl/research-rainfallradar/blob/897bfa3/aimodel/src/lib/ai/components/CallbackExtraValidation.py"&gt;https://github.com/sbrl/research-rainfallradar/blob/897bfa3/aimodel/src/lib/ai/components/CallbackExtraValidation.py&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;How to pass to &lt;code&gt;.fit()&lt;/code&gt;?&lt;/h3&gt;
&lt;p&gt;Just for completeness, this is how you pass the above in &lt;code&gt;.fit()&lt;/code&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-python"&gt;model.fit(
    dataset_input,
    dataset_labels,
    callbacks = [
        CallbackExtraValidation({
            "test": my_extra_dataset
        })
    ]
)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;..in short, the &lt;code&gt;callbacks&lt;/code&gt; argument of &lt;code&gt;tf.keras.Model&lt;/code&gt; takes a &lt;code&gt;list()&lt;/code&gt; of &lt;code&gt;tf.keras.callbacks.Callback&lt;/code&gt; instances. Simply instantiate an instance of your custom callback class, and you're away, just as if it were an official part of the Tensorflow framework!&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;This has been a not-so-quick post (I swear I meant this to be shorter.....!) about doing a 3-way dataset split in Tensorflow because Tensorflow doesn't support it natively.&lt;/p&gt;
&lt;p&gt;I hope you found this useful - let me know if you have any other questions or comments - I'm happy to answer them - both in the comments below and as subjeccts for future blog posts!&lt;/p&gt;
&lt;p&gt;The end of the teaching is on the horizon (though I'm having to do a teaching course which is meh because it's eating into my time again) - so I'm hoping that my energy levels will start to recover once I've found a new rhythm for this new semester that is just starting.&lt;/p&gt;&lt;span style='display: none;' itemprop='image' itemscope itemtype='https://schema.org/ImageObject'&gt;&lt;meta itemprop='url' content='http://starbeamrainbowlabs.com/favicon.png' /&gt;&lt;meta itemprop='width' content='256' /&gt;&lt;meta itemprop='height' content='256' /&gt;&lt;/span&gt;
&lt;/div&gt;&lt;meta itemprop='commentCount' content='0' /&gt;&lt;meta itemprop='datePublished' content='2025-01-23T23:59:00+00:00' /&gt;&lt;meta itemprop='dateModified' content='2025-03-15T17:58:55+00:00' /&gt;&lt;hr /&gt;
			&lt;footer class='small-panel centretext'&gt;
				by &lt;span itemprop='author publisher' itemscope itemtype='http://schema.org/Person'&gt;&lt;span itemprop='name'&gt;Starbeamrainbowlabs&lt;/span&gt;&lt;meta itemprop='image' content='https://starbeamrainbowlabs.com/favicon-small.png' /&gt;&lt;/span&gt; | &lt;span class='oi' data-glyph='clock' title='Published on' aria-hidden='true'&gt;&lt;/span&gt;
			&lt;span title='Thursday 23rd of January 2025 at 11:59pm GMT' style='cursor:help;'&gt;23-1-2025 at 11:59 pm&lt;/span&gt; | &lt;span class='oi' data-glyph='tag' title='Tags' aria-hidden='true'&gt;&lt;/span&gt;&lt;a href='//starbeamrainbowlabs.com/blog/?tags=PhD'&gt;PhD&lt;/a&gt;, &lt;a href='//starbeamrainbowlabs.com/blog/?tags=Artificial%20Intelligence'&gt;Artificial Intelligence&lt;/a&gt;, &lt;a href='//starbeamrainbowlabs.com/blog/?tags=Python'&gt;Python&lt;/a&gt; | &lt;a itemprop='url' href='https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F557-tensorflow-3-way-dssplit.html'&gt;&lt;span class='oi' data-glyph='link-intact' title='Permanent Link' aria-hidden='true'&gt;&lt;/span&gt;Permanent Link&lt;/a&gt; | &lt;span class='oi' data-glyph='monitor' title='Views'&gt;&lt;/span&gt;484 views&lt;img class='icon nomargin' data-src='https://starbeamrainbowlabs.com/blog/viewtracker.php?action=record&amp;format=image&amp;post-id=posts%2F557-tensorflow-3-way-dssplit.html' alt='View tracking image. Download it to increment the view counter!' /&gt; | &lt;a href='https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F557-tensorflow-3-way-dssplit.html#comments' itemprop='discussionUrl'&gt;&lt;span class='oi' data-glyph='comment-square' title='Comments' aria-hidden='true'&gt;&lt;/span&gt;0 comments&lt;/a&gt; | &lt;span class='oi' data-glyph='people' title='Share' aria-hidden='true'&gt;&lt;/span&gt;Share via:
&lt;a href='https://starbeamrainbowlabs.com/share2fediverse/#text=Doing%20a%203-way%20dataset%20split%20in%20Tensorflow%20%2F%2F%20PhD%20Aside%203%20-%20Blog%20post%0Ahttps%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F557-tensorflow-3-way-dssplit.html' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/fediverse.svg' class='icon' title='Share on the Fediverse' alt='Share this post on the Fediverse' /&gt;&lt;/a&gt;
&lt;a href='https://twitter.com/share?url=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F557-tensorflow-3-way-dssplit.html&amp;text=Doing%20a%203-way%20dataset%20split%20in%20Tensorflow%20%2F%2F%20PhD%20Aside%203%20-%20Blog%20post&amp;via=SBRLabs' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/twitter.svg' class='icon' title='Share via Twitter' alt='Share this post via Twitter' /&gt;&lt;/a&gt;
&lt;a href='https://facebook.com/sharer/sharer.php?u=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F557-tensorflow-3-way-dssplit.html' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/facebook.svg' class='icon' title='Share via Facebook' alt='Share this post via Facebook' /&gt;&lt;/a&gt;
&lt;a href='http://www.addtoany.com/add_to/evernote?linkurl=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F557-tensorflow-3-way-dssplit.html&amp;title=Doing%20a%203-way%20dataset%20split%20in%20Tensorflow%20%2F%2F%20PhD%20Aside%203' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/evernote.svg' class='icon' title='Share via Evernote' alt='Share this article via Evernote' /&gt;&lt;/a&gt;
&lt;a href='mailto:?Subject=Stardust%20Blog%20Post%3A%20Doing%20a%203-way%20dataset%20split%20in%20Tensorflow%20%2F%2F%20PhD%20Aside%203&amp;#38;Body=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F557-tensorflow-3-way-dssplit.html'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/mail.svg' class='icon' title='Share by Email' alt='Share by Email' /&gt;&lt;/a&gt;			&lt;/footer&gt;
		&lt;/article&gt;
</content>
    <category term="phd" label="PhD"/>
    <category term="artificial-intelligence" label="Artificial Intelligence"/>
    <category term="python" label="Python"/>
    <author>
      <name>Starbeamrainbowlabs</name>
      <email>sbrl@starbeamrainbowlabs.com</email>
      <uri>https://starbeamrainbowlabs.com</uri>
    </author>
    <published>2025-01-23T23:59:00+00:00</published>
  </entry>
  <entry>
    <title type="html">PhD Update 20: Like a bad smell.....</title>
    <link href="https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F558-phd-update-20-like-a-bad-smell.html"/>
    <id>https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F558-phd-update-20-like-a-bad-smell.html</id>
    <updated>2025-06-14T22:52:58+01:00</updated>
    <rights type="html">CC-BY-SA</rights>
    <content type="html">&lt;article class='post' data-post-title='PhD Update 20: Like a bad smell.....' itemscope itemtype='http://schema.org/BlogPosting'&gt;
			&lt;a id='posts%2F558-phd-update-20-like-a-bad-smell.html'&gt;&lt;/a&gt;
&lt;div itemprop='articleBody'&gt;&lt;!--
Release on  | 6th June 2025 at 3:15pm
Author      | Starbeamrainbowlabs
Tags        | University, PhD, Update
--&gt;
&lt;p&gt;Hi again! Another wild blog post appeared. PhD corrections, I have come to realise, have a habit of hanging around long past the time you want to have had them finished and done.&lt;/p&gt;
&lt;p&gt;Before we get into all of that though, here's the customary list of posts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/388-phd-update-1-directions.html"&gt;PhD Update 1: Directions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/397-phd-2-experiments.html"&gt;PhD Update 2: The experiment, the data, and the supercomputers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/404-phd-3-simulating-simulations.html"&gt;PhD Update 3: Simulating simulations with some success&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/417-phd-4-gimornous-data.html"&gt;PhD Update 4: Ginormous Data&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/430-phd-update-5-hyper-optimisations-and-frustrations.html"&gt;PhD Update 5: Hyper optimisation and frustration&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F438-phd-update-6-the-road-ahead.html"&gt;PhD Update 6: The road ahead&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/452-phd-update-7.html"&gt;PhD Update 7: Just out of reach&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/463-phd-update-8-eggs-baskets.html"&gt;PhD Update 8: Eggs in Baskets&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/471-phd-update-9.html"&gt;PhD Update 9: Results?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/476-phd-update-10.html"&gt;PhD Update 10: Sharing with the world&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/485-phd-update-11-answers.html"&gt;PhD Update 11: Answers to our questions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/493-phd-12-enough.html"&gt;PhD Update 12: Is it enough?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/501-PhD-Update-13-a-half-complete.html"&gt;PhD Update 13: A half complete&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/512-phd-update-14.html"&gt;PhD Update 14: An old enemy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/sources/520-phd-update-15.md"&gt;PhD Update 15: Finding what works when&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/528-phd-update-16.html"&gt;PhD Update 16: Realising the possibilities of the past&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/539-phd-update-17.html"&gt;PhD Update 17: Light at the end of the tunnel&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/546-phd-update-18.html"&gt;PhD Update 18: The end and the beginning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/552-phd-update-19-reckoning.html"&gt;PhD Update 19: The Reckoning&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;See also &lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F557-tensorflow-3-way-dssplit.html"&gt;Doing a 3-way dataset split in Tensorflow // PhD Aside 3&lt;/a&gt;, which I posted since the last one of these PhD update blog posts.&lt;/p&gt;
&lt;p&gt;Things have not been easy over the last 9 months, but I am making it through. I can't promise when blog posts will come, but know that I have a lot of ideas and it's just a case of having the energy to write them. See also &lt;a href="https://fediscience.org/@sbrl"&gt;my fediverse account @sbrl@fediscience.org&lt;/a&gt; (&lt;a href="https://fediscience.org/@sbrl.rss"&gt;rss feed&lt;/a&gt;) for smaller updates in between times.&lt;/p&gt;
&lt;h3&gt;Corrections&lt;/h3&gt;
&lt;p&gt;One of the things I did not realise when I started my PhD was just how much work you are expected to do outside of your main scholarshiped research period. There's writing the thesis, doing the viva, and, of course, the corrections afterwards.&lt;/p&gt;
&lt;p&gt;While I'm not sure how much I can share about the corrections I've been given I can say that the process of completing them has been both long and annoying.&lt;/p&gt;
&lt;p&gt;More importantly, &lt;strong&gt;it is now coming to a close!&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Yep, that's right: I'm almost done with my corrections! I just need a laundry list of people to check them and say they are okay, and then I can &lt;em&gt;finally&lt;/em&gt; get this PhD thing over with and move on to cooler researchy things that I'll talk about later in this blog post.&lt;/p&gt;
&lt;p&gt;As with &lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/552-phd-update-19-reckoning.html"&gt;my viva&lt;/a&gt;, the corrections I received were mainly organisational and big picture stuff in nature, though I also had my fair share of experiment redos to complete (ewwww), which have been very time consuming.&lt;/p&gt;
&lt;p&gt;Once everything is done, I do plan on making my thesis available for free here on my website if my institution will let me. I doubt it will get indexed in any scholarly search engines any time soon, but hopefully it will be useful to someone here.&lt;/p&gt;
&lt;p&gt;Speaking of, I'd like to share a Cool Graph™ I created whilst doing my corrections:&lt;/p&gt;
&lt;p&gt;&lt;img itemprop="image" src="https://starbeamrainbowlabs.com/blog/images/20250606-rainfall_crossval-stbl7_ALL_stddev.png" alt="A grid of graphs showing the stability of the metrics for my rainfall radar models over 7 runs. There are areas shaded on the graphs to show the standard deviation and min/max values for each epoch" /&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(Above: A grid of graphs showing the stability of the metrics for my rainfall radar models over 7 runs)&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;This is, as the caption suggests, a random cross-validation (because anything else would be far too complicated to implement) run of my rainfall radar model &lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/528-phd-update-16.html"&gt;I have mentioned before&lt;/a&gt;. This was one of the things I was asked to do in my corrections.&lt;/p&gt;
&lt;p&gt;The code behind this is kinda cool, as it aggregates a &lt;code&gt;metrics.tsv&lt;/code&gt; file from every experiment directory in in a given directory.&lt;/p&gt;
&lt;p&gt;As I write this I realise that's kinda confusing, so let me show you what the directory of experiments actually looks like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;+ 202412_crossval-stbl7
    + 2024-12-12_deeplabv3+_rainfall_csgpu_ri_celdice_lr0.00001_us2_t0.1_bs32_crossval-stbl7-A
    + 2024-12-12_deeplabv3+_rainfall_csgpu_ri_celdice_lr0.00001_us2_t0.1_bs32_crossval-stbl7-B
    + 2024-12-12_deeplabv3+_rainfall_csgpu_ri_celdice_lr0.00001_us2_t0.1_bs32_crossval-stbl7-C
    + 2024-12-12_deeplabv3+_rainfall_csgpu_ri_celdice_lr0.00001_us2_t0.1_bs32_crossval-stbl7-D
    + 2024-12-12_deeplabv3+_rainfall_csgpu_ri_celdice_lr0.00001_us2_t0.1_bs32_crossval-stbl7-E
    + 2024-12-12_deeplabv3+_rainfall_csgpu_ri_celdice_lr0.00001_us2_t0.1_bs32_crossval-stbl7-F
    + 2024-12-12_deeplabv3+_rainfall_csgpu_ri_celdice_lr0.00001_us2_t0.1_bs32_crossval-stbl7-G&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The experiment series directory (&lt;code&gt;202412_crossval-stbl7&lt;/code&gt;) contains 7 different runs, matching the &lt;code&gt;stbl7&lt;/code&gt; part of the experiment series name &lt;code&gt;crossval-stbl7&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The directory names there look pretty complicated, but it's actually just made of up all the parameters that I'm currently interested in for that experiment series. Each part is separated by an underscore &lt;code&gt;_&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So, to break down &lt;code&gt;2024-12-12_deeplabv3+_rainfall_csgpu_ri_celdice_lr0.00001_us2_t0.1_bs32_crossval-stbl7-C&lt;/code&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;2024-12-12&lt;/code&gt;:&lt;/strong&gt; The date the (individual) experiment was run. These all ran in parallel on a HPC at my university, hence all the dates are the same even though it takes more than 24 hours to train the rainfall radar model.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;deeplabv3+&lt;/code&gt;:&lt;/strong&gt; The architectural backbone of the model in question - this time &lt;a href="https://doi.org/10.48550/arXiv.1802.02611"&gt;DeepLabV3+&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;rainfall&lt;/code&gt;:&lt;/strong&gt; Identifier code for the project, &lt;code&gt;rainfall&lt;/code&gt; is the traditional informal and short name I gave to the rainfall radar model.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;csgpu&lt;/code&gt;:&lt;/strong&gt; The place it was trained on. In this case &lt;code&gt;csgpu&lt;/code&gt; is a small HPC cluster in my department. &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;ri&lt;/code&gt;:&lt;/strong&gt; This marks the start of the experiment hyperparams I'm interested in, in no particular order (but the order usually remains constant for a given project). &lt;code&gt;ri&lt;/code&gt; stands for &lt;strong&gt;R&lt;/strong&gt;emove &lt;strong&gt;I&lt;/strong&gt;solated.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;celdice&lt;/code&gt;:&lt;/strong&gt; The loss function. &lt;strong&gt;C&lt;/strong&gt;ross-&lt;strong&gt;E&lt;/strong&gt;ntropy &lt;strong&gt;L&lt;/strong&gt;oss + &lt;strong&gt;Dice&lt;/strong&gt; loss.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;lr0.00001&lt;/code&gt;:&lt;/strong&gt; The &lt;strong&gt;L&lt;/strong&gt;earning &lt;strong&gt;R&lt;/strong&gt;ate, this time 0.00001&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;us2&lt;/code&gt;:&lt;/strong&gt; &lt;strong&gt;U&lt;/strong&gt;p&lt;strong&gt;S&lt;/strong&gt;cale 2 - a property of the model in which it upscales the input x2 and downscales it just before the output. This improves the fidelity of the output at the cost of a higher memory usage.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;t0.1&lt;/code&gt;:&lt;/strong&gt; &lt;strong&gt;T&lt;/strong&gt;hreshold of 0.1 - the delimiter between water and no water. At some point, I want to split into multiple bins.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;bs32&lt;/code&gt;:&lt;/strong&gt; &lt;strong&gt;B&lt;/strong&gt;atch &lt;strong&gt;S&lt;/strong&gt;ize of 32.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;crossval-stbl7-C&lt;/code&gt;:&lt;/strong&gt; The experiment series code - see above.&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;crossval-stbl&lt;/code&gt;:&lt;/strong&gt; The main part of the experiment series code&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;7&lt;/code&gt;:&lt;/strong&gt; The number of cross-validation runs&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;C&lt;/code&gt;:&lt;/strong&gt; The differentiator. In this case it's part C of the experiment series since they are all the same, but usually each model has something unique about it, e.g. &lt;code&gt;regresstest-regress&lt;/code&gt; vs &lt;code&gt;regresstest-class&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Hmmm, looking at this it might be a bit more complicated a system than I first expected, but it makes sense to me. I wonder if I've blogged about how I organise experiments already? If not, that should go on the todo list.&lt;/p&gt;
&lt;p&gt;Anyway, this is the foundation of my entire organisational system for running experiments. I've developed quite an intricate system since I started running experiments in 2020, but fundamentally it is based on the principle of preserving as much information about any given experiment that I've run as possible, as I am sure to need it later.&lt;/p&gt;
&lt;p&gt;Even if I don't think I'll need it!&lt;/p&gt;
&lt;p&gt;In fact, &lt;em&gt;especially&lt;/em&gt; if I don't think I'll need it, because I've been bitten enough times to know that it's not a case of if, it's most certainly a case of &lt;em&gt;when&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;Corrections? What corrections?&lt;/h3&gt;
&lt;p&gt;Not to get &lt;em&gt;too&lt;/em&gt; distracted, while I don't think the University would like it very much if I shared my exact list of corrections, it boiled down to the following basic principles, in no particular order:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;There wasn't a clear narrative carrying the problem forwards through the thesis&lt;/li&gt;
&lt;li&gt;They wanted more experiments running to confirm the stability of the models trained - hence &lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F557-tensorflow-3-way-dssplit.html"&gt;this post on a 3-way split&lt;/a&gt; since they wanted a 3-way split, and also hence the stability testing done to produce the graph above amongst others&lt;/li&gt;
&lt;li&gt;They wanted a regression model training for the rainfall radar model and a comparative analysis against my existing classification-based approach&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It doesn't sound like much, but it has been quite a lot of work to get to this point, especially since I have been doing more teaching than I expected &lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/553-ificating.html"&gt;starting in September last year&lt;/a&gt;. I'm glad now that I applied for a 6 month extension and for the help of the people around me (and 2 people in particular - not sure if I can mention your names, but you know who you are), otherwise I would have run out of time to complete my corrections long ago.&lt;/p&gt;
&lt;h3&gt;Future research&lt;/h3&gt;
&lt;p&gt;Now that my corrections are (hopefully) coming to and end and I'm starting to get a handle on the teaching I've been asked to do (&lt;a href="https://starbeamrainbowlabs.com/blog/article.php?article=posts/554-ducks.html"&gt;wow&lt;/a&gt;, and that isn't even the half of it), I'm &lt;em&gt;finally&lt;/em&gt; starting to get myself into a place in which I can FINALLY start to look forwards to some more research that is actually useful, as opposed to making seemingly endless corrections to my thesis (the social media chapter in particular I can do SO MUCH BETTER).&lt;/p&gt;
&lt;p&gt;First of all are real improvements to my &lt;a href="https://github.com/sbrl/research-rainfallradar/"&gt;rainfall radar model&lt;/a&gt;. These improvements largely fall into a few categories:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Analysing and improving the model's ability to actually predict floods, and applying &lt;a href="20250606-rainfallwater_records_tfrecord-COUNTS_COMPARATIVEPLOT_hist-water_weights-norm.png"&gt;sample weighting&lt;/a&gt; (psst, secret second graph for those of you who are still reading!) to hopefully measuably improve my model's ability to make actually useful predictions&lt;/li&gt;
&lt;li&gt;Swapping out the physics-based model the model is trained on because it's bad and I didn't prepare the data very well and it's all bad&lt;/li&gt;
&lt;li&gt;Exanding the model's ability to predict multiple bins instead of just a binarised water/no-water situation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are not necessarily in order, but I imagine I'll likely tackle them in something like this order.&lt;/p&gt;
&lt;p&gt;On the social media side, I know that I can do &lt;em&gt;so much better&lt;/em&gt; than &lt;a href="https://doi.org/10.1016/j.cageo.2023.105405"&gt;my social media paper&lt;/a&gt; which somehow has &lt;a href="https://scholar.google.com/scholar?cluster=11925562228893860339"&gt;41 citations&lt;/a&gt; (just HOW??!). Binary sentiment analysis is cute and all, but at the intersection of AI, disaster situational awareness, and user interface (UI) design and user experience (UX) I believe that I can do much better in the organisation of unstructured data.&lt;/p&gt;
&lt;p&gt;With the use of contemporary AI algorithms and UI/UX, the extraction &lt;em&gt;and presentation&lt;/em&gt; of richer information should be possible.&lt;/p&gt;
&lt;p&gt;Even though these research plans won't be part of my PhD, I will still continue blogging about it! Who knows, I might even start a new long-running blog post series to mark the beginning of a new era in my life.&lt;/p&gt;
&lt;p&gt;And, of course, I'll continue to share Cool Graphs™!&lt;/p&gt;
&lt;h3&gt;BlueSky&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;BlueSky:&lt;/strong&gt; As a last thing, I'm going to blog about it at some point but I'm now using &lt;a href="https://fed.brid.gy/"&gt;bridgy fed&lt;/a&gt; to allow you to follow me on Bluesky! I'm &lt;a href="https://bsky.app/profile/sbrl.fediscience.org.ap.brid.gy"&gt;@sbrl.fediscience.org.ap.brid.gy&lt;/a&gt;, and to interact with me you'll need to follow &lt;a href="https://bsky.app/profile/ap.brid.gy"&gt;@ap.brid.gy&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;BlueSky seems to be becoming very popular, especially my circles - but while it pretends to be decentralised, &lt;a href="https://fediscience.org/@FediTips@social.growyourown.services/113636279870303408"&gt;it isn't&lt;/a&gt;. For this reason and others, my primary social media will remain on &lt;a href="https://fedi.tips/"&gt;the Fediverse&lt;/a&gt; to ensure and preserve the long-term viability of my account.&lt;/p&gt;
&lt;p&gt;I encourage you to join the fediverse too - it's a nice and friendly place :D&lt;/p&gt;
&lt;h3&gt;Final thoughts&lt;/h3&gt;
&lt;p&gt;It has been a long road, but I am finally nearing the end of one book and the beginning of another. This is &lt;em&gt;not the last post in this series&lt;/em&gt; - I have at least 1 more planned. When I have the energy, I want to talk about my experiences learning to teach (I'm doing a course called PCAP right now, as it was a stipulation of my contract) in what may be a longer blog post than I expect.&lt;/p&gt;
&lt;p&gt;I'm looking forward to continuing my research journey and blogging along the way right here at my stardust blog (I think this is the first time I've mentioned my blog's name!).&lt;/p&gt;
&lt;p&gt;I'll see you next time, in what might be one of the last blog posts in this series: &lt;strong&gt;PhD Update 21: Where the water meets the sky&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;--Starbeamrainbowlabs&lt;/p&gt;&lt;span style='display: none;' itemprop='image' itemscope itemtype='https://schema.org/ImageObject'&gt;&lt;meta itemprop='url' content='https://starbeamrainbowlabs.com/blog/images/20250606-rainfall_crossval-stbl7_ALL_stddev.png' /&gt;&lt;meta itemprop='width' content='7078' /&gt;&lt;meta itemprop='height' content='1558' /&gt;&lt;/span&gt;
&lt;/div&gt;&lt;meta itemprop='commentCount' content='0' /&gt;&lt;meta itemprop='datePublished' content='2025-06-06T15:15:00+01:00' /&gt;&lt;meta itemprop='dateModified' content='2025-06-14T22:52:58+01:00' /&gt;&lt;hr /&gt;
			&lt;footer class='small-panel centretext'&gt;
				by &lt;span itemprop='author publisher' itemscope itemtype='http://schema.org/Person'&gt;&lt;span itemprop='name'&gt;Starbeamrainbowlabs&lt;/span&gt;&lt;meta itemprop='image' content='https://starbeamrainbowlabs.com/favicon-small.png' /&gt;&lt;/span&gt; | &lt;span class='oi' data-glyph='clock' title='Published on' aria-hidden='true'&gt;&lt;/span&gt;
			&lt;span title='Friday 6th of June 2025 at 03:15pm BST' style='cursor:help;'&gt;6-6-2025 at 03:15 pm&lt;/span&gt; | &lt;span class='oi' data-glyph='tag' title='Tags' aria-hidden='true'&gt;&lt;/span&gt;&lt;a href='//starbeamrainbowlabs.com/blog/?tags=University'&gt;University&lt;/a&gt;, &lt;a href='//starbeamrainbowlabs.com/blog/?tags=PhD'&gt;PhD&lt;/a&gt;, &lt;a href='//starbeamrainbowlabs.com/blog/?tags=Update'&gt;Update&lt;/a&gt; | &lt;a itemprop='url' href='https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F558-phd-update-20-like-a-bad-smell.html'&gt;&lt;span class='oi' data-glyph='link-intact' title='Permanent Link' aria-hidden='true'&gt;&lt;/span&gt;Permanent Link&lt;/a&gt; | &lt;span class='oi' data-glyph='monitor' title='Views'&gt;&lt;/span&gt;463 views&lt;img class='icon nomargin' data-src='https://starbeamrainbowlabs.com/blog/viewtracker.php?action=record&amp;format=image&amp;post-id=posts%2F558-phd-update-20-like-a-bad-smell.html' alt='View tracking image. Download it to increment the view counter!' /&gt; | &lt;a href='https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F558-phd-update-20-like-a-bad-smell.html#comments' itemprop='discussionUrl'&gt;&lt;span class='oi' data-glyph='comment-square' title='Comments' aria-hidden='true'&gt;&lt;/span&gt;0 comments&lt;/a&gt; | &lt;span class='oi' data-glyph='people' title='Share' aria-hidden='true'&gt;&lt;/span&gt;Share via:
&lt;a href='https://starbeamrainbowlabs.com/share2fediverse/#text=PhD%20Update%2020%3A%20Like%20a%20bad%20smell.....%20-%20Blog%20post%0Ahttps%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F558-phd-update-20-like-a-bad-smell.html' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/fediverse.svg' class='icon' title='Share on the Fediverse' alt='Share this post on the Fediverse' /&gt;&lt;/a&gt;
&lt;a href='https://twitter.com/share?url=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F558-phd-update-20-like-a-bad-smell.html&amp;text=PhD%20Update%2020%3A%20Like%20a%20bad%20smell.....%20-%20Blog%20post&amp;via=SBRLabs' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/twitter.svg' class='icon' title='Share via Twitter' alt='Share this post via Twitter' /&gt;&lt;/a&gt;
&lt;a href='https://facebook.com/sharer/sharer.php?u=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F558-phd-update-20-like-a-bad-smell.html' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/facebook.svg' class='icon' title='Share via Facebook' alt='Share this post via Facebook' /&gt;&lt;/a&gt;
&lt;a href='http://www.addtoany.com/add_to/evernote?linkurl=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F558-phd-update-20-like-a-bad-smell.html&amp;title=PhD%20Update%2020%3A%20Like%20a%20bad%20smell.....' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/evernote.svg' class='icon' title='Share via Evernote' alt='Share this article via Evernote' /&gt;&lt;/a&gt;
&lt;a href='mailto:?Subject=Stardust%20Blog%20Post%3A%20PhD%20Update%2020%3A%20Like%20a%20bad%20smell.....&amp;#38;Body=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F558-phd-update-20-like-a-bad-smell.html'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/mail.svg' class='icon' title='Share by Email' alt='Share by Email' /&gt;&lt;/a&gt;			&lt;/footer&gt;
		&lt;/article&gt;
</content>
    <category term="university" label="University"/>
    <category term="phd" label="PhD"/>
    <category term="update" label="Update"/>
    <author>
      <name>Starbeamrainbowlabs</name>
      <email>sbrl@starbeamrainbowlabs.com</email>
      <uri>https://starbeamrainbowlabs.com</uri>
    </author>
    <published>2025-06-06T15:15:00+01:00</published>
  </entry>
  <entry>
    <title type="html">Defending against DDoS attacks hammering my git server</title>
    <link href="https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F559-git-server-anubis.html"/>
    <id>https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F559-git-server-anubis.html</id>
    <updated>2025-09-24T11:57:45+01:00</updated>
    <rights type="html">CC-BY-SA</rights>
    <content type="html">&lt;article class='post' data-post-title='Defending against DDoS attacks hammering my git server' itemscope itemtype='http://schema.org/BlogPosting'&gt;
			&lt;a id='posts%2F559-git-server-anubis.html'&gt;&lt;/a&gt;
&lt;div itemprop='articleBody'&gt;&lt;!--
Release on  | 24th September 2025 at 9:00am
Author      | Starbeamrainbowlabs
Tags        | linux, server, software, security
--&gt;
&lt;p&gt;It's no sekret that I have &lt;a href="https://git.starbeamrainbowlabs.com/"&gt;a git server&lt;/a&gt;. I host all sorts of stuff on there - from stuff I've talked about on this blog to many other things I have, and still others that are private repositories that I can't share / yet for one reason or another.&lt;/p&gt;
&lt;p&gt;While I can't remember exactly when I first set it up, I do remember that &lt;a href="https://about.gitea.com/"&gt;gitea&lt;/a&gt; wasn't even a thing back then, and I originally setup &lt;a href="https://github.com/gogs/gogs"&gt;go git service&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Nowadays, I run the fork of gitea called &lt;strong&gt;&lt;a href="https://forgejo.org/"&gt;forgejo&lt;/a&gt;&lt;/strong&gt;, which is a fork of go git service.&lt;/p&gt;
&lt;p&gt;Either way, it's been around for a while!&lt;/p&gt;
&lt;p&gt;Unfortunately, now that smaller git servers are becoming more common (we still need a social/federated git standard like e.g. &lt;a href="https://www.w3.org/TR/activitypub/"&gt;ActivityPub&lt;/a&gt;), &lt;a href="https://codeberg.org/forgejo/discussions/issues/320"&gt;so are attacks against such servers&lt;/a&gt;&lt;a href="https://forgejo.codeberg.page/2025-03-monthly-update/"&gt;²&lt;/a&gt;, and one I dealt with yesterday was particularly nasty, so I decided to make a blog post about it.&lt;/p&gt;
&lt;h3&gt;I'll have CPU for breakfast, lunch, and tea thank you&lt;/h3&gt;
&lt;p&gt;Before I explain how I dealt with it (&lt;em&gt;mitigated&lt;/em&gt; is the technical term I understand), it's important to know the anatomy of the attack. After all, security is important but we can only &lt;em&gt;be&lt;/em&gt; secure if we know what we're defending against.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;threat model&lt;/em&gt;, if you will.&lt;/p&gt;
&lt;p&gt;In this case, the attacker sent random requests to random files on random commits in a large git repository I have on my aforementioned git server.&lt;/p&gt;
&lt;p&gt;Yesterday, I measured almost 1 &lt;em&gt;million&lt;/em&gt; unique IP addresses making exactly 2 requests at a time each.&lt;/p&gt;
&lt;p&gt;If I had the energy, I'd plot em all on a &lt;a href="https://blog.benjojo.co.uk/post/scan-ping-the-internet-hilbert-curve"&gt;hilbert curve&lt;/a&gt;&lt;a href="https://en.wikipedia.org/wiki/Hilbert_curve"&gt;²&lt;/a&gt; with a colour gradient for age, maybe even with an animation.&lt;/p&gt;
&lt;p&gt;The result of all of this is 100% CPU usage on my 3rd generation dedicated server I rent and a slow terminal experience, because to serve each request Forgejo has to call a &lt;code&gt;git&lt;/code&gt; subprocess to inspect the repository and extract the version of the file requested.&lt;/p&gt;
&lt;p&gt;That's a very expensive way to handle a HTTP/S request!&lt;/p&gt;
&lt;p&gt;At first, I thought I was infected, but further inspection of the logs revealed it not to be so.&lt;/p&gt;
&lt;p&gt;With all this in mind, the goal of my expedition was to avoid the spammy HTTP/S calls from hitting the application server (forgejo).&lt;/p&gt;
&lt;p&gt;This is all interesting, because it means that a number of common steps to achieve this won't work:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;We can't just block the IP address, because there are too many and most of them will be compromised IoT (Internet of Terrible security) devices etc in peoples' homes that are roped into being a botnet.&lt;/li&gt;
&lt;li&gt;We can't keep the git server turned off, because I need to use it&lt;/li&gt;
&lt;li&gt;I can't block access to the problematic paths on the server, because then the attacker will switch to another set and access to the git server is still impaired&lt;/li&gt;
&lt;li&gt;I can't just allow specific IP addresses through, as I have blog post stuff hosted on there and you, one of my readers, would be cut off from accessing it (and I access from my phone sometimes which doesn't have a fixed IP)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;...so that just leaves us stuck right?&lt;/p&gt;
&lt;h3&gt;Teh solutionses!&lt;/h3&gt;
&lt;p&gt;No so. There's still a strategy that we haven't tried: a &lt;a href="https://en.wikipedia.org/wiki/Web_application_firewall"&gt;Web Application Firewall&lt;/a&gt;. Traditionally, such tools are big and very very expensive, but I discovered the other week a tool that did the job and inside an envelope (a couple of megabytes) and price point (free!) I could afford.&lt;/p&gt;
&lt;p&gt;That tool is &lt;a href="https://anubis.techaro.lol/docs/"&gt;Anubis&lt;/a&gt;, and despite the.... interesting name it acts like something of a firewall that sits in front of on the application server, but behind your reverse proxy:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt; Public Internet ║ Inside server                                               
                 ║                                                             
                 ╟───────────────┐         ┌───────────────┐  ┌───────────────┐
                 ║     Caddy     │         │    Anubis     │  │    Forgejo    │
Inbound  ────────▶       •       ├─────────▶       •       ├──▶       •       │
requests   80/tcp║ Reverse proxy │         │   Firewall    │  │  App server   │
          443/tcp╟───────────────┘         └───────────────┘  └───────────────┘
                 ║                                localhost           localhost
                 ║                                 2999/tcp            3000/tcp&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Essentially, when each request comes in it weighs the risk of a request. 'high-risk' requests, such as those coming from browsers which attackers love to impersonate, get served a small challenge that they must solve to gain access to the website. Low-risk clients, such as &lt;code&gt;git&lt;/code&gt; or &lt;code&gt;curl&lt;/code&gt; or &lt;a href="http://elinks.or.cz/"&gt;&lt;code&gt;elinks&lt;/code&gt;&lt;/a&gt; can go straight through.&lt;/p&gt;
&lt;p&gt;This is in the form of a hashing problem: the browser must tell the server what nonce (&lt;strong&gt;n&lt;/strong&gt;umber only used &lt;strong&gt;once&lt;/strong&gt;) that, alongside a given unique challenge string, produces a hash with a certain number of zeroes (&lt;code&gt;0&lt;/code&gt;) when hashed.&lt;/p&gt;
&lt;p&gt;Correctly completing the challenge (which doesn't take very long), sets a cookie for that client to gain access to the website without completing another challenge for a certain period of time.&lt;/p&gt;
&lt;p&gt;I could go on, but &lt;a href="https://anubis.techaro.lol/docs/design/how-anubis-works"&gt;the official documentation&lt;/a&gt; explains it pretty well.&lt;/p&gt;
&lt;p&gt;Essentially, by serving challenges to high-risk clients instead of allowing requests straight through attempts to access expensive HTTP/S calls (such as loading a random file from a random commit in a random git repo) a server's resources can be protected to give a better experience to the users who use it on a day-to-day basis.&lt;/p&gt;
&lt;p&gt;This isn't without its flaws - namely inadvertently blocking good bots - but it does strike enough of a balance that I can keep my git server online without giving up the entirety of my server's resources in the process, which I need to use for other things.&lt;/p&gt;
&lt;h2 itemprop='headline'&gt;But how?!&lt;/h2&gt;
&lt;p&gt;I'll assume you already have some sort of reverse proxy in front of some sort of application server. In my case, that's &lt;a href="https://caddyserver.com/"&gt;caddy&lt;/a&gt; and &lt;a href="https://forgejo.org/"&gt;forgejo&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Anubis' latest release can be downloaded from &lt;a href="https://github.com/TecharoHQ/anubis/releases"&gt;here&lt;/a&gt;, but for Debian/Ubuntu users who want an apt repository I'm rehosting the &lt;code&gt;.deb&lt;/code&gt; files from Anubis' releases page in my personal apt repository:&lt;/p&gt;
&lt;p&gt;&lt;a href="https://apt.starbeamrainbowlabs.com/"&gt;https://apt.starbeamrainbowlabs.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Assuming you have an e.g. Ubuntu server, you'll want to install anubis and then navigate to &lt;code&gt;/etc/anubis&lt;/code&gt;, in which you should create a configuration file with the name of the user account you'll be starting anubis under.&lt;/p&gt;
&lt;p&gt;Each instance of anubis can only handle 1 domain/app at a time, so you'll want 1 system user account per application you want to protect.&lt;/p&gt;
&lt;p&gt;For example, I have a config file at &lt;code&gt;/etc/anubis/anubis-git.env&lt;/code&gt; with the following content:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-env"&gt;TARGET=http://[::1]:3000
BIND=:2999
METRICS_BIND=:2998&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;....my internal git server is listening on port 3000 on the IPv6 localhost address &lt;code&gt;::1&lt;/code&gt; for HTTP requests, so that's the target that anubis should forward requests to, as in the ASCII diagram above (made in &lt;a href="https://monosketch.io/"&gt;monosketch&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Then, start the new anubis instance like so:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;sudo systemctl enable --now anubis@anubis-git.service&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;....in my case, the username I created (&lt;code&gt;sudo useradd --system anubis-git&lt;/code&gt; etc etc) was &lt;code&gt;anubis-git&lt;/code&gt;, so that's what goes in the filename above and after the &lt;code&gt;@&lt;/code&gt; sign when we start the service.&lt;/p&gt;
&lt;p&gt;If you haven't seen this syntax before in systemd service names, it allows you to set the username that a supporting service file will start a service with. &lt;a href="https://syncthing.net/"&gt;syncthing&lt;/a&gt; does the same thing with the default systemd service definition it provides.&lt;/p&gt;
&lt;p&gt;In other words, it lets you start multiple instances of the same service without them clashing with each other.&lt;/p&gt;
&lt;p&gt;At any rate, the final piece of the puzzle is &lt;a href="https://anubis.techaro.lol/docs/admin/environments/caddy"&gt;telling your reverse proxy to talk to anubis&lt;/a&gt;:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-caddy"&gt;git.starbeamrainbowlabs.com {
    log

    reverse_proxy http://[::1]:2999 {
        # ref anubis config setup both of these are required
        header_up X-Http-Version {http.request.proto}
        # ref anubis config, this is esp. required
        header_up X-Real-Ip {remote_host}
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Replace &lt;code&gt;http://[::1]:2999&lt;/code&gt; with the address of Anubis instead of your application server directly, then check the config and reload:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-bash"&gt;sudo caddy validate -c /etc/caddy/Caddyfile &amp;#38;&amp;#38; sudo systemctl reload caddy&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(replacing &lt;code&gt;/etc/caddy/Caddyfile&lt;/code&gt; with the path to your Caddyfile of course)&lt;/p&gt;
&lt;h2 itemprop='headline'&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;....and you're done!&lt;/p&gt;
&lt;p&gt;We've successfully put an application server behind anubis to protect it from malicious requests.&lt;/p&gt;
&lt;p&gt;Over time, I assume I will need to tweak the anubis settings, which is possible through what seems to be a &lt;a href="https://anubis.techaro.lol/docs/admin/policies/"&gt;rather detailed policy file system&lt;/a&gt; (which allows RSS/Atom files through by default, if you're crazy enough to be subbed to any feeds from my git server).&lt;/p&gt;
&lt;p&gt;If something seems broken to you now that I've set this up, please do get in touch and I'll try my best to help you out.&lt;/p&gt;
&lt;p&gt;I'll be continuing to &lt;a href="https://lnav.org/"&gt;keep an eye on&lt;/a&gt; my web server traffic to see if anything gets through that shouldn't, and adjusting my response as necessary.&lt;/p&gt;
&lt;p&gt;Thanks for sticking with me, and when I have the energy I have lots of other cool things to talk about here soon.&lt;/p&gt;
&lt;p&gt;--Starbeamrainbowlabs&lt;/p&gt;
&lt;h2 itemprop='headline'&gt;Aside: IP blocking with Caddy&lt;/h2&gt;
&lt;p&gt;While implementing the above approach, I found I did need to bring my git server up for my &lt;a href="https://laminar.ohwg.net/docs.html"&gt;Continuous Integration system&lt;/a&gt; (I implemented it well before forgejo got workers and I haven't checked out the latter yet) to work.&lt;/p&gt;
&lt;p&gt;To do this, I temporarily implemented an IP address-based allowlist.&lt;/p&gt;
&lt;p&gt;If you're curious, here's the code for that:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-caddy"&gt;# temp solution to block anyone who isn't in the allowlist outright
# note that given the sheer range of IPs from what's probably a compromised device-based botnet, we can't just IP block this long-term.
@denied not client_ip 1.2.3.4 5.6.7.8/24 127.0.0.1/8 ::1/128
abort @denied&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;....throw this in one of the server blocks in your &lt;code&gt;Caddyfile&lt;/code&gt; before a &lt;code&gt;reverse_proxy&lt;/code&gt; directive - changing the allowed IP addresses of course (leave the IPv4 &amp;#38; IPv6 ones!) - validate &amp;#38; reload, and you should have an instant IP address allowlist system in place!&lt;/p&gt;&lt;span style='display: none;' itemprop='image' itemscope itemtype='https://schema.org/ImageObject'&gt;&lt;meta itemprop='url' content='http://starbeamrainbowlabs.com/favicon.png' /&gt;&lt;meta itemprop='width' content='256' /&gt;&lt;meta itemprop='height' content='256' /&gt;&lt;/span&gt;
&lt;/div&gt;&lt;meta itemprop='commentCount' content='0' /&gt;&lt;meta itemprop='datePublished' content='2025-09-24T09:00:00+01:00' /&gt;&lt;meta itemprop='dateModified' content='2025-09-24T11:57:45+01:00' /&gt;&lt;hr /&gt;
			&lt;footer class='small-panel centretext'&gt;
				by &lt;span itemprop='author publisher' itemscope itemtype='http://schema.org/Person'&gt;&lt;span itemprop='name'&gt;Starbeamrainbowlabs&lt;/span&gt;&lt;meta itemprop='image' content='https://starbeamrainbowlabs.com/favicon-small.png' /&gt;&lt;/span&gt; | &lt;span class='oi' data-glyph='clock' title='Published on' aria-hidden='true'&gt;&lt;/span&gt;
			&lt;span title='Wednesday 24th of September 2025 at 09:00am BST' style='cursor:help;'&gt;24-9-2025 at 09:00 am&lt;/span&gt; | &lt;span class='oi' data-glyph='tag' title='Tags' aria-hidden='true'&gt;&lt;/span&gt;&lt;a href='//starbeamrainbowlabs.com/blog/?tags=linux'&gt;linux&lt;/a&gt;, &lt;a href='//starbeamrainbowlabs.com/blog/?tags=server'&gt;server&lt;/a&gt;, &lt;a href='//starbeamrainbowlabs.com/blog/?tags=software'&gt;software&lt;/a&gt;, &lt;a href='//starbeamrainbowlabs.com/blog/?tags=security'&gt;security&lt;/a&gt; | &lt;a itemprop='url' href='https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F559-git-server-anubis.html'&gt;&lt;span class='oi' data-glyph='link-intact' title='Permanent Link' aria-hidden='true'&gt;&lt;/span&gt;Permanent Link&lt;/a&gt; | &lt;span class='oi' data-glyph='monitor' title='Views'&gt;&lt;/span&gt;398 views&lt;img class='icon nomargin' data-src='https://starbeamrainbowlabs.com/blog/viewtracker.php?action=record&amp;format=image&amp;post-id=posts%2F559-git-server-anubis.html' alt='View tracking image. Download it to increment the view counter!' /&gt; | &lt;a href='https://starbeamrainbowlabs.com/blog/article.php?article=posts%2F559-git-server-anubis.html#comments' itemprop='discussionUrl'&gt;&lt;span class='oi' data-glyph='comment-square' title='Comments' aria-hidden='true'&gt;&lt;/span&gt;0 comments&lt;/a&gt; | &lt;span class='oi' data-glyph='people' title='Share' aria-hidden='true'&gt;&lt;/span&gt;Share via:
&lt;a href='https://starbeamrainbowlabs.com/share2fediverse/#text=Defending%20against%20DDoS%20attacks%20hammering%20my%20git%20server%20-%20Blog%20post%0Ahttps%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F559-git-server-anubis.html' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/fediverse.svg' class='icon' title='Share on the Fediverse' alt='Share this post on the Fediverse' /&gt;&lt;/a&gt;
&lt;a href='https://twitter.com/share?url=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F559-git-server-anubis.html&amp;text=Defending%20against%20DDoS%20attacks%20hammering%20my%20git%20server%20-%20Blog%20post&amp;via=SBRLabs' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/twitter.svg' class='icon' title='Share via Twitter' alt='Share this post via Twitter' /&gt;&lt;/a&gt;
&lt;a href='https://facebook.com/sharer/sharer.php?u=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F559-git-server-anubis.html' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/facebook.svg' class='icon' title='Share via Facebook' alt='Share this post via Facebook' /&gt;&lt;/a&gt;
&lt;a href='http://www.addtoany.com/add_to/evernote?linkurl=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F559-git-server-anubis.html&amp;title=Defending%20against%20DDoS%20attacks%20hammering%20my%20git%20server' target='_blank'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/evernote.svg' class='icon' title='Share via Evernote' alt='Share this article via Evernote' /&gt;&lt;/a&gt;
&lt;a href='mailto:?Subject=Stardust%20Blog%20Post%3A%20Defending%20against%20DDoS%20attacks%20hammering%20my%20git%20server&amp;#38;Body=https%3A%2F%2Fstarbeamrainbowlabs.com%2Fblog%2Farticle.php%3Farticle%3Dposts%252F559-git-server-anubis.html'&gt;&lt;img src='https://starbeamrainbowlabs.com/images/logos/mail.svg' class='icon' title='Share by Email' alt='Share by Email' /&gt;&lt;/a&gt;			&lt;/footer&gt;
		&lt;/article&gt;
</content>
    <category term="linux" label="linux"/>
    <category term="server" label="server"/>
    <category term="software" label="software"/>
    <category term="security" label="security"/>
    <author>
      <name>Starbeamrainbowlabs</name>
      <email>sbrl@starbeamrainbowlabs.com</email>
      <uri>https://starbeamrainbowlabs.com</uri>
    </author>
    <published>2025-09-24T09:00:00+01:00</published>
  </entry>
</feed>
