|
9 October 2023 09:00
"Hello, my name is Steve" - those are words I've said a million times in my life, however they are not true words.
If you want to get all technical about things, my name has always been SteveN.
Mostly this hasn't mattered to me, or anybody else, I introduce myself as Steve, people call me Steve, and Steve is the name that makes me turn my head, when shouted across a bar. However things changed when I moved to Finland.
In Finland I had to open new bank accounts, sign mortgages, hand over IDs, and there were many many pieces of paper I signed, or forms I filled out. Unfortunately I screwed up:
- If I were thinking clearly I'd think "Oh, this is something official, I'd best write SteveN".
- If I were distracted, or not being careful I'd write my name as "Steve", and then sign it as Steve.
The end result? I've been in Finland for approximately eight years, and I have some official documentation calling me Steve, and some other official documentation calling myself Steven. (For example my "Permanent Residency Permit" calls me Steve, but my Social Security ID knows me as Steven.)
Every now and again somebody queries the mismatch, and there are daily moments of pain where I have to interact with different agencies, so I made the obvious decision: I'm gonna change my name.
A fee of €60 and a simple online form was sufficient to initiate the process. The processing time was given as "one to five months" on the official forename changing page, but happily the process was complete in a month.
I will now need to do a little housekeeping by getting updated bank-cards, etc, and then complete the process by changing my UK passport to match. Hopefully this won't take too long - but I guess if Finland knows me as Steve and the UK knows me as Steven I'll still be in a bit of a screwed up state, albeit one that is consistent in each country!
Not a big change really, but also it feels weird to suddenly say "Hello, my name is Steve" and mean it.
People are weird.
Names are interesting.
The end.
Fin.
Tags: name, personal, steve
|
24 September 2023 19:00
I'm not sure if I've talked about my job here, but I recently celebrated my one year anniversary - whilst on a company offsite trip to Sweden. When I joined the company there were approximately 100 people employed by it. Nowadays the numbers are much higher.
Having more people around is pretty awesome, but I realized that there were a lot of people wandering around the office who I didn't recognize so it occurred to me to make a game of it.
I had the idea I could write a slack bot to quiz me on my colleagues:
- Show a random face, using the Slack profile picture.
- Give a list of 5 names.
- Ask me which was correct.
I spent an hour messing around with various Slack APIs, and decided the whole thing was too much of a hassle. Instead I wrote a simple script to download the details of all members of the workspace:
- Name.
- Email address.
- Profile picture URL.
Then using that data, users.json , I hacked up a simple web application in Python, using the flask API. There only needed to be two pages:
- A page ("/") to show five random images, each with five random names beneath them.
- A page ("/quiz") to receive the HTTP POST, and score.
All in all this took only two hours or so. Old-school CGI is pretty awesome like that - Hidden values meant the whole thing could be stateless:
<input type="hidden" name="1answer" value="Bob Smith" ..
<input type="hidden" name="1profile" value="Sales" ..
<input type="hidden" name="1url" value="https://.." ..
<input type="hidden" name="2answer" value="Sally Smith" ..
<input type="hidden" name="2profile" value="Sales" ..
<input type="hidden" name="2url" value="https://.." ..
The only downside is that I don't have any authentication, so there is no ability to have a leaderboard. I've looked at the Okta samples and I think it would be easy to add, but I guess that would make it more complex and less portable. That said I'm not sharing the code this time, so who cares if it is tied to the company?
Anyway sometimes I forget how fast and easy it is to spinup a random virtual machine and present a HTTP(S) service for interactive use. This is one of those times when I remembered.
Tags: cgi, python, slack, work
|
24 June 2023 13:00
So my previous post documented a couple of simple "scripting languages" for small computers, allowing basic operations in a compact/terse fashion.
I mentioned that I might be tempted to write something similar for CP/M, in Z80 assembly, and the result is here:
To sum up it allows running programs like this:
0m 16k{rP _ _}
C3 03 EA 00 00 C3 06 DC 00 00 00 00 00 00 00 00
Numbers automatically get saved to the A-register, the accumulator. In addition to that there are three dedicated registers:
- M-register is used to specify which RAM address to read/write from.
- The instruction
m copies the value of accumulator to the M-register.
- The instruction
M copies the value of the M-register to the accumulator.
- K-register is used to execute loops.
- The instruction
k copies the value of accumulator to the K-register.
- The instruction
K copies the value of the K-register to the accumulator.
- U-register is used to specify which port to run I/O input and output from.
- The instruction
u copies the value of accumulator to the U-register.
- The instruction
U copies the value of the U-register to the accumulator.
So the program above:
0m
0 is stored in the accumulator.
m copies the value of the accumulator to the M-register.
16k
16 is stored in the accumulator.
k copies the value of the accumulator (16) to the K-register, which is used for looping.
{ - Starts a loop.
- The K-register is decremented by one.
- If the K-register is greater than zero the body is executed, up to the closing brace.
- Loop body:
r Read a byte to the accumulator from the address stored in the M-register, incrementing that register in the process.
P : Print the contents of the accumulator.
_ _ Print a space.
} End of the loop, and end of the program.
TLDR: Dump the first sixteen bytes of RAM, at address 0x0000, to the console.
Though this program allows delays, RAM read/write, I/O port input and output, as well as loops it's both kinda fun, and kinda pointless. I guess you could spend hours flashing lights and having other similar fun. But only if you're like me!
All told the code compiles down to about 800 bytes and uses less than ten bytes of RAM to store register-state. It could be smaller with some effort, but it was written a bit adhoc and I think I'm probably done now.
Tags: assembly, cpm, github, z80
|
22 June 2023 13:00
Recently I was looking around the internet and looking for something to do with some ESP8266 devices, which I've been neglecting over recent years.
When I was on paternity-leave, five years ago, I decided I wanted a new hobby for my "down" time. I had two obvious choices a) developing applications for mobiles, or b) working with "hardware". I chose the latter.
By accident I came across a couple of simple scripting languages, FORTH-esque. Sample usage looks something like this (which obviously sends the command over a serial-device to the connected-board):
$ echo '5{ 6d 1o 100m 0o 100m }' >/dev/cu.usbmodem12341
That's a little terse, but briefly:
- 5{ ... }
- Execute the block five times.
- 6d
- Set the output pin, in the example "D6".
- 1o
- Output "1" to the pin we've selected, D6 in this example.
- 100m
- Delay for 100 milliseconds.
- 0o
- Output "0" to the pin we've selected, D6 in this example.
The end result is a blinking LED, for five iterations anyway. The code for this interpreter is described in the following link, with the code in the linked gist:
This is derived from an older, and simpler, project which has a similar focus but slightly different built-in operations (and which lacks loops/conditionals):
Both of these implementations are very similar, I guess due to the shared history and obvious FORTH-inspiration. Each allows port I/O, delays, and simple math opertions. We can pretend they're stack-based, though there are some differences and some niggles.
I'm kinda tempted to port one of them to Z80 assembly, and see if I can get it running under CP/M. I guess I could add a REPL for interactive use, though without actual hardware connected to my single-board computer it might all feel a little pointless. Then again I have Turbo Pascal, and even a tiny C-compiler, so I guess with those in mind any toy-language is pointless in a completely different regard.
Tags: simple, txtzyme
|
21 April 2023 10:00
It seems I'm having a theme recently on this blog, of making emacs-related posts. Here's another.
I write a bunch of stuff in markdown, such as my emacs init-file, blog-posts and other documents. I try to be quite consistent about vertical spacing, for example a post might look like this:
# header1
Some top-level stuff.
## header2
Some more details.
## header2
Some more things on a related topic.
# header2
Here I'm trying to breakup sections, so there is a "big gap" between H1 and smaller gaps between the lesser-level headings.
After going over my init file recently, making some changes, I noticed that the spacing was not at all consistent. So I figured "How hard could it be to recognize headers and insert/remove newlines before them?"
A trivial regexp search for "^# " identifies headers, and that counting the "# " characters lets you determine their depth. From their removing any previous newlines is the work of a moment, and inserting the appropriate number to ensure consistency is simple.
I spent 15 minutes writing the initial implementation, which was markdown-specific, then another 30 minutes adding support for org-mode files - because my work-diary is written using the org-diary package (along with other helpers, such as the org-tag-cloud.
Anyway the end result is that now when I save a markdown/org file the headers are updated automatically:
Tags: emacs
|
24 February 2023 10:00
As I've mentioned in the past I keep a work-log, or work-diary, recording my activities every day.
I have a bunch of standard things that I record, but one thing that often ends up happening is that I make references to external bug trackers, be they Jira, Bugzilla, or something else.
Today I hacked up a simple emacs minor-mode for converting these references to hyperlinks, automatically, via the use of regular expressions.
Given this configuration:
(setq linkifier-patterns '(
("\\\<XXX-[0-9]+\\\>" "https://jira.example.com/browse/%s")
("\\\<BUG-[0-9]+\\\>" "https://bugzilla.example.com/show?id=%s")))
When the minor-mode is active the any literal text that matches the pattern, for example "XXX-1234", will suddenly become a clickable button that will open Jira, and BUG-1234 will become a clickable button that opens the appropriate bug in Bugzilla.
There's no rewriting of the content, this is just a bit of magic that changes the display of the text (i.e. I'm using a button/text-property).
Since I mostly write in org-mode I could have written my text like so:
[[jira:XXX-1234][XXX-1234]]
But that feels like an ugly thing to do, and that style of links wouldn't work outside org-files anyway. That said it's a useful approach if you're only using org-mode, and the setup is simple:
(add-to-list 'org-link-abbrev-alist
'("jira" . "http://jira.example.com/browse/%s"))
Anyway, cute hack. Useful too.
Tags: emacs
|
28 December 2022 10:00
This year had a lot of things happen in it, world-wide, as is always the case.
Being more selfish here are the things I remember, in brief unless there are comments/questions:
- I learned more Finnish.
- Lots of things with our child.
- I helped teach him to swim.
- He learned to tell the time with an analog clock/watch.
- I took him to a circus for the first (only) time ever.
- He cut his hair for the first time in six years.
- He spent his a birthday with my parents, in the UK - His languages skills were on top-form, understanding the various UK accents.
- And another with family here in Finland - Where he watched me roll, naked, in the snow after sauna, and then he asked "Daddy why you did that?"
On the topic of Finnish I'm getting pretty damn good at understanding, albeit less good in speaking. Finnish is all about the suffixes, so:
- A car
- My car
- In a car
- In my car
- With my car
- From a car
- Car-less
Most of this is regular, so you can be childless via the "ton" suffix - lapsiton is "lapsi" (child) "ton" (less). The hard part in communication is thus twofold:
- Knowing the word you want to use, be it car, cake, spoon, or smile.
- Getting the appropriate suffix for the use you want.
Our child turned six recently, and most of the year was spent doing things with him, for him, and to him. He's on the verge of learning to read (English and Finnish), he's interested in maths and completes little puzzles freely and happily. He likes to help with Sodoku, for example and not just the child-versions.
In the past couple of weeks I let him play Super Mario & Super Mario Bros 3, on a NES Classic, and he dies constantly, with a smile on his face. But he does love to tell me what to do when he watches me play!
He's learned to ice-skate, and ski, and almost learned to swim. (I'll say he can swim 3m inside a pool, without aid, but then he starts to sink.) We've got a couple of regular rituals with each other - including going to sauna every week or two, and other similar things.
He's gotten more interested in helping me cook, and his mother too. (My wife and I live in separate houses..)
I guess the next big milestone will be him walking to school by himself, which will start next year. As things stand I wake up early, go over to his house, and do all the morning-things, before I take him there. I expect I'll still want to go there, give him his breakfast, his medicine, and help him get dressed. After that I guess I kick him out, and he makes his own way there.
Happily the walk to school is a few hundred meters, and doesn't involve crossing any roads. But of course it does bring other complications: if he's not collected, and walks home himself, then he needs a key to one/other house, and there's the potential need for a phone to say "I'm late", "I'm lost", or us to say "Where are you?".
Anyway .. interesting year .. good year. Despite everything else.
Tags: 2022, family, personal, random
|
28 November 2022 22:00
I recently wrote about yet another lisp I'd
been having fun with.
Over the past couple of years I've played with a few toy scripting languages,
or random interpreters, and this time I figured I'd do something beyond the
minimum, by implementing the Language Server Protocol.
In brief the language server protocol (LSP) is designed to abstract
functionality that might be provided by an editor, or IDE, into a small
"language server". If the language-server knows how to jump to definitions,
provide completion, etc, etc, then the editor doesn't need to implement those
things for NN different languages - it just needs to launch and communicate
with something that does know how to do the job.
Anyway LSP? LISP? Only one letter different, so that's practically enough
reason to have a stab at it.
Thankfully I found a beautiful library that implements a simple framework
allowing the easy implementation of a golang-based LSP-serverÖ
Using that I quickly hacked up a server that can provide:
- Overview of all standard-library functions, on hover.
- Completion of all standard-library functions.
I've tested this in both GNU Emacs and Neovim, so that means I'm happy
I support all editors! (More seriously if it works in two then that
probably means that the LSP stuff should work elsewhere too.)
Here's what the "help on hover" looks like, within Emacs:

Vim looks similar but you have to press K to see the wee popup. Still
kinda cute, and was a good experiment.
Tags: golang, lisp, lsp
|
3 November 2022 22:00
So this week I recycled a talk I'd given in the past, about how even using
extremely simple parsers allows a lot of useful static-analysis to be done,
for specific niche use-cases.
This included examples of scanning comments above classes to ensure they
referred to the appropriate object, ensuring that specific function
calls always included a specific (optional) parameter, etc.
Nothing too complex, but I figured I'd give a new example this time, and
I remembered I'd recently written a bunch of functions for an interpreter
which I'd ordered quite deliberately.
Assume you're writing a BASIC interpreter, you need to implement a bunch of
built-in maths functions such as SIN , COS , TAN , then some string-related
functions LEFT$ , RIGHT$ , MID$ , etc.
When it comes to ordering there are a couple of approaches:
- Stick them all in one package:
- Create a package and group them:
builtins/maths.go
builtins/string.go
- .. etc
Personal preference probably dictates the choice you make, but either way I think it would be rational and obvious that you'd put the functions in alphabetical order:
func ABS( args []primitive.Object) (primitive.Object, error) {
..}
func COS( args []primitive.Object) (primitive.Object, error) {
..}
func SIN( args []primitive.Object) (primitive.Object, error) {
..}
func TAN( args []primitive.Object) (primitive.Object, error) {
..}
I did that myself, and I wrote a perl-script to just parse the file using a simple regexp "^func\s+([^(]+)\( " but then I figured this was a good time to write a real static-analysis tool.
The golang environment is full of trivial little linters for various purposes, and the standard "go vet .. " driver makes it easy to invoke them. Realizing that I was going to get driven in the same way it was obvious I'd write something called "alphaVet".
So anyway, half written for a talk, half-written because of the name:
- Golang linter that reports failures if functions aren't in alphabetical order
Tags: alphavet, golang, linting
|
8 October 2022 15:00
Over the past few months (years?) I've posted on my blog about the various toy interpreters I've written.
I've used a couple of scripting languages/engines in my professional career, but in public I think I've implemented
- BASIC
- evalfilter
- FORTH
- Lisp
- Monkey
- TCL
Each of these works in similar ways, and each of these filled a minor niche, or helped me learn something new. But of course there's always a question:
In the real world? It just doesn't matter. For me. But I was curious, so I hacked up a simple benchmark of calculating 12! (i.e. The factorial of 12).
The specific timings will vary based on the system which runs the test(s), but there's no threading involved so the relative performance is probably comparable.
Anyway the benchmark is simple, and I did it "fairly". By that I mean that I didn't try to optimize any particular test-implementation, I just wrote it in a way that felt natural.
The results? Evalfilter wins, because it compiles the program into bytecode, which can be executed pretty quickly. But I was actually shocked ("I wrote a benchmark; The results will blow your mind!") at the second and third result:
BenchmarkEvalFilterFactorial-4 61542 17458 ns/op
BenchmarkFothFactorial-4 44751 26275 ns/op
BenchmarkBASICFactorial-4 36735 32090 ns/op
BenchmarkMonkeyFactorial-4 14446 85061 ns/op
BenchmarkYALFactorial-4 2607 456757 ns/op
BenchmarkTCLFactorial-4 292 4085301 ns/op
here we see that FOTH, my FORTH implementation, comes second. I guess this is an efficient interpreter too, bacause that too is essentially "bytecode". (Looking up words in a dictionary, which really maps to indexes to other words. The stack operations are reasonably simple and fast too.)
Number three? BASIC? I expected better from the other implementations to be honest. BASIC doesn't even use an AST (in my implementation), just walks tokens. I figured the TCO implemented by my lisp would make that number three.
Anyway the numbers mean nothing. Really. But still interesting.
Tags: basic, forth, github, lisp, tcl
|
|