Sander's Bleats

If you also find the Leave button in Slack Huddles moves about a lot at the end of meetings, you can click on the headphone toggle in the bottom of the left sidebar to leave a huddle. (or try your luck at russian roulette and press the shortcut which either starts, joins, leaves or ends a huddle)

April 12 at 10:39 am

Turns out yaml_parse() in PHP automatically parses a front matter block out of a markdown based post.

April 11 at 3:08 pm

Entry titles aren't optional in Atom feeds, how to micro blogs deal with that? Update: it seems by making the title an empty element.

April 10 at 11:04 am

The AI evolution seems scary until you realise most of the applications are summarised as a wrapper around the OpenAI API that does all the work, with the context provided by a prompt prefix. So with half a day's study most programmers can participate. #technology

April 10 at 10:41 am

Ubuntu's minimal installation appears to be the standard installation plus the removal of some packages! That's unexpected as I was trying to save installation time. #ubuntu #technology

April 6 at 10:43 am

Map Eject to Multitasking View

So I use ElementaryOS and in version 7 you are no longer able to map just the Eject key. I like to map this to the Multitasking View (something like the macOS Expose).

The solution is to use the DConf Editor application and search for show-desktop. ElementaryOS repurposes the show desktop to the multitasking view. Simply set the value to ['Eject']

Alternatively you can set the left-super key (windows/command) to the Multitasking View. This seems better supported.

. #elementaryos #linux

April 4 at 1:55 pm

Lamb 0.2

I've released Lamb 0.2, my micro blogging app that's powering this site.

What's new?

. #lamb #projects

More info and download link

March 24 at 9:46 am

Anyone, regardless of coding experience can now create scripts and simple WordPress plugins:

WordPress developers who want to share their AI-assisted creations with the community have also started submitting them to

We can imagine the headlines in six months when another popular site or plug-in is hacked, when both the author and the generator and the webmaster don’t understand the code, and can’t review it for security weaknesses, The current tools are proof of concept creators, but please be careful not to assume production ready code.

If you want a code review done hit up an engineer, like myself #technology #ai #wordpress

March 24 at 7:24 am

I've released php-activate 0.1.2, a PHP project version manager for Linux systems using native PHP packages.

Made for those working with multiple projects using a variety of PHP versions, this script will automatically switch to the correct PHP version after cding into the project folder. It does not require sudo, so even works in IDEs.

The latest version contains only documentation changes, but I've been using this successfully for a few months, so wanted to share this more widely. #projects #phpactivate

March 21 at 2:28 pm

Basic routing using REQUEST_URI

So for nginx it is not straightforward to setup PHP-FPM so that PATH_INFO is correctly populated. Lamb uses the following /index.php/some/other type routing, where /some/other should be the PATH_INFO. Instead I want to make setup for a variety of web-servers straightforward, so I've switched to the more robust REQUEST_URI. This simplifies nginx configuration and Caddy and the PHP built-in web-server are compatible.

REQUEST_URI contains everything after the domain name, including the query string, so that needs to be removed:

$request_uri = '/home';
if ( $_SERVER['REQUEST_URI'] !== '/' ) {
    $request_uri = strtok( $_SERVER['REQUEST_URI'], '?' );

We can see that for a request for the root of the site, REQUEST_URI returns / whereas PATH_INFO would be empty, so the code above takes that into account. We can then deduct a router action as follows:

$action = strtok( $request_uri, '/' );

Once the $action is known, it can be checked against an allowed list of actions:

switch ( $action ) {
    case 'edit':

. #php #lamb

March 21 at 12:41 pm

Godot simplified drag n drop tutorial

I was "following" Generalist Programmer's Godot drag and drop tutorial and I made a few refinements that I wanted to share. Please read the tutorial and then follow along.

Drop-in behaviour

Wouldn't it be cool to give a node drag and drop behaviour simply by dropping in a node with the script, independent of any other scripting?

We can do this by creating a new child node (here called Drag-and-drop Dropin), and attaching the script to it. It must extend from the dropin Node2D.

Node structure

In the script itself we make two changes:

  1. Disconnect the KinematicBody2D's input_event signal, and write it in code in the dropin's _ready function. Call it on it's parent: get_parent().connect("input_event", self, "_on_KinematicBody2D_input_event"). We want to process the input_event of the KinematicBody2D, not the dropin.
  2. In the _process function, assign the mouse position to the parent of the dropin: get_parent().position = Vector2(mousepos.x, mousepos.y).
  3. Same for the last line in the script where we set the position of the parent.

The script then reads as follows:

extends Node2D

var dragging = false

signal dragsignal

func _ready():
    connect("dragsignal", self, "_set_drag_pc")
    get_parent().connect("input_event", self, "_on_KinematicBody2D_input_event")

func _process(delta):
    if dragging:
        var mousepos = get_viewport().get_mouse_position()
        get_parent().position = Vector2(mousepos.x, mousepos.y)

func _set_drag_pc():
    dragging = !dragging

func _on_KinematicBody2D_input_event(viewport, event, shape_idx):
    if event is InputEventMouseButton:
        if event.button_index == BUTTON_LEFT and event.pressed:
        elif event.button_index == BUTTON_LEFT and !event.pressed:
    elif event is InputEventScreenTouch:
        if event.pressed and event.get_index() == 0:
            get_parent().position = event.get_position()

Simplifying the script

I was refactoring this, and it turns out we can simplify this further.

  1. We don't need a dragsignal because the signal is both emitted and consumed within the same script. We can just replace the emit_signal calls with calls to _set_drag_pc(). We can then remove the connect() call in the _ready function, and the signal dragsignal.
  2. The same function is called when the left mouse button is both pressed and not pressed, so we can remove that conditional and remove the elif statement in the input event handler.
  3. As there is only one invocation of _set_drag_pc() we can inline it.

The final script becomes:

extends Node2D

var dragging = false

func _ready():
    get_parent().connect("input_event", self, "_on_KinematicBody2D_input_event")

func _process(delta):
    if dragging:
        var mousepos = get_viewport().get_mouse_position()
        get_parent().position = Vector2(mousepos.x, mousepos.y)

func _on_KinematicBody2D_input_event(viewport, event, shape_idx):
    if event is InputEventMouseButton:
        if event.button_index == BUTTON_LEFT:
            dragging = !dragging
    elif event is InputEventScreenTouch:
        if event.pressed and event.get_index() == 0:
            get_parent().position = event.get_position()

So this dropin can now be added to any node to add Drag-and-Drop behaviour. I think the script can be improved a little so that the node is not centered under the mouse cursor but takes account the offset where it is picked up.

Let me know your thoughts! #godot

March 18 at 12:06 am

404 Fallback comes to Lamb

I've added a 404 fallback feature to Lamb. What this means is that if you request a URL that doesn't exist on your Lamb instance, it will redirect to the same relative path on the domain you have provided in the configuration, if you enabled this feature.

This means you can move your site from to say and then set that as the 404 fallback url and you will not lose any SEO traffic! Here's an example! #lamb #projects

March 16 at 4:49 pm

Whilst building Lamb I have realised that RedBean ORM, SQLite + plain PHP (used here) or CodeIgniter makes for a very nice setup. Turns out the frameworks just add loads of extra knowledge, that you don't really need if you know not to shoot yourself in the foot with security stuff.

(Famous last words)

March 15 at 4:15 pm

Alright got the webserver configuration figured out and the full site is up. Didn't forget about Caddy. #lamb #projects

March 15 at 12:42 pm

Hello, world! #new_site

March 14 at 5:13 pm