Previous skills and experience

I have been writing software for more than thirty years. I've learned a range of languages including C, C#, CSS, HTML, Java, JavaScript, Perl, SQL, and Visual Basic. I enjoy learning new languages (I'm currently experimenting with Lisp) both to find new ways of solving of problems, and to see where and how much languages overlap (ignoring syntax, low level features like if statements and for loops are very similar across most popular modern languages).

I dislike boring, repetitive tasks, and try to automate them where possible. My previous role included manually updating HTML pages (which was both boring and error prone), which lead to me creating a new guidance platform for HMRC that eliminated that role. (That also won me an "Innovator of the Year" award).

I worked as a telephone advisor for HMRC's contract centers for more than a decade, answering customer queries by phone and updating customer records in line with guidance and HMRC security policy. This job gave me strong empathy with our customers, and convinced me of the importance of the mission statement "Putting customers at the heart of everything we do."

That role also taught me how to explain complicated technical issues to non-technical people, and how to adjust the level of technical detail in an explanation in realtime based on the recipients reactions.


Laying on the sofa with a book and a kitten. Life is not all terrible.

In other news I've put in an application for a promotion at work, should be about £300/month extra for the same sort of work (mostly programming, although with a bit more authority).


Have I mentioned that I like the "Murderbot Diaries" series of books? I've just finished a re-read and they were still good.

The protagonist is a cyborg with poor social skills due to a history of slavery and abuse. Don't let that put you off, the books are entertaining and give an extreme version of what it feels like inside my head quite a lot of the time.


Each endpoint has:

  • Name (string, human readable, short for preference)
  • Uri
  • LastChecked (Timestamp)
  • LastSuccess (Timestamp)
  • FailedCheckCount (number, default 0)
  • LastAlert (Timestamp?)
  • Enabled (bool, default true)

Timestamps are probably going to be ISO format, but they could just be counts (although storing wallclock time does allow for periodic reminders)

A healthy host has last success equal to last checked.

Each failed check adds one to FailedCheckCount. A successful check resets FailedCheckCount to zero.

If FailedCheckCount is over a specified threshold, then an alert is sent and LastAlert is set.


Not much going on, waiting to hear back about the job application, otherwise same old, same old.



Signed up to Andrews and Arnold last night for their VoIP/SmS service, probably overkill for the monitoring system but at least I'm confident it's not a scam. (Plus, now I'm a customer it might be easier to justify using them as our ISP once the BT contact is done)


All tired right now, not sure why, factors likely to be affecting me include:

  • Depression
  • Antidepressants (and that those two pull in the same direction sucks)
  • Interrupted sleep (woke up a couple of times for the loo, husband snoring)
  • Late night (aimed to go to bed at 23 yesterday, wasn't asleep until at least 00:30)
  • Early morning (Woke up around 06:30, was at work by 07:20, felt at the time that I should have slept more, but also felt that when I have tried to sleep another hour in the morning I've ended up feeling worse)
  • Ate early (Had a sandwich before work, generally has a negative effect on the whole being awake thing)

I've been thinking about getting a "proper" (expensive, mechanical) keyboard for a while, I'm getting close to a requirements list:

  • ISO-UK layout (deal-breaker)
  • Wired (deal-breaker, work security rules require it)
  • "Brown" switches (Tactile (have positive 'yup, I've been pushed' feedback) but not clicky)
  • Number pad
  • Media keys (at least play/pause, volume, next/previous)


I'm in limbo at work, I'm waiting to hear about this promotion but I think someone else is a better fit. Obviously I want the money, but, I dunno, I'd pick them. (Mostly it's that they asked for time to write the docs for a project. Seriously! Who does that! Grab 'em quick before they realise what they're letting themselves in for).

Ah, well.


If I want to build a DOM in C, then I'll need a base Node type, probably an Element type, and a bunch of functions with names starting with dom_, node_, and element_.

Doesn't sound hard in principal...

typedef enum {
  NODE_ELEMENT,
  NODE_TEXT
} NodeType;

typedef struct node {
  struct node* Parent;
  struct node** Children;
} Node;

... except I'm not sure what it gets me.

I want to transform the stuff in the HTML5 spec into something machine readable, so I can parse HTML and then render it.

I keep going round on this, I've got a range of languages available and they've all got advantages and disadvantages. It would probably help me to have a clearer picture of what I want, but that (at least partly) depends on what language I'm thinking in at the time.

C# has got cross platform support (except it can't do GUI on Linux), it's got three really good IDEs (two owned by Microsoft, one with a licensing fee) that make it really smooth to write, but it's big (a carefully engineered "hello world" can get down to maybe 30Mb) and poor to zero JavaScript support.

C has poor Windows support, OK IDE (which will improve once I've learned ctags for vim), good JavaScript support (hello QuickJS), but it's a bit painful to write. I'd need to find/choose a GUI library (or two, one for Linux and WinForms for Windows), and either pick s library or write my own networking code.

I've got two options for "interpreted code on C", JavaScript (via QuickJS), or Loxish (based on Crafting Interpreters). They've both got the same "need to wrap libraries/write low level code" that C does, but with the option of working in a higher level language. The more code I write in the interpreted language the slower the app, but that's balanced against less C work (e.g., exposing low level read()/write() network primatives Vs a fetch() method).

Of the two, it will be easier to get help for JavaScript, but it will be easier to mould Loxish into what I want. I'll need to pull QuickJS in as a dependency either way, but it's not nearly so heavy (and much easier to isolate) if I'm only using it for document scripting.

I think I want to use C+Loxish for the control and the "I built it"-ness, but I'm scared of how much work I'm looking at.

But circling back to the start, I'm going to need to write the HTML parser in something, sooner or later. (Ah-ha! Something in my head just said 'but if I write it in C#, it's easier to reuse '.)



[HttpGet("Inbox")]
[Authorise(Role = "me")]
public GetInbox() => store.Inbox

[HttpPost("Inbox")]
[AllowAnonymous]
public PostInbox(Message m) => store.Inbox.Add(m);

[HttpPost("Outbox")]
[Authorise(Role = "me")]
public PostOutbox(Message m) => m.To.Select(address => network.Post(address, message));

[HttpGet("Outbox")]
[AllowAnonymous]
public GetOutbox() => store.Outbox;



abstract class APObject {

	[JsonPropery("@context")]
	public string Context {get;set;} = "https://www.w3.org/ns/activitystreams";


	[JsonProperty("id")]
	public string? Id {get;set;} = default;

	[JsonProperty("type")]
	public string Type {get;set;}

}

abstract class Activity ; APObject {


}

Every 3 or 4 generations after the previous Empire falls, the next starts to rise. It's happened often enough that some historian is trying to get a natural law named after themselves.

Starting an empire, given the right conditions, is easy. You need a small, well armed, and focused polity; a couple of systems and a strong religion normaly does it, although a burning need to bring 'peace' or 'justice' has also worked.

And 'well armed' doesn't always mean millitray might, although that is considered the easy path. Fierce debating skills, a solid traiding tradition, once even a strong sense of empathy have all started empires.


Bought a keyboard/mouse/headphone set yesterday, took it back to the shop today, it was nearly brilliant, but was actually crap. Really quite disappointing.


I forgot/never really grocked that Lisp identifiers don't have to be alphanumeric. This opens up a bunch of toys, but specifically makes adding attributes to html tags much cleaner; instead of (p (attr (class "info")) "hello world"), I can do something like (p (@ ... (although I think that @ already has meaning attached).


Game thoughts

Thing is, I don't really want a 'game' with winners and losers. I want an interesting simulation of something like a world that I can watch develop, and maybe influence (and maybe see what ifs? for).

I've got techniques (in the sense of "I know what they're called, and roughly what the limits are) to generate landscape ("Diamond/Square" for large scale, simulated erosion for smaller). I can populate the world with agents that have goals and behaviours, and that interact with each other. I think it just feels weird to build it as art.

I'm also not sure what to write it in. JavaScript gives me the browser (although don't forget QuickJS). C# gives me a server. C gives speed (theoretically). Loxish gives me control.

I think I should stay very much focused on writing for myself, rather than for what I think other people might want. Yes, it would be cool to make a world that other people want to play in, but I'd far rather build a world that I want to play in.

I very much want a clean separation between the display and the rest of the code so I can e.g. start using OpenGL later (or sooner).

I've got a fuzzy picture in my head of writing code for agents in a way that allows me to tweak (or rewrite completely) without stopping the main engine. I also want to be running lots of agents, so that stuff is happening all over the map even if the player isn't looking.


Game components

Display

Takes the state of the game and shows it to someone. Could be graphical, drawing the terrain and agents, or could be textural, describing the game state and events.

Engine

Takes the game state at tn and ptoduces the state at tn+1

Terrain Generator

Makes a new world


Store terrain as a single linear array of longs, and use masks/shifts to store data.

Start with terrain being read only after generation, and maybe do something like a piece table later for changes (e.g., roads, landscaping).

Call the surface a torus, with the top/bottom linked and the two sides linked.

I'm assuming some kind of grid here, do I want to use hexes? Do I want to tie actors to the grid, or is it just for terrain?

square grid, tied actors is most simple and therefore least realistic. (Although the grid can be much finer than the actors, which helps hide the simplicity).

Hex grid solves some of the square grid problems (diagonal movement, mostly), but has a chunk of extra work, and ongoing integration/understand issues (plus, most algorithms assume a square grid).

Disconnecting actors from the grid gives them much more freedom, but then we have to handle "what if an actor straddles a border" issues. (Same as the fine grid option above, I guess)

Hmm.


Messing with OpenGL (well, WebGL really) again, it is nice and fast, but it's a bugger to get all the bits lined up right.

Roughly:

  • Objects are made of triangles
  • Triangles are made from vertexes (vertices, but no one says that)
  • One can load a bunch of data up to the GPU, and it stays there. I think this is a Virtual Buffer Object (VBO)
  • Drawing is getting everything set up, then calling 'draw' (Imagine a huge panel with switches, sliders, dials, and a big red button. Toggle the switches, set the dials and sliders, and then press the button. A printer in the corner busts into life.)
  • WebGL doesn't know anything about frames, one just lines up the data, calls draw, and then calls clear when it's time to start the next frame
  • There's a bunch of stuff (model/view/perspective transforms, lighting, shading) that's nearly standard, but not really.

I've implemented diamond- square (whoop!), and the GPU is drawing triangles (double whoop!), I want to get lighting/shading next (Husband says use cross product to get normals, i.e., at any given triangle corner, get the vectors to the other corners and the normal is the cross of that), and then start on camera movement.

I'm starting to get pictures in my head of flying close to the ground around tree covered mountains. This could be really quite cool.


Medium term choices include:

  • scale factor: How big is a heightmap pixel relative to (e.g.) trees, or the camera viewpoint.

  • An I going to actually draw the torus, or am I going to cheat and just draw cpoies at the edge of the map.

    I really like the idea of the torus, and hopefully the transform isn't that expensive (I think it might just be a matrix multiplication, but there's probably trig in there somewhere).

Anyway. Sleepy time, g'd night fair reader.


I've started following a roguelike tutorial, which has been bloody good so far.

The tutorial's code is written in Java, which is well easy to convert to C#. The prose is easy to read and goes into detail where needed (so far I haven't found anything that it should explain that it doesn't explain), and feels like it's written by someone who knows their stuff.

Luckily, I've got the windows console/ANSI/vt100 stuff from the editor, else I'd need to write that all. I'm leaving it in text mode for now, I'm sure I'll start thinking about a web front end sooner or later (but since it's all keystroke driven, I can have an engine sleeping in the server that only wakes up on a POST. I can probably store the state somewhere, and have a pure update function. But that's next version).

The tutorial is very much "here's the minimum you need to get x working", but the x's are things like random dungeons, fighting, separate screens for inventory so it's fairly comprehensive.

I wonder how far I'll get?


This is pretty bad, I lasted less than 15 minutes before running out of energy/motivation at $WORK this morning. I guess I need to do something about that.

(And I'm waiting to hear back about this job application as fast as I can, but even if I get it it's going to me more of the same, only better paid) (And yes, better paid is cool but doesn't actually make the job any better)


The cheap way to port dungeon to the web, I think, is to write a JavaScript terminal emulator.

It looks like terminals have a bit of state (cursor (x,y), colours, and is the cursor visible), and rules like "writing a visible character increases cursor.y by one" (where visible characters have an ASCII code of 32 or more).

Given what I need the terminal for, i think it's going to be easiest to use canvas as the substrate, for easy x,y positioning. Alternatives that I've thought about are tables and grid.

Table based output needs to be generated in one pass, so any overwriting needs to be worked out ahead of time. (Which is roughly parsing to a screen sized buffer and then reading that out to the table.

Grid is easier than table, because each cell is addressed directly, so later cells with the same location overlay older cells (note: set explicit opaque background).

Transport can be basic request/response, send a keystone (converting arrow keys too escape codes) and get the screen back. Given a http2 connection the response time shouldn't be that bad. Using a websocket will cut out some overhead from repeated headers.


Although it might be worth implementing a terminal as an off screen grid of cells, with glyph and colour properties, and then just banging that to the display every so often.

I guess it's the difference between a proper terminal emulator that handles a steam of characters/instructions in real-time, and what I need for the web based dungeon client, which is to translate the IDisplay calls to HTML.

(Yes, I am still thinking about an IDisplay implementation that outputs html)


Talked with a nurse practitioner at my GPs yesterday to get a referral to counciling, and a referral to the local adult ADHD assessment centre.

Not very convinced, but I'll see what comes back.


Web terminal

Uses CSS grid. Basic setup with

#terminal {
  --rows: 25;
  --cols: 80;
  display: grid;
  grid-template-rows: repeat(var(--rows), 1em);
  grid-template-cols: repeat (var(--cols), 1em);
}

gives a grid of addressable cells.


Whoop! Web terminal is working! Yeah, baby! Now with colour!

It's working for dungeon, which is great, but it'll clearly work in other contexts. My first thought was a basic bash terminal (I'll need to add some stuff to support vim, but I don't think it's going to be a step-change in difficulty).

I've just realised that I can do the "editor in 1kloc" stuff, /in JavaScript/, in the browser! That's going to be a giggle .

I've got rough ideas of some kind of text/CLI interface for the/a website, but I'm not really sure what I'd want to do with it.

But I'm so chuffed. Using CSS grid has make it so much easier than the alternatives. I don't have to worry about getting stuff in order, like I would with tables, and I don't have to mess with low level font stuff that canvas implies.

So, as is traditional, a list of what next?

  • Scrolling
  • Finish colours
  • More chapters from the roguelike tutorial
  • More monster behaviour
    • Flee at low heath
    • Game of life fungus
    • Flocking bats
    • Patrolling guards
  • More level generation types (rooms and corridors, rather than caves)
  • Light sources
  • Equipment slots (main hand, off hand, body, legs, ...)
  • Quests (or at least tasks)
  • Persistence (save game, non fatal death)
  • Multiplayer (maybe)

I'm fairly sure that I'm going to go for an "anonymous people can't save state" option, at least in the short term, but I'm worried about the whole "managing accounts" thing. If I'm going to run this thing in any kind of public way, I guess I'm putting it on it's own machine, possibly in it's own account somewhere.

I like aws in principal, but I don't like the potentially unlimited costs. I could use Fly.io, or I could rent a second machine from mythic. I should probably think about a name/dns, and a proper skin, if I'm going to "release" the game in any useful way.

Then, of course, monitisation starts creeping in.

Let's not get ahead of myself, yeah?


Funny thing in testing, I was fighting a zombie and a bat stumbled into it and got the last hit, so got a couple of levels (cue genuine laughter).

I think creatures will start tracking who has done them damage and award xp proportionally (modulo attackers staying in some kind of range). Husband suggests bonuses for first/last hit, I'm not entirely sure about that.



So the article on writing functional games (writing games in a functional style, not waiting games that function) said something like update functions should return a list of events. The example in my head is a "died" event that can be intercepted by a potion of resurrection.



Interview tomorrow so of course I'm staying up late the night before. (Brain chemistry/depression/ADHD/insomnia has nothing to do with it).

Been a few good days at work, been working solid days writing code and feeding good about myself. Broke nonprod this afternoon but only for an hour or so, and it was installing an update that people have been asking about for a while.

I think I've cracked the combinations/bag packing problem that Husband gave me (something about fitting enchants to equipment). Turns out I really like the algorithm stuff, it gives my brain a useful workout.

However. I'm going to grab a snack and call it a day. Tomorrow will be here soon enough, I can do the interview and then forget about it (although CS Jobs posted me a "Senior DevOps Engineer" advert that has management responsibilities, I'm a bit tempted by).


Alright gentletheys, that was the interview. Took about forty minutes, four questions, not sure any of them covered the topics the advert said, but I think I coped well enough (I've read the guidelines enough that I can hit the right words, maybe).

Should hear back next week sometime. (Yes, form a certain point of view the job was aimed right at me, but I trust that the panel will judge people fairly, just because the squew is in my favour doesn't make it any better.)


(Posted to Facebook)

Earlier today I again performed the sacred ritual of "The Job Interview".

I suffered the ritual cleansing, daubed myself with unglents said to be pleasing to the Gods (I argued against it, since it was a video call, but Husband wisley suggested it would be a bad idea to insult the Gods on ritual day), and donned the sacred robes (thanks again Maisie for the tie!)

I improvsed poems on the four themes given; 'The Fall of Leaves in Springtime', 'The Emperor's Third Penguin' (that threw me a bit of a curve, I'd ony read up on the First and Fourth Penguins), 'The Use And Practice of Caching in a Hetrogenous Network Environment' (Easy, a standard ABC CBA rhyme scheme), and 'Duty' (Duty always comes up, so I used the poem I prepared last night).

I await the Emperor's messenger who will hopefully bring me the blue coral button that marks one as a 'Senior' developer.

(The interview went well, I think, although I've got quality competition. I should hear back in a week. Its a promotion within my team, looks like it's going to be roughly the same kind of work, but probably with a bit more managent thrown in. +300£/month net) (I am going to be so depressed if I don't get it.)


Working on nouns for 'Goblin Town' (provisional name), and I think that instead of doing some complicated thing trying to guess the articles and the plurals, I should just set them for each noun (so "a cat", "some cats", "an egg", etc)

Although maybe I should also think about the kinds of places that I'm going to find nouns (and it's when I'm outputting lines like "{subject} {verbs} {article} {noun}") (and the article is going to depend on context, "You smile at the bat" vs "You hear a bat in the distance").

Definite article is always 'the', indefinite isn't regular enough for easy rules ("if it starts with a vowel sound then use 'an'" is great, except I haven't found a easy to check for vowel sound types yet), however can just tag nouns as 'a' type or 'an' type (idea: new Noun("a fish"), and then parse out the article at construction time).


I've got a bit blocked on the game - turns out that I don't really want to play a dungeon crawler - and so I'm looking around for the next project.

I'm moving this blog into a database, but that shouldn't take long.

I've been thinking about building c# expressions back end for the Lox interpreter. (I've been thinking about building a CLR bytecode version, but that's a bit hard, I think.)

I kind of want to get the terminal component from the game into some kind of useful shape, at least good enough to run as an actual Linux terminal, but again, that feels more like a task for it's own sake rather than something objectively useful.

Or something. I think I'm just down. Husband says it's because I didn't get the job (and they may have a point), but that doesn't feel right? I think it might be the whole banality of existence thing, but that might be symptom rather than cause



WebGL stuff is going well. I wrote a JavaScript implementation of the Diamond-Square terrain generation algorithm a while back (Not sure when, since the current year ticked over, I think), and had got a far as converting the square mesh to triangles, throwing it at the GPU, and getting pixels on screen, but I ran out of interest/energy while it was still in flatland.

Over this weekend however, I've beaten it into 3d, added lighting, and got an animated camera to "fly" round following the terrain! It looks really cool (well, ish, I'm using "normal per triangle" for the lighting, so triangles look flat, but I'm not convinced. On the other hand, normal per vertex would be a bunch of extra work).

I've even got as far as applying a tourus transform (to the position stuff, at least), but I'm having problems getting the camera in the right place.

I've got a couple of things to try next. First is to move the torus transform into the vertex shader. Second is to transform the eye, target, up vectors of lookat (I think I've only tried transforming eye).

Interestingly, those ideas are incompatible - either I can do the transforms in JavaScript (on the CPU) of in GLSL (on the GPU), bit not both.

Anyway. time for sleep. I wonder if the GPU can do trig?


(Just a follow up, not only can GPUs to trig, they can do them in hardware as fast as everything else! Neat!)


Built (well, assembled) a new piece of furniture for the study, an IKEA Kallax 'storage unit'. It's not quite a set of shelves (ok, it is exactly a set of shelves), designed to take 30 cm (roughly) cubic boxes (or other 'inserts'; there's a set of drawers, a cupboard with a door, and a third party set of thin shelves for paper).

It's a bit more imposing than I'd imagined. Also, I really should get photos working.


I was going to be all whiney about "hitting a complexity wall" in my flight sim, but then I realised: I wasn't writing a flight sim! I was writing a terrain generator, and that's working great!

I do want to write a flight sim (or at least, some kind of game where the control system is kind of aircrafty), so I should think about that, but I should start with a blank sheet and build it up properly.

Mostly, the choice I need to make is how much of the low level graphics stuff do I want to do, and how much can/should/do I want to hand over to a library (twgl and three.jshttps://threejs.org/ are the current options).



I've added a ui to ping (status monitor) and added heart checks to the other sites and that's all working nice.

I still need to add rules that mean I only get one text per outage, rather than one per failed ping. I'm also thinking about adaptable rules for sites ("ping every n minutes, at least m consecutive fails").

On the other hand, a simple, offsite, cheap status checker: Yup.


What we have here is a state machine. A given endpoint is either FINE, FAILING (n), FAILED, or RECOVERING(n). Failing and recovering states have n copies.

Possible transitions:

FINE & !ping(ok) => Failing(0)

Failing(x) & ping(ok) => Fine Failing(x < n) & !ping(ok) => Failing(x+1) Failing(x == n) => Failed

Failed & ping(ok) => Recovering(0)

Recovering(x < n) & ping(ok) => recovering(x + 1) Recovering(x) & !ping(ok) => Failed Recoverin (x = n) => Fine

Or, in English, if we're fine and we get a bad ping, to into failing. Any good pings in failing take us back into fine. Otherwise, each bad ping takes us one step closer to failed. After n bad pings in a row we move into failed (and this transition sends a message). In failed, the situation is reversed. A good ping in failed puts us in recovering, any bad pings in recovering put us back into failed (no notification). After n good pings in a row we move back into fine (and probably trigger a notification).

Each endpoint needs to track it's current state, and the length and sign (good/bad) of the current streak. (Streaks have a minimum length of 1 since they're driven by the ping that has just returned)

StateNames enum (Fine, Failing, Failed, Recovering) PingResult enum (Ok, NotOk) Streak struct {uint count, PingResult sign}


Idle question: What are good uses for a sms to http endpoint? (That is, what useful text messages could I send my machine?)


I've been thinking about a calculator/scratch pad for a while, and I've just realised that what I actually want is the Smalltalk environment.

Imagine a blank screen. Click anywhere and start typing. Select text, right click and 'evaluate'. Right click to bring up tools (number pad, calendar, file upload whynot, timers, API calls). I also want to be able to link bits together, so the output of one calculation can feed into another.

It's persistant (changes are saved straight away) and maybe networked (so that I can open the page here or on my phone or at work).

Its got bits of OneNote, but that doesn't have any calculation/scripting.

I'm also thinking about 'layers' rather than 'pages' - layers stack on top of each other, and can be turned off and on. Disabled layers don't contribute to calculations.

Adding in data pipelines, to take e.g. a JSON source, parse it, filter it, reduce it, give an output, or a base64 encoded blob, decode it to utf8.


Chunks have got properties:

  • version
  • position (top, left)
  • dimension (width, height)
  • content
  • title?
  • tags[]
  • id (auto-generated)
  • input[]
  • output[]

And methods:

  • update()

Chunk service commands/events:

  • create(top, left)/created
  • move(top, left)/moved
  • resize(width, height)/resized
  • delete()/deleted
  • setContent(content)/contentChanged

Just noticed that my status app is ipv6 only.

And ok, I kind of noticed when I only have it an ipv6 address, but it didn't really sink in until just now.

(I was about to be all "welcome to the future babe!", but then I checked with 4g and it turns out my mobile connection isn't ipv6? I could have sworn...)


"My lady, you are both beautiful and wise, a rare and treasured combination in these troubled times. Would ye fancy a quick knee trembler in the trees yonder?" She snorted a laugh, and quickly regained control. "Alas," she said, and gestured to the collar around her neck. "My lord has required me to wait upon his immediate return, else how could I refuse such an eloquent and specific proposal."


Feeling ok today, getting stuff done at work (bits of dropping into other peoples problems and solving them, sling work doing the work I should be doing).

Bought myself a new Bluetooth mouse so I can play games on my laptop without borrowing Husband's spare wired mouse.

Moved the cables from their boxes in the box room to the new shelves in the study. (I'm going to call them shelves, even though it's not quite right, but "The IKEA Kallax storage unit" takes a while to type). I've also bought a bunch of reusable (velcro) cable ties that I'll start using sooner or later to actually tidy the cables.

So just basic life stuff, yeah?


So that's a (mostly) functional core built for the notes thing. It takes in commands and the current state of notes and generates events based on the command.

The ui listens for browser events, turns them into commands, and sends the commands to the core while waiting for the core to generate events for the ui to react to.

I'm starting work on a storage service that will listen for events and write them (or rather, the materialized states) to disk. It will also listen for events like to DOMContentLoaded, and use that as a trigger to dispatch it's own (noteLoaded) events via the core.

(I've just realised, when the UI makes a change, it can listen for a noteSaved event to let the user know their change is safe).

'Disk' in the case will be browser local storage, I'm also planning a network service that will ship events to (and from) other machines (for things like offsite backup and shared context).

Should be fun.


I've started getting serious about type checking in JavaScript by using typescript/jsdoc notation to label functions and variables, and it's turning out to be really nice/useful/verbose.

I could go full on typescript, except the compiler is a node.js script, and I've still got serious reservations about that whole ecosystem.


Starting to put together the server side of notes, and it looks like I'm going to use "workspaces" as the holder for notes.

All notes must be in a workspace.

The index page shows a list of known workspaces (stored in a table in the database) and create/delete buttons.

A "My first workspace" is created if the list of workspaces is empty. It's should be created from a template (but with unique ids for notes).

User can bookmark a workspace, and/or set one as default.

Workspaces have 'create workspace ' buttons.

Nothing is saved to the server until the user opts in.

Workspace commands:

  • Create(name) => workspace-created(name, id)
  • Load(id) => workspace-loaded(name, note[])
  • CreateNote(id, note) => note-created(id, note)
  • UpdateNote(id, note) => note-updated(id, note)
  • DeleteNote(id, note) => note-deleted(id, note)
  • Delete(id) => workspace-deleted(name, id)

Putting together a language (lox, again) needs a tokenizer (basic), a parser (got two examples), and a backend (again, two examples).

I prefer the Pratt parser (over the recursive decent), it looks much easier to extend. I also liked having an ast over jumping straight into code generation (with the bytecode vm).

I'd like to make a self hosting compiler, just to get that box ticked off. If I target wasm (or JavaScript, I guess), then I can run in the browser, although I'd really like something that can run on either browser or server.

I've gone though bits of this process a bunch of times now, and I'm not seriously thinking about picking up one of those old versions. I've got a version somewhere that's got arrays and a few other things, but that's written in C.

I think I want to do this version in C#, with the Pratt parser and the AST. I should be able to then write visitors to generate a few different backends - JavaScript, wasm, C# expressions, and maybe CLR bytecode (in rough order of difficultly).

I also want to write it as a library first. I need to make a choice about where to put generated nugget packages (and it's going to be GitLab) so I can start putting a library of useful stuff together.


After lox, the next library is 'web' for a bunch of asp.core stuff:

  • Openid Auth setup (not big, but irritating)
  • JavaScript, at least the lib.js that turns up places
  • Maybe a _Layout.cshtml and supporting files (like rocket.svg, basic site.css with a header/content/footer grid).

There are a few themes here. First, make it easier to start a project (so let's add a new project template to the list). Next, take out some of the style decisions. Finally, centralise some common code so that improvements can be distributed.


I don't want the template to embed files directly where possible, instead of should depend on the appropriate libraries.


Immune system is running hot today (has been last 3? days). Sore throat, too much phlegm at the back of my mouth, coughs and sneezes today, and mild cognitive deficit (today).

I'm calling it a cold. First one in ages, mildly sucks, but then it's a mild cold.


Still sick. Flippin' body lied to me this morning, said I was fine, but then gave up after about an hour.

However, I've dug out my old bluetooth keyboard and hooked it into the phone, so might be able to get some stuff done anyway..




  • poll says theres new data available on our socket
  • add data to the buffer
  • Check for EOL in the new data
  • If found, check state and hand off to the next routine

Connections have a current request (and probably current response). Requests have:

  • Method (enum, why not)
  • Target URI/path
  • Header hash (think about multiple headers)
  • Possible content (in memory vs cache to disk)

[This stack overflow answer] (https://stackoverflow.com/a/17905131/195833) shows how to do state machine functions (functions that return pointers to functions of their type)


For this http server, main loop looks something like:


// set up listen socket
int listenSocket = ...

// Install signal handler(s) to clear the running flag

struct pollfd *pollData = ... // add listenSocket to poll 

while (running) {
  int pollResult = poll(...)

  switch (pollResult) {
    case -1:
       // Handle poll error, probably by falling out the loop
    case 0:
      // Poll timeout, continue the loop
      // (going this to give signals a chance to gracefully shut down)
      continue;
  }
  
  // this is where i got bored/ran out of energy
}

// Tidy up

// close listen socket
// close client sockets




Maybe i just need to be happier writing slowly. Maybe I need to acknowledge that I'm not young any more, and my brain works not slowly. Maybe my antidepressants really do suck.

Current project/dream list

  • ActivityPub/Masterdon
  • browser (but not really)
  • link share (and updating hydra)
  • shopping list (always with the shopping list)
  • game (2d/3d, roguelike, flight sim, whatever)
  • language (or finding a good use for one)
  • webmail (hasn't had a rewrite in ages)

I think activity pub is the one with most scope, but if I can get link share info some kind of working state then I can finally delete Facebook.

Anyway. Hello people, it's been a while, hope you're all well.



Cluster services

  • k3s (cluster software)
  • step-ca (certificate manager)
  • cert-manager (cluster to step gateway)
  • traefik (web proxy/gateway)
  • Prometheus (metrics)
  • Grafana (metrics display)
  • Something for logs
  • Something for alerts?

I want tenants to be able to use mTLS internally, so cert-manager needs two providers, one for step and one for Lets encrypt.

Cluster tenants

  • mail
    • postfix (smtp server)
    • dovecot (imap server and email storage)
    • spamassassin (spam filter)
    • opendkim
    • opendmarc
  • osric.uk
  • shinjuspottery
  • fluffypeople
  • kamelion

Cluster Management

  • helm?

That looks like a bunch of namespaces and then mail has a small collection of pods.

I'd like to give everyone their own ipv6 address, and I can front the web servers with mythics ipv4 proxy, only running mail through native ipv4.

Still, I'm not sure what it gets me. I want to be able to throw up a new service (and take it down later) with close to zero effort. I've newly got that now, but there is a bunch of setup on the server to do.

(I also want to split osric.uk down into a bunch of tiny services, but I'm worried about the overhead of running c# vms)

I think I can setup a helm chat for "deploy to server", and then just change the names. I'll look at that.


Ipv6 address toy - use a range tag to adjust the subnet, and show the start/end addresses underneath


New cluster is up and routed on merit.

K3s, again, this time with a public /64 via a VPN (Linux routing is harder than it looks).

I'm annoyed that Ipv4 is so expensive, it would be nice to give merit it's own ip. Options:

  • Pay for L2TP from A&A (£10/month)
  • Forward the appropriate ports from wepiu to merit
  • Remember that the plan is to put the cluster on wepiu anyway, so can use wepiu's ip
  • Find out how much mythic charge for extra ips

Support stuff:

  • Container registry (zot seems to work)
  • Internal CA, for mtls (cert-manager is designed for this)
  • Edge proxy (traefik is built in, so I'll take it)
  • Monitoring/Logging/Tracing/alerting
  • OIDC
  • Outbound mail?

I've been playing with a new k3s install the last week or so (if you didn't pick that up from the last few posts), but I've been stalled for a few days. Tonight I discovered why.

K3s comes with traefik (an edge proxy), and a slightly complicated way of configuring it. K3s ships with a basic configuration, and then the cluster admin (me, in this case) needs to add an extra file to overwrite the default.

I thought I was going to need to reinstall the cluster every time I wanted to update the config, and I was dreading that as I tend to work in a "make a small change, measure it's effect" loop, and I didn't want to wait five minutes for the install to finish every time.

So that was wrong, all I need to do is run a kubectl apply command with the updated config file and k3s makes the change and restarts traefik.

I even wrapped the command in a Makefile, to make it even easier to deploy.

Conclusion: Automation really is the bees knees.


Feeling lost again.

Started this new job, big whoop. They're going to pay me better, and the people seem ok, but the build environment sucks bigtime.

It's all Windows, and dotnet 4.x, and locked down tight, and the build machines have been running for years(? I think) with odd config tweaks so nobody can bring up a new one.

And the app doesn't seem to have any monitoring/alerting (although there is an on call rota?), and the code-to-bullshit ratio is something like 1:4.

And yes, two years ago even I wouldn't have noticed this stuff, but I am noticing now, and it's in my job description to try to fix this stuff. So I guess that's what I'm going to do?


Meanwhile, at home, I'm not sure what to do with myself. It's probably just a down swing, but I don't feel like doing anything.

I've got this "world simulation" thing that I've been thinking about for years, I should probably update ptah, wepiu, khonsu to new debian (I've got this whole "move everything to containers/kube" thing going on).

Husband got me playing Warcraft again, and then bounced to craftopia. And I'm just sat here going "What?". It's pissing me off, but not in a way that's helpful.

I suppose none of that stuff is urgent in any real sense. I'd be happy sleeping most of the time, although I do like chatting to husband.

Bollocks to it. G'd night.


Mail Pod

Obvious services

  • Postfix
  • Dovecot
  • opendkim
  • spampd.pl (from https://github.com/Moosemorals/spampd)
  • postfix-policyd-spf-python

New plan, lox to wasm. Crafting Interpreters and "An Incremental Approach to Compiler Construction" should give me enough of a toolkit. Need to choose between binary representation (more hardcore) and text representation (easier to debug).


Things to think about so far:

  • IO - where does the source come from and where does it go?
  • Write tests

Turns out that you can compile and load wasm at runtime! Who'd have guessed?

I'm not sure if that's /useful/ in any strict sense of the word, but it's sure fun!


Arghh! I'm surrounded by bullshit!

C# doesn't have sum types. I'm begining to see this as a fatal problem, and maybe I really should move to F#.

Frickin' nginx didn't start after a reboot, because it couldn't reach one of the hosts its the proxy for.

Time to move the "replace nginx with traefik" plans forward I guess.

Don't know what to do about c# though. I think I need to have more of a think about the problem. Quack.

I'm re-writing the Hydra frontend stuff, and I'm moving code out of the controller. After the user has logged in they need to be shown a 'consent' screen that asks them to confirm that they're ok with the client getting access to their data.

However, under certain conditions the consent screen is skipped and the user can be redirected without seeing it.

I was returning two values from the function, a bool 'is skip needed' and a nullable string 'redirectTarget' that's set when skipNeeded is true. However, I can instead return two nullables, the redirect string, or the info needed to show the consent screen.

Quack indeed.


There's a minigame that's shown up in a couple of places that I've liked playing, sending agents to run missions.

Some benevolent entity wants stuff done, and will reward you for doing it. You pick an available job/task/mission, assign some of your people to it, and wait for the random number generator to decide your fate.

The skill/challenge/fun comes from matching your people to tasks - Peter is a fighter, Joan is a diplomat, so send Peter to hunt deer/fight zombies, and Joan gets the negotiation jobs.

You must also manage opportunity costs - if Peter has been assigned hunting duties, they can't enter into a competition that there'd easily win.

More complex versions can bring in resource management. Peter brings back a boar from a hunt, +5 food, but took damage so -1 medicine, and they can't be assigned for a day or two.

Early on, missions can be simple templates: "The local village is being attacked by (zombies|robots|frogs), kill n for a reward from the mayor", but I kind the idea that there is a world behind the missions - hunt too many wolves and the local deer population jumps up, but that leads to overgrazing and damage to young trees.

The flow of time also needs to be modelled. Is there a 1:1 match between mission time and real time, or do missions run faster (or slower!).

How does the player interact? A point and click webpage would work fine, but maybe play by email? (Especially for something with a more sci-fi or espionage skin).


Network connection(s) for node001

Node001 is my new Raspberry Pi. I'm going to set it up as a k3s machine, and I want it to have access to some of my public IPv6 addresses (Go Mythic!)

I'm also thinking about isolating it from the local network somehow, but I don't think I can do that without having it behind some kind of hardware firewall (which would need to be ptah in this context).

I can get a WiFi card for ptah, and hang node001 off that, since I've got a "No more cables near ptah" requirement.

...

Raspberry Pi supports 'ac' WiFi ("WiFi 5", apparently), and a new card for ptah looks like £20-30. So let's work on that basis.

I can route everything from the card through to wepiu via the VPN, so even if naughty people completely own the pi, they won't be able to break into the house network.

I can also setup a hub so that the pi's can talk over ethernet to each other.


Player:

  • Create(Name)
  • Change Name(Name)
  • Delete()

Template:

  • Create(Name, Duration, Slots, Factors[])
  • ChangeAttribute
  • Delete()

The big question is how do I a) keep these organized (separate) while b) only having one Decide method.

IDecider {
 IEnumerable<Event> Decide(Command command);
}

I want a pair of top level types for Command and Event, and then I can just have a CombiningDecider that takes IDeciders and offers commands to each in turn.

I could make IDecider generic and filter based on types, or I can specify in the contract that Decide ignores (returns an empty sequence for) commands it doesn't recognise. Which I think sounds easier.

It's it worth doing the same thing for evolve?

I'm not sure about evolve, I've got a couple of things to do with each event that aren't really related (store the raw event, update the aggregate(s), post the event to web listeners). I'm getting a vague shape of each event processor having it's own copy of Evolve, but that seems inefficient (except, for sure there's going to be a JavaScript copy in the browser).

Hmm.

(Been coughing off and on all day, totally sucks. Took the day off sick, will do again tomorrow unless I'm feeling 100% when I wake up)


Mission jobs

  • Convert commands to use ids instead of instances

  • Dump factors (missions) and attributes (assets) in favour of key/value pairs

    This one needs a bit more thought. Problems include:

    • Are keys registered somewhere, or are they just convention? Convention is easier to program, keys are strings and I'm careful when I type them. Registration is safer (typo proof) but needs a registry (that, ideally, JavaScript has access to)
    • Are values typed? String/Number/Boolean opens up options, and something like units (gold, kg, hp) opens up more. Cost is that strings are easier to deal with.
    • Scope creep. If these pairs get complex enough, I can redefine missions/players as collections of pairs (instead of having some actual native properties). It's that a bad thing?
  • Start thinking about authorization/roles, splitting out admin functions on the front end, and authentication, mapping users to players


  • Do something about persistence

The caches can be updated to be async, with a fallback to something more permanent.

Should get the event storage stuff working, then can do event replay at app start time, and maybe start using event source's last id.


Hello people! I've been ill for a couple of weeks, I think that was probably covid. I've lost my sense of smell (plus the coughing, sweating, sneezing, aching, and fatigue), hopefully temporarily, but it's still weird eating and just getting texture - I can't even remember what foods tasted like.

I'm recovering now, helped by a "fit note" that's given me permission for a week off work, so I've been sleeping/relaxing/watching a lot of you tube.

I bought a Raspberry Pi (v4, 4GB) a couple of weeks back with a "build a cluster" plan, but I'm really not sure it's worth the money or effort. I don't want to hang the cluster off the home network, to protect the home network if someone cracks the cluster, so I've been looking at 4G/LTE modems, and that's got me all depressed.

I can buy a second hand Vodaphone USB modem dongle through eBay for under £20, and Id mobile will sell me unlimited 4G data for £16/month, and I'll have to (well, really want to) get a tunnel from A&A for £10/month, and I still don't know what I want to do with the cluster!

I've got a vague "kubenetes + web servers" plan, but the remote server I've got works well enough without all that messing about, and £26/month will rent me 2.9 pis from Mythic, without the up front cost of the hardware.

Ah, well. I've bought one pi, and if I come up with a use case I'll let you know.


Cooked myself an omlette for dinner, and I cooked it really quite well. I should think about doing that more often.


Tonights entertainment is setting up an iSCSI target for my new Pi, and trying to network boot off it (so I can talk to Mythic about swapping NFS for iSCSI).

I've installed dracut on the Pi to manage the initramfs (the normal Debian tools just don't cut it, apparently), and I've spun up a a VM (tayet - The One Who Weaves) as the iSCSI host.

I'm going to try to use the right terminology: iSCSI talks in terms of 'initiator' (client) and 'target' (server).

First, setup passwordless access by appending the contents of $env:USERDIR\.ssh\id_ed25519.pub to $HOME/.ssh/authorized_keys.

Config file for tayet - /etc/tgt/config.d/node001.conf (this is the 'target')

<target iqn.2023-08.uk.co.aaru:node001-root>
  backing-store /srv/iscsi/node001.img
  initiator-name iqn.2023-08.uk.co.aaru:node001-initiator01
  incominguser johnathan partridge
</target>

(yes, that's not really XML.)

I'm just going to leave the link to the instructions I followed for node001 (I'm getting tired, and they are a bit messier)


Foof! I've setup most of a network root for the pi. Still to do:

  • Install and configure dnsmasq on tayet ss a dhcp/tftp server.
  • Setup ipxe so that the pi, when it asks tayet for a kernel, gets pointed towards the right place
  • Find out how much of the iscsi client stuff I need to install on the pi. (Thinking, if the kernel has booted of the remote disk, do I need the client tools?)
  • Dream about a shared read-only /usr disk
  • Go though that all again, but this time with the USB stick (four times faster than the sd card, and I'm only doing the iscsi thing as a test/demo for Mythic)

Dnsmask doesn't do IPv6 very well, so I've installed ISC Kea, which feels a bit over-engineered, but so far so good.

I've got it installed and running with a tftp server defined in the config, but I've left it switched off for now because I need to check that it's not going to try to stomp on the BT router.

Poot. Just read the docs for Kea, and it won't run as a 'proxy' (that is, send out DHCP replies with options set but no ip address).

Bollocks to it, I'll get an OS installed on the USB stick, and then I can use that Pi for whatever.


Physical vs cloud, that old chestnut.

Cloud machines work, have good connectivity, are IPv6 only (with workarounds).

Physical machines don't have a recurring cost, have more permanance, can be used to interface to the actual world.

Hybrid cluster gives me security concerns. Gah.


Duck time again.

I've got this new machine ("hedgehog", hosted by Hetzner, 6 core, 64gb, 1TB disk, 30EUR/month, no ipv4), and I'm still not sure where it fits in the network.

It can, obviously, just be it's own machine. Easy to setup, but it doesn't have IPv4 (and Hetzner don't run a gateway in either direction).

I could put it behind a CDN (only just thought of that!), but I don't want to pay any more than I have to, and I don't wan't to depend on people I don't need to.

Or, and this is what I want really, I can setup a VPN to wepiu and route traffic, possibly by putting both machines into a cluster.

(Or, I can just drop wepiu and spend the extra 2EUR/month on a IPv4 address).

That last one is a new thought, but it's got a point. Oh, but it would mean moving from Mythic's IP reputation to Hetzners. Let's not do that.


Looks like that's most of the work done for the Auth server. Next up is getting it running somewhere.

That depends on getting VMs up and running, which I think is waiting on networking (Wireguard is a layer 3 (IP) tunnel, but simple VM network setups expect a layer 2 (ethernet) tunnel).

Ah, well. Tomorrow's problems.


New infrastructure update: Traefik and let's encrypt are up.

I'm fairly sure I'm over-engineering again, but that's the fun part, yeah?

Request goes to Mythic's proxy over public internet. Proxy connects to tayet, a VM at the end of a VPN that hosts a k3s node. I might be able to eliminate the VPN, but I don't want to, I like having the "internal" network. (Now that it's been pointed out to me, I do wish that Wireguard operated at level 2, but you can't have everything) (TODO: Look up Ipsec, see if it's as bad as people make it out to be).

The dependency tree suggests that the container registry is next, then hydra/oidc, and then 'observability' (grafana et al.).

Also todo, find/write a cheap nuget repo.


Hello people, I got a new phone (Motorola Edge 40), and while I'd love to talk about it, I've still got depression. Sorry.


I think I've got elastic search setup to parse metrics out of the postfix logs!

It's taken a week, off and on, to work it out, but now I know.

One must add a "custom ingest pipeline" to the journald integration of the agent that's sharing a host with postgres.

Now I know that, I can start adding rules for dovecot (although really I should be able to scrape their Prometheus metrics), spampd, and the rest of the mail pipeline. I wonder if I can get them all to log a trace id ?

I'm also getting the infrastructure for the Elastic APM stuff sorted. The Elastic server (or maybe as Kibana) can do things like organise a new API key, so it's irritating it can't generate a zip of TLS keys to download.


I've been working half days at work on phased return from sick leave, and it's probably time to work up to full days. Yuch! Working half days has been really nice, shame we can't afford for me to go half time.


Measures

I've been writing this spreadsheet, and I've decided that what it needs is units, or rather measures

A measure is the amount of a thing, e.g., it's length, mass, duration, or some combination (length per duration is speed, for example)

A unit is the ratio of a measure to a standard (metres for length, seconds for duration, etc.), or some multiple of the ratio (feet, pounds, days).

Storing measures needs to keep track of it's dimensions, it's magnitude, and it's unit (we're keeping the unit for display).


Next step, for every combination of ValueType op ValueType, i need to write down (as code) what it means.


Current Computer Equipment Wish List

  • New monitor(s).

    Either 1 4k or a couple of 1440. Maybe curved? Must have speakers, HDR would be nice. Check specs of 1080, no point spending extra on e.g. 144Hz if the card can only do 60Hz

  • KVM switch.

    I can (and am!) swapping the keyboard/mouse/headphones USB over manually, and I've got Silk and the work laptop plugged into different inputs for the monitors, but ideally there'd be one less impediment to using the desktop.

  • 6E router

    Will only bring useful network up to 1Gbps, but could maybe put a 2.5Gbps card in ptah (although the bottleneck there is still the disks).

  • More storage space

    Lounge is full again, 18TB disks are out there (and best £/Gb), although I'd want to get two and mirror them. Equally, 2Tb NVMe drives are getting really cheap, problem is organizing enough M2 slots/PCIe lanes to use them.


Lisp as a system management language

Just the start of a though for now, but something like:

(def! apt-install (fn* (names) (apply exec "/usr/bin/apt-get" "install" names))

apply takes a function and a list of arguments, where the last argument is a list. It spices the last argument with the others and then calls the function with the combined list.


Since I'm going to be implementing in c#, I don't want to hobble my self from the start. Mostly this means c# strings are data types.

(Don't get distracted thinking about JavaScript, this is "Lisp as system scripting language", remember?)

record Pair(object? Data, Pair? Next)

record Pair<T>(T? Payload, Pair? Next) : base(Payload, Next)

... maybe


Hello world!

So I've got this new desktop PC - Silk - and first job is to distribute my SSH key. (Yes, I am going to look into SSH certs, no not today).

Step 1 - Copy the key to a machine that is already trusted. I feel I should just be able to dump it here, but there's no point being silly. I've copied it to OneDrive so I can reach it from the laptop.

(Aside: The laptop is doing it's usual "Got to have a power supply even at 98% charged thing". I really should save up and get a Chromebook or something)

Step 2 - Copy the key to target machines. Easy enough to do manually, but I wish I had a script for it. Ah, well.

Anyway, I'm up on wepiu, so I guess that wasn't the trauma I was expecting. See y'all later!



Hey folks!

I've finally got ground to writing a nuget server! It's dead simple but I can publish packages to it, and pull packages from it at build time. Rider doesn't like/use/understand the search, but that's easy to work round with dotnet add package.

That, as well as the container registry ('zot') I've installed means that I can start splitting code into libraries (As a smoke test I've put the OIDC stuff into a package) which should allow me to break the site into a bunch of tiny servers (e.g., separate out the blog) that are all SSO, and all sharing css/layout/menus (I might end up with almost everything in it's own package and one server to host them, or I might just keep the menu updated manually).

I think next up is finishing the Hydra front-end/user management service. (it occurs to me that I can hang e.g. mal off the new server without disrupting the old service). I know that realistically it's only ever going to be me and husband (and husband only uses webmail), but I'd still like to get things like roles right (Of course, the right way to do roles is in three layers, users, roles, and actions. Users are assigned roles, and roles are groups of actions. Admins group actions together to create roles, and then roles are allocated to users. But that's probably overkill)

Anyway. It's going well.


I assembled the various bits of my new hydra ui for the first time tonight (Hydra 2.2, the ui, and a client), and it's starting to come together.

I seem to have picked a nice colour palette (although I'm sure that husband will disagree), I can't remember how I did it though.

Still got bugs, clearly, but i think we're in "yeah, this is going to work" territory.

Wishlist:

  • user management (add, password reset, scope/role assign, suspend, delete)
  • client management (add, edit, delete, reissue secret) (Note the advantage of this is that all the settings apart from name and callback uri can be preset, making it much easier to add a client)
  • scope/role management. I should make a choice soon about how I'm going to do this, but I'm fairly sure that roles and scopes are different, and there's no point making life complicated.
  • self management (set password, name, revoke permissions, remote logout)

Anyway, it's late and a work night.


I think one of the things I like most about JavaScript is that only the code you run has to be semantically correct. So long as broken code matches the syntax rules, the runtime doesn't complain until the code actually breaks.

Of course, this means that you don't find out about certain problems until runtime. As ever, these things are a trade off.


State of play:

  • auth is up. It's got a UI for client creation, and the client programming stuff is in a nuget package so it's easy to include (just add a stanza to config).

  • shared.web is started. It's got some/most of the "always going to want this" stuff for a web app in a couple of extensions. I need to add lib.js, lib.css, and probably a _Layout, along with the tag helpers from auth.

    It's also got the CSP stuff I wrote a while back, and I want to add a nonse tag helper.

  • mal has been converted to the new style as a test. It works great, except it doesn't have a menu. Still thinking about menus (clearly the answer is to check some dynamic source for menu contents at page create time, but what's the best way to store/edit/distribute the data?)

What's next:

  • Install the ELK stack (or at least, ElasticSearch, Kibana, and the Elastic APM stuff) on a VM and hook that into the shared.web library.

  • Sort out a local CA and setup mtls.

  • Split out the blog from the rest of osric.uk (depends on the menu, ish)


I've got mal, and this blog, and I'm not sure what other bits of the door do keep.

'About you' is interesting, and id like to get weather fettled up at some point, but really, the only wiring parts are those two.

I can split the blog into it's own service, and then strip down the "top level" bit to the front page with the calender.

(TODO: turn the calender into a component that takes a collection of (Date, Uri) pairs so I can draw e.g blog entries and Dr who episodes)

On the list at the moment:

  • Editor, for both mal and the blog.
  • Dr who database. Using the data that husband put together, I want to do some date based stuff.
  • particles/flocking/collision avoidance

anyway. no overwhelming need to keep most of the stuff


Semantic Versioning is bogus, because every change changes the behaviour of code.

The CPU no longer overheats when you hold down the spacebar
XKCD: Workflow

Since people are mostly not crazy/stupid, I've clearly misunderstood what Semantic Versioninig is about.



Looks like sql window functions should let me dump blog entries and their edited versions into a table, and then do something like

SELECT *
FROM (
    SELECT
      ROW_NUMBER() OVER (
        PARTITION BY "EntryId"
        ORDER BY "Date" DESC
      ) AS "rank",
      Text, EntryId, Date
    FROM "Entries"
  ) sub
WHERE
  "sub"."rank" = 1

To get the latest version of any given entry. I'll need to drop into raw sql, but EF should cope with that ok.

(Do I really need to keep old versions of entries? Life is far more simple if I don't, but disk space is cheap enough and I like to let my hording tendencies loose now and then.)


I still want to add automatic entries to the blog, although the only thing I can think of at the moment is git commits.


Looking back at an entry from November about Lisp pairs ('conses', i think), it is now obvious that they should be something like

public abstract class MalValue {} // the base type for values

public class MalPair(MalValue first, MalValue rest) : MalValue {} 

(C#'s new "Primary Constructor" syntax is nifty)

Because MalPair extends MalValue, either side of the pair can be another pair. I wonder how much work it would be to drop lists and construct these instead. Probably not worth it (I can only see it costing performance), but it might be fun.


Pros and cons of moving auth.shared to shared (and therefore shared.auth).

Pros are mostly "that's where the shared code is" and "the names will line up better".

Cons are "it's work (and need to update its consumers)" and "that's were the auth code is".

Hmm.


To remember your current position in the blog, this page must store some data in this browser.

Are you OK with that?