Junited 2026 is over, and once again, I only managed to create a handful of links. I wonder if these kinds of blogging events are even for me.https://maurice-renck.de/en/blog/2026/junited-recap
The firefly season is ending. I only saw 200 of them or so. There was one female directly on the forest road. If only I brought my camera and tripod, that would have worked out I reckon. I had my torch with me and this looked really cool.
Dusk took forever today. It was really long light out there. Full moon is tomorrow.
On the way back, there was suddenly a load clatter and crashing sound 100 meters away from me. I didn’t see anything, but a tree fell over in the forest out of the blue. Fuck me dead, that was scary as hell. Luckily, I was already on the main road, only meadows around me. It’s the second time I witnessed a tree accidentally coming down. The first one was during the most expensive hail storm in our area so far in 2011 behind me when setting up a summer camp. The weather changed in less than 15 minutes.
Maybe not such a good idea to go out so late alone. :-? Any rustling in the forest immediately reminded me of the boar the other day. Luckily, always false alarm. Still a bit terrified from that event.
Ah, with lazy loading, browsers only start loading images when the load event occurs. And that takes time. Hm. Not a fan, I might revert this. 🤔
In the light of current events, I will first consult my pillow and only then write an article about readable code.
There was an event being held at the lake, so I couldn’t do my run there. Came home and jumped rope for 81 minutes! I wil be sore tomorrow, but it was worth it.
tt. But then, in the message tree, I spot another missed typo. My process is then to go to my twtxt.txt and fix it by hand. However, I still have to clean up tt's cache. This is rather tidious:
Now I’m curious how movwin deals with that. ;-)
Focus handling? I hardly remember, lol. 😅 Did that 6 months ago and haven’t touched it since. Let’s see.
The core main loop gets keyboard/mouse events from curses. At this level, the main loop only knows about exactly one widget, so it passes the event to that widget (whatever that is, doesn’t matter – they all inherit from the Widget base class, it could be a Window, a WindowManager, or an Edit box directly).
The outermost widget is usually a WindowManager. It implements a few hotkeys of its own, like switching to another window. If none of those hotkeys match, it passes the event to the currently focused window.
Same story here: Window implements some hotkeys (like opening the menu bar). If none of those match, then … the magic happens.
Each Window acts as a focus manager. It can descend into its child widget hierarchy and collect all child widgets in a depth-first search. They are collected into a flat list. Each Window then has an attribute _focus_position, which is an index into that list. Pressing Tab or Shift+Tab increases or decreases that index and that allows you to select the next/previous focusable widget in the current window.
Eventually, Window passes the input event to the currently focused widget.
Usually on initialization, the application can ask a Window object to focus a certain widget. The file selection dialog does that, for example, because the “natural” focus order would be to focus the Edit box at the top of the window first – but that’s not what the user wants, the Table showing the list of files should be focused.
If no widget ever feels responsible for handling a certain input event, then there’s a global unhandled_input callback that the application can provide (same as in urwid).
I think that’s it.
Hm, that’s more complicated than I remembered, but apparently it works fine, because I completely forgot about this. 😅 All I did in the last few months was make new classes that inherit from Widget, like the new Table class or Edit or HexEdit or whatever, and if they want to get input events, then they must implement the methods input_key() or input_mouse().
Does this answer your question? 😅 (I admit that I didn’t exactly understand your scenario, so I just went ahead and rambled about my implementation. 😅)
@bender@twtxt.net Apologies, I’m still working through some layout issues with TwtStrm and frequently miss mentions…
Magic: the Gathering does not use a Game Master (although professional referees are often used in sanctioned events). While the game has alot of thematic crossover with with D&D (or fantasy games in general), the system is much more of an abstract, card-dueling system involving things like “the stack” and insanely specific rules on card timing and interactions.
Like, we joke about “I’m sending my army of (goblins / elves / angels / whatever) at you,” but that’s about as far into the “role-playing” element most magic games get in my experience (and most of the “official” competitive games I’ve played at my FLGS were even more abstract and less thematic, although it’s been years since I played in one of those).
Many people started to become distrustful of big tech in the wake of the COVID-19 pandemic. I began feeling pessimistic back in 2016, when AlphaGo beat master Go player Lee Sedol four games to one. Something about that event has soured me on the future of technology ever since.
@kiwu@twtxt.net I returned home from an on-site week at work. Commute was an adventure every day. It started off with a canceled train on Monday morning. Luckily, some very good mates granted my asylum. But even with shorter rides, I faced delays due to fuckwits on the tracks, then the train was terminated early due to the large delay, so we had to change trains. On the bright side, they then sent an entirely empty one, but I don’t get why they just didn’t continue with the first one instead. Due to another delayed train I didn’t catch my connection and the next one was canceled, so I had to wait for the following one. Super great fun. I’m very exhausted now and am very glad that I had already filed in flex time for tomorrow before the on-site event was scheduled.
Meeting my workmates in person was actually nice. It’s okay to do that once a quarter, I don’t need to do that more often. We should have had more meetings, though, trying to work in the office was expectedly incredibly inefficient. We certainly would have had more topics to actually discuss and think about. And most of them would have really benefited from nearly everybody being in the same room. Anyway.
Today, I even met my workmates from past projects in the office, too. So, the socializing was great.
world events are designed to be negative right now, and it’s a real drag on the mental.
A Phlog about the mysteries of history and the most incredible events, new conspiracy theories and the wildest world news gopher://shibboleths.org/1/phlog
I need some time away, work, world events, wearing on a guy..
@bender@twtxt.net I’m already using it for tracktivity (meant for tracking activities and events, like weather, food consumption, stuff like that), which is basically a somewhat-fancy CSV editor:
https://movq.de/v/f26eb836ee/s.png
I have a couple of other projects where I could use it, because they are plain curses at the moment. Like, one of them has an “edit box”, but you can’t enter Unicode, because it was too complicated. That would benefit from the framework.
Either way, it’s the most satisfying project in a long time and I’m learning a ton of stuff.
I’m trying to implement configurable key bindings in tt. Boy, is parsing the key names into tcell.EventKeys a horrible thing. This type consists of three information:
- maybe a predefined compound key sequence, like Ctrl+A
- maybe some modifiers, such as Shift, Ctrl, etc.
- maybe a rune if neither modifiers are present nor a predefined compound key exists
It’s hardcoded usage results in code like this:
func (t *TreeView[T]) InputHandler() func(event *tcell.EventKey, setFocus func(p tview.Primitive)) {
return t.WrapInputHandler(func(event *tcell.EventKey, setFocus func(p tview.Primitive)) {
switch event.Key() {
case tcell.KeyUp:
t.moveUp()
case tcell.KeyDown:
t.moveDown()
case tcell.KeyHome:
t.moveTop()
case tcell.KeyEnd:
t.moveBottom()
case tcell.KeyCtrlE:
t.moveScrollOffsetDown()
case tcell.KeyCtrlY:
t.moveScrollOffsetUp()
case tcell.KeyTab, tcell.KeyBacktab:
if t.finished != nil {
t.finished(event.Key())
}
case tcell.KeyRune:
if event.Modifiers() == tcell.ModNone {
switch event.Rune() {
case 'k':
t.moveUp()
case 'j':
t.moveDown()
case 'g':
t.moveTop()
case 'G':
t.moveBottom()
}
}
}
})
}
This data structure is just awful to handle and especially initialize in my opinion. Some compound tcell.Keys are mapped to human-readable names in tcell.KeyNames. However, these names always use - to join modifiers, e.g. resulting in Ctrl-A, whereas tcell.EventKey.Name() produces +-delimited strings, e.g. Ctrl+A. Gnaarf, why this asymmetry!? O_o
I just checked k9s and they’re extending tcell.KeyNames with their own tcell.Key definitions like crazy: https://github.com/derailed/k9s/blob/master/internal/ui/key.go Then, they convert an original tcell.EventKey to tcell.Key: https://github.com/derailed/k9s/blob/b53f3091ca2d9ab963913b0d5e59376aea3f3e51/internal/ui/app.go#L287 This must be used when actually handling keyboard input: https://github.com/derailed/k9s/blob/e55083ba271eed6fc4014674890f70c5ed6c70e0/internal/ui/tree.go#L101
This seems to be much nicer to use. However, I fear this will break eventually. And it’s more fragile in general, because it’s rather easy to forget the conversion or one can get confused whether a certain key at hand is now an original tcell.Key coming from the library or an “extended” one.
I will see if I can find some other programs that provide configurable tcell key bindings.
@lyse@lyse.isobeef.org It’s not super comfortable, that’s right.
But these mouse events come with a caveat anyway:
ncurses uses the XM terminfo entry to enable mouse events, but it looks like this entry does not enable motion events for most terminal emulators. Reporting motion events is supported by, say, XTerm, xiate, st, or urxvt, it just isn’t activated by XM. This makes all this dragging stuff useless.
For the moment, I edited the terminfo entry for my terminal to include motion events. That can’t be a proper solution. I’m not sure yet if I’m supposed to send the appropriate sequence manually …
And the terminfo entries for tmux or screen don’t include XM at all. tmux itself supports the mouse, but I’m not sure yet how to make it pass on the events to the programs running inside of it (maybe that’s just not supported).
To make things worse, on the Linux VT (outside of X11 or Wayland), the whole thing works differently: You have to use good old gpm to get mouse events (gpm has been around forever, I already used this on SuSE Linux). ncurses does support this, but this is a build flag and Arch Linux doesn’t set this flag. So, at the moment, I’m running a custom build of ncurses as a quick hack. 😅 And this doesn’t report motion events either! Just clicks. (I don’t know if gpm itself can report motion events, I never used the library directly.)
tl;dr: The whole thing will probably be “keyboard first” and then the mouse stuff is a gimmick on top. As much as I’d like to, this isn’t going to be like TUI applications on DOS. I’ll use “Windows” for popups or a multi-window view (with the “WindowManager” being a tiny little tiling WM).
And now the event loop is not a simple loop around curses’ getch() anymore but it can wait for events on any file descriptor. Here’s a simple test program that waits for connections on a TCP socket, accepts it, reads a line, sends back a line:
https://movq.de/v/93fa46a030/vid-1767547942.mp4
And the scrollbar indicators are working now.
I’ll probably implement timer callbacks using timerfd (even though that’s Linux-only). 🤔
At around 19 seconds in the video, you can see some minor graphical glitches.
Text mode applications in Unix terminals are such a mess. It’s a miracle that this works at all.
In the old DOS days, you could get text (and colors) on the screen just by writing to memory, because the VGA memory was mapped to a fixed address. We don’t have that model anymore. To write a character to a certain position, you have to send an escape sequence to move the cursor to that position, then more escape sequences to set the color/attributes, then more escape sequences to get the cursor to where you actually want it. And then of course UTF-8 on top, i.e. you have no idea what the terminal will actually do when you send it a “🙂”.
Mouse events work by the terminal sending escape sequences to you (https://www.xfree86.org/current/ctlseqs.html#Mouse%20Tracking).
ncurses does an amazing job here. It’s fast (by having off-screen buffers and tracking changes, so it rarely has to actually send full screen updates to the terminal) and reliable and works across terminals. Without the terminfo database that keeps track of which terminal supports/requires which escape sequences, we’d be lost.
But gosh, what a mess this is under the hood … Makes you really miss memory mapped VGA and mouse drivers.
Day 7 was pretty tough, I initially ended up implementing an exponential in both time and memory solution that I killed because it was eating all the resources on my Mac Studio, and this poor little machine only has 32GB of memory (I stopped it at 118GB of memory, swapping badly!), This is what I ended up doing before/after:
- Before: Time O(2^k · L), memory O(2^k), where k is the number of splitters along a reachable path and L is path length. Exponential in k.
- After: Time O(R·C) (or O(R·C + s) with s split events), memory O©, where R = rows, C = columns. Polynomial/linear in grid size.
@movq@www.uninformativ.de I bet. I wouldn’t be surprised if it more popular in some Discord servers too. I mean, the event itself is quite obscure, so… yeah.
Scheduling the next Yarn.social Call for next month, a month in advance. Hope y’all can make the next one 🤞
👋 Reminder that we’re starting up our social calls again (monthly), RSVP here 🤟 It starts in 13h27m 😅 Hope to see some/all of you there 👌
I had a looksie (just to be sure) at the database, and they were thankfully legit test events. But this did spark/trigger me to make sure I have some form of anti-spam measures in place. So I added some per-event / per-rsvp rate-limiting and honeypot(s).
This was a great read, btw. 😃 If you liked Event Horizon, this is for you. I’m gonna get her other two scifi books as well, that’s for sure.
@prologic@twtxt.net so far, yup. I recommend to make the event banner bigger. I almost missed the details of it, as the text is quite tiny.
So just @bender@twtxt.net and I attending our monly call eh?
@movq@www.uninformativ.de This is actually a good positive change I think!
Personally, I’ll probably stretch it out over 24 days. Giving myself more time to solve each puzzle and I really want this event to last the entire month. 😅
I might even do AoC this year with the elevated stress/pressure! – The last few times I’ve tried, I’ve always felt far too much pressure and felt like a failure 😞 (mostly ya know because of my vision impairment, I couldn’t keep up!)
Advent of Code will be different this year:
There will only be 12 puzzles, i.e. only December 1 to December 12. This might make it more interesting for some people, because it’s (probably) less work and a lower chance of people getting burned out. 🤔
Personally, I’ll probably stretch it out over 24 days. Giving myself more time to solve each puzzle and I really want this event to last the entire month. 😅
Maybe this makes it more interesting for some people around here as well?
Reminder, kick-starting our monthly social call! 📞 Please RSVP if you can make it!
Hey all 👋 Starring up the monthly social call we used to have 🤞 Please RSVP here if you can make it! 🙏
Warum erfahre ich erst im Jahr 2025 von Server-sent events (SSE) 🤔?
Das Zeug scheint für die webbasierte Server-Client-Kommunikation in JavaScript ideal zu sein und ist sehr einfach umzusetzen.
is the first url metadata field unequivocally treated as the canon feed url when calculating hashes, or are they ignored if they’re not at least proper urls? do you just tolerate it if they’re impersonating someone else’s feed, or pointing to something that isn’t even a feed at all?
and if the first url metadata field changes, should it be logged with a time so we can still calculate hashes for old posts? or should it never be updated? (in the case of a pod, where the end user has no choice in how such events are treated) or do we redirect all the old hashes to the new ones (probably this, since it would be helpful for edits too)
@movq@www.uninformativ.de Oh, nice read!
If I’m in the woods, I’d like to not waste my time with computers and focus on the beauty of nature. ;-) So, I’m not gonna participate in that event. But I’d read your articles on that subject anytime. :-)
psst i’ll be at my local event for HTML day!!! i’m very excited but very nervous, i don’t even know what i’ll be working on! but i’ll figure it out…
@movq@www.uninformativ.de I also don’t think that I’m a particularly good speaker. :-) The workshop model is a good idea, I like that.
Yeah, it’s really good fun. I can highly recommend it. This is also a good way to train (new) developers to think like attackers, how to break in, destroy something or raise awareness of some classes of bugs. Then you can avoid them next time. It’s surprising to me what vulnerabilities come up during this event every time. So, absolutely worth it, win, win.
They’re all talks, not real hands-on trainings like you did.
I love listening to good, well-structured talks. Problem is, not everybody is a good speaker and many screw it up. 🥴 I’m certainly not a great speaker, which is why I gravitate more towards “workshops”, in the hopes that people ask questions and discussions arise. Doesn’t always work out. 🤣 At the very least, I almost always have some other person connect to the projector/beamer/screenshare and then they do the stuff – this avoids me being wwwwaaaaaaaaayyyy too fast.
We are usually drowned in stress and tight deadlines, hence events like today are super rare … We used to do it more often until ~10 years ago.
Once a year the security guys organize a really great hacking event, though.
Oh dear, I’d love to participate in that. 🤯 That sounds like a lot of fun. (Why don’t we do this?!)
@movq@www.uninformativ.de Interesting internal education sessions are way too infrequent here as well. There are a bunch of “knowledge transfer” meetings actually, but 90% of the topics already sound totally boring to me. The other 9% talks turned out to be underwhelming, sadly. I only attended a single one where it was delivered what has been promised. They’re all talks, not real hands-on trainings like you did.
Once a year the security guys organize a really great hacking event, though. Teams can volunteer to hand in their software dev instances and all workmates are invited to hack them and report security vulnerabilities. That’s a lot of fun, but also gets frustrating towards the end when you don’t make any progress. :-) There’s also some actual hands-on training in advance for preparation of the two days. Unfortunately, I missed the last event due to my own project being very stressful at the time.
When I had a Do What You Want Day I also show my direct teammates what I learned in the hopes of this being interesting to them as well. I’m the only one in my team using this opportunity, sadly.
One of the nicest things about Go is the language itself, comparing Go to other popular languages in terms of the complexity to learn to be proficient in:
- Go:
25keywords (Stack Overflow); CSP-style concurrency (goroutines & channels)
- Python 2:
30keywords (TutorialsPoint); GIL-bound threads & multiprocessing (Wikipedia)
- Python 3:
35keywords (Initial Commit); GIL-bound threads,asyncio& multiprocessing (Wikipedia, DEV Community)
- Java:
50keywords (Stack Overflow); threads +java.util.concurrent(Wikipedia)
- C++:
82keywords (Stack Overflow);std::thread, atomics & futures (en.cppreference.com)
- JavaScript:
38keywords (Stack Overflow); single-threaded event loop &async/await, Web Workers (Wikipedia)
- Ruby:
42keywords (Stack Overflow); GIL-bound threads (MRI), fibers & processes (Wikipedia)
Am Sonnabend ist es wieder so weit: ESC 20235. Gestern wurde die zweite Hälfte der Kandidaten für das Finale bestimmt. https://eurovision.tv/event/basel-2025/grand-final
Mir gefällt, dass viele Lieder in Landessprache vorgetragen werden. Meine Favoriten sind:
- 🇮🇹 Italien
- 🇱🇻 Lettland
- 🇱🇹 Litauen
- 🇵🇹 Portugal
🇩🇪 Deutschland hat mich stimmlich leider nicht überzeugt, auch wenn die Musik einen mitnehmen kann - aber für die kann ich ja eh nicht abstimmen.
@mana@yarn.girlonthemoon.xyz i LOVEEEE her 2018 BD event sm
yarnd UI/UX experience (for those that use it) and as "client" features (not spec changes). The two ideas are quite simple:
This expands the usefulness of Twtxt / Yarn.social to:
- Sharing small posts
- Sharing links
- Sharing media
- Having long conversations
- Voting on topics, opinions or decisions
- RSVPing to virtual or physical events
#event:abc123 RSVP: yes +1
yarnd UI/UX experience (for those that use it) and as "client" features (not spec changes). The two ideas are quite simple:
#event:abc123 Go Meetup – Sat Apr 27, 3pm @ Darling Harbour
💡 I had this crazy idea (or is it?) last night while thinking about Twtxt and Yarn.social 😅 There are two things I think that could be really useful additions to the yarnd UI/UX experience (for those that use it) and as “client” features (not spec changes). The two ideas are quite simple:
- Voting – a way to cast, collect a vote on a decision, topic or opinion.
- RSVP – a way to “rsvp” to a virtual (pr physical) event.
Both would use “plain text” on top of the way we already use Twtxt today and clients would render an appropriate UI/UX.
SDL2 ported to Mac OS 9
Well, this you certainly don’t see every day. This is a “rough draft” of SDL2 for MacOS 9, using CodeWarrior Pro 6 and 7. Enough was done to get it building in CW, and the start of a “macosclassic” video driver was created. It DOES seem to basically work, but much still needs to be done. Event handling is just enough to handling Command-Q, there is no audio, etc etc etc. ↫ A cast of thousands The hardest part was a video driver for the classic Mac OS, which had to be created mostly f … ⌘ Read more
There’s a secret art easter egg thing, hidden on my website ( https://thecanine.ueuo.com ), for this years April fools event - it’s been there for a few weeks, but now I can finally give hints.
In a couple of days I’ll be giving a talk about #twtxt https://www.meetup.com/es-ES/python-valencia-meetup/events/306769708/
I saw 100% I/O wait in htop today but couldn’t find a process which actually does I/O. Turns out, I/O wait isn’t what it used to be anymore:
https://lwn.net/Articles/989272/
In my case, it was mpd which triggered this:
https://github.com/MusicPlayerDaemon/MPD/issues/2241
mpd doesn’t actually do anything, it just sits there and waits for events. To my understanding, this is similar to something blocking on read(). I’m not quite sure yet if displaying this as I/O wait (or “PSI some io”) is intentional or not – but it sure is confusing.
