BigSmoke

Smokes your problems, coughs fresh air.

Verification of salt-archive-keyring.gpg fingerprints

Because a hacked website can easily replace GPG keys, I wanted to write down for myself what the verified fingerprints of the Salt archive keyring are:

# sha256sum /usr/share/keyrings/salt-archive-keyring.gpg
ea38e0cdbd8dc53e1af154a8d711a2a321a69f81188062dc5cde9d54df2b8c47  /usr/share/keyrings/salt-archive-keyring.gpg
 
 
# gpg /usr/share/keyrings/salt-archive-keyring.gpg
gpg: WARNING: no command supplied.  Trying to guess what you mean ...
pub   rsa2048 2014-06-24 [SC]
      754A1A7AE731F165D5E6D4BD0E08A149DE57BFBE
uid           SaltStack Packaging Team <packaging@saltstack.com>
sub   rsa2048 2014-06-24 [E]

WordPress for my forest vacation home in Norg

For a decade and a half, my uncle had been maintaining the website for our vacation home in the forests of Drenthe in Dreamweaver. This worked fine, except that:

  1. it didn’t allow me to edit and add content and photos simultaneously;
  2. the website had started to look and feel dated;
  3. it wasn’t mobile-ready; and
  4. all this was affecting its ranking in Google.

That’s why I had been having a new WordPress website in the pipeline since forever. However, in true 80/20 fashion, I was postponing the final steps of copying over the last bits of content and the training of my uncle to edit the website in WordPress instead of in Dreamweaver.

Why WordPress?

The last few websites I built I built myself from scratch, like in the good old days, using a simple static site generation pipeline (basically a fancy Makefile). The reasoning is that comments are too much hassle to moderate anyway, and comments and trackbacks are what WordPress offered me. Apart from that I very much prefer authoring in vim.

But that’s me. Most people, my uncle included, are way more comfortable with WYSIWYG editors—in other words: WordPress its Gutenberg editor.

A mature developer has to be able to sidestep his preferences to deliver something that’s best for the “customer”. (Indeed this post will be me bragging of how mature a developer I am. I do turn 40 tomorrow after all.)

My main “design” goal was that I didn’t want to change too much at once. The site structure and site content had to remain mostly identical, so that we would have fewer points of discussion to surmount before going live.

At the same time, I did want to clean up the content and the formatting. The old website had a distinct lack of bullets, formal headings, use of bold text, etc. (No, I don’t have pictures.) That made the text a bit difficult to parse, especially when the visitor—a potential tenant of our forest home—was just trying to find a specific piece of information at a glance.

Proper formatting makes long page much more accessible.

The new website is not fancy. The theme is just one of WordPress its default themes, and I ended up not even using a graphical header to get the first version online. Important to me is that I can now easily add blog posts (like about a pretty yellow flower that I got to grow there abundantly). Also, whenever now I want to edit some text in one of the informational pages, I can.

The “page with booking information and booking availability gave me the most headaches and demanded the most from my maturity. The first thing to swipe off the table was the use of any type of booking plugin. This turned out to be the most important decision (and a very good call!). The old website (with light-yellow background) had one of those old-fashioned tables with big-ridged borders around every cell. I wanted to at least make this table look good and modern.

I gave the booking periods table a sticky header. That was something at least. What I did not do was giving the individual cells a border. But, as much as he tried liking it, my uncle hated that incarnation of the table. So I put back in some cell borders, which I had already done in the print CSS version.

Then there was the issue that my uncle had gotten used to printing out the booking schedule, and it now spanned a number of pages. Thus I did a lot of tinkering in the print CSS to make it all fit (and to make the table header repeat, just in case). And it turned that both cleaning ladies didn’t like the spacious table layout on the screen either. I had altogether forgot about them as consumers of the table, focusing instead on potential tenants. More squeezing followed, until everybody was happy, and I was … relieved.

The booking schedule of our vacation home in Norg, Drenthe, the Netherlands.

It deserves mentioning that I did all these CSS within WordPress its theme customizer. Normally, I would have preferred to use a child theme for this, but it felt to early to start a child-theme, as long as I haven’t fully committed to a particular parent theme. Also, the CSS for that booking schedule table is some of the worst you might have seen. After all, the HTML is not semantic at all. It’s not like I’m going to train my uncle to specify class names on each cell. Without proper classification, I had to use implicit classification, ending up with selectors such as the td:nth-child(4):not([colspan]):not(:empty) selector that I use to make the background of occupied periods black, but only if they are not some special multi-column note. To scare the CSS wizards out there, here’s the current CSS for the table:

@media screen {
table.wp-block-advgb-table.advgb-table-frontend {
	border-width: 0;
	border-spacing: 0;
	border-collapse: separate;
	table-layout: auto;
}
.wp-block-advgb-table > thead > tr {
	position: sticky;
	top: 0;
}
.wp-block-advgb-table > thead > tr > th {
	background-color: white;
	box-sizing: border-box;
	border-top: 1px solid black;
	border-left: none;
	border-right: 1px solid black;
	border-bottom: 2px solid black;
	padding: 2px 4px;
}
.wp-block-advgb-table > thead > tr > th {
	border-left: 1px solid black;
}
.wp-block-advgb-table > tbody > tr > td {
  border-top: none;
	border-left: none;
	border-right: 1px solid black;
	border-bottom: 1px solid black;
	padding: 2px 4px;
}
.wp-block-advgb-table > tbody > tr > td:first-child {
  border-left: 1px solid black;
}
.wp-block-advgb-table > tbody > tr > td:nth-child(4):not([colspan]) {
	width: 2em;
	font-size: 70%;
}
	.wp-block-advgb-table > tbody > tr > td:nth-child(4):not([colspan]):not(:empty) {
		background-color: black;
		color: white;
	}
.wp-block-advgb-table > tbody > tr > td[rowspan] {
}
}
@media screen and (max-width: 1000px) {
	table.wp-block-advgb-table.advgb-table-frontend {
		position: relative;
		left: -7.6923%;
		max-width: none;
	  font-size: 70%;
	}
	.wp-block-advgb-table > thead > tr > th, .wp-block-advgb-table > tbody > tr > td {
		padding: 0px 1px;
	}
	.wp-block-advgb-table > thead > tr > th {
		overflow-wrap: break-word;
	}
	.wp-block-advgb-table > thead > tr > th:nth-child(3) {
		font-size: 0; /* ugly hack to hide regular text. */
	}
	.wp-block-advgb-table > thead > tr > th:nth-child(3):after {
		content: 'Prijs';
		font-size: 12px; /* ugly override because percentage would be percentage of 0. */
	}
	.wp-block-advgb-table > thead > tr > th:nth-child(4) {
		font-size: 0; /* ugly hack to hide regular text. */
	}
	.wp-block-advgb-table > thead > tr > th:nth-child(4):after {
		content: 'Vrij?';
		font-size: 12px; /* ugly override because percentage would be percentage of 0. */
	}
	.wp-block-advgb-table > tbody > tr > td:first-child {
		min-width: 8ch;
		max-width: 12ch;
	}
	.wp-block-advgb-table > tbody > tr > td:nth-child(2) {
		word-spacing: -.2ch;
		min-width: 15ch;
		max-width: 20ch;
	}
}
@media screen and (min-width: 1001px) {	 .wp-block-advgb-table > thead > tr {
		top: 21px;  /* Space from the theme that somehow has a weird z-indexy effect. */
	}
	body.admin-bar .wp-block-advgb-table > thead > tr {
		top: calc(31px + 21px);
	}
	.wp-block-advgb-table > tbody > tr > td:nth-child(2) {
		white-space: nowrap;
		max-width: 20em;
  }
}
/* filter bypass hack */@media print {
  .wp-block-advgb-table.advgb-table-frontend {
		width: 100%;
	  border: 1pt solid black important!;
	  border-spacing: 0;
		border-collapse: collapse;
		font-size: 8pt;
		table-layout: auto;
  }
	.wp-block-advgb-table > thead > tr > th {
		border: 2pt solid black !important;
		padding: 2pt 4pt;
	}
	table.wp-block-advgb-table > tbody > tr > td {
		border: 1pt solid black !important;
		padding: 1pt 4pt;
	}
	.wp-block-advgb-table > tbody > tr > td:first-child {
		white-space: nowrap;
	}
	.wp-block-advgb-table > thead > tr > th:nth-child(3) {
		font-size: 0; /* ugly hack to hide regular text. */
	}
	.wp-block-advgb-table > thead > tr > th:nth-child(3):after {
		content: 'Prijs';
		font-size: 12px; /* ugly override because percentage would be percentage of 0. */
	}
	.wp-block-advgb-table > thead > tr > th:nth-child(4) {
		font-size: 0; /* ugly hack to hide regular text. */
	}
	.wp-block-advgb-table > thead > tr > th:nth-child(4):after {
		content: 'Vrij?';
		font-size: 12px; /* ugly override because percentage would be percentage of 0. */
	}
	.wp-block-advgb-table > tbody > tr > td:nth-child(3) {
		max-width: 8ch;
	}
}

Which reminds me of something quite terrible about Gutenberg. Its table block doesn’t support merged cells, like—what the fuck?—why is this not considered a priority? Fucking hipsters and their having to reinvent the wheel every year and taking years to put all the spokes back into place. The “solution” was to install a plugin—PublishPress Blocks—that among other blocks that I don’t need (and could thankfully turn off) an “Advanced Table Block” that does support cell merging, but with such nasty bugs that it’s really hard to train my uncle to work around them. Sadly, there has been no activity yet to fix either one of them.

That’s it. This project didn’t make me more of a WordPress fan. (I’m no hater either. I think that WordPress its UX, specifically, has long been excellent, and exemplary in its non-nerdiness, quite the contrast with other popular open source CMSs.) But I chose the right tool for the right job and managed to make myself and the other “customers” happy. Since the go-live, I’ve added a number of blog posts already, and it’s great fun to now be able to contribute to this website’s content.


Did this get you interested? Feel free to book a stay in our idyllic vacation home in Norg, Drenthe, the Netherlands

Automatically switch node versions between projects

At my day job we work with Node 12 for our projects, but I wanted to check out NuxtJS 3, which requires version 14 or 16. Once I updated npm, I found out me old projects no longer worked properly. Reinstalling node_modules didn’t solve the problem, and besided, I didn’t want to saddle up my colleagues with version incompatibilities I couldn’t detect myself. So, I looked into finding a solution. And found one!

With n you can switch easily between Node versions. To install:

npm install -g n
echo "export N_PREFIX=/home/jeroen/.local/n" >> ~/.bashrc
echo "export PATH=$N_PREFIX/bin:$PATH" >> ~/.bashrc

Don’t install it as root, that will make it much more annoying to work with. 

Now it is easy to change between versions:

n 16
node -v
>> v16.13.1

n 14
node -v
>> v14.18.2

But still, you would have to remember which version is used in which project. That’s not fun at all, so that’s what avn was made for. I guess I’m not the only one who is annoyed by such things.

To install avn:

npm install -g avn avn-nvm avn-n
avn setup

That last command adds a line to ~/.bash_profile, which is ignored in my setup, so I had to move that line to ~/.bashrc :

echo '[[ -s "$HOME/.avn/bin/avn.sh" ]] && source "$HOME/.avn/bin/avn.sh" # load avn' >> ~/.bashrc

Now add a .node-version file to the root of your project (or in my case the root of all the projects of my boss):

echo "12.22.8" >> ~/projects/.node-version

I also did the same for my own project (with version 16), and now when I switch to any child folder of ~/projects I see this:

Switching node versions works!

Mission accomplished!

Troubleshoot

While installing this to Macos, I ran into a bit of trouble:

cb.apply is not a function 🧐

If found this solution for it:

n 10.13.0 # Install node version 10.13.0 by n
rm -R ~/.avn
nvm exec 10.13.0 npm install -g avn avn-nvm avn-n  # Use installed version to install the packages
nvm exec 10.13.0 avn setup

This only works with already installed node versions. When I went to a directory with a node version that isn’t installed yet, I got this:

My current solution is to just install that version manually with n:

n 16.11.1

Mission accomplished again!

Rapidly firing myself in the foot with C pointers

Now that I am dedicated to becoming a somewhat decent C programmer, I need to master pointers. Last week, I leveled up in my pointer usage by debugging a particularly nasty segfault. It took the help of gdb (the GNU Project Debugger) for me to notice that my segfault was accompanied by very weird values for some increment counters, while the pointer involved was a char* pointer, not a pointer to an int.

GDB

First, some notes on the GNU Project Debugger: it’s excellent! And … it’s easy to use. I have no idea why looong ago, when as a budding programmer I was trying to use it, I had so much trouble using it that it stuck into my memory as a very tough tool to use. Well, this is not the same brain anymore, so time to get rid of all these printf() statements everywhere (that I wouldn’t dare use in a programming language that I do have some fluency in, mind you!) [lines of shame: L45, L100, L101, L119 ].

With the help of gdb xjot-to-xml (and then, from within GDB, run < my-test-file.xjot), I noticed that some of the ints I used to track byte, line and column positiion had ridiculously high values for the input line, especially since I was pretty sure that my program crashed already on the first character.

In GDB, such things are easy to find out: you can very simply set a breakpoint anywhere:

break 109
run < tests/element-with-inline-content.xjot
Starting program: /home/bigsmoke/git/xjot/xjot-to-xml < tests/element-with-inline-content.xml
a
b

Breakpoint 1, _xjot_to_xml_with_buf (in_fd=537542260, out_fd=1852140901, buf=0x6c652d746f6f723c, buf_size=1024)
    at xjot_to_xml.c:109
109                 byte = ((char*)buf)[0];

From there, after hitting the breakpoint, I can check the content of the variable n that holds the number of bytes read by read() into buf.

print n
$1 = 130

So, the read() function had read 130 bytes into the buffer. Which makes sense, because element-with-inline-content.xjot was 128 characters, and the buffer, at 1024 bytes, is more than sufficient to hold it all.

But, then line_no and col_no variables:

(gdb) print line_no
$2 = 1702129263
(gdb) print col_no
$4 = 1092645999

It took me a while to realize that this must have been due to a buffer overrun. Finally, I noticed that I was feeding the address of the buf pointer to read() instead of the value of the pointer.

(I only just managed to fix it before Wiebe, out of curiosity to my C learning project, glanced at my code and immediately spotted the bug.)

The value of pointers

C is a typed language, but that doesn't mean that you cannot still very easily shoot yourself in the foot with types, and, this being C, it means that it's easiest to shoot yourself in the foot with the difference between pointers and non-pointers.

I initialized my buffer as a plain char array of size XJOT_TO_XML_BUFFER_SIZE_IN_BYTES. Then, the address of that array is passed to the _xjot_to_xml_with_buf() function. This function expects a buf parameter of type void*. (void* pointers can point to addresses of any type; I picked this “type”, because read() wants its buffer argument to be of that type.)

What went wrong is that I then took the address of void* buf, which is already a pointer. That is to say: the value of buf is the address of buffer which I passed to _xjot_to_xml_with_buf() from xjot_to_xml().

When I then took the address of the void* buf variable itself, and passed it to read(), read() started overwriting the memory in the stack starting at that address, thus garbling the values of line_no and col_no in the process.

The take-home message is: pointers are extremely useful, once you develop an intuition of what they're pointing at. Until that time, you must keep shooting yourself in the foot, because errors are, as Huberman says, the thing that triggers neuroplasticity.

WW challenge 1: learning better C by working on XJot

Since the beginning of this month (October 2021), I become officially jobless, after 6 years at YTEC. That’s not so much of a problem for a software developer in 2021—especially one in the Dutch IT industry, where there has been an enormous shortage of skilled developers for years. However… I don’t (yet) want a new job as a software developer, because: in the programming food pyramid, I’m a mere scripter. That is, the language in which I’m most proficient are all very high-level languages: Python, PHP, XSLT, Bash, JavaScript, Ruby, C# (in order of decreasing (recency of) experience. I have never mastered a so-called systems language: C, C++, Rust.

Now, because of the circumstances in which YTEC and I decided to terminate the contract, I am entitled to government support until I find a new job. During my last job, I’ve learned a lot, but almost all I learned made me even more high-level and business-leaning than I already was. I’ve turned into some sort of automation & integration consultant / business analyst / project manager. And, yes, I’ve sharpened some of my code organization, automated testing skills as well. Plus I now know how to do proper monitoring. All very nice and dandy. But, what I’m still missing are ① hardcore, more low-level technical skills, as well as ② front-end, more UX-oriented skills. Only with some of those skills under my belt will I be able to do the jobs I really want to do—jobs that involve ① code that has to actually work efficient on the hardware level—i.e., code that doesn’t eat up all the hardware resources and suck your battery (or your “green” power net) empty; and I’m interested in making (website) application actually pleasant (and accessible!) to use.

If I start applying for something resembling my previous job, I will surely find something soon enough. However, first I am to capture these new skills, if I also wish to continue to grow my skill-level, my self-respect, as well as my earning (and thus tax paying) potential. Hence, the WW challenge. WW is the abbreviation for Wet Werkeloosheid, a type of welfare that Dutchies such as myself get when they temporarily are without job, provided that you were either ⓐ fired or ⓑ went away in “mutual understanding” (as I was). If ⓒ you simply quit, you don’t have the right to WW (but there are other fallbacks in the welfare state of the NL).

Anyways, every month, I have to provide the UWV—the governmental organization overseeing people in the WW—with evidence of my job-seeking activities. Since I decided that I want to deepen my knowledge instead of jumping right back into the pool of IT minions, I will set myself challenges that require the new skills I desire.

My first goal is to become more comfortable with the C programming language. I have some experience with C, but my skill level is rudimentary at best. My most recent attempt to become more fluent in C was that I participated in the 2020 Advent of Code challenge. I didn’t finish that attempt, because, really, I’m a bread programmer. Meaning: before or after a 8+-hour day at the office, I have very little desire to spend my free time doing even more programming. To stay sane (and steer clear of burnout), that time is much-needed for non-digital activities in social space, in nature, and by inhabiting my physical body.

So now I do have time and energy to learn some new skills that really require sustained focus over longer periods of time to acquire. On the systems programming language level, besides C, I’m also interested in familiarizing myself with C++ and Rust. And it is a well-known facts that C knowledge transfers very well to these two languages.

Okay, instead of doing silly Christmas puzzles, this time I’ve resumed my practice by writing an actual program in C that is useful to me: xjot-to-xml. It will be a utility to convert XJot documents to regular XML. XJot is an abbreviated notation for XML, to make it more pleasant to author XML documents—especially articles and books.

« Older posts

© 2022 BigSmoke

Theme by Anders NorenUp ↑