Log in
Seblog.nl

Seblog.nl

Using PHPStan to fill Vim's Quickfix list

I am using PHPStan and the ALE plugin to add some error checking to my Vim. It gives red arrows on lines that contain errors in my currently opened files. But sometimes, in a big refactor, I want to know all errors in my project.

Vim has a build-in feature for this: the quickfix list. It is designed to take the error output of a compiler and lets you jump to all those locations with the :cnext and :cprev commands. I personally use the essential Unimpaired plugin by the one and only tpope, which maps these to ]q and [q.

I use these a lot: the :grep command fills the quickfix list with all the occurrences of your search, like normal grep but with pagination (or, if you set your grepprg to something faster: like ripgrep with pagination).

To get PHPStan to fill this quickfix list, I looked for plugins, but they all seemed hairy. I was convinced this should be simple, and it was. The following leader mapping seems to just work:

nmap <leader>pa :cexpr system('vendor/bin/phpstan analyse --no-progress --error-format=raw')<cr>

Customising Git: some things I did

One thing that always puzzled me a bit about my own workflow, is that almost all of it is based in the terminal (I use Vim and Tmux), except for Git: where most people seem to use the Git CLI commands, I use a graphical program (Fork, which is quite good).

Another thing then: I never used Github professionally, apart from the time I was a self employed web developer, but back then I was the only developer on my projects. All my previous jobs had a self-hosted Gitlab running somewhere.

Long story short: I am trying to get better at Git in the terminal and using Github. And 'better at Git' to me both means 'being able to confidently rebase' as well as 'customise my workflow'.

Aliases in the Gitconfig file

Customising Git means setting configuration in the ~/.gitconfig file. This file contains settings for Git, like your name and email, but can also be used to add aliases. To create the first alias you can run git config --global alias.co checkout. After this, you can use git co as git checkout, which is shorter to type and yes I use this often now.

Another alias I have is this one:

publish = !git push --set-upstream origin $(git symbolic-ref --short HEAD)

If you try to push a branch that has no linked branch on Github (the upstream), Git will complain about it. It will be nice to you and state the command you should have ran, but I got tired of having to copy and paste that new command.

fatal: The current branch feature/new-shoes has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin feature/new-shoes

In Fork, this was just a checkbox away. With my new git publish command I get the convenience again: it will push the branch and set the upstream with the same name as I have locally, exactly as Git suggested I should have done, but in less typing.

Links to Github

So far we have seen two kinds of aliases: one that just aliases a simple Git command (b = branch) and one that actually ran a shell command, because we started it with a ! (note that you will have to start with ! git there). But there is another way: having a command that starts with git- in your path.

I have the following file as ~/bin/git-github, marked as executable (chmod +x ~/bin/git-github) and in my path (export PATH="$HOME/bin:$PATH" in my ~/.zshrc file):

#!/bin/zsh

local url
url=$(git remote get-url $(git remote))
url=$(echo $url | sed 's/.*github\.com[:\/]\(.*\).git$/https:\/\/github.com\/\1/')

if [ -n "$1" ]; then
  append="/$1/$(git symbolic-ref --short HEAD)"
fi

open -u "$url$append"

Yes, my ZSH is crude. Yes, I can better share this in Bash. Yes, it could've probably been on one line and be included as an alias in my Gitconfig. But it works for me.

The command figures out the Github URL of the project, based on the URL of the remote (it assumes you have only one). It then opens that URL with the macOS open command. If an argument is given, it appends that to the URL, with the name of the branch too.

In my Gitconfig I have two aliases that use this command:

pr = github pull/new
compare = github compare

With git github, my default browser will open a tab with the 'homepage' of the repository. With git compare, it will open a tab that contains a diff of the current branch and the default branch on Github (the remote versions of those). With git pr, the browser will open the correct page to open a for the current branch.

And you mentioned Vim and Tmux?

Yes, I actually use the obligatory Tim Pope plugin Fugitive. This means I can do a lot of things which you can also read about in the help file. (Which I read a lot these days.)

But this allows me to stage and commit and rebase and reword all my changes in Vim, and then when I am ready, run :G publish and :G pr and make a PR for it on Github. These two commands alone make me feel so much more productive: no longer do I have to search for another program to compose commits and then search for the browser to handle the cooperative side of it... I just handle everything in my editor.

For Tmux I have another nice addition: in my ~/.tmux.conf I have the following command:

bind-key y display-popup -E -h "90%" "git log --oneline --decorate --graph --all"

This will – when I press <prefix> + y – open a popup window, which closes when the command exits and has a certain height. It will show me an ASCII-art style graph of all the commits – one of the features I missed from Fork – as an overlay over my editor, a small keystroke away.

With this configuration – and a lot of reading the Fugitive help file – I feel much more at home with Git in the terminal.

I also watched this fantastic series on mastering Git and these unfortunately dated but still useful screencasts on Fugitive.

Storing posts by juggling with Git internals

I have been wanting to rework the core of this website for a couple of years now, but since the current setup still works, and since I have many other things to do, and finally since I am very picky about how I want it to work, I have never really finished this part at all. This makes me stuck at the save version of this site, both visually as behind the scenes.

Now that I am in between jobs I wanted to work on it a bit more, but I still do not have time enough to fully finish it. I guess it all comes down to a few choices I have to make regarding trade-offs. In order to make better decisions, I wanted document my current storage and the one I have been working on. After I wrote it all out I think I am deciding not to use it, but it was a nice exploration so I will share it anyway.

The description heavily leans on some knowledge about Git, which is software for versioning your code, or in this case, plain text files. I will try to explain a bit along the way but it is useful to have some familiarity with it already.

tl;dr: I did fancy with Git but might not pursue.

How it is currently done

At the time of writing, my posts are stored in a plain text format with a lot of folders. It is derived from the format which the Kirby CMS expects: folders for pages with text files within it, of which the name of the text file dictates the template that is being used to render the page. In my case, it is always entry.txt.

I have one folder per year, one folder per day of the year and one folder per post of the day. In that last folder is the entry.txt and some other files related to the post, like pictures, but also metadata like received and sent Webmentions.

An example of the tree view is below. It shows two entries on two days in one year. Note that days and years also have their own .txt file that is actually almost empty and pretty much useless in this setup, but still required for Kirby to work properly. The first day of the year my site is broken because it does not automatically create the required year.txt (or did I fix that finally?).

./content
└── 2022
    ├── 001
    │   ├── 1
    │   │   └── entry.txt
    │   │   ├── .webmentions
    │   │   │   ├── 1641117941-f6bc3209f3f33f0cb8e4d92e5d46b5090b53aa11.json
    │   │   │   └── pings.json
    │   └── day.txt
    ├── 002
    │   ├── 1
    │   │   ├── some_image.jpg
    │   │   └── entry.txt
    │   └── day.txt
    └── year.txt

Also note that there is a hidden .webmentions folder which contains a pings.json for all the sent webmentions and a JSON file with timestamp and content hash in the name for every received webmention. Not in the diagram but also present are some other folders for pages like ./login/login.txt (because that is how Kirby works) and ./isbn/9780349411903/book.txt (for books).

All these files are stored in a Git repository, which I manually update every so often (more bimonthly than weekly, sadly) via SSH to my server. I give it a very generic commit name (’sync’ or so) and push to a private repo on Github, which takes a while because the commits and the repo contain all those images and all those folders.

What is wrong with this

The main point of wanting to move off of this structure by Kirby, is that it requires those placeholder pages in my content folder. I have no need for a ./login/login.txt: the login page is just a feature of the software and should be handled by that part of the code. But at least that file contains some text for that page: the files for year.txt and day.txt are completely useless.

Another point is that I want to make the Git commits automatically with every Micropub request: Git provides me with a history, but only if I actually commit the files once I changed them. Also, if I do not push the changes to Github, I have no backup of recent posts.

The metadata of the received and sent Webmentions are now also available in the repo. This is nice, as it stores the information right next to the post it belongs to, but on the other hand it feels kind of polluting: these Webmentions contain content by others, where as the rest of the content is by me. There is some other external content hidden in the entry.txt file but I’ll get to that later.

The last point is that the full size images are stored in the repo and every book and article about Git says that you should not use it to store big files in it. Doing a git status takes a while and also the pushes are much slower than any other Git repository I work with.

Git history: the Git Object Model

Before I go further into the avenue I am taking to solve the problem, I need to explain a bit about the Git Object Model, also known as ‘how Git works under the hood’. For a more thorough explanation, see this chapter in the Git Book.

As you’ll learn from that chapter, every object is represented as a file, referenced by the SHA1 hash of its contents. And there are three (no, four) types of objects:

  • blobs, which are the contents of files tracked by Git (and thus also the versions of those files)
  • trees, which are listings of filenames with references to blobs or other trees. These trees together create the file structure of a version.
  • commits, which are versions. A commit contains a reference to the root tree of the files you are tracking, a parent commit (the previous version) and a message and some metadata.
  • tags, are not mentioned by the chapter, but do exists: these look like commits, but create a way to store a message with a tag (making annotated tags, I’ll explain plain tags soon).

Note that Git does not store diffs, it always stores the full contents of every version of the file, albeit zlib compressed and sometimes even packed in a single file, but let’s not get into that right now.

Git’s tags and branches are just files and folders (they can have / in their names) which contain the hashes (names) of the specific commits they point to. The tags can also point to a tag object, which will then contain a message about the tag (which makes them ‘annotated tags’).

This all brings me to the final point about my storage: for every new post, Git has to create a lot of files. First, it needs to add a blob for the entry.txt, possibly also a blob for the image and blobs for other metadata. Then it needs to create a tree for the entry folder, listing entry.txt and if present the filenames of the images and metadata files. Then it creates a new tree for the day, with all the existing entries plus the newly created one. Then it creates a new tree for the year, to point to this new version (tree) of the day. Then it creates a new tree for the root, with this new version of the year in it. And finally it also needs to create a commit object to point to that new root tree. Every update requires all these new trees. The trees are cheap, but it feels wasteful.

Also note that a version of a file always relies on the version of all other files. This is what you want for code (code is designed to work with other code), but it does not feel like the right model for posts (I might come back on this tho).

And there is also the question of identifiers: currently, my posts are identified as year, day of year, number (2022/242/1), but especially that number can only be found in the name of the folder and thus in the tree, not in the blob. I have not yet found a good solution for this, but maybe I am seeing too many problems.

The new setup

To get rid of some of the trees, I tried to apply my knowledge of the Git Object Model to store my posts in another way. To do this, I used the commands suggested by the chapter in the Git Book in a script that looped over all my files, to store them in a new blank repo to try things out.

For each year, for each day, for each post, I would find the entry.txt and put the contents in a Git blob with git hash-object -w ./content/2022/242/1/entry.txt. The resulting hash I used in the command git update-index --add --cacheinfo 100644 $hash entry.txt to stage the file for a new tree. I would do that too for all images and related files, and then I would run git write-tree to write the tree and get the hash for it and git commit-tree $hash -m "commit" to create a commit based on it (with a bad message indeed). With that last hash I would run git update-ref refs/heads/2022/242/1 $hash to create a branch for that commit. (I contemplate adding an annotated tag in between, for storing some metadata like ‘published at’ date.)

This would result in a Git repository with over 10,000 branches (I have many posts) neatly organised in folders per year and day. When one were to check out one of these branches, just the files of that posts will appear in the root of your repo: there are no folders. When you check out another branch, other files will appear. This is not how Git usually works, but it decouples all posts from one-another.

Multiple types of pages

The posts I describe above all follow the year-day-number pattern because they are posts: they are sequential entries tied to a date. There are other objects I track, though, that are not date-specific. One example is topical wiki-style pages: these pages may receive edits over time, but their topic is not tied to a date. (I don’t have these yet.)

Another example is the books that I track to base my ‘read’ posts off. I haven’t posted them in a while, but I would like to expand this book collection to also include other types of objects to reference, such as movies, games or locations. These objects also have no date to them attached, at least not a date meaningful to my posts.

I could generate UUIDs for these objects and pages, and store branches for those commits in the same way Git does store it’s objects internally, with a folder per first two characters of the hash (or UUID) and a filename of the rest:

./refs/heads
├── 0a
│   ├── 8342d2-d6f1-4363-a287-a32948d04eaa
│   └── edcb13-433c-48d2-b683-a407c3a88f57
└── 3d
    ├── 243a27-114e-4eee-9bd8-2a51b01939e6
    ├── 25965b-2da5-422d-abce-f3337fa97fc4
    └── 611b59-499a-48a0-b931-afe06192e778

I could even reference the same post/object with multiple identifiers this way. Maybe I want to give every book a UUID, but also reference it by its ISBN. The downside to that, however, is that I need to update both branches to point to the same commit once I make an update do the book-page.

Drawbacks of the approach

The multiple identifiers are probably not feasible, but there are some other drawbacks too. My main concern is that it is much harder to know whether or not you pushed all the changes: one would have to loop over all 10,000+ branches and perform a push or check. In this loop you would probably have to check out the branch as well. It is of course better to just push right after you make a change, but my point is that the ‘just for sure’ push is a lot of work.

Another drawback is actually the counter to what I initially was seeking: wiki-style pages might actually reference each other, and thus their version may depend on a version of another page. In this case, you would want the history to capture all the pages, just as the normal Git workings do. My problem was with the date-specific posts, but once you are mixing date-specific and wiki-style pages, you might be better off with the all-file history.

One problem this whole setup still does not solve is that of large files. The git status command is much faster for it does not have to check all the blobs in the repo to get an answer, but the files are still in the repo, taking up space. And there do exist other solutions for big files in git, such as Git LFS, the Large File Storage extension.

Also, I am still not 100% sure it is a good idea to store metadata in the Git commits and tags. When we already store the identifier in the tree objects, I thought I could also add the ‘published at’ date into the commit. Information about the author is already present, and as my site supports private posts, it also seemed like a reasonable location to store lists of people who can view the post. But again, maybe that should be stored in another way, and not be so deeply integrated with Git.

Conclusion

It was very helpful to write this all out, for by doing so I made up my mind: this is just all a bit too complicated and way too much deeply coupled to Git internals. I would be throwing out the ‘just plain text files’ principle, because I would store a lot of data in Git’s objects, which are actually not plain text, since they are compressed with a certain algorithm.

My favourite Git GUI Fork is able to work with the monstrous repository my script produced, but many of the features are now strange and unusable, because the repo is so strangely set up. I would have to create my own software to maintain the integrity of the repo and that could lead to bugs and thus faulty data and maybe even data loss.

I still think there are some nice properties to the system I describe above, but I won’t be using it. But I learned a few new things about Git internals along the way, and I hope you did too.

Quickly look up PHP docs from Vim

As I don’t use a full IDE like PHPStorm, I don’t get much help with the parameters to function calls from my editor. On one hand I find this a good thing: IDE users rely so much on autocomplete that they don’t remember names of things at all. On the other hand: who has the mental space to waist on such things?

My middle ground is that I look up a lot of things on PHP.net. They make that very simple: just add the name of the function you are looking for after the slash and they will give you the correct documentation. But: switching to a browser and typing out the address requires a lot of keystrokes. I found a solution.

nmap <Leader>pd :silent !open https://php.net/<c-r><c-w><cr>

This adds a leader key mapping to look up the word (so: function name) under the cursor. I prefix all my PHP related leader mappings with a p, but feel free to pick something else.

The :! runs a shell command, in this case open, which on Mac can be given a URL, which will then be opened in the default browser. I added silent to ignore the output of the command: I just want to open a URL.

As the URL, I let Vim type out the address to PHP.net, and since we are in command mode, one can do Ctrl+R, Ctrl+W, which will paste the word that is currently under the cursor (very nice to know in itself). We end the sequence with an enter (carriage return) to run it.

So the tip within the tip is Ctrl+R (register) Ctrl+W (word). In general Ctrl+R in insert mode gives you this interesting ‘paste from register’ mode that is good to know. See :help i_ctrl-r and :help c_ctrl-r for more.

Ik weet weer het antwoord op de vraag ‘waarom heb ik geen secondelijm in huis’, wat een nare vingertoppen krijg je ervan. Maar het is per saldo vast beter voor het milieu dan een nieuw telefoonhoesje kopen.

Pride Run

Van de week schreef ik al over de Eurogames en dat ik daar een race van 5km deed. Gister deed ik nog een keer 5km in een race, de Pride Run in Amsterdam, en dat ging goed.

De Eurogames race was een beetje een gehaaste race: ik had de Pride Run al gepland, en schreef me pas de avond van te voren in omdat ik er toen pas achter kwam dat ik aan deze mee kon doen als ‘local hero’. Als Nijmegenaar wilde ik dat dus wel.

De ochtend was ik ook al naar Amsterdam geweest, niet voor de Pride Run maar de Pride Walk. Ik deed 20 minuten over de eerste 200 meter, maar het was fijn om mee te doen.

Het jammere was dus wel dat ik vrij gehaasd bij de Eurogames aankwam: snel thuis omkleden en toen nog flink doorfietsen om mijn startnummer op tijd op te halen. Ik dacht, da’s gelijk warming up, en dat was wel zo, maar ik had ook het idee dat ik al net te veel energie aan het verbruiken was.

Het was ontzettend heet en ik had te weinig gedronken: al na één kilometer had ik dorst. En er kwam een waterpost, want ik ging maar één rondje. En ik hield me misschien in? Al met al was ik teleurgesteld met de tijd van 24:26, maar aan de andere kant was het de eerste keer sinds een lange tijd dat ik onder de 25 zat, dus zo erg was het niet.

Dan dus gister: vrijwel alles klopte bij de Pride Run. Het was relatief koel, ik had goed gedronken, beetje ingelopen, er waren veel mensen, de route was vlak en de ondergrond ook. Ja, ik ging veel te hard van start – eerste drie kilometer 4:15/km – maar het ging goed.

Uiteindelijk had ik een tijd van 22:27, waarmee ik dus bijna twee minuten sneller was dan vorige week. En ik heb mijn ‘haha dat kan niet’ doel van 22:30 dus gehaald. Ik ben heel blij.

Shoe Dog

Net klaar met het lezen van Shoe Dog van Phil Knight, de oprichter van Nike. Het is alweer uit 2016, maar ik kwam het tegen in de boekhandel en aangezien ik volgende maand met een nieuwe baan begin in het schoenvak, leek het me interessant om te lezen.

Het bleek ook inderdaad een goed geschreven en interessant boek te zijn, waarin schoenen ook samengaan met hardlopen (waar ik de laatste tijd weer heel actief mee bezig ben) en Japan (waar Phil zijn eerste schoenen vandaan haalt en waar ik al een tijd ook interesse in heb).

Gaandeweg wordt het boek steeds iets meer een verslag van ‘legal battles’, want een groot bedrijf wordt je niet zonder dat. Dat ze worden gewonnen snap je als lezer wel, want anders was Nike niet zo groot als het nu is. Daarnaast blijft ook wel de indruk: Phil Knight houdt erg van zichzelf. Alles lijkt hij uiteindelijk te willen verbinden aan een soort voorbestemdheid, dat hij Nike wel móest oprichten van het universum, gezien alle tekens. Maar goed, als je steeds blijft winnen, is dat dan Tao, of geluk? We lezen natuurlijk niet de boeken van de mensen met Crazy Ideas die het niet gehaald hebben.

Toch vond ik het soms echt wel ‘oei’. Van bepaalde dingen kan je nog zeggen ‘ach het waren de jaren 60, 70’, maar er is dus in het boek veel sprake van ongelijkheid, van mannetjes, van machtsverhoudingen en van een beschreven cultuur die hij zelf duidelijk op het moment van schrijven nog altijd niet als problematisch zag. Aan de andere kant was hij voor die tijd juist vooruitstrevend – of zo wil het boek het – door een handel in atletische schoenen te laten runnen door o.a. een man in een rolstoel en een man met overgewicht.

Bij de hele zaak tegen de aanvankelijk samenwerkende schoenenfabrikant Onitsuka kreeg ik ook juist wel sympathie voor de Japanners: Phil heeft ook absoluut tegen ze gelogen. Leuk om daarna te ontdekken dat ze nog steeds in business zijn, alleen dan onder de naam Asics, en laat dat nou net het merk zijn van mijn huidige hardloopschoenen.

Al met al dus wel een interessant en vermakelijk boek.

Juli 2022

Geen idee of ik dit goed ga volhouden, maar ik zag een paar mensen die wekelijks of maandelijks een overzicht van gebeurtenissen uit hun leven schrijven. Ik schrijf niet al te veel meer over mijn dagelijkse bezigheden – er was een tijd dat ik dagelijks een maf stukje typte – maar eenmaal per maand een overzicht lijkt me wel een leuk idee. Hier de eerste editie voor juli 2022.

  • De maand begon met mijn eerste meerdaagse festival: Down The Rabbit Hole. Ik had er speciaal een nieuwe tent voor aangeschaft (al had ik er al twee) en ik vond vooral het kampeer-aspect heel leuk. Qua optredens vond ik Moderat het hoogtepunt, maar ook leuke dingen gezien die ik nog niet kende (zoals L’Imperatrice). Ik zou zo nog eens gaan (en ik wil nog eens kamperen deze zomer).
  • Ook heb ik deze maand besloten een overstap te maken qua werkgever: ik maak nu een prijsvergelijker maar ga binnenkort schoenen verkopen. Of ja, daarbij helpen dan, en pas vanaf september.
  • Mijn stiefmoeder was jarig en vierde dat met een heerlijke lunch aan het water met alle broers. Sowieso ben ik veel in Leiden geweest omdat het steeds iets minder gaat met mijn vader, waarvoor veel geregeld moet worden.
  • Juli is natuurlijk ook de maand van de Nijmeegse Vierdaagse. Ik ben op zaterdag naar het vuurwerk wezen kijken, ben op dinsdag (heetst van de dag, 39º) met collega’s ‘de stad’ in geweest (meer in de schaduw hangen), heb op woensdag in de pauze een collega aangemoedigd die langs kantoor kwam en op vrijdag kwamen er wat vrienden uit Amsterdam over voor de intocht. Ook zonder de hele week vrij te nemen was het best wel een fijne Vierdaagseweek.
  • Go spelen ligt een beetje stil vanwege de zomerstop op de club, maar ik ben wel nog een middagje bij de Hubert gaan zitten, waar op vrijdag vaak wel spelers zijn. Was een fijne partij in de schaduw, die ik wel verloor, maar de muziek was goed.
  • Hardlopen gaat juist steeds beter. Ik trek nu meerdere keren per week de schoenen aan voor een rondje en dat voelt lekker. Ik ben nog nooit in de buurt geweest van dik zijn, maar merk toch een verschil in mijn lichaam nu ik weer fit ben. Ik dacht juli af te sluiten met een 5k race, maar ben gister alsnog naar de zondagochtendtraining gegaan. Het is een beetje verslavend.
  • De 5k race was in het kader van de Eurogames. Die ochtend heb ik ook nog in Amsterdam meegelopen aan de Pride Walk, want Pride is a protest. Komende week ook nog een 5k bij de Pride Run, maar dat is augustus.

Net de Pride Walk in Amsterdam gelopen, omdat ik vorige jaren steeds pas op de botenparade bedacht dat ik daar ook aan had willen meerdoen. Pride is een leuk feest, maar pride is ook een protest, zo lang als dat nodig is.

Ik ga nu snel terug naar Nijmegen waar de Eurogames bezig zijn. Vanavond nog even 5km hardlopen bij een side-event ervan. Hopelijk gaat dat sneller dan de Pride Walk.

Van de week liep ik met wat collega’s en hun vraag was: moet dat nou, een sportevenement voor homo’s? Zo sluit je je af, maak je het juist apart. Mijn antwoord was dat er meer zichtbaarheid moet zijn, maar ze werden alleen maar stelliger.

‘Voor een gaybar heb ik nog respect,’ zei iemand, ‘dat is makkelijker, als je on the hunt bent, dat je niet hoeft te vragen.’ Maar een sportevenement was daarin niet praktisch, dus overbodig, vond hij.

Ik heb daar dus nu een halve week mee in mijn maag gezeten. Is het overbodig?

Ik had geen antwoord. Maar het antwoord is: zolang een dergelijk evenement als politiek wordt ervaren, is het politiek en dus nodig als protest. En als het niet meer politiek is, is het er alleen voor de leuk, en dan is het nodig omdat het leuk is.

Ergens vind ik het nog steeds eng: ik zit nu bij een nieuwe atletiekvereniging en ik ben daar niet expliciet uit de kast, dus zit ik er nog in, zo gaat dat. Ga ik de run van vanavond op Strava zetten? En de Pride Run volgende week? Het doet niet ter zake maar toch wel.

Eerst maar even zorgen dat ik daar op tijd aankom en überhaupt meeren. Het is nodig. Pride is protest.

Broccoli-spinazisoep

Een paar jaar terug ontdekte ik de beste makkelijke maaltijd van Albert Heijn: pureersoep broccoli-spinazi. Men koopt de bak, warmt olie in een soeppan, mikt de inhoud van de bak in de pan (maar niet het zakje kruidenmix en de peterselie), bakt de groenten een beetje, voegt dan wat water (zitten zelfs maatstreepjes in de bak) en de kruiden toe en laat staan koken voor 13 minuten. Later heb ik de moeite genomen daadwerkelijk een pureerstaaf te kopen om het af te maken, maar eerlijk gezegd: die stap is optioneel als je echt lui bent.

Een paar maanden terug ontdekte ik opeens dat de broccoli-spinazisoep uit het assortiment was gehaald. Er waren diverse pureersoepen, waaronder een nieuwe groene (met courgette), maar geen van al die soepen was zo magisch als de broccoli-spinazisoep, naar mijn mening. Ik vond dit verlies best tragisch.

Een paar weken terug ontdekte ik dat hij weer terug was, of in elk geval, in een Albert Heijn waar ik normaal niet kom stond hij opeens naast de courgettesoep. Ik heb de bak direct aangeschaft, maar beter nog, ik heb een foto genomen van de lijst met ingrediënten.

Een paar dagen terug kocht ik alle dingen die ik nodig dacht te hebben.

En het is gelukt: ik heb de broccoli-spinazisoep met succes ge-reverse-engineerd. Het was iets meer snijden, maar deze soep nemen ze me niet meer af. Het gaat als volgt: fruit wat uien en wat knoflook, gooi er daarna dus de broccoli en spinazi bij, bak dat wat op, dan nog kikkererwten in de pan gooien (ik deed blikje maar je kan ook losgaan op zelf koken). De kruiden blijken eigenlijk gewoon de ‘hot curry’ mix te zijn (kurkuma, koriander, peper, mosterdzaad, fenegriek, gember, komijn, karwijzaad, piment, nootmuskaat, lavas, venkel… ongeveer dat en het zal wel goed zijn). Daarnaast natuurlijk iets van een bouillonpoeder en vergeet het water niet. Kooktijd was bij mij iets langer, want ik had iets meer, maar de smaak was heel goed (beetje bijpoederen soms, hij hoort wat scherp te zijn).

Ik was dit weekend in Utrecht voor een go-toernooi en in de pauze daarvan ben ik nog even de binnenstad in gewandeld. Op mijn lijstje van plekken om te bezoeken stond nog boekhandel Broesse, want die zijn verhuisd en ik was er nog niet wezen kijken. Dat is de eerste tip: ga daar heen, het is een mooie boekhandel.

Eenmaal daar stond ik oog in oog met een Bambook. Dit is precies wat ik al een tijdje beschrijf als wat ik wil hebben: een meeneembaar whiteboard in de vorm van een opschrijfboekje. Ik heb in het verleden daarwerkelijk een whiteboardje van 30 bij 30 cm meegenomen naar kantoor voor dit doel, maar het was nooit echt handzaam. Ik heb natuurlijk direct de kleinste Bambook meegenomen als impulsaankoopje.

En dat is dus de tweede tip: dit is een heel fijn ding. Nee, het is wat gladder dan papier en de pen schrijft niet zoals balpen of potlood, maar het werkt heel aardig. Met nul schuldgevoel schrijf ik hele pagina’s vol.

De laatste tip is om die aantekeningen binnen het uur van je meeting even uit te tikken. Ik heb dat nu al twee keer gedaan voor twee verschillende behoorlijk informatie-zware afspraken, en in beide gevallen voel ik me een stuk lichter omdat ik het idee heb dat alle informatie netjes in een lopende tekst is gevat. Moet ik wel bij zeggen dat ik snel en makkelijk typ.

Vandaag is er een reünie op de plek waar ik mijn eerste biertje dronk. Nu drink ik 0.0, want ik moet nog rijden. Mijn gebruikelijke autoschaamte wordt hier verdrongen door autotrots, want sinds kort kan ik ook rijden. Ik ben niet langer die ene die op een ov-fiets aan komt zetten, die sowieso niet de bob is want ja, geen rijbewijs.

De trots wordt beantwoord met kinderen, kinderen die kunnen lopen en praten en ‘papa’ en ‘mama’ zeggen tegen hen die ik nog als kind ken. De mensen van wie ik wist dat ze ouders waren geworden hebben hun kinderen niet eens mee: te oud, waarschijnlijk, hadden wel betere dingen te doen.

‘Een witte Volkswagen Up,’ vertel ik tegen een papa. ‘Ah,’ zegt hij, ‘wij twijfelen nog. Onze tweede auto is kapot, maar zo’n kleine is toch wel fijn om erbij te hebben.’ De Chinees na afloop sla ik over, maar zonder goed excuus, thuis zit er niemand op me te wachten. ‘Nee sorry,’ zeg ik, ‘het is een lange reis.’

The day before yesterday I posted about how to divide up posts into various 'post topics', to aid readers in finding something interesting.

Just now I came across an interesting read (in Dutch) by NRC, how they put articles on their homepage. The gist of it: they have some automation, but most of it is actually hand picked by a team.

I don't know if I want to hand pick something like that for my own site, but I like the idea of hand-picked content over algorithms. Or even 'assisted hand-picking', something like that might work.

Another perspective I wanted to add to my own post: by creating these three to five main categories, one is also creating three to five 'personas' to write for. It is like writing a letter to a friend, but then have three friends with different interests, so you write them different stories. What I mean is that these main topics can also aid the writing process itself.

When @hacdias.com posted about our conversation about post topics I couldn’t stay behind to also formulate my part of it in a blogpost.

Currently I have various feeds for various post types. I don’t want to link them all here, in case I want to change them around, but I have different feeds that only show my likes, my photos, my replies, etc (you can probably guess the URLs).

These feeds are relatively easy to set up: does it have a photo? Then it’s a photo. Does it have a title? Then it’s an article. This post doesn’t have any, so it’s a note. I have a few of those rules set up and they fill these pages.

But when you scroll through my photo feed, you will also see drawings. When you scroll through my notes, there are various topics represented. It is not that bad right now, but that is mainly because I don’t post as much as I could, because I don’t want to bore my readers with topics they don’t want to follow.

On social media, we live a siloed life, and the people on the IndieWeb are trying to bring that all back to their own site. But, in the siloed life, we can pick the silo for the post. ‘Insta is for friends, Twitter is more business, Reddit is shitposting’, something like that. Sometimes the silo is aimed at a certain kind of post, sometimes it is just the kind of bubble you created for yourself on that silo that makes you post a certain way.

On the IndieWeb, I have only one site. Of course I can get multiple – I have – but I like having all my posts in one place. But I also want to give people options for how to follow me, different persona to share posts with.

I do have tags but most are not that useful. Most of them only contain one post, and also, most of them are very specific. I like the indieweb and vim tags, for they are quite topical, but those are exceptions.

At one point (not now) I would like to divide posts up into probably five rough categories. The homepage might still show a selection of all, and there will also be a place to actually see everything, but I think these categories make sense to me:

  • professional / helpful for all those posts in which I share something about IndieWeb, Vim, something about programming, something I learned
  • personal for stories about what happened in my life, maybe also some tweets, the more human connection
  • too personal for checkins, books I’ve read, food I’ve eaten, movies I’ve watched, still about life but without commentary
  • art for those good pictures, occasional drawings, fiction stories, the things I post too little

I said five and I posted four, because I don’t think this is final. I might also want to add a ‘current obsession’ category, to blog about those things I am deeply into. (There has been posts about keyboards here, you missed Getting Things Done, currently I am into the game of Go again.)

A last category I might also need is ‘thinking out loud’, as this is a post that would fall into that. For what is worth, I’ll post it anyway.

Kleine follow-up op mijn toepassing van NFC-stickers: ik heb zojuist een sticker op mijn wasmachine geplakt. Hoe meer je gaat leven met een app waar je al je todo's in bewaart, hoe meer je ook andere todo's daar in wil stoppen. Zo heb ik dus een herhalende herinnering om de was te doen, dat is, de inhoud van de wasmand in de wasmachine te stoppen. De vraag is, wie haalt het er dan weer uit?

Daarnet bleek ik dat dus vergeten te zijn. De was zat nog in de machine terwijl die al een tijd klaar was. De nieuwe sticker op de wasmachine lost dat op: zodra ik 'm scan maakt mijn iPhone een taak aan genaamd 'was ophangen', in de context 'thuis' en met de datum van vandaag. De nieuwe taak opent direct zodat ik een specifiekere herinnering kan instellen als dat nodig is. Na het aanzetten even scannen en klaar. Kind kan de was doen.

WorkOutDoors hardloop app

Om maar gewoon met de deur in huis te vallen: de beste hardloop-app voor Apple Watch heet WorkOutDoors. Ik ben helemaal blij.

Voorheen nam ik mijn hardlooprondjes op via de standaard Workouts app van Apple. Dit is een prima app: het meet wat het moet meten. Ik gebruik een app genaamd HealthFit om mijn rondjes naar Strava te syncen (en ooit, ooit ook naar dit weblog). Op Strava heb ik vervolgens allemaal analyses.

Kleine pro-tip tussendoor: je kan tijdens een workout dubbeltappen op je Apple Watch, dat neemt een nieuwe lap/interval op. Hiermee hak je je workout op in stukjes, die je later kan analyseren. Eerst vier minuten snel, dan drie langzaam? Twee tapjes tussendoor en je ziet later precies statistiekjes over de twee losse stukken.

En dat brengt me bij mijn grootste probleem met de Workout app: het geeft me allerlei gegevens tijdens het lopen, maar niet de verstreken tijd sinds het begin van de huidige interval. Eerst vier minuten snel, dan drie langzaam? Dan mag je dus zelf heen en weer naar de stopwatch-app, om een timertje te zetten. Ik vind dat niet echt lekker werken.

Nou, dan niet WorkOutDoors. Mis je in deze app een bepaald cijfertje? Binnen no-time heb je het toegevoegd op een van de vele schermen die je kan instellen. En dan echt élk soort cijfertje wat je maar kan verzinnen, op elk soort scherm dat je maar wil. Mijn enige kritiekpunt is dat de app té nerdy is, te veel is aan te passen. Maar tegelijkertijd vind ik het dikke prima: het is precies wat ik wil, zelfs als ik straks misschien wat anders wil.

Toen ik van de week bij Cifla trainde had ik het er met iemand over. Zij miste juist een andere feature: van te voren een set aan intervals en tijden instellen en dan dat programma laten afdraaien tijdens het rennen. Die feature zit hier ook gewoon in; ik heb ‘m net gebruikt voor een rondje, en achteraf gezien is dat inderdaad een feature die ik ook gemist heb. Eerst vier minuten snel, dan drie minuten langzaam? Stel het van te voren in en alles komt goed.

Ik grapte toen nog dat het een gat in de markt was dat dit nog niet bestond, dat ik zelf die app maar moest gaan maken. Maar hij bestaat dus wél, voor 6 euro. Shut up and take my money.

De twee vormen van privacy

In discussies over privacy merk ik vaak dat mensen het over verschillende dingen hebben. Van het woord ‘bank’ is vaak uit de context wel duidelijk of het om een financiële instelling of om een zitmeubel gaat, maar bij ‘privacy’ lopen de concepten een beetje door elkaar heen.

Er zijn naar mijn idee twee vormen van privacy: mens-mens-privacy en mens-bedrijf-privacy. Waar ‘bedrijf’ staat kan ook ‘instantie’ staan of iets anders dat op een onpersoonlijk rechtspersoon duidt. In beide vormen is het volgens mij belangrijk om privacy te hebben, en de reden ervoor brengt ze uiteindelijk weer bij elkaar tot één begrip van privacy.

De meest begrijpelijke vorm van privacy is denk ik de mens-mens-privacy. Persoonlijk ben ik liever alleen als ik naar het toilet ga. Sommige dingen vertel je wel aan je moeder maar niet aan collega’s en andere dingen juist niet aan je moeder maar wel aan je collega’s.

Privacy gaat over relaties, over hoe ik mij verhoud tot collega’s en mijn moeder. Het is gezond om dingen achter te houden voor bepaalde mensen, niet omdat het echt geheim is, maar gewoon omdat de omgang prettiger is zonder die informatie. Ze doen het zelf ook naar mij toe.

De andere vorm, mens-bedrijf-privacy, gaat over data. Als ik een vriend vertel over mijn weekend is dat een verhaal, als mijn telefoon verbinding maakt met de wifi van de Albert Heijn is dat een data-punt. In deze vorm van privacy gaat het nog steeds om een relatie, namelijk die van mij tegenover de instantie die mijn data interpreteert, maar de relatie is uit balans.

Bedrijven en instanties hebben veel data, en kunnen daarmee komen tot voor hen nuttige inzichten over mij. Die inzichten geven de relatie vorm die ze met mij willen hebben, maar zelf heb ik niet zo’n concreet beeld van hen. In veel gevallen weet ik niet eens wie mijn data interpreteert en met welk doel.

Ook vergeten instanties dingen niet snel meer. Dankzij regelgeving horen ze gegevens periodiek te verwijderen, gelukkig, maar als ze niet op de knop drukken hebben ze nog altijd een even scherp beeld van mij als dat ze hadden toen ze de data vergaarden. Een anekdote van een bekende in de kroeg zakt na een paar maanden wel weg.

Het belang van de mens-mens-vorm van privacy wordt ook onderschat, denk ik. Voor beide moet aandacht zijn. In beide vormen gaat het om de noodzaak om zelf controle te houden over de relaties die anderen met je op proberen te bouwen.

Meer laden