From 515d4b10e383dd84d29aacc16270bb14da4690d7 Mon Sep 17 00:00:00 2001
From: alifeee
Date: Wed, 8 Jan 2025 14:35:49 +0100
Subject: [PATCH] replace email with alifeee.net email
---
bike-to-cambridge/index.html | 811 +++++++++++-----
factorio-proximity-chat/index.html | 1125 +++++++++++++++++-----
font-workshop/index.html | 301 ++++--
gists/index.html | 1393 +++++++++++++++++++++-------
hackspace-adventures/index.html | 4 +-
hull-bus-sign/index.html | 4 +-
index.html | 2 +-
index_template.html | 4 +-
making-bogface/index.html | 804 +++++++++++-----
railcards/index.html | 767 ++++++++++-----
ring-populations/index.html | 385 +++++---
sketch-your-society/index.html | 169 +++-
snippets-of-a-degree/index.html | 280 +++---
steam-collage-api/index.html | 4 +-
what-is-a-third-space/index.html | 496 +++++++---
15 files changed, 4884 insertions(+), 1665 deletions(-)
diff --git a/bike-to-cambridge/index.html b/bike-to-cambridge/index.html
index 4bbccef..b423939 100644
--- a/bike-to-cambridge/index.html
+++ b/bike-to-cambridge/index.html
@@ -84,239 +84,602 @@ alifeee's blog
- I biked from Birmingham to Cambridge (a tribute to National Cycle Routes)
-
-
-- Technicalities - how far did I bike?
-- How to plan a bike route
-- Google Maps hates bikes
-
-
-- National Cycle Routes!
-- Why get lost when you can not get lost
-- Do they go the right way?
-- Why go the right way when you can go the wrong way
-
-
-- Conclusion ("And what?")
-- Appendix: Tools
-
-In April, I biked from Birmingham to Cambridge.
-More accurately, I half-biked, half-trained from Birmingham to Cambridge.
-The original plan was to be on the bike the whole way, from Birmingham to Leamington Spa, to Wellingborough, through Bedford, and finally into Cambridge (it may sound a haphazard route, but I'd managed to find someone who would host me at each town!). This route was half on established cycle routes, and half country roads where I'd have to find my own way. Not bad, but it might be annoying to navigate on roads which were completely new to me.
-But then... why should I have to bike on unlabelled routes and terrible roads? Why am I biking in the first place? Ultimately:
-
-- Because I can,
-- It sounds fun,
-- I've always wanted to go on a bike tour and this is almost that
-
-Therefore, why bother with a convoluted and annoying bike just for the sake of having biked the whole way. Let's ditch the idea of "purity"... and just catch a few trains to make it more pleasant. Here was the final route:
-
-
-
-Look ma! I did most of it with my own legs!
-Source.
-
-
-In an ideal world, I would have biked closer to Cambridge, but I injured my foot just before the final day, so I couldn't. Hence, the horrific detour by train! (turns out, the Bedfordshire council does not let you take a bike onto their buses)
-So, what's the rest of this post about? Basically...
-
-- Alternatives to Google Maps for finding a bike route
-- Me using the opportunity of having data to make pretty graphs with Python
-- Why you should cheat if you go on a bike ride
-
-Technicalities - how far did I bike?
-As the crow flies, the distance from my house to where I ended up in Cambridge is 141.1 km.
-If said crow got tired and wanted to stop off at the same places I stopped off, the distance would be 148.4 km (thanks to my friend trigonometry for such a small change.)
-
-
-
-If I were a crow, it would be a nice life.
-I would also get to Cambridge in 148 km, with stopovers.
-From Google Maps.
-
-
-According to my records, I biked 150.3 km. That's more than 148.4 km!
-I'm better than a crow! Or, I can (in the most roundabout of technicalities) now say:
-"I biked the distance from Birmingham to Cambridge!"
-That sounds pretty good! I'll start telling people that, and they'll be none the wiser.
-Since this seems to be the section with all the statistics, let's finish off with the rest of them:
-
-
-
-Statistic |
-Value |
-
-
-
-Crow-distance from Birmingham to Cambridge |
-141.1 km |
-
-
-Sleepy crow-distance from Birmingham to Cambridge |
-148.4 km |
-
-
- |
- |
-
-
-Distance I biked |
-150.3 km |
-
-
-Total time cycling |
-11hr 54min |
-
-
-Total climb |
-746 m |
-
-
-Average speed |
-12.6 km/h |
-
-
-How to plan a bike route
-Before this, I'd not planned a very long bike ride before. I had biked from Durham to Newcastle, but that's basically a straight shot up the A167 until you find a "Newcastle Road" that you can follow. The biggest gripe I remember from this and other long-ish rides was that the directions Google Maps gave me were: not great for biking; and took way longer than the estimate said. These are basically encapsulated in what I will call my "top 2 criteria for a perfect bike route":
-
-- I don't want to bike on roads unfriendly to bikes (I think I should be allowed to desire to not be run over by a car)
-- I don't want to stop to check my phone for directions (I'm afraid I'm not bourgeois enough to have one of those fancy phone holders on my handlebars)
-
-I ended up finding a great website for finding any distance bike routes: cycle.travel. As well as actual bike-friendly routes (which are, naturally, slightly longer than Google's suggestions but ten times more pleasant to bike on), the website provides some information about the type of roads on the route. This solves the first problem above, and also how I figure that...
-Google Maps hates bikes
-Here are the routes that Google Maps and cycle.travel give me for the route:
-Birmingham → Leamington Spa → Wellingborough → Bedford → Cambridge
-
-
-
-Spot the difference.
-From gpx.studio.
-
-
-They look pretty similar! Now let's use cycle.travel's route planner to see what types of roads you'd be biking on if you followed these routes:
-
-
-
-Which of these would you rather bike on?
-Source.
-
-
-Now personally, 2 of these 5 road types I find enjoyable to bike along, and the other three far less so. I'll leave it to you to imagine which. Needless to say, the directions Google gives you are not made for cycling.
-Additionally, Google Maps seems to think that you are some kind of cycling God, presumably decked out with Lycra, speed stripes, and one of those back-pockets. I say this because the time estimate it gives you expects you to be cycling 19.1 km/h. If you aren't acutely aware of the relative speeds of biking, what are you doing with your life. But, if not, I would describe this as "very fast". To contextualise: over three days, I managed an average of 12.6 km/h, and going what I felt was a moderate speed I would get to about 15 km/h. Meanwhile, cycle.travel's travel time estimates estimate that you are doing around 15.8 km/h. Much more reasonable. (though I personally still have to add an hour to any time estimates. What can I say, I love dawdling.)
-So, cycle.travel (or probably many other cycling websites) solves my first bike route desire: I don't want to be run over. How do we solve the second: I don't want a SatNav?
-National Cycle Routes!
-Biking can be very pleasant when it's relaxing and stress-free (see: when there are no cars). National Cycle Routes are exactly that! They are a network of paths, roads, and bridges through the UK which are kept navigable, and they are all very well signed.
-
-The National Cycle Network is a UK-wide network of signed paths and routes for walking, wheeling, cycling and exploring outdoors.
-
-- Sustrans
-The goal of national cycle routes is to make it pleasant to bike on them. As I have expressed, the main goal of this whole adventure was also to have an enjoyable time, so why not use national cycle routes as much as possible!
-
-
-Ramp down to the Stratford canal, National Cycle Route 5.
-
-
-Why get lost when you can not get lost
-One of my favourite things about the routes is that they are very well signed. Sustrans do a great job keeping them up to date and making any diversions obvious. Set off down a route, and you'll encounter a familiar blue and red sign at every turn keeping you on track. This pretty neatly deals with my "I don't want to stop for directions" criterion.
-If you blindly follow the routes, you will end up skirting round villages and past large roads in long, winding, or counterintuitive diversions, but you'll also end up encountering what you might not if you try and zoom through everywhere that you visit via the fastest route possible.
-
-
-
-Whoosh!
-Picture from a bridge next to the ford.
-Would've been fun to try and get through on a bike though.
-
-
-There is a definite comfort in knowing that you're on the right track. If I weren't, then after every turn I'd feel the need to check if I'm going the right way, so I don't end up careening down a hill for ten minutes only to find I've made a wrong turn and all the freewheeling fun was for nothing.
-
-
-
-Get to the end of this, but a thousand times, and you might end up in Cambridge.
-
-
-Do they go the right way?
-No.
-The national cycles routes come with the problem that they might simply not align with where you want to go. That was certainly the case for me. You try and find a good way from Birmingham to Cambridge that doesn't end up in a huge detour of a winding mess.
-
-
-
-Here's a game. Why does everything go the wrong way?
-Sorry, that wasn't a game.
-From OS Maps.
-
-
-However, for me, biking along a cycle route offers too many benefits in contrast to the alternative: making sweeping shortcuts across Northamptonshire.
-Why go the right way when you can go the wrong way
-If my mind was cavernous and my thighs thunderous, I would be able to set off and bike straight towards Cambridge. Stopping only to sleep, this is the overall direction I would end up going in, thanks to petty limitations of the real world like "roads don't go in perfectly straight lines":
-
-
-
-Turns out the fastest way to get somewhere is to go that way.
-Source.
-
+
+ I biked from Birmingham to Cambridge (a tribute to National Cycle
+ Routes)
+
+
+
+ -
+ Technicalities - how far did I bike?
+
+ -
+ How to plan a bike route
+
+ -
+ Google Maps hates bikes
+
+
+
+ -
+ National Cycle Routes!
+
+ -
+ Why get lost when you can not get lost
+
+ -
+ Do they go the right way?
+
+ -
+ Why go the right way when you can go the wrong way
+
+
+
+ -
+ Conclusion ("And what?")
+
+ - Appendix: Tools
+
+ In April, I biked from Birmingham to Cambridge.
+
+ More accurately, I half-biked, half-trained from Birmingham to
+ Cambridge.
+
+
+ The original plan was to be on the bike the whole way, from Birmingham
+ to Leamington Spa, to Wellingborough, through Bedford, and finally
+ into Cambridge (it may sound a haphazard route, but I'd managed to
+ find someone who would host me at each town!). This route was half on
+ established cycle routes, and half country roads where I'd have to
+ find my own way. Not bad, but it might be annoying to navigate on
+ roads which were completely new to me.
+
+
+ But then... why should I have to bike on unlabelled routes and
+ terrible roads? Why am I biking in the first place? Ultimately:
+
+
+ - Because I can,
+ - It sounds fun,
+ -
+ I've always wanted to go on a bike tour and this is almost that
+
+
+
+ Therefore, why bother with a convoluted and annoying bike just for the
+ sake of having biked the whole way. Let's ditch the idea of
+ "purity"... and just catch a few trains to make it more
+ pleasant. Here was the final route:
+
+
+
+
+
+
+ Look ma! I did most of it with my own legs!
+ Source.
+
+
-The sad news was I don't have a cavernous mind or thunderous thighs (the latter is at least achievable with more cycling). And with the fact that the direct route lies on approximately zero national cycle routes, it did not seem a good way to go. However! There was a solution! Trains! I could just hop on a quick 30-minute train and re-align myself with the curious spider web of cycleways. I just had to find out when and where I could do that, which is where the National Rail route map comes in:
-
-
+
+ In an ideal world, I would have biked closer to Cambridge, but I
+ injured my foot just before the final day, so I couldn't. Hence,
+ the horrific detour by train! (turns out, the Bedfordshire council
+ does not let you take a bike onto their buses)
+
+ So, what's the rest of this post about? Basically...
+
+ - Alternatives to Google Maps for finding a bike route
+ -
+ Me using the opportunity of having data to make pretty graphs with
+ Python
+
+ - Why you should cheat if you go on a bike ride
+
+
+ Technicalities - how far did I bike?
+
+
+ As the crow flies, the distance from my house to where I ended up in
+ Cambridge is 141.1 km. If said crow got tired and wanted to stop off
+ at the same places I stopped off, the distance would be 148.4 km
+ (thanks to my friend trigonometry for such a small change.)
+
+
+
+
+
+
+ If I were a crow, it would be a nice life. I would also get to
+ Cambridge in 148 km, with stopovers. From
+ Google Maps.
+
+
-An insight into my definitely organised mind:
-what I sketched to see which trains I could use on my journey if I needed to.
-Blue is the bike route, with green the trains that could be used as shortcuts.
-Background from National Rail (PDF).
-
+
+ According to my records, I biked 150.3 km. That's more than 148.4
+ km!
+
+
+ I'm better than a crow! Or, I can (in the most roundabout of
+ technicalities) now say:
+
+ "I biked the distance from Birmingham to Cambridge!"
+
+ That sounds pretty good! I'll start telling people that, and
+ they'll be none the wiser.
+
+
+ Since this seems to be the section with all the statistics, let's
+ finish off with the rest of them:
+
+
+
+
+ Statistic |
+ Value |
+
+
+
+
+ Crow-distance from Birmingham to Cambridge |
+ 141.1 km |
+
+
+ Sleepy crow-distance from Birmingham to Cambridge |
+ 148.4 km |
+
+
+ |
+ |
+
+
+ Distance I biked |
+ 150.3 km |
+
+
+ Total time cycling |
+ 11hr 54min |
+
+
+ Total climb |
+ 746 m |
+
+
+ Average speed |
+ 12.6 km/h |
+
+
+
+ How to plan a bike route
+
+ Before this, I'd not planned a very long bike ride before. I had
+ biked from Durham to Newcastle, but that's basically a straight
+ shot up the A167 until you find a "Newcastle Road" that you
+ can follow. The biggest gripe I remember from this and other long-ish
+ rides was that the directions
+ Google Maps gave me were: not
+ great for biking; and took way longer than the estimate said.
+ These are basically encapsulated in what I will call my "top 2
+ criteria for a perfect bike route":
+
+
+ -
+ I don't want to bike on roads unfriendly to bikes (I think I
+ should be allowed to desire to not be run over by a car)
+
+ -
+ I don't want to stop to check my phone for directions (I'm
+ afraid I'm not bourgeois enough to have one of those fancy phone
+ holders on my handlebars)
+
+
+
+ I ended up finding a great website for finding any distance bike
+ routes: cycle.travel. As well as
+ actual bike-friendly routes (which are, naturally, slightly longer
+ than Google's suggestions but ten times more pleasant to bike on),
+ the website provides some information about the type of roads on the
+ route. This solves the first problem above, and also how I figure
+ that...
+
+ Google Maps hates bikes
+
+ Here are the routes that
+ Google Maps and
+ cycle.travel give me for the route:
+
+
+ Birmingham → Leamington Spa → Wellingborough → Bedford → Cambridge
+
+
+
+
+
+
+ Spot the difference. From
+ gpx.studio.
+
+
-I ended up doing a completely different route which goes off both the top and bottom of that map, but it planted the seed that trains were only here to help.
-
-
+
+ They look pretty similar! Now let's use
+ cycle.travel's route planner to
+ see what types of roads you'd be biking on if you followed these
+ routes:
+
+
+
+
+
+
+ Which of these would you rather bike on?
+ Source.
+
+
-I'm big. My bike is big.
-Sometimes we fit in a train.
-
+
+ Now personally, 2 of these 5 road types I find enjoyable to bike
+ along, and the other three far less so. I'll leave it to you to
+ imagine which. Needless to say, the directions Google gives you are
+ not made for cycling.
+
+
+ Additionally, Google Maps seems
+ to think that you are some kind of cycling God, presumably decked out
+ with Lycra, speed stripes, and one of those back-pockets. I say this
+ because the time estimate it gives you expects you to be cycling
+ 19.1 km/h. If you aren't acutely aware of the
+ relative speeds of biking, what are you doing with your life. But, if
+ not, I would describe this as "very fast". To contextualise:
+ over three days, I managed an average of 12.6 km/h, and going what I
+ felt was a moderate speed I would get to about 15 km/h. Meanwhile,
+ cycle.travel's travel time
+ estimates estimate that you are doing around 15.8 km/h. Much more
+ reasonable. (though I personally still have to add an hour to
+ any time estimates. What can I say, I love dawdling.)
+
+
+ So, cycle.travel (or probably many
+ other cycling websites) solves my first bike route desire: I don't
+ want to be run over. How do we solve the second: I don't want a
+ SatNav?
+
+ National Cycle Routes!
+
+ Biking can be very pleasant when it's relaxing and stress-free
+ (see: when there are no cars). National Cycle Routes are exactly that!
+ They are a network of paths, roads, and bridges through the UK which
+ are kept navigable, and they are all very well signed.
+
+
+
+ The National Cycle Network is a UK-wide network of signed paths and
+ routes for walking, wheeling, cycling and exploring outdoors.
+
+
+
+ -
+ Sustrans
+
+
+ The goal of national cycle routes is to make it pleasant to bike on
+ them. As I have expressed, the main goal of this whole adventure was
+ also to have an enjoyable time, so why not use national cycle routes
+ as much as possible!
+
+
+
+
+
+ Ramp down to the Stratford canal, National Cycle Route 5.
+
-If we look back at the route I finally did, I ended up on national cycle routes for the whole thing.
-
-
+
+ Why get lost when you can not get lost
+
+
+ One of my favourite things about the routes is that they are very well
+ signed. Sustrans do a great
+ job keeping them up to date and making any diversions obvious. Set off
+ down a route, and you'll encounter a familiar blue and red sign at
+ every turn keeping you on track. This pretty neatly deals with my
+ "I don't want to stop for directions" criterion.
+
+
+ If you blindly follow the routes, you will end up skirting round
+ villages and past large roads in long, winding, or counterintuitive
+ diversions, but you'll also end up encountering what you might not
+ if you try and zoom through everywhere that you visit via the fastest
+ route possible.
+
+
+
+
+
+
+ Whoosh! Picture from a bridge next to the ford. Would've been
+ fun to try and get through on a bike though.
+
+
-It's all national cycle routes?
-Always has been.
-Source.
-
+
+ There is a definite comfort in knowing that you're on the right
+ track. If I weren't, then after every turn I'd feel the need
+ to check if I'm going the right way, so I don't end up
+ careening down a hill for ten minutes only to find I've made a
+ wrong turn and all the freewheeling fun was for nothing.
+
+
+
+
+
+
+ Get to the end of this, but a thousand times, and you might end up
+ in Cambridge.
+
+
+
+ Do they go the right way?
+ No.
+
+ The national cycles routes come with the problem that they might
+ simply not align with where you want to go. That was certainly the
+ case for me. You try and find a good way from Birmingham to Cambridge
+ that doesn't end up in a huge detour of a winding mess.
+
+
+
+
+
+
+ Here's a game. Why does everything go the wrong way? Sorry, that
+ wasn't a game. From
+ OS Maps.
+
+
-This ended up meaning that some days I was biking not towards Cambridge at all, which - if I were only biking - would usually mean zero progress towards the end. But not so bad here! It's easily fixable with a train or two.
-
-
+
+ However, for me, biking along a cycle route offers too many benefits
+ in contrast to the alternative: making sweeping shortcuts across
+ Northamptonshire.
+
+
+ Why go the right way when you can go the wrong way
+
+
+ If my mind was cavernous and my thighs thunderous, I would be able to
+ set off and bike straight towards Cambridge. Stopping only to sleep,
+ this is the overall direction I would end up going in, thanks to petty
+ limitations of the real world like "roads don't go in
+ perfectly straight lines":
+
+
+
+
+
+
+ Turns out the fastest way to get somewhere is to go that way.
+ Source.
+
+
-Going the right way is for nerds.
-Source.
-
+
+ The sad news was I don't have a cavernous mind or thunderous
+ thighs (the latter is at least achievable with more cycling). And with
+ the fact that the direct route lies on approximately zero national
+ cycle routes, it did not seem a good way to go. However! There was a
+ solution! Trains! I could just hop on a quick 30-minute train and
+ re-align myself with the curious spider web of cycleways. I just had
+ to find out when and where I could do that, which is where the
+ National Rail route map comes in:
+
+
+
+
+
+
+ An insight into my definitely organised mind: what I sketched to see
+ which trains I could use on my journey if I needed to. Blue is the
+ bike route, with green the trains that could be used as shortcuts.
+ Background from
+ National Rail
+ (PDF).
+
+
-Conclusion ("And what?")
-To me, my journey counts as a bike tour. I will also say: bike touring is fun! You have one thing to do: bike. Go forwards. Head empty. Eat snack. Pedal.
-Also, let's not be purist. Trains make it so much better. You can pick and choose the best bike routes, all while retaining the feeling of slow progress towards your destination.
-10/10 would bike again.
-
-
+
+ I ended up doing a completely different route which goes off both the
+ top and bottom of that map, but it planted the seed that
+ trains were only here to help.
+
+
+
+
+
+ I'm big. My bike is big. Sometimes we fit in a train.
+
-My bike in front of millennium milepost 897X.
-6 km into day 2, the 80 km day.
-
+
+ If we look back at the route I finally did, I ended up on national
+ cycle routes for the whole thing.
+
+
+
+
+
+
+ It's all national cycle routes? Always has been.
+ Source.
+
+
-
-Here are a few tools I used to get data from the bike ride, and subsequent GPS data:
-
-You can also view the data analysis in the GitHub repository! In particular, check out these Jupyter notebooks:
-
-You can open and play with these notebooks on Binder.
+
+ This ended up meaning that some days I was biking not towards
+ Cambridge at all, which - if I were only biking - would usually mean
+ zero progress towards the end. But not so bad here! It's easily
+ fixable with a train or two.
+
+
+
+
+
+
+ Going the right way is for nerds.
+ Source.
+
+
+
+ Conclusion ("And what?")
+
+ To me, my journey counts as a bike tour. I will also say: bike touring
+ is fun! You have one thing to do: bike. Go forwards. Head empty. Eat
+ snack. Pedal.
+
+
+ Also, let's not be purist. Trains make it so much better. You can
+ pick and choose the best bike routes, all while retaining the feeling
+ of slow progress towards your destination.
+
+ 10/10 would bike again.
+
+
+
+
+
+ My bike in front of
+ millennium milepost 897X. 6 km into day 2, the 80 km day.
+
+
+
+
+
+ Here are a few tools I used to get data from the bike ride, and
+ subsequent GPS data:
+
+
+
+ You can also view the data analysis in the
+ GitHub repository! In particular, check out these Jupyter notebooks:
+
+
+
+ You can open and play with these notebooks on
+ Binder.
+
@@ -324,7 +687,7 @@
Comments
Email me →
- alifeee.web@outlook.com
+ alifeee@alifeee.net
:)
@@ -344,7 +707,7 @@
Comments
Linktree
-
+
Email
diff --git a/factorio-proximity-chat/index.html b/factorio-proximity-chat/index.html
index 13602e7..b29d047 100644
--- a/factorio-proximity-chat/index.html
+++ b/factorio-proximity-chat/index.html
@@ -81,105 +81,407 @@ alifeee's blog
- Coding Projects! #2: Proximity-based voice chat for Factorio
-
-Earlier this year, I played Barotrauma weekly for 21 weeks with friends. Barotrauma is a "2D co-op submarine simulator – in space, with survival horror and RPG elements", and most importantly for me: it has a proximity voice-chat system. This means that if you are crafting some nuclear fuel rods at the rear of the ship, you will not hear your crewmates being torn apart by eldritch beings that found their way into the front of the ship. You will be on your way past the medbay to fix a leak in the crew quarters, and hear the medical doctors through the door discussing which of the crewmembers to use for their next 'experiment'. You will be picked as the next dead-man-walking to leave the submarine to mine precious metals, and will make your way across the ship to get orders in-person from the captain.
-
-
-
-Here, three of us make small talk while we mine outside the submarine. What conversations were being had inside the submarine, we were unaware.
-
+
+ Coding Projects! #2: Proximity-based voice chat for Factorio
+
+
+
+ Earlier this year, I played
+ Barotrauma
+ weekly for 21 weeks with friends. Barotrauma is a "2D co-op
+ submarine simulator – in space, with survival horror and RPG
+ elements", and most importantly for me: it has a proximity
+ voice-chat system. This means that if you are crafting some nuclear
+ fuel rods at the rear of the ship, you will not hear your crewmates
+ being torn apart by eldritch beings that found their way into the
+ front of the ship. You will be on your way past the medbay to fix a
+ leak in the crew quarters, and hear the medical doctors through the
+ door discussing which of the crewmembers to use for their next
+ 'experiment'. You will be picked as the next
+ dead-man-walking to leave the submarine to mine precious metals, and
+ will make your way across the ship to get orders in-person from the
+ captain.
+
+
+
+
+
+
+ Here, three of us make small talk while we mine outside the
+ submarine. What conversations were being had inside the submarine,
+ we were unaware.
+
+
-As you can tell, I had a lot of fun playing Barotrauma; it probably deserves a blog post of its own. When we played, we were usually around 8 players, which, had we used Discord for voice chat, would have been chaos trying to hear what everyone was saying. Proximity chat added greatly to our enjoyment of the game, and planted the question in my mind of which other games which could be as fun. In my view, there are a few criteria which made Barotrauma great and that I would like in another game that could be as fun. They are:
-
-- Proximity chat. Games which come to mind immediately which have this are Among Us and Minecraft. There are lists online.
-- Campaign-based. By this, I mean games where you play the same save, and wouldn't start fresh every week. Among Us is out.
-- Players are... in proximity to each other. In Barotrauma, you can always hear mutterings and ramblings of other people as you are all trapped inside a submarine. In Minecraft, you may travel massive distances and end up spending most of your time separate from each other.
-
-The games on the above list that are probably most like what I'm after are Sea of Thieves and Ark/Rust. However, the secret fourth category is: people I know must own the game. So, after all that, I was suggested Factorio, which I thought would be a bunch of fun to play with a bunch of people. Factorio doesn't pass the third criterion of "players are always vaguely close to each other", but it's a great game, so I'm sure I can allow it one strike. Since I've not played yet, it remains to be seen how close people remain to each other when playing: maybe people stick together more if they have proximity chat!
-There was only one problem with Factorio: it didn't have proximity chat. That, my dear friend, is why we're here. I wanted to play Factorio with proximity chat so much that I made it myself. Within these words lies the tales, struggle, and strife of that process.
-
-- Research
-- How do other games do it?
-- How can I do it for Factorio?
-- Using Mumble
-- Memory hacking?
-- Using the Link plugin?
-- Using the filesystem?
-
-
-
-
-- Making the Factorio Mod
-- Making the Mumble Plugin
-- Build the C files
-- Bundle the plugin
-- Spit out random data
-- Only run when
Factorio.exe
is running
-- Parse the Factorio log file
-- Check the log file exists
-- Check the log file is recent
-- Build it on Windows
-
-
-- It works! (for a bit)
-- It works! (weirdly)
-- It works! (actually)
-- Conclusion
-- People who helped
-- Testing it works!
-- Reddit thread ⇗
-- Factorio discord ⇗
-- Mumble Matrix ⇗
-
-
-- Links
-
-Research
-How do other games do it?
-The only game I had played with user-created proximity chat before was Among Us. I had remembered that we had all downloaded "BetterCrewLink", which was a desktop app, which connected to a voice server, connected to the game running on your machine, and somehow did proximity chat from that. Looking at the code on GitHub, the program read the memory addresses of things like player position, and also looked like it implemented its own entire VoIP system (Voice over IP).
-This seemed a lot of work. I didn't fancy creating (or even trying to clone) what is basically Discord or TeamSpeak, so I did some more Googling.
-How can I do it for Factorio?
-Googling around, the only mention I could find of Factorio and proximity voice chat was a single Reddit thread.
-
-Without this thread, I don't think I would have started trying to make a Factorio proximity chat mod. But, with the thread, I had some leads. Faxxobeat made me aware that Mumble - an open source voice chat client (like Discord or TeamSpeak) - had support for "positional audio" via "plugins". There were already plugins for many games and lots of documentation on PA (Positional Audio). This sounded like an approachable plan, since this way all I had to do to implement proximity chat in Factorio was make a plugin for Mumble, which would handle the rest of the voice chat. And, reading the requirements for a Mumble plugin, I just had to write a plugin which gave Mumble the player position, player name and the current game server. It seemed "easy enough".
-Using Mumble
-I found a lot of different documentation for Mumble and Mumble's PA. There was a wiki, a website, and some markdown files. These were, respectively: outdated with a banner saying as such; outdated with no such information; and up-to-date. Initially, I did not find the third guide (the up to date one), so naturally after seeing the wiki was outdated, I used the second, outdated (unbeknownst to me at the time) guide. This had several pages:
-
-That's a lot of docs. The guide above is very comprehensive, so I tried to follow it. However, as I said, it was outdated. Having followed links from the wiki which said "the wiki is outdated, please use the website", the potential that the website was outdated was not on my radar, so I ploughed on.
-Memory hacking?
-The plugin guide leads you through creating a plugin which searches a game's memory for memory addresses of the player position and other variables. I attempted this a little with Cheat Engine, but it led nowhere for Factorio. As I could've learnt by reading the Reddit thread I already found: Factorio does not use static memory addresses for player data. Thus, I could not use memory hacking to make a plugin.
-Using the Link plugin?
-The next option was the link plugin, which works generically for any game. This is meant to be for the developers of the game to implement themselves (by providing some known-location memory addresses which are updated with player position data, which Mumble can then find), but I also thought that it could be possible to make a mod which does similar (at game startup: write position data to memory and keep it updated when playing).
-Factorio provides a modding API, using Lua, making everyone's lives easier when it comes to modding, as you can just write a mod in Lua, and it should stay compatible with small game updates.
-This seems much more fun than other ecosystems like Minecraft where mods become unplayable because they have to be updated for each version of the game that releases.
-Since I wanted whatever I made to be long-lasting, I wanted to use the official modding API. This meant using Lua. Everything that I could do with code was now described by the Factorio API Docs. Unfortunately, playing with memory was not on this list, so using the Link plugin was also not possible.
-Using the filesystem?
-My final idea was that I could make a simple Factorio mod in Lua which writes the position of the player to a file, and then I could write a Mumble plugin in C which looks for and reads this file, exposing the data to Mumble's Positional Audio system. This would mean that to use the plugin, you need to install two things: the Factorio mod; and the Mumble plugin, but it also made the connection between Mumble and Factorio minimal, as either the mod or plugin could be easily changed without needing to change the other, since they were only interacting via file write or file read.
-At this point, I had popped my head into the Mumble Matrix chat via a link I found on the website and chatted with some developers about making the plugin. Thankfully, this is when I found out that I'd been following an outdated guide, and was pointed to the most recent, updated, and clear markdown documentation.
-Making the Factorio Mod
-The brief was clear: make a mod which took the player position, and write it to a file.
-I had never modded Factorio or used Lua before, so I read some Factorio modding tutorial and read about Lua too.
-Then, I joined the Factorio discord to ask how I could go about doing what I wanted. Less than 30 minutes¹ after my initial message, a user, Xorimuth, told me that you could write files with Factorio's write_file function, and provided a code snippet to do what I wanted:
-script.on_nth_tick(30, function()
+
+ As you can tell, I had a lot of fun playing Barotrauma; it probably
+ deserves a blog post of its own. When we played, we were usually
+ around 8 players, which, had we used Discord for voice chat, would
+ have been chaos trying to hear what everyone was saying. Proximity
+ chat added greatly to our enjoyment of the game, and planted the
+ question in my mind of which other games which could be as fun. In my
+ view, there are a few criteria which made Barotrauma great and that I
+ would like in another game that could be as fun. They are:
+
+
+ -
+ Proximity chat. Games which come to mind immediately which have this
+ are Among Us and Minecraft. There are
+ lists online.
+
+ -
+ Campaign-based. By this, I mean games where you play the same save,
+ and wouldn't start fresh every week. Among Us is out.
+
+ -
+ Players are... in proximity to each other. In Barotrauma, you can
+ always hear mutterings and ramblings of other people as you are all
+ trapped inside a submarine. In Minecraft, you may travel massive
+ distances and end up spending most of your time separate from each
+ other.
+
+
+
+ The games on the
+ above list
+ that are probably most like what I'm after are Sea of Thieves and
+ Ark/Rust. However, the secret fourth category is: people I know must
+ own the game. So, after all that, I was suggested
+ Factorio, which I thought would be
+ a bunch of fun to play with a bunch of people. Factorio doesn't
+ pass the third criterion of "players are always vaguely close to
+ each other", but it's a great game, so I'm sure I can
+ allow it one strike. Since I've not played yet, it remains to be
+ seen how close people remain to each other when playing: maybe people
+ stick together more if they have proximity chat!
+
+
+ There was only one problem with Factorio: it didn't have proximity
+ chat. That, my dear friend, is why we're here. I wanted to play
+ Factorio with proximity chat so much that I made it myself. Within
+ these words lies the tales, struggle, and strife of that process.
+
+
+ -
+ Research
+
+ -
+ How do other games do it?
+
+ -
+ How can I do it for Factorio?
+
+ -
+ Using Mumble
+
+ - Memory hacking?
+ -
+ Using the Link plugin?
+
+ -
+ Using the filesystem?
+
+
+
+
+
+ -
+ Making the Factorio Mod
+
+ -
+ Making the Mumble Plugin
+
+ - Build the C files
+ - Bundle the plugin
+ - Spit out random data
+ -
+ Only run when
Factorio.exe
is running
+
+ -
+ Parse the Factorio log file
+
+ -
+ Check the log file exists
+
+ -
+ Check the log file is recent
+
+ - Build it on Windows
+
+
+ - It works! (for a bit)
+ - It works! (weirdly)
+ - It works! (actually)
+ - Conclusion
+ -
+ People who helped
+
+ - Testing it works!
+ - Reddit thread ⇗
+ - Factorio discord ⇗
+ - Mumble Matrix ⇗
+
+
+ - Links
+
+ Research
+ How do other games do it?
+
+ The only game I had played with user-created proximity chat before was
+ Among Us. I
+ had remembered that we had all downloaded
+ "BetterCrewLink", which was a desktop app, which connected to a voice server,
+ connected to the game running on your machine, and somehow did
+ proximity chat from that. Looking at the code on GitHub, the program
+ read the memory addresses of things like player position, and also
+ looked like it implemented its own entire
+ VoIP system
+ (Voice over IP).
+
+
+ This seemed a lot of work. I didn't fancy creating (or even trying
+ to clone) what is basically Discord or TeamSpeak, so I did some more
+ Googling.
+
+ How can I do it for Factorio?
+
+ Googling around, the only mention I could find of Factorio and
+ proximity voice chat was a single
+ Reddit thread.
+
+
+
+
+
+ Without this thread, I don't think I would have started trying to
+ make a Factorio proximity chat mod. But, with the thread, I had some
+ leads.
+ Faxxobeat made me
+ aware that Mumble - an open
+ source voice chat client (like Discord or TeamSpeak) - had support for
+ "positional audio" via "plugins". There were
+ already
+ plugins for many games
+ and lots of documentation on PA (Positional Audio). This sounded like
+ an approachable plan, since this way all I had to do to implement
+ proximity chat in Factorio was make a plugin for Mumble, which would
+ handle the rest of the voice chat. And, reading the
+ requirements for a Mumble plugin, I just had to write a plugin which gave Mumble the player position,
+ player name and the current game server. It seemed "easy
+ enough".
+
+ Using Mumble
+
+ I found a lot of different documentation for Mumble and
+ Mumble's PA. There was a
+ wiki, a
+ website, and
+ some markdown files. These were, respectively: outdated with a banner saying as such;
+ outdated with no such information; and up-to-date. Initially, I did
+ not find the third guide (the up to date one), so naturally after
+ seeing the wiki was outdated, I used the second, outdated (unbeknownst
+ to me at the time) guide. This had several pages:
+
+
+
+ That's a lot of docs. The guide above is
+ very comprehensive, so I tried to follow it. However, as I
+ said, it was outdated. Having followed links from the wiki which said
+ "the wiki is outdated, please use the website", the
+ potential that the website was outdated was not on my radar, so I
+ ploughed on.
+
+ Memory hacking?
+
+ The plugin guide leads you through creating a plugin which searches a
+ game's memory for memory addresses of the player position and
+ other variables. I attempted this a little with Cheat Engine, but it
+ led nowhere for Factorio. As I could've learnt by reading the
+ Reddit thread
+ I already found: Factorio does not use static memory addresses for
+ player data. Thus, I could not use memory hacking to make a plugin.
+
+ Using the Link plugin?
+
+ The next option was the
+ link plugin, which works generically for any game. This is meant to be for the
+ developers of the game to implement themselves (by providing some
+ known-location memory addresses which are updated with player position
+ data, which Mumble can then find), but I also thought that it could be
+ possible to make a mod which does similar (at game startup: write
+ position data to memory and keep it updated when playing).
+
+
+ Factorio provides a modding API, using Lua, making everyone's
+ lives easier when it comes to modding, as you can just write a mod in
+ Lua, and it should stay compatible with small game updates. This seems
+ much more fun than other ecosystems like Minecraft where
+ mods become
+ unplayable
+ because they have to be
+ updated for
+ each version of
+ the game that
+ releases. Since
+ I wanted whatever I made to be long-lasting, I wanted to use the
+ official modding API. This meant using Lua. Everything that I could do
+ with code was now described by the
+ Factorio API Docs.
+ Unfortunately, playing with memory was not on this list, so using the
+ Link plugin was also not possible.
+
+ Using the filesystem?
+
+ My final idea was that I could make a simple Factorio mod in Lua which
+ writes the position of the player to a file, and then I could write a
+ Mumble plugin in C which looks for and reads this file, exposing the
+ data to Mumble's Positional Audio system. This would mean that to
+ use the plugin, you need to install two things: the Factorio mod; and
+ the Mumble plugin, but it also made the connection between Mumble and
+ Factorio minimal, as either the mod or plugin could be easily changed
+ without needing to change the other, since they were only interacting
+ via file write or file read.
+
+
+ At this point, I had popped my head into the Mumble Matrix chat via a
+ link I found on the website
+ and chatted with some developers about making the plugin. Thankfully,
+ this is when I found out that I'd been following an outdated
+ guide, and was pointed to the most recent, updated, and clear
+ markdown documentation.
+
+ Making the Factorio Mod
+
+ The brief was clear: make a mod which took the player position, and
+ write it to a file.
+
+
+ I had never modded Factorio or used Lua before, so I read some
+ Factorio modding tutorial
+ and read about Lua too.
+
+
+ Then, I joined the
+ Factorio discord to
+ ask how I could go about doing what I wanted. Less than 30 minutes¹
+ after my initial message, a user,
+ Xorimuth, told
+ me that you could write files with Factorio's
+ write_file
+ function, and provided a code snippet to do what I wanted:
+
+ script.on_nth_tick(30, function()
for _, player in pairs(game.connected_players) do
game.write_file("player_position.txt", serpent.dump(player.position), false, player.index)
end
end)
-This, basically, was the finished Factorio mod. I made some small changes and re-formatted it and the whole Factorio mod is one script and 12 lines:
-script.on_nth_tick(5, function()
+
+ This, basically, was the finished Factorio mod. I made some small
+ changes and re-formatted it and the whole Factorio mod is one script
+ and 12 lines:
+
+ script.on_nth_tick(5, function()
for index, player in pairs(game.connected_players) do
local info = "XYZ, Player, sUrface, Server\n" ..
"x: " .. player.position.x .. "\n" ..
@@ -192,13 +494,22 @@ Making the Factorio Mod
end
end)
-
+
+
+ In Lua, ..
concatenates strings and whitespace is
+ ignored. Fun :).
+
+
-In Lua, ..
concatenates strings and whitespace is ignored. Fun :).
-
-
-Every 1/12 of a second (5 ticks), this outputs something a text file into Factorio's script-output
folder that looks like:
-XYZ, Player, sUrface, Server
+
+ Every 1/12 of a second (5 ticks), this outputs something a text file
+ into
+ Factorio's script-output
folder
+ that looks like:
+
+ XYZ, Player, sUrface, Server
x: -54.8046875
y: 71.08203125
z: 0
@@ -206,26 +517,97 @@ Making the Factorio Mod
u: 1
s: alifeee
-
-
-You may complain at me for sUrface
, but I think it's neat.
-
+
+
+ You may complain at me for sUrface
, but
+ I think it's neat.
+
+
-That's it! Now for the Mumble plugin. I'm sure it will definitely be as easy and not take much, much longer.
-Making the Mumble Plugin
-After finding the up-to-date documentation for-real-this-time, I also found the Mumble plugin template. This was a simple implementation of a Mumble plugin, with the latest API, written in C. In theory, it was possible to use C++ or Rust to write the plugin, but to keep it simple, I decided to keep to C. I had also found that there was a Positional Audio Helper, which was only available in the pre-release of Mumble, version 1.5, so I installed that (which will come back to bite me, as you will see...). The helper showed all the data involved with positional audio:
-
-
-
-PA uses: position
(where you are), direction
(which way you're facing) and axis
(which way you're leaning, for games with leaning) for the player and the camera; Context
(usually a server ID) to determine if the players are in the same game-server; and Identity
(usually player ID) to tell players apart. If your context is the same as another person's, you will hear them based on where they are in the game. Positional audio!
-
+
+ That's it! Now for the Mumble plugin. I'm sure it will
+ definitely be as easy and not take much, much longer.
+
+ Making the Mumble Plugin
+
+ After finding the up-to-date documentation for-real-this-time, I also
+ found the
+ Mumble plugin template. This was a simple implementation of a Mumble plugin, with the
+ latest API, written in C. In theory, it was
+ possible to use C++ or Rust
+ to write the plugin, but to keep it simple, I decided to keep to C. I
+ had also found that there was a
+ Positional Audio Helper, which was only available in the pre-release of Mumble,
+ version 1.5, so I installed that (which will come back to bite me, as you will
+ see...). The helper showed all the data involved with positional
+ audio:
+
+
+
+
+
+
+ PA uses: position
(where you are),
+ direction
(which way you're facing) and
+ axis
(which way you're leaning, for games with
+ leaning) for the player and the camera;
+ Context
(usually a server ID) to determine if the
+ players are in the same game-server; and
+ Identity
(usually player ID) to tell players apart. If
+ your context is the same as another person's, you will hear them
+ based on where they are in the game. Positional audio!
+
+
-Now, I had a debug window showing lots of 0s that I needed to put values in, and a well-described plugin API, so I forked the Mumble plugin template and started developing.
-Build the C files
-First, I had to be able to build the plugin. After screwing around for too long installing GCC I decided to just use GitHub Actions to build the C file, as I found an official template for building multi-platform C and C++ projects. This built the plugin for Linux and Windows whenever I pushed to the repository. I also was able to build the plugin with GCC, for Linux, on WSL, but I hadn't managed to install it for Windows yet, and had to wait several minutes for the action to complete if I wanted a Windows version. This worked fine initially, as I mostly was writing and testing C code on Linux, then I would copy it into the main plugin file if I wanted to try it on Windows. Because I was just reading and writing a file initially, it didn't matter whether I was writing on Windows or Linux. At least, not until I wanted to test it at the same time as playing Factorio.
-Bundle the plugin
-Next, I wanted to make the plugin installable using the Mumble UI. Following the bundling guide, this involved writing a manifest.xml
file
-<?xml version="1.0" encoding="UTF-8"?>
+
+ Now, I had a debug window showing lots of 0s that I needed to put
+ values in, and a well-described plugin API, so I forked the
+ Mumble plugin template
+ and started developing.
+
+ Build the C files
+
+ First, I had to be able to build the plugin. After screwing around for
+ too long installing GCC I decided
+ to just use GitHub Actions to build the C file, as I found an
+ official template for building multi-platform C and C++ projects. This built the plugin for Linux and Windows whenever I pushed to
+ the repository. I also was able to build the plugin with GCC, for
+ Linux, on WSL, but I hadn't managed to install it for Windows yet,
+ and had to wait several minutes for the action to complete if I wanted
+ a Windows version. This worked fine initially, as I mostly was writing
+ and testing C code on Linux, then I would copy it into the main plugin
+ file if I wanted to try it on Windows. Because I was just reading and
+ writing a file initially, it didn't matter whether I was writing
+ on Windows or Linux. At least, not until I wanted to test it at the
+ same time as playing Factorio.
+
+ Bundle the plugin
+
+ Next, I wanted to make the plugin installable using the Mumble UI.
+ Following
+ the bundling guide, this involved writing a manifest.xml
file
+
+ <?xml version="1.0" encoding="UTF-8"?>
<bundle version="1.0.0">
<assets>
<plugin os="windows" arch="x64">plugin.dll</plugin>
@@ -235,22 +617,39 @@ Bundle the plugin
<version>1.0.0</version>
</bundle>
-...and then zipping the built C files and manifest.xml
file, and renaming the file to end in .mumble_plugin
. This is well summarised by the GitHub workflow that does exactly that:
-- name: Bundle
+
+ ...and then zipping the built C files and
+ manifest.xml
file, and renaming the file to end in
+ .mumble_plugin
. This is well summarised by the
+ GitHub workflow that does exactly that:
+
+ - name: Bundle
run: |
mv build/libfactorio_linux_x86_64.so libplugin.so
mv build/Release/plugin.dll plugin.dll
mv mumble/manifest.xml manifest.xml
zip -MM factorio.mumble_plugin manifest.xml libplugin.so plugin.dll
-
-
-Every character has a story. Here, the story is that little -MM
. Without it, zip
ignored any missing files. I spent a while wondering why my plugin didn't work before realising that manifest.xml
didn't exist, and zip
was just happily ignoring that fact.
-
+
+
+ Every character has a story. Here, the story is that little
+ -MM
. Without it, zip
ignored any missing
+ files. I spent a while wondering why my plugin didn't work
+ before realising that manifest.xml
didn't exist,
+ and zip
was just happily ignoring that fact.
+
+
-Spit out random data
-The function that Mumble calls to get positional data is mumble_fetchPositionalData
. To check it worked before I carried on, I first output random data to see it in the helper.
-bool mumble_fetchPositionalData(float *avatarPos, float *avatarDir, float *avatarAxis, float *cameraPos, float *cameraDir, float *cameraAxis, const char **context, const char **identity)
+ Spit out random data
+
+ The function that Mumble calls to get positional data is
+ mumble_fetchPositionalData
. To check it worked before I
+ carried on, I first output random data to see it in the helper.
+
+ bool mumble_fetchPositionalData(float *avatarPos, float *avatarDir, float *avatarAxis, float *cameraPos, float *cameraDir, float *cameraAxis, const char **context, const char **identity)
{
avatarPos[0] = 0.01f + ((float)rand() / (float)RAND_MAX) * 0.01f;
avatarPos[1] = 0.01f + ((float)rand() / (float)RAND_MAX) * 0.01f;
@@ -261,12 +660,29 @@ Spit out random data
return true;
}
-This worked great!
-
-Now I had remembered how C works, and had a better grasp of the Mumble API, I could start attaching the plugin to Factorio.
-Only run when Factorio.exe
is running
-At this stage, the plugin was always active. The first integration step was to get it to only activate if Factorio.exe
was running. Mumble occasionally calls mumble_initPositionalData
for each installed plugin to see if they should begin. In this case, we should begin (return OK) if the game is open.
-uint8_t mumble_initPositionalData(const char *const *programNames, const uint64_t *programPIDs, size_t programCount)
+ This worked great!
+
+
+
+
+ Now I had remembered how C works, and had a better grasp of the Mumble
+ API, I could start attaching the plugin to Factorio.
+
+
+ Only run when Factorio.exe
is running
+
+
+ At this stage, the plugin was always active. The first integration
+ step was to get it to only activate if Factorio.exe
was
+ running. Mumble occasionally calls
+ mumble_initPositionalData
for each installed plugin to
+ see if they should begin. In this case, we should begin (return OK) if
+ the game is open.
+
+ uint8_t mumble_initPositionalData(const char *const *programNames, const uint64_t *programPIDs, size_t programCount)
{
// programNames is a list of, e.g., ["Notion.exe", "System", "firefox.exe", "factorio.exe"]
// loop through programs, if FACTORIO_EXE is found, return MUMBLE_PDEC_OK
@@ -289,9 +705,12 @@ Only run when Factorio.exe
return MUMBLE_PDEC_OK;
}
-Parse the Factorio log file
-To get the data from the text file, it has to be parsed. This is done with this code
-int parse_factorio_logfile(float *x, float *y, float *z, int *player, int *surface, char **server, size_t *server_len, int *error)
+ Parse the Factorio log file
+
+ To get the data from the text file, it has to be parsed. This is done
+ with this code
+
+ int parse_factorio_logfile(float *x, float *y, float *z, int *player, int *surface, char **server, size_t *server_len, int *error)
{
f_data = c_read_file(factorioLogfile, &err, &f_size);
@@ -328,14 +747,27 @@ Parse the Factorio log file
}
}
-
+
+
+ There's some funky C stuff going on here. Functions can't
+ return multiple values, so the function arguments are pointers which
+ are edited (a way of getting data from a function).
+ strtok
is another weird one, which splits strings on a
+ value, requiring you to sometimes give the first argument
+ NULL
for it to return the second or
+ third split.
+
+
-There's some funky C stuff going on here. Functions can't return multiple values, so the function arguments are pointers which are edited (a way of getting data from a function). strtok
is another weird one, which splits strings on a value, requiring you to sometimes give the first argument NULL
for it to return the second or third split.
-
-
-Check the log file exists
-At this point, the plugin would now see Factorio.exe
and immediately try to open the log file. Problem is: it might not be there; if the user hasn't installed the Factorio mod yet, or not loaded a save. To protect against this, I wrote some C to check if the file exists before opening it
-int file_exists(const char *fname)
+ Check the log file exists
+
+ At this point, the plugin would now see Factorio.exe
and
+ immediately try to open the log file. Problem is: it might not be
+ there; if the user hasn't installed the Factorio mod yet, or not
+ loaded a save. To protect against this, I wrote some C to check if the
+ file exists before opening it
+
+ int file_exists(const char *fname)
{
FILE *file;
if ((file = fopen(fname, "r")))
@@ -346,53 +778,188 @@ Check the log file exists
return 0;
}
-Check the log file is recent
-The final issue I considered was that the plugin would still see the log file if you quit a game to the main menu. This would mean that you would still hear people from the most recent server you were connected to. To solve this, I wanted to either blank the log file, or write different data to it when you quit a server. However, Factorio doesn't allow executing code on exiting a save. So, my rudimentary solution was to just only enable the plugin if the log file was written recently. This way, when you quit, the file grows stale so is no longer used. I did this with a fairly simple C function (here, simple stands for "short" and not "the code is understandable")
-time_t get_file_modified_time(char *path)
+ Check the log file is recent
+
+ The final issue I considered was that the plugin would still see the
+ log file if you quit a game to the main menu. This would mean that you
+ would still hear people from the most recent server you were connected
+ to. To solve this, I wanted to either blank the log file, or write
+ different data to it when you quit a server. However, Factorio
+ doesn't allow
+ executing code on exiting a save. So, my rudimentary solution was to
+ just only enable the plugin if the log file was written recently. This
+ way, when you quit, the file grows stale so is no longer used. I did
+ this with a fairly simple C function (here, simple stands for
+ "short" and not "the code is
+ understandable")
+
+ time_t get_file_modified_time(char *path)
{
struct stat attr;
stat(path, &attr);
return attr.st_mtime;
}
-Build it on Windows
-At this point, I’d only been able to compile the code locally on Linux (via WSL). For Windows, I used GitHub actions. This was possible as I didn’t yet need to test it with Mumble, as it was mainly just opening and parsing a file, which could be done on Linux. However, I use Windows for both Factorio and Mumble. Building via Actions took around 5 minutes; I wanted to be able to compile locally for a quicker development cycle. This was ultimately a pain as I didn’t want to install Visual Studio on my (not-a-lot-of-space) laptop, so I tried to install GCC for windows, which had many issues. I ended up finding that you could install Visual Studio build tools and use it from the CLI.
-
-
-
-Installing Visual Studio Build Tools. I've never seen so many installation options or checkboxes than in the Visual Studio installer (which is an entire program in itself).
-
+ Build it on Windows
+
+ At this point, I’d only been able to compile the code locally on Linux
+ (via WSL). For Windows, I used GitHub actions. This was possible as I
+ didn’t yet need to test it with Mumble, as it was mainly just opening
+ and parsing a file, which could be done on Linux. However, I use
+ Windows for both Factorio and Mumble. Building via Actions took around
+ 5 minutes; I wanted to be able to compile locally for a quicker
+ development cycle. This was ultimately a pain as I didn’t want to
+ install Visual Studio on my (not-a-lot-of-space) laptop, so I tried to
+ install GCC for windows, which had many issues. I ended up finding
+ that you could install Visual Studio build tools and use it from the
+ CLI.
+
+
+
+
+
+
+ Installing Visual Studio Build Tools. I've never seen so many
+ installation options or checkboxes than in the Visual Studio
+ installer (which is an entire program in itself).
+
+
-After adding a bunch of functions which were available on Linux but missing on Windows, I could now build the mumble plugin locally on Windows. With one command I could build, and package the code into factorio.mumble_plugin
, so I could quickly change the code and reinstall it.
-cmake -S .\mumble\ -B .\build\ -DCMAKE_C_COMPILER=cl; cmake --build .\build\ --config Release; bash package_windows.sh
+
+ After adding a bunch of functions which were available on Linux but
+ missing on Windows, I could now build the mumble plugin locally on
+ Windows. With
+ one command
+ I could build, and package the code into
+ factorio.mumble_plugin
, so I could quickly change the
+ code and reinstall it.
+
+ cmake -S .\mumble\ -B .\build\ -DCMAKE_C_COMPILER=cl; cmake --build .\build\ --config Release; bash package_windows.sh
-The build and package command for Windows Powershell
+
+ The build and package command for Windows Powershell
+
-It works! (for a bit)
-Now, I had followed the steps that I dreamt up and had a Factorio mod which wrote the player position to a file, and a Mumble plugin which read from that file, parsed the position, and gave it to Mumble. Opening Factorio and Mumble at the same time, it worked!
-
-
-
-The PA helper shows me as in-game, and correctly displays my position!
-
-
-There was only one small, tiny, nagging issue.
-Every time I started it, Mumble crashed after 10 or so seconds.
-
-
+ It works! (for a bit)
+
+ Now, I had followed the steps that I dreamt up and had a Factorio mod
+ which wrote the player position to a file, and a Mumble plugin which
+ read from that file, parsed the position, and gave it to Mumble.
+ Opening Factorio and Mumble at the same time, it worked!
+
+
+
+
+
+
+ The PA helper shows me as in-game, and correctly displays my
+ position!
+
+
-:(
-
+ There was only one small, tiny, nagging issue.
+ Every time I started it, Mumble crashed after 10 or so seconds.
+
+
+
+
+ :(
+
-This was the first point at which I didn't know what was going on. Initially, I thought there may be problems with file reading/writing at the same time. That is, that Factorio would write a file in the middle of Mumble trying to read it. So, I tried to fix it by reducing the read-time of the file, and by returning an error if the file was changed midway through reading it. This didn't fix it: it was still crashing. I had now run out of guesses for why.
-In its current implementation, the code tried to read the file, and if it failed to read it, did nothing. If the file was there and was opened with no issue, then it continued as normal. So what caused the crash?
-After many days of thinking and a few hours of debugging, most of which I've forgotten what I tried, I eventually just started printing out the log file and watching it with my eyes. It looked normal, apart from it was supposed to print every 12th of a second, and the rhythm was slightly off (you can tell how long I sat watching scrolling text). This was when I realised I probably should have been printing a header, or something in-between prints, because what was happening was that sometimes the file was empty. I am still not sure why this is the case, but I assume it is something to do with Factorio falling behind on code execution, so rather than waiting, it just writes an empty file and moves on to the next task.
-This, naturally, meant that the C code tried to find the "x: "
row, failed, and crashed (perhaps there's also something to say here about my error handling while parsing the file...). I added a catch for if the file was empty and rebuilt the plugin.
-It works! (weirdly)
-Now it wasn't crashing, I could test the whole reason for making this: the voice chat! I found a friend, called "a game dev who hates their corporate job" [sic], and we hopped in a game together, installed the mod and plugin, and started monologuing (the sound-test type, not the vanity type).
-After a lot of running around and a lot of mental gymnastics, we figured out that it 'sort of' worked. This is a synonym for 'didn't work but spicily'. We found that our 'ears' were stuck at the map origin, (0, 0)
, and our 'mouths' were attached to our players. This meant that if one of us stood in the centre of the map, and the other walked around, proximity chat worked as expected (their volume decreased, and they came out of the left/right headphones), but if we both walked around, we could still hear each other as if we were stood still at (0, 0)
.
-To be honest, I still can't explain how this happens, but I already had a suspicion why: because I hadn't actually thought about Mumble's coordinate system. I just plugged Factorio's x
and y
coordinates into Mumble's. After reading Mumble's documentation, I came up with a transform from Factorio to Mumble coordinates and rewrote the code.
-// Factorio coordinates are:
+
+ This was the first point at which I didn't know what was going on.
+ Initially, I thought there may be problems with file reading/writing
+ at the same time. That is, that Factorio would write a file in the
+ middle of Mumble trying to read it. So, I
+ tried to fix it
+ by reducing the read-time of the file, and by returning an error if
+ the file was changed midway through reading it. This didn't fix
+ it: it was still crashing. I had now run out of guesses for why.
+
+
+ In its current implementation, the code tried to read the file, and if
+ it failed to read it, did nothing. If the file was there and was
+ opened with no issue, then it continued as normal. So what caused the
+ crash?
+
+
+ After many days of thinking and a few hours of debugging, most of
+ which I've forgotten what I tried, I eventually just started
+ printing out the log file and watching it with my eyes. It looked
+ normal, apart from it was supposed to print every 12th of a second,
+ and the rhythm was slightly off (you can tell how long I sat watching
+ scrolling text). This was when I realised I probably should have been
+ printing a header, or something in-between prints, because what was
+ happening was that sometimes the file was empty. I am still
+ not sure why this is the case, but I assume it is something to do with
+ Factorio falling behind on code execution, so rather than waiting, it
+ just writes an empty file and moves on to the next task.
+
+
+ This, naturally, meant that the C code tried to find the
+ "x: "
row, failed, and crashed (perhaps
+ there's also something to say here about my error handling while
+ parsing the file...). I
+ added a catch
+ for if the file was empty and rebuilt the plugin.
+
+ It works! (weirdly)
+
+ Now it wasn't crashing, I could test the whole reason for making
+ this: the voice chat! I found a friend, called "a game dev who
+ hates their corporate job" [sic], and we hopped in a game
+ together, installed the mod and plugin, and started monologuing (the
+ sound-test type, not the vanity type).
+
+
+ After a lot of running around and a lot of mental gymnastics, we
+ figured out that it 'sort of' worked. This is a synonym for
+ 'didn't work but spicily'. We found that our
+ 'ears' were stuck at the map origin, (0, 0)
, and
+ our 'mouths' were attached to our players. This meant that if
+ one of us stood in the centre of the map, and the other walked around,
+ proximity chat worked as expected (their volume decreased, and they
+ came out of the left/right headphones), but if we both walked around,
+ we could still hear each other as if we were stood still at
+ (0, 0)
.
+
+
+ To be honest, I still can't explain how this happens, but I
+ already had a suspicion why: because I hadn't actually thought
+ about Mumble's coordinate system. I just plugged Factorio's
+ x
and y
coordinates into Mumble's. After
+ reading
+ Mumble's documentation, I came up with a transform from Factorio to Mumble coordinates and
+ rewrote the code.
+
+ // Factorio coordinates are:
// x: east- west+
// y: north- south+
@@ -406,58 +973,154 @@ It works! (weirdly)
// y: Factorio z
// z: Factorio -y
-The final issue I had was that on Mumble 1.5 (experimental release), the voice chat volume never went silent, no matter how far away someone was. However, this was an issue with Mumble, and already known about. This meant that we had to use Mumble 1.4. The negative with that was that there was no PA Viewer, but since the plugin was already made, that was fine enough. It would just require reinstalling Mumble 1.5 to debug it again.
-It works! (actually)
-After all that, it worked!
-
-
-
-This time the coordinates are correct!
-
+
+ The final issue I had was that on Mumble 1.5 (experimental release),
+ the voice chat volume never went silent, no matter how far away
+ someone was. However, this was an issue with Mumble, and
+ already known about. This meant that we had to use Mumble 1.4. The negative with that
+ was that there was no PA Viewer, but since the plugin was already
+ made, that was fine enough. It would just require reinstalling Mumble
+ 1.5 to debug it again.
+
+ It works! (actually)
+ After all that, it worked!
+
+
+
+
+ This time the coordinates are correct!
+
-The only further thing I did was grab two more friends to play a four-player game of Factorio for 20 minutes to test the entire process in-situ. This worked great! We could hear each other when close, and could do our own things in pairs!
-I cleaned up the presentation of the project, made a logo, and made the 1.0.0 release. The mod is available on the Factorio mods website and the source code on the GitHub :)
-
-Conclusion
-To wrap things up, I also commented on the original Reddit thread telling the author I'd made the mod.
-The only thing left to do now is... play the game! As mentioned in the introduction, I hope to play a 'big game' of Factorio, which should be helped greatly by the option of proximity-based voice chat.
-As of writing, there are six open issues on the GitHub, so... still lots to do! This was a fun project to create, and I've definitely learnt a lot. [Other conclusionary remarks redacted]
-Go forth and chat!
-People who helped
-Lots of people helped me make this! As well as the standard anonymous forum people who provided C functions, help, and debugging ideas, I had a lot of help from others. Here are some!
-Everyone's help was invaluable, and I wouldn't have been developing this if not for it :)
-Testing it works!
-
-- A game dev who hates their corporate job [sic]
-- Roberto
-- Branton
-
-Reddit thread ⇗
-
-Factorio discord ⇗
-
-- Xorimuth
-- justarandomgeek
-- Solonarv, Mernom, Danielv123
-
-Mumble Matrix ⇗
-
-- @davidebeatrici
-- @hartmnt
-- @krzmbrzl_raven
-
-Links
-
+
+ The only further thing I did was grab
+ two more friends to play a four-player
+ game of Factorio for 20 minutes to test the entire process in-situ.
+ This worked great! We could hear each other when close, and could do
+ our own things in pairs!
+
+
+ I cleaned up the presentation of the project, made a
+ logo, and made the
+ 1.0.0 release. The mod is available on the
+ Factorio mods website
+ and the source code on
+ the GitHub
+ :)
+
+
+
+
+ Conclusion
+
+ To wrap things up, I also
+ commented on the original Reddit thread
+ telling the author I'd made the mod.
+
+
+ The only thing left to do now is... play the game! As mentioned in the
+ introduction, I hope to play a 'big game' of Factorio, which
+ should be helped greatly by the option of proximity-based voice chat.
+
+
+ As of writing, there are six
+ open issues
+ on the GitHub, so... still lots to do! This was a fun project to
+ create, and I've definitely learnt a lot. [Other conclusionary
+ remarks redacted]
+
+ Go forth and chat!
+ People who helped
+
+ Lots of people helped me make this! As well as the standard anonymous
+ forum people who provided C functions, help, and debugging ideas, I
+ had a lot of help from others. Here are some!
+
+
+ Everyone's help was invaluable, and I wouldn't have been
+ developing this if not for it :)
+
+ Testing it works!
+
+ - A game dev who hates their corporate job [sic]
+ - Roberto
+ - Branton
+
+
+ Reddit thread
+ ⇗
+
+
+
+ Factorio discord ⇗
+
+
+ - Xorimuth
+ - justarandomgeek
+ - Solonarv, Mernom, Danielv123
+
+
+ Mumble Matrix
+ ⇗
+
+
+ - @davidebeatrici
+ - @hartmnt
+ - @krzmbrzl_raven
+
+ Links
+
@@ -465,7 +1128,7 @@ Links
Comments
Email me →
- alifeee.web@outlook.com
+ alifeee@alifeee.net
:)
@@ -485,7 +1148,7 @@
Comments
Linktree
-
+
Email
diff --git a/font-workshop/index.html b/font-workshop/index.html
index 162151f..bc8c8c1 100644
--- a/font-workshop/index.html
+++ b/font-workshop/index.html
@@ -113,88 +113,221 @@ alifeee's blog
- I ran a computer font-making workshop!
-
-This week I ran a computer font-making workshop at my local hackspace. It was a bunch of fun, and I really enjoyed seeing the creativity come out of people via the medium of creating typefaces :)
-Why?
-I like fonts
-Who, Where, When?
-I ran the workshop at my local hackspace. I'd seen that they had run workshops before on knife-making and other things, and I thought it would be neat if I did something similarly collective. Often, people are together at the hackspace, which I enjoy in and of itself. But, it is extra neat if people can be together and all be working on similar things.
-About three or four weeks ago, I decided to just "do it", and I made up a sign and put it up at the hackspace.
-
-
-
-Some have pointed out an irony that a poster for a computer font workshop was handwritten...
-
-
-As far as I was concerned, "a workshop" was not really an established idea. But that's part of the reason I like community spaces like the hackspace: I can pretend something is an established idea and people will believe it is.
-I didn't start with a great plan, but rather started by motivating myself to create a plan (by putting up the poster). This turned out to be a nice method of motivation, as I had set a date for my "workshop", which forced me to consider what a "workshop" would involve.
-What does a workshop involve?
-I ended up giving a short presentation about why I like fonts, some things to think about when designing a font, and an overview of how to use FontForge, which is the program that I made BogFace in.
-The presentation
-I thought about using Google Slides to make a presentation. However, you can't use custom fonts, which was... kind of a killer for a font workshop.
-I went with RevealJS, which I had seen one of my computer-loving lecturers use at university. It's quite neat to use, mainly because everything is written in HTML. I guess I am fate-bound to never use a WYSIWYG editor again.
-The presentation is hosted at https://alifeee.co.uk/font-workshop/, but since it is a website, I can also embed it here! Have a scuttle around (press space to slow down progress.)
-
-
-
-
-If I do another workshop in the future, I will probably update this a bit, and this embed would change :)
-
-
-What people made
-I helped five people make their own fonts. Each one went about it quite (or slightly, depending on how much you care about fonts) differently.
-No method was wrong. Some methods were slower, fostering - I think - more appreciation for digital graphic work. All methods were very creative, and it was great to see different ways people went about making a font.
-Described briefly, and each description written in their own font, here are the ways people created their fonts:
-(Some are incomplete. Some will be updated as time passes.)
-
-
-
Auto-traced handwriting
-
Tanya¹ did what many designate the "classic move" in font-making: they made a handwriting font.
-
The method was to draw the letters a through z on paper and take a picture of it. Then, each letter was isolated into a bitmap image of each letter. potrace was used to convert the bitmap images into SVG images, which were then imported into FontForge, where they could be resized and moved around to look good.
-
-
-
-
-
Manually traced hand-designed letters
-
Ivanka¹ drew some guidelines on paper, and designed and drew block letters on the sheet. Then, they took a picture of the hand-drawn letters and digitised them manually, using the vector tools in FontForge.
-
-
-
-
-
Designed a Morse code font
-
Dragomir¹ designed a Morse font. You are reading it now.
-
-
-
-
-
-
Katya¹ designed their letter forms entirely digitally, within FontForge. After a few, they were able to copy stylistic parts of letters to other letters, such as the caps of "b" and "d".
-
-
-
-
-
Stroke-expanded lines drawn via touchscreen
-
Tomislav¹ used their touchscreen laptop to draw the letters with a single stroke, and then used FontForge's "Expand Stroke" to turn the one-dimensional drawings into two-dimensional vector shapes.
-
-
-I'd love to do another workshop!
-I had a lot of fun helping people make fonts, through thinking about design to how to practically using tools. It was very interesting and cool to me that each person involved made their font differently.
-In terms of how I ran it, and my presentation, I have some ideas of how to make things clearer and easier to understand.
-It was very fun to do, and I'd love to run another font workshop!
-Resources
-
-
-
+
+ I ran a computer font-making workshop!
+
+
+
+ This week I ran a computer font-making workshop at my local hackspace.
+ It was a bunch of fun, and I really enjoyed seeing the creativity come
+ out of people via the medium of creating typefaces :)
+
+ Why?
+ I like fonts
+ Who, Where, When?
+
+ I ran the workshop at my local hackspace. I'd seen that they had
+ run workshops before on knife-making and other things, and I thought
+ it would be neat if I did something similarly collective. Often,
+ people are together at the hackspace, which I
+ enjoy in and of itself. But,
+ it is extra neat if people can be together and all be working on
+ similar things.
+
+
+ About three or four weeks ago, I decided to just "do it",
+ and I made up a sign and put it up at the hackspace.
+
+
+
+
+
+
+ Some have pointed out an irony that a poster for a computer font
+ workshop was handwritten...
+
+
+
+
+ As far as I was concerned, "a workshop" was not really an
+ established idea. But that's part of the reason I like community
+ spaces like the hackspace: I can pretend something is an established
+ idea and people will believe it is.
+
+
+ I didn't start with a great plan, but rather started by motivating
+ myself to create a plan (by putting up the poster). This turned out to
+ be a nice method of motivation, as I had set a date for my
+ "workshop", which forced me to consider what a
+ "workshop" would involve.
+
+ What does a workshop involve?
+
+ I ended up giving a short presentation about why I like fonts, some
+ things to think about when designing a font, and an overview of how to
+ use FontForge, which is the program
+ that I made BogFace in.
+
+ The presentation
+
+ I thought about using Google Slides to make a presentation. However,
+ you can't use custom fonts, which was... kind of a killer for a
+ font workshop.
+
+
+ I went with RevealJS, which I had
+ seen one of my computer-loving lecturers use at university. It's
+ quite neat to use, mainly because everything is written in HTML. I
+ guess I am fate-bound to never use a WYSIWYG editor again.
+
+
+ The presentation is hosted at
+ https://alifeee.co.uk/font-workshop/, but since it is a website, I can also embed it here! Have a scuttle
+ around (press space to slow down progress.)
+
+
+
+
+
+ If I do another workshop in the future, I will probably update this
+ a bit, and this embed would change :)
+
+
+
+ What people made
+
+ I helped five people make their own fonts. Each one went about it
+ quite (or slightly, depending on how much you care about fonts)
+ differently.
+
+
+ No method was wrong. Some methods were slower, fostering - I think -
+ more appreciation for digital graphic work. All methods were very
+ creative, and it was great to see different ways people went about
+ making a font.
+
+
+ Described briefly, and each description written in their own font,
+ here are the ways people created their fonts:
+
+ (Some are incomplete. Some will be updated as time passes.)
+
+
Auto-traced handwriting
+
+ Tanya¹ did what many designate the
+ "classic move" in font-making: they made a handwriting
+ font.
+
+
+ The method was to draw the letters a through z on paper and take a
+ picture of it. Then, each letter was isolated into a bitmap image of
+ each letter.
+ potrace was used to
+ convert the bitmap images into SVG images, which were then imported
+ into FontForge, where they could be resized and moved around to look
+ good.
+
+
+
+
+
+ Manually traced hand-designed letters
+
+
+ Ivanka¹ drew some guidelines on paper, and
+ designed and drew block letters on the sheet. Then, they took a
+ picture of the hand-drawn letters and digitised them manually, using
+ the vector tools in FontForge.
+
+
+
+
+
Designed a Morse code font
+
+ Dragomir¹ designed a Morse font. You are
+ reading it now.
+
+
+
+
+
+
+ Katya¹ designed their letter forms entirely
+ digitally, within FontForge. After a few, they were able to copy
+ stylistic parts of letters to other letters, such as the caps of
+ "b" and "d".
+
+
+
+
+
+ Stroke-expanded lines drawn via touchscreen
+
+
+ Tomislav¹ used their touchscreen laptop to
+ draw the letters with a single stroke, and then used FontForge's
+ "Expand Stroke"
+ to turn the one-dimensional drawings into two-dimensional vector
+ shapes.
+
+
+
+
+ I'd love to do another workshop!
+
+
+ I had a lot of fun helping people make fonts, through thinking about
+ design to how to practically using tools. It was very interesting and
+ cool to me that each person involved made their font differently.
+
+
+ In terms of how I ran it, and my presentation, I have some ideas of
+ how to make things clearer and easier to understand.
+
+
+ It was very fun to do, and I'd love to run another font workshop!
+
+ Resources
+
+
+
@@ -202,7 +335,7 @@
Comments
Email me →
- alifeee.web@outlook.com
+ alifeee@alifeee.net
:)
@@ -222,7 +355,7 @@
Comments
Linktree
-
+
Email
diff --git a/gists/index.html b/gists/index.html
index 01a8651..8ba6843 100644
--- a/gists/index.html
+++ b/gists/index.html
@@ -98,128 +98,521 @@ alifeee's blog
- Why I like (GitHub) gists and a short tour through ones I have created
-
-I like sharing code and instructions. Thus, I like gists.
-
-- What are gists?
-- Why I like creating gists
-- I can share them with people
-- I can share them with myself in the future
-- The ramblings of my existence can end up in the same place
-
-
-- Why I like finding other people's gists
-- Someone else has probably done what I want to do before
-
-
-- I could or should put things elsewhere (not on GitHub)
-- My gists, or "the gist-list"
-- BLOG POSTS
-- 1. how to start blogging
-- 2. a hat blog
-
-
-- JUST DATA
-- DATA I MANUALLY MADE
-- 3. my spotify wrapped 2023
-- 4. a toki pona word list
-- 5. my vscode extension list
-
-
-- DATA THAT'S AUTOMATICALLY UPDATED
-- 6. my json resume
-- 7. my web bookmarks
-
-
-
-
-- HOW-TOS
-- THINGS I WANTED TO DO MULTIPLE TIMES
-- 8. how to generate and host a Factorio map
-- 9. how to download data from Toggl's api
-- 10. reusable ffmpeg commands
-- 11. how to make bar charts in bash
-- 12. how to make graphs in bash
-
-
-- THINGS THAT OTHER PEOPLE COULD WANT TO DO
-- 13. a script to remove all styles from an html file
-- 14. common RSS extensions
-- 15. a script to combine Squarespace RSS feeeds
-- 16. a script to convert font files to css styles
-- 17. a script to convert gpl files to css styles
-
-
-- HOW TO SET UP THINGS ON A LINUX SERVER
-- 18. how to set up rsa encryption keys
-- 19. how to set up nginx
-- 20. how to transfer folders over scp
-- 21. how to run a program as a service with systemd
-- 22. how to set up a mumble server
-- 23. how to install ruby and jekyll on linux
-- 24. how to set up ftp on linux
-
-
-
-
-
-
-- The end
-
-What are gists?
-GitHub Gists are "some text on the Internet". Usually, people put code snippets or Markdown in them, and then can share a link to anyone. It's like Pastebin but without (explicit) ads. Here's an example gist and here's the same on Pastebin.
-Gists can be used for blog posts, or just to share copied text, or to host a single-branch version controlled script or code snippet. They are also often used to host data which is automatically updated from elsewhere, and can be referenced as the most up-to-date version of that data, for example by ideas like https://jsonresume.org/.
-Anyone with a GitHub account can make a gist. It's a very easy way to share nicely formatted text (for example in Markdown), which is why it's the first - and most simple - thing I suggest in my "how to blog" guide.
-There are good reasons you may not want to support GitHub. There are other ways to share snippets, with other gist tools, Pastebin, and other options. However, a lot of other code- or text-sharing websites seem fleeting, have ads, and do not look as nice (honourable mention here to https://wormhole.app/, a website for sharing files that looks incredible.)
-Why I like creating gists
-I like creating gists because they make text easy to share with two groups of people. Those two groups are...
-I can share them with people
-The first group of people is "other people", either specifically for someone, or just information or code I share a lot, so I like having a quick link to it. Gists I've made in this category include:
-
-- how to create a blog? - I share this one with people whenever they muse about blogging and talk about using some complicated- or expensive-sounding tool, to try and convince them that they need not take on such an undertaking, and can just "put text on the Internet".
-- Remove all CSS styles from HTML files with bash - this is a bash script I wrote and shared for CSS Naked Day 2024. There were lots of ways of removing styles for site-builders and site-backends, but none for pure HTML.
-- How to use Ruby and Jekyll on Linux - when I set up Jekyll to edit a website for the first time, it was really confusing, partly because I'd never used Ruby before.
-
-I can share them with myself in the future
-The second group of people is really just one person, and they are "me in the future". Most of my usage of gists has been to remember how I did some specific thing with code or how I installed something. Writing it down in the first place help future me a lot to remember, because all I have to remember is in what context I did the thing, and then I can find out exactly how by reading the gist. Some examples of gists that have been very helpful to future- (well, now past-) me are:
-
-The ramblings of my existence can end up in the same place
-I make a lot of random scripts. In another world, they would end up either buried in random repositories on GitHub, or buried in random folders on my computer or laptop. They would get lost.
-Gists make it easy to paste a script somewhere, and then find it later, as they are all (I'm sure much to GitHub's enjoyment) in the same place.
-Why I like finding other people's gists
-More than just being able to share my own code, I like gists because other people have the same ideas as me!
-Someone else has probably done what I want to do before
-If I'd like to accomplish a small scripting task, understand something self-contained, or find a code snippet for a specific task, I often search for it on the web. Unfortunately, in our Lord's year 2024, pages and pages of whatever search I make are mostly AI garbage (here is an article I have not read to pretend to verify my point). One help here is independent search engines like Marginalia Search or Wiby. While they are fun for exploring a more indie version of the web, I also find adding "site:gist.github.com"
to my web search often results in finding exactly what I want to do.
-For example, here is a small list of gists from my Internet history that I've found to be useful recently (and as a by-product, an eye into my life and desires for the past several months).
-
-I could or should put things elsewhere (not on GitHub)
-The existence of GitHub in the above has mainly been a sidenote. The main thing that excites me about gists is the collaborative nature of them. This is not something that GitHub must have control over, and indeed something that they probably shouldn't have control over.
-I've been reading recently a lot about self- or community-hosted alternatives to different things like Git servers (like sourcehut) and, I use Mastodon (talking of self-hosting, I'd like to find an instance that's not mastodon.social) a lot.
-I could put my snippets on my website, or something more free. But, I haven't. Yet.
-My gists, or "the gist-list"
-The list is long. I keep comments brief. I have categorised them as to my whims. The code blocks show either the full gist, or - if you see "...
" - a snippet or section of it.
-BLOG POSTS
-
-# How to start blogging
+
+ Why I like (GitHub) gists and a short tour through ones I have created
+
+
+ I like sharing code and instructions. Thus, I like gists.
+
+ - What are gists?
+ -
+ Why I like creating gists
+
+ -
+ I can share them with people
+
+ -
+ I can share them with myself in the future
+
+ -
+ The ramblings of my existence can end up in the same place
+
+
+
+ -
+ Why I like finding other people's gists
+
+ -
+ Someone else has probably done what I want to do before
+
+
+
+ -
+ I could or should put things elsewhere (not on GitHub)
+
+ -
+ My gists, or "the gist-list"
+
+ -
+ BLOG POSTS
+
+ -
+ 1. how to start blogging
+
+ - 2. a hat blog
+
+
+ -
+ JUST DATA
+
+ -
+ DATA I MANUALLY MADE
+
+ -
+ 3. my spotify wrapped 2023
+
+ -
+ 4. a toki pona word list
+
+ -
+ 5. my vscode extension list
+
+
+
+ -
+ DATA THAT'S AUTOMATICALLY UPDATED
+
+ - 6. my json resume
+ -
+ 7. my web bookmarks
+
+
+
+
+
+ -
+ HOW-TOS
+
+ -
+ THINGS I WANTED TO DO MULTIPLE TIMES
+
+ -
+ 8. how to generate and host a Factorio map
+
+ -
+ 9. how to download data from Toggl's api
+
+ -
+ 10. reusable ffmpeg commands
+
+ -
+ 11. how to make bar charts in bash
+
+ -
+ 12. how to make graphs in bash
+
+
+
+ -
+ THINGS THAT OTHER PEOPLE COULD WANT TO DO
+
+ -
+ 13. a script to remove all styles from an html
+ file
+
+ -
+ 14. common RSS extensions
+
+ -
+ 15. a script to combine Squarespace RSS feeeds
+
+ -
+ 16. a script to convert font files to css styles
+
+ -
+ 17. a script to convert gpl files to css styles
+
+
+
+ -
+ HOW TO SET UP THINGS ON A LINUX SERVER
+
+ -
+ 18. how to set up rsa encryption keys
+
+ -
+ 19. how to set up nginx
+
+ -
+ 20. how to transfer folders over scp
+
+ -
+ 21. how to run a program as a service with systemd
+
+ -
+ 22. how to set up a mumble server
+
+ -
+ 23. how to install ruby and jekyll on linux
+
+ -
+ 24. how to set up ftp on linux
+
+
+
+
+
+
+
+ - The end
+
+ What are gists?
+
+ GitHub Gists are "some
+ text on the Internet". Usually, people put code snippets or
+ Markdown in them, and then can share a link to anyone. It's like
+ Pastebin but without (explicit)
+ ads. Here's
+ an example gist
+ and here's
+ the same on Pastebin.
+
+
+ Gists can be used for blog posts, or just to share copied text, or to
+ host a single-branch version controlled script or code snippet. They
+ are also often used to host data which is automatically updated from
+ elsewhere, and can be referenced as the most up-to-date version of
+ that data, for example by ideas like
+ https://jsonresume.org/.
+
+
+ Anyone with a GitHub account can make a gist. It's a very easy way
+ to share nicely formatted text (for example in Markdown), which is why
+ it's the first - and most simple - thing I suggest in my
+ "how to blog" guide.
+
+
+ There are
+ good reasons
+ you may not want to support GitHub. There are other ways to share
+ snippets, with
+ other gist tools,
+ Pastebin, and other options.
+ However, a lot of other code- or text-sharing websites seem fleeting,
+ have ads, and do not look as nice (honourable mention here to
+ https://wormhole.app/, a website
+ for sharing files that looks incredible.)
+
+ Why I like creating gists
+
+ I like creating gists because they make text easy to share with two
+ groups of people. Those two groups are...
+
+ I can share them with people
+
+ The first group of people is "other people", either
+ specifically for someone, or just information or code I share a lot,
+ so I like having a quick link to it. Gists I've made in this
+ category include:
+
+
+ -
+ how to create a blog?
+ - I share this one with people whenever they muse about blogging and
+ talk about using some complicated- or expensive-sounding tool, to
+ try and convince them that they need not take on such an
+ undertaking, and can just "put text on the Internet".
+
+ -
+ Remove all CSS styles from HTML files with bash
+ - this is a bash script I wrote and shared for
+ CSS Naked Day 2024.
+ There were lots of ways of removing styles for site-builders and
+ site-backends, but none for pure HTML.
+
+ -
+ How to use Ruby and Jekyll on Linux
+ - when I set up Jekyll to edit a website for the first time, it was
+ really confusing, partly because I'd never used Ruby before.
+
+
+
+ I can share them with myself in the future
+
+
+ The second group of people is really just one person, and they are
+ "me in the future". Most of my usage of gists has been to
+ remember how I did some specific thing with code or how I installed
+ something. Writing it down in the first place help future me
+ a lot to remember, because all I have to remember is in what
+ context I did the thing, and then I can find out exactly how by
+ reading the gist. Some examples of gists that have been very helpful
+ to future- (well, now past-) me are:
+
+
+
+ The ramblings of my existence can end up in the same place
+
+
+ I make a lot of random scripts. In another world, they would end up
+ either buried in random repositories on GitHub, or buried in random
+ folders on my computer or laptop. They would get lost.
+
+
+ Gists make it easy to paste a script somewhere, and then find it
+ later, as they are all (I'm sure much to GitHub's enjoyment)
+ in the same place.
+
+
+ Why I like finding other people's gists
+
+
+ More than just being able to share my own code, I like gists because
+ other people have the same ideas as me!
+
+
+ Someone else has probably done what I want to do before
+
+
+ If I'd like to accomplish a small scripting task, understand
+ something self-contained, or find a code snippet for a specific task,
+ I often search for it on the web. Unfortunately, in our Lord's
+ year 2024, pages and pages of whatever search I make are mostly AI
+ garbage (here
+ is an article I have not read to pretend to verify my point). One help
+ here is independent search engines like
+ Marginalia Search or
+ Wiby. While they are fun for
+ exploring a more indie version of the web, I also find adding
+ "site:gist.github.com"
to my web search often
+ results in finding exactly what I want to do.
+
+
+ For example, here is a small list of gists from my Internet history
+ that I've found to be useful recently (and as a by-product, an eye
+ into my life and desires for the past several months).
+
+
+
+ I could or should put things elsewhere (not on GitHub)
+
+
+ The existence of GitHub in the above has mainly been a sidenote. The
+ main thing that excites me about gists is the collaborative nature of
+ them. This is not something that GitHub must have control over, and
+ indeed something that they probably shouldn't have
+ control over.
+
+
+ I've been reading recently a lot about self- or community-hosted
+ alternatives to different things like Git servers (like
+ sourcehut) and, I use
+ Mastodon (talking of
+ self-hosting, I'd like to find an instance that's not
+ mastodon.social) a lot.
+
+
+ I could put my snippets on my website, or something more free. But, I
+ haven't. Yet.
+
+
+ My gists, or "the gist-list"
+
+
+ The list is long. I keep comments brief. I have categorised them as to
+ my whims. The code blocks show either the full gist, or - if you see
+ "...
" - a snippet or section of it.
+
+ BLOG POSTS
+
+ # How to start blogging
You might not think you should blog. I think you should.
@@ -240,25 +633,39 @@
-I love hats
+
+
+ I created this for one person who asked me "how do I start a
+ blog". Since I made it a gist, I have shared it with many
+ people.
+
+
+
+
+ I love hats
...
-
-
-This is a blog about hats.
-
-
-JUST DATA
-DATA I MANUALLY MADE
-
-# ...
+
+ This is a blog about hats.
+
+
+ JUST DATA
+ DATA I MANUALLY MADE
+
+ # ...
[totals]
minutes = 60_724
songs = 7_309
@@ -269,35 +676,69 @@ 3. TOML for lots of things around the same time Spotify Wrapped came out last year. It was fun to think of a way of putting it into TOML format. TOML is fun.
-
-
-
-#...
+
+
+ I started using TOML for lots of
+ things around the same time Spotify Wrapped came out last year. It
+ was fun to think of a way of putting it into TOML format. TOML is
+ fun.
+
+
+
+
+ #...
cat words.txt | awk -F'[^a-zA-Z]' 'BEGIN {delete wds} { if (length($0) > 0 && length($0) < 10) { if (!($1 in wds)) {print $1; wds[$1]} } }' > nimi-ale-pi-toki-pona.txt
#...
-
-
-I wanted a toki pona word list for something. I can't remember what, but it was probably lipu tenpo related. I put the command and generated list into a gist because I spent some time tinkering with awk
to create the command, and I was proud of it. You may spot that theme continuing on.
-
-
-
-{
+
+
+ I wanted a toki pona word list
+ for something. I can't remember what, but it was probably
+ lipu tenpo related. I put the
+ command and generated list into a gist because I spent some time
+ tinkering with awk
to create the command, and I was
+ proud of it. You may spot that theme continuing on.
+
+
+
+
+ {
"name": "newprofile1",
"extensions": "[{\"identifier\":{\"id\":\"bbenoist.doxygen\",\"uuid\":\"aab644b7-f446-4774-87fc-2cce8f0d5a4f\"}},{\"identifier\":{\"id\":\"cschlosser.doxdocgen\",\"uuid\":\"da7e26d5-d57c-4742-ab47-d77fb189e195\"},\"displayName\":\"Doxygen Documentation Generator\"},{\"identifier\":{\"id\":\"davidanson.vscode-markdownlint\",\"uuid\":\"daf8b44d-8aae-4da2-80c5-1f770219f643\"},\"displayName\":\"markdownlint\"},{\"identifier\":{\"id\":\"eamodio.gitlens\",\"uuid\":\"4de763bd-505d-4978-9575-2b7696ecf94e\"},\"displayName\":\"GitLens — Git supercharged\"},{\"identifier\":{\"id\":\"esbenp.prettier-vscode\",\"uuid\":\"96fa4707-6983-4489-b7c5-d5ffdfdcce90\"},\"displayName\":\"Prettier - Code formatter\"},{\"identifier\":{\"id\":\"formulahendry.auto-rename-tag\",\"uuid\":\"6e440e71-8ed9-4f25-bb78-4b13096b8a03\"},\"displayName\":\"Auto Rename Tag\"},{\"identifier\":{\"id\":\"github.copilot\",\"uuid\":\"23c4aeee-f844-43cd-b53e-1113e483f1a6\"},\"displayName\":\"GitHub Copilot\"},{\"identifier\":{\"id\":\"github.vscode-github-actions\",\"uuid\":\"04f49bfc-8330-4eee-8237-ea938fb755ef\"},\"displayName\":\"GitHub Actions\"},{\"identifier\":{\"id\":\"github.vscode-pull-request-github\",\"uuid\":\"69ddd764-339a-4ecc-97c1-9c4ece58e36d\"},\"displayName\":\"GitHub Pull Requests and Issues\"},{\"identifier\":{\"id\":\"jock.svg\",\"uuid\":\"4ae6dc82-7981-4f10-bd81-2d72aec37f39\"},\"displayName\":\"SVG\"},{\"identifier\":{\"id\":\"leonhard-s.python-sphinx-highlight\",\"uuid\":\"a0f17d96-c9f3-4ce4-92b7-27b8c936835b\"},\"displayName\":\"Python Sphinx Highlighter\"},{\"identifier\":{\"id\":\"mhutchie.git-graph\",\"uuid\":\"438221f8-1107-4ccd-a6fe-f3b7fe0856b7\"},\"displayName\":\"Git Graph\"},{\"identifier\":{\"id\":\"ms-python.black-formatter\",\"uuid\":\"859e640c-c157-47da-8699-9080b81c8371\"},\"displayName\":\"Black Formatter\"},{\"identifier\":{\"id\":\"ms-python.pylint\",\"uuid\":\"8dc47276-5882-4c5f-903d-7eef7b9d1584\"},\"displayName\":\"Pylint\"},{\"identifier\":{\"id\":\"ms-python.python\",\"uuid\":\"f1f59ae4-9318-4f3c-a9b5-81b2eaa5f8a5\"},\"displayName\":\"Python\"},{\"identifier\":{\"id\":\"ms-python.vscode-pylance\",\"uuid\":\"364d2426-116a-433a-a5d8-a5098dc3afbd\"},\"displayName\":\"Pylance\"},{\"identifier\":{\"id\":\"ms-toolsai.jupyter\",\"uuid\":\"6c2f1801-1e7f-45b2-9b5c-7782f1e076e8\"},\"displayName\":\"Jupyter\"},{\"identifier\":{\"id\":\"ms-toolsai.jupyter-keymap\",\"uuid\":\"9f6dc8db-620c-4844-b8c5-e74914f1be27\"},\"displayName\":\"Jupyter Keymap\"},{\"identifier\":{\"id\":\"ms-toolsai.jupyter-renderers\",\"uuid\":\"b15c72f8-d5fe-421a-a4f7-27ed9f6addbf\"},\"displayName\":\"Jupyter Notebook Renderers\"},{\"identifier\":{\"id\":\"ms-toolsai.vscode-jupyter-cell-tags\",\"uuid\":\"ab4fb32a-befb-4102-adf9-1652d0cd6a5e\"},\"displayName\":\"Jupyter Cell Tags\"},{\"identifier\":{\"id\":\"ms-toolsai.vscode-jupyter-slideshow\",\"uuid\":\"e153ca70-b543-4865-b4c5-b31d34185948\"},\"displayName\":\"Jupyter Slide Show\"},{\"identifier\":{\"id\":\"ms-vscode.cpptools\",\"uuid\":\"690b692e-e8a9-493f-b802-8089d50ac1b2\"},\"displayName\":\"C/C++\"},{\"identifier\":{\"id\":\"ms-vscode.cpptools-extension-pack\",\"uuid\":\"3957b2f6-f086-49b5-a7b4-5da772123130\"},\"displayName\":\"C/C++ Extension Pack\"},{\"identifier\":{\"id\":\"ms-vscode.cpptools-themes\",\"uuid\":\"99b17261-8f6e-45f0-9ad5-a69c6f509a4f\"},\"displayName\":\"C/C++ Themes\"},{\"identifier\":{\"id\":\"ms-vscode.powershell\",\"uuid\":\"40d39ce9-c381-47a0-80c8-a6661f731eab\"},\"displayName\":\"PowerShell\"},{\"identifier\":{\"id\":\"ms-vscode.vscode-typescript-next\",\"uuid\":\"15305aca-2588-4ca0-8147-ab2c64730b82\"},\"displayName\":\"JavaScript and TypeScript Nightly\"},{\"identifier\":{\"id\":\"mushan.vscode-paste-image\",\"uuid\":\"ffaf4ec8-f001-4f02-b671-705ecf079cde\"},\"displayName\":\"Paste Image\"},{\"identifier\":{\"id\":\"naumovs.color-highlight\",\"uuid\":\"121396ad-85a1-45ec-9fd1-d95028a847f5\"},\"displayName\":\"Color Highlight\"},{\"identifier\":{\"id\":\"njpwerner.autodocstring\",\"uuid\":\"2d6fea35-f68e-461d-9b7b-5cd05be99451\"},\"displayName\":\"autoDocstring - Python Docstring Generator\"},{\"identifier\":{\"id\":\"rangav.vscode-thunder-client\",\"uuid\":\"2fd56207-78ef-49d4-95d2-9b801eee4dbf\"},\"displayName\":\"Thunder Client\"},{\"identifier\":{\"id\":\"ritwickdey.liveserver\",\"uuid\":\"b63c44fd-0457-4696-99e9-dbfdf70d77de\"},\"displayName\":\"Live Server\"},{\"identifier\":{\"id\":\"tumido.cron-explained\",\"uuid\":\"6ee451cb-7b81-4520-9eb4-059db43a1431\"},\"displayName\":\"Cron Explained\"},{\"identifier\":{\"id\":\"usernamehw.errorlens\",\"uuid\":\"9d8c32ab-354c-4daf-a9bf-20b633734435\"},\"displayName\":\"Error Lens\"},{\"identifier\":{\"id\":\"valentjn.vscode-ltex\",\"uuid\":\"840e9c85-0e99-42ce-aa62-81088245e699\"},\"displayName\":\"LTeX – LanguageTool grammar/spell checking\"},{\"identifier\":{\"id\":\"yzhang.markdown-all-in-one\",\"uuid\":\"98790d67-10fa-497c-9113-f6c7489207b2\"},\"displayName\":\"Markdown All in One\"}]"
}
-
-
-When I originally made this, it was human-readable: you could see a nice, multi-line list of my VSCode extensions. They have since changed how the export/import works, so now it looks very ugly. I no longer find this useful.
-
-
-DATA THAT'S AUTOMATICALLY UPDATED
-
-#...
+
+
+ When I originally made this, it was human-readable: you could see a
+ nice, multi-line list of my VSCode extensions. They have since
+ changed how the export/import works, so now it looks very ugly. I no
+ longer find this useful.
+
+
+
+
+ DATA THAT'S AUTOMATICALLY UPDATED
+
+
+ #...
"references": [
{
"reference": "\"This is very neat thank you for this contribution.\"",
@@ -311,13 +752,34 @@ 6. CV repository. I used to use json-resume a bit more, but I stopped doing the themes how they did it and made it myself. I still use the schema, though, and still update this gist, so I can view my CV in many different styles. Neat!
-
-
-
-{
+
+
+ This is auto-updated by my
+ CV repository.
+ I used to use json-resume a
+ bit more, but I stopped doing the themes how they did it and made it
+ myself. I still use the schema, though, and still update this gist,
+ so I can view my CV in
+ many
+ different
+ styles. Neat!
+
+
+
+
+ {
"last_modified": "2024-03-25T00:44:15.551843Z",
"bookmarks": {
"TOP 10 personal websites/blogs": [
@@ -335,16 +797,38 @@ 7. Firefox bookmark exporter. I don't really use this gist, but I guess having the data in machine-readable format is nice. Although alifeee.co.uk/bookmarks probably already fills that role.
-
-
-HOW-TOS
-THINGS I WANTED TO DO MULTIPLE TIMES
-
Most of these gists exist because I spent a while figuring out how to do a process, and I thought that I would want to repeat the process in the future.
-
-...
+
+
+ After making my CV automatically push to a gist, it was easy to do
+ similar when I was making my
+ Firefox bookmark exporter. I don't really use this gist, but I guess having the data in
+ machine-readable format is nice. Although
+ alifeee.co.uk/bookmarks
+ probably already fills that role.
+
+
+
+ HOW-TOS
+
+ THINGS I WANTED TO DO MULTIPLE TIMES
+
+
+ Most of these gists exist because I spent a while figuring out how to
+ do a process, and I thought that I would want to repeat the process in
+ the future.
+
+
+ ...
## To create maps
With:
@@ -365,18 +849,38 @@ 8. FactorioMaps
to create an interactive map of the save after every week. You can (maybe) see the final map on https://server.alifeee.co.uk/factorio/.
-
who is it for?
-Myself. It took a few hours to set this up the first time, and I was doing it every week, so making a gist helped me do it repeatedly and more mindlessly.
-have I come back to it?
-Every week for ten weeks when I was generating the maps often.
-
-
-
-...
+
+ why did I make it?
+
+ I played a big multiplayer Factorio world once a week for ten weeks,
+ and I used
+ FactorioMaps
+ to create an interactive map of the save after every week. You can
+ (maybe) see the final map on
+ https://server.alifeee.co.uk/factorio/.
+
+ who is it for?
+
+ Myself. It took a few hours to set this up the first time, and I was
+ doing it every week, so making a gist helped me do it repeatedly and
+ more mindlessly.
+
+ have I come back to it?
+ Every week for ten weeks when I was generating the maps often.
+
+
+
+ ...
KEYS="${TOGGL_KEYS:-.id, .workspace_id, .project_id, .task_id, .billable, .start, .stop, .duration, .description, .duronly, .at, .server_deleted_at, .user_id, .uid, .wid, .pid}"
# print CSV headers
@@ -385,13 +889,25 @@ 9. https://toggl.com/. I do not pay for it, so they do not keep my data past 3 months. So, every month I download the month's data. Rather than remembering which buttons to press on the UI, I wrote a script that I can run. I thought it might be nice to accidentally come across it if you were a netizen.
-
-
-
-# FFmpeg Commands
+
+
+ I track time using
+ https://toggl.com/. I do not pay
+ for it, so they do not keep my data past 3 months. So, every month I
+ download the month's data. Rather than remembering which buttons
+ to press on the UI, I wrote a script that I can run. I thought it
+ might be nice to accidentally come across it if you were a netizen.
+
+
+
+
+ # FFmpeg Commands
## Turn mp4 into gif
@@ -401,13 +917,23 @@
-...
+
+
+ I thought I'd use this one more, but I haven't. I made it
+ because I love writing an FFmpeg command for a repeatable task, as
+ it's so easy to do something again the same way later on. But, I
+ haven't really been doing much video/audio stuff recently.
+
+
+
+
+ ...
# > ./bar.sh 25 100 12
# ███░░░░░░░░░
awk -v prog=$1 -v TOTAL=$2 -v TOTSEG=$3 'BEGIN {
@@ -422,13 +948,29 @@ 11. my Advent of Code statistics, or comparing magazine release date differences.
-
-
-
-...
+
+
+ I love bash, I love awk, and I love statistics. This combines them
+ wonderfully. I use this vaguely regularly when I want to visually
+ compare numbers, such as for
+ my Advent of Code statistics, or
+ comparing magazine release date differences.
+
+
+
+
+ ...
Plot graphs using the terminal. E.g.,
> cat sensor.txt | awk -F ':| *' '{print $2}' | eplot -d -t CO2 2> /dev/null
@@ -458,29 +1000,65 @@ 12. CO2 monitor, to sanity check the results I was getting. I had it set up to just send numbers through serial, so I found out how to graph it to be able to better compare those numbers to one another.
-
I wanted to do it in bash, so I could do it interactively, and watch the graph change in real time. If I wanted a pretty graph, I'd use Matplotlib.
-
-
-THINGS THAT OTHER PEOPLE COULD WANT TO DO
-These are things that I did once, or do repeatedly and remember how to do. But, I put them into gists so that I could share with people how I do common things, or so people with very specific google searches might stumble across something useful.
-
-...
+
+
+ As I said already, I love statistics. I made this when I was setting
+ up a
+ CO2 monitor,
+ to sanity check the results I was getting. I had it set up to just
+ send numbers through serial, so I found out how to graph it to be
+ able to better compare those numbers to one another.
+
+
+ I wanted to do it in bash, so I could do it interactively, and watch
+ the graph change in real time. If I wanted a pretty graph, I'd
+ use Matplotlib.
+
+
+
+
+ THINGS THAT OTHER PEOPLE COULD WANT TO DO
+
+
+ These are things that I did once, or do repeatedly and remember how to
+ do. But, I put them into gists so that I could share with people how I
+ do common things, or so people with very specific google searches
+ might stumble across something useful.
+
+
+ ...
# to change lots of files, use `find` and `xargs`
# e.g., find all files ending with ".html" and replace them with the output of this script
# find . -name "*.html" -print0 | xargs -0 -i bash -c './scripts/naked.sh "{}" > "{}.temp" && mv "{}.temp" "{}"'
cat "$1" | perl -0777pe 's|<link[^>]*rel="stylesheet"[^>]*/>||gms' | perl -0777pe 's|<style>.*?</style>||gms' | perl -0777pe 's|style="[^"]*"||gms'
-
-
-I made this to make it easy for me to participate in CSS Naked Day 2024. I shared it so that anyone else could do the same. There were many ways of removing styles on the homepage, but they were all for PHP, or Django, or Perl, or ... etc. Nothing for "just HTML", so I added it.
-
-
-
-# Common RSS URL extensions
+
+
+ I made this to make it easy for me to participate in
+ CSS Naked Day 2024. I
+ shared it so that anyone else could do the same. There were many
+ ways of removing styles on the
+ homepage, but they
+ were all for PHP, or Django, or Perl, or ... etc. Nothing for
+ "just HTML", so I added it.
+
+
+
+
+ # Common RSS URL extensions
I like blogs. I like RSS feeds. Often, blogs don't have an RSS feed link. Often, these blogs *do* have an RSS feed, thanks to whatever site generator they use.
@@ -505,13 +1083,27 @@