Where Authors & Readers find each other

The Fantastic (Group) of Lord Matt, Super Geek


Games I am looking forward to playing (maybe this year)

October 10, 2024 in games-and-gaming by Matthew Brown

Ever since my beloved old Linux Pc died, I have been saving up to replace it with a cutting-edge (or close to) gaming PC. I’m almost there.

The trouble is that I have a growing list of games that I want to play the day I build the new PC. If I suddenly stop posting, this is why.

Starting with the games where I have a tab open to remind me about it, I want to play:

Dungeon Tycoon – a lovely blend of silly RPG humour and a tycoon game/sim. This looks like a game I can dip into for short play but will probably lose entire days to.

Be my horde – a top-down survival roguelike that I can see stealing says of otherwise productive time from my life.

Goobies – an autoshooter roguelike that should try to make my new PC and GPU cry. There was a whole glut of letplays a little while ago and I think I watched all of them.

Nodebuster – a short roguelike incremental game that looks super addictive.

The Planet Crafter – build a base, terraform a plant, craft stuff… sign me up.

And finally, the one I keep dreaming about playing:

Space Engineers – harvest stuff, build bases, and fly into space. I want to play this so badly. Soon…

How do I become a better writer when I hate reading?

October 1, 2024 in my-very-best-content by Matthew Brown

I like telling stories, but I don’t care so much for reading them. It’s not for me. But the number one advice to become a better author is to read a lot.

Is there anything else I can do?

How do I become a better writer when I hate reading?, Kippy, Writing SE, 2019

This was my answer back in 2019

As a dyslexic, I understand the general aversion to reading. As someone who loves storytelling, I nevertheless want to be exposed to stories.

There are some life-hacks for the reading adverse that want to write.

Get the audiobook

Not only does an audiobook outsource the reading to someone else, but it is something you can listen to while travelling to work, sitting on the bus, or whatever.

Read along with the audiobook

There is a second use of audiobooks that I do not see discussed much – read-alongs. As a kid, I loved read-along storybooks. I must have listened to “Autobots Lightning Strike” so often it must have driven my mother spare. To this day, I can still replay the whole thing in my head.

Reading along with the narrator takes the pressure off. If you want to just get used to the pleasure of holding a book and get a feel for the flow of words on a page, this is ideal.

Record audiobooks

There are sites you can go on (I’ll let you find them yourself) where you can get paid to read and record audiobooks. If you are the sort of person for whom money is a great motivator then this one is for you.

Find a series to be passionate about

For me as a kid, it was robots and adventure stories. My mum gave me the Enid Blyton book, “The Boy Next Door” and I was soon reading every one of her books as fast as my mum could buy them for me. These days, I find those books boring and repetitive but that’s just because my tastes have changed.

I know of other dyslexics who never read at all. That is until Harry Potter hit the shops. Suddenly it did not matter how exhausting it was to read, they wanted to find out what happened next.

When your passion for a series, genre, or author gets strong enough, nothing will stop you from getting hold of more and just reading the heck out of them. Terry Pratchett’s books are great for this.

There is a reason us nerds and geeks tend to be experts – we consume everything there is to find on our favourite subjects. Don’t like fiction? Try travel guides, technical manuals, science textbooks, biographies – whatever floats your boat. You are not likely to learn story writing so fast but you will pick up a thing or two about tone and pacing.

Join a writer’s group

No matter how much you generally avoid writing, the quid quo pro of reading a little of a person’s work and offering feedback in return for a load of feedback on your work forces you to read but in a fun setting with people that you can get along with.

As the reading is bite-sized and you take a break to discuss it afterwards it hardly feels like reading at all.

Learn about the theory of storytelling

There are some amazing videos on youtube that dig into the mechanics and theory of storytelling (film, TV, and books). Terms to search “the hero’s journey”, “the three-act structure” (also “the five-act structure” and “seven-act structure” too), and storytelling tropes.

This will turn all your Netflix binges into storyteller training. Although, I have to warn you that learning the patterns of storytelling will spoil some of the more formulaic series.

I spend a fair amount of time deconstructing the story pace in my favourite Netflix shows. I write humour and so tend to try and work out why a joke is funny. That is not for everyone but it works for me.

Make your peace with reading

Sooner or later, if you are serious about writing, you will have to make a sort of begrudging peace with reading. Some dyslexics I know invest in coloured overlays which help calm the text down and make it easier to read. Others read exclusively on their phones (don’t ask me why – it sounds terrible to me).

What helps is that the more you read, the more you enjoy reading and the easier it gets. Even if you are dyslexic or for some other reason a weak reader. Sure, you start off at a disadvantage but that only means you need a bit more effort to catch up. Read books you love and you will hardly notice you are doing it.

Watch and read

Some of the better adaptations are so much more enjoyable to read after you have seen the series. Good Omens is a perfect example of that. Watch it, read it, and then watch it again. It is amazing.

I would add in 2024

I stand by my answer. I’d add something but I stand by it.

Today, I would add that a good streaming service can feed you many examples of good stories. You won’t pick up on the word-to-word skills you might with reading but if you actively watch, you will still learn from them.

Python data and variable types

September 30, 2024 in coding-and-development by Matthew Brown

I am a great believer in “blog your homework”. By homework, I mean (in this case) what I am learning about Python for my visual novel. In addition to my learning, I have two friends who are or are about to start using Python. This is a primer for all (3) of us.

Those who know their Python are invited to chip in if I missed anything or got something wrong. I’m here to learn too. There may be parts of this with updates from future me who just learned a thing.

What are variables

A quick refresher: Python, like most programming languages, has two things that are data-related:

  1. Variables
  2. Functions aka Mthods in some contexts

Variables hold data and functions do something with data. 2+3=5 is a function where 2 and 3 are variables and 5 is the new variable that + made. This is what it looks like in code.

def adding(var,othervar):
    return var+othervar

myvar = 2
myothervar = 3
myanswer = adding(myvar,myothervar)
print(myanswer) # 5

Types of variable – in general

Before we get to the depths of Python-specific stuff I want to revise variables in general.

Most of this will also apply to things called constants which are values that cannot (or should not) change. Constants are a special case that I shall only tough on a bit.

Boolean (bool)

Booleans are the most primitive variable type. They can be True or False and that is it. This should relate to binary 1 or 0 but different languages handle them differently. On the whole, booleans are [1] or [NOT 1] but can also be [0] and [NOT 0] because screw consistency, I guess.

Most languages have True and False as core contestants and it is best to use those. Python is no exception.

Later note: False and 0 are considered the same in Python.

Integer (int)

Whole numbers (called integers by maths and computer science people) are something you will probably work with at some point. These are the variables in my silly example of variables vs functions.

The number 42 is an int but 4.2 is not. That dot is what is different.

Reals, floats, doubles and their friends

These are all variables of various and fairly arbitrary precision. For now, the difference between these is not important. It might come up later but just think of numbers with a decimal point. That 4.2 (four point two) from earlier belongs here.

If you cast (converted) 42 into one of these floating point types, you would get 42.0 or more likely 42.000000…

Casting floats into ints gives you weird behaviour and maths errors. For example, push 3.14 (three point one four) and 4.2 through an adding function that outputs only ints, and you will get 7 (instead of 7.34).

Personal peeve side story: When you see a number like 3.14 and you say “three point fourteen” please understand that I may wish to percusively educate you with a large plank of wood. This is because this number is three point one four. The only time you may call it three point fourteen if it is part of a version number like this: 3.14.0.2289. Otherwise, please slam your head in the door until you can say it properly.

Char

A single character like a letter or a number (as text). This will come up in database stuff as a common field type is varChar (variable characters).

Array

An array is basically a list of variables. The details vary between languages and Python gets fussy about them.

An array has two parts – the index and the value.

Here is a PHP example because I know PHP better and Python gets a bit complicated.

$myarray = array('bannas','apples',12);
$myarray[0] = 'Chips';
$myarray[] = 'boats';
$myarray['foo'] = 'bar';
print_r($myarray);
/*
array(
    0 => 'chips',
    1 => 'apples',
    2 => 12,
    3 => 'boats',
    'foo' => 'bar'
)
*/

Arrays index by number starting from 0 (most of the time). In Python, a negative index number is the point that number from the end. In PHP a negative index is just another index.

Some arrays can have text (strings) as an index. In PHP that last array element also has a secret index value of 4.

Try not to worry about this, things only get stranger from here.

Strings

We mentioned strings. Strings are characters all hanging out together in a single variable. This entire post is stored as a complicated string.

Just to confuse you, some languages like Ruby don’t really have strings, they have arrays of char. Thus, you can grab any character you want from the string. A fair amount of languages now allow you to treat strings as pseudo-arrays (treat them like arrays even though they are strings).

Strings have encodings. This is because there are a lot of languages with a lot of different characters. And now there are emojis as well. While this should not matter until you start processing external data or using databases, it will come up eventually. If in doubt, I use UTF-8. However, check with your data provider or database person because mismatched encodings give funny-looking results.

Python defaults to UTF-8.

Weak or strongly typed variables

Sooner or later, you are going to come up against typing issues. For example:

myStr = "42"
myInt = 42
myResult = myStr+myInt # what will you get from this?

As this answer explains, in Python you will get an error. This is because Python is strongly typed and adding a number to text makes no sense.

In PHP you will get “4242” because PHP is weakly typed and you just merged the int into a string like a complete noob.

Classes (in general)

Most programming languages have the concept of a class object. A class holds variables and has methods with are just functions that belong to the class. Python is one such language. If I mention classes (and I will because Python data types are classes) this is what I am on about.

In python, you can use (dot) methods on classes.

Variable Names

It is said there are two hard problems in computer science – naming variables, invalidating cache, and off-by-one errors.

In this example, I have named the variables so as to remind you what they are. This is terrible practice for anything that is not really basic notes. Please, name your variables something that describes what it is for. Your future self and whoever inherits your code will thank you.

Don’t do this:

n = 'bob'
i=22
tt = '01843 123456'

You might know now what those variables are but will you always remember?

Instead, do yourself a favour and do something like this:

BobName = "Bob"
BobID = 22
BobTelephoneNumber = '01843 123456'

There are better ways of handling names and numbers than this but at least you won’t come across code like this and wonder what it is about.

if(i>23):
    tt=''

What is that code even doing?

Advanced example (skip if confusing)

As per my snark about the “good” example not being good: Assuming you made a class called person in a library called myPersonThing, you can make Bob an instance of that.

import myPersonThing
Bob = myPersonThing.person('Bob',22,'01843 123456')
# Bob.Name = "Bob"
# Bob.ID = 22
# Bob.TelephoneNumber = '01843 123456'

Note: When we come to dict(), you will have yet another way to approach this.

Variable types: Python specifics

This is where the blogging my homework comes in. While the basics are already covered, its time to get crazy. I’ll start us off slow.

For reference, there is a proper list of Python’s built-in types here. You can add more via libraries but I am not covering those.

Booleans

Booleans work exactly as you should expect them to. They are True or False. 0 counts as False. Logical.

AreYouAlive = True
if AreYouAlive:
   breath()
else:
   rot()

A better example:

UserCredits = GetUserCredits(Bob)
if (UserCredits>0):
    print("Welcome citizen")
else:
    print("Begone worthless fool")

The boolean here is hidden inside the logical test (UserCredits>0). But that is a topic for another long post. The outcome is unknown but depends on what the GetUserCredits() function returns. Judging from the code, we are expecting a number.

String (Str)

The str type is exactly what you would expect.

myStr = "42"
print(type(myStr))

You will get an answer that this is a class of type str. You remember I mentioned classes, string is a class (technically str is a class).

This allows such behaviour as:

myStr = "foo bar baz boo"
myNewStr = myStr.capitalize()
print(myNewStr) # Foo bar baz boo

The capitalize() (note the spelling) method gives you a copy with the first letter capitalised.

Other methods you may need for working with other data encodings may include this one:

myStr = "foo bar baz boo"
mySafeStr = myStr.encode('mac_latin2','ignore')

This will give you a copy of the string converted (as best as Python can) to mac_latin2 bytes. Here is a list of all encodings.

You can join strings together like this:

myStr = "foo"
myOtherStr = "bar"
myNewStr = myStr+' '+myOtherStr # we add the two with a space in the middle (that's a string too)
print(myNewStr) # foo bar

Numbers

Python, it turns out, has three number types.

  1. int
  2. float
  3. complex

That third one was a surprise to me.

Note: There is a fourth thing called a range but I covered it in the lists and arrays section like a fool.

Int

We covered integers in the general theory section. This is a whole number.

Here is how you might use them.

def adding(var,othervar):
    return var+othervar

myvar = 2
myothervar = 3
myanswer = adding(myvar,myothervar)
print(myanswer) # 5

A better function would check the inputs are a number type. Do not copy this for any real-world code.

Float

When you encounter reals, floats, doubles and their friends in database stuff, they are all floats in Python. You should remember (unless you skipped it) that floats are numbers with a decimal point (also called a floating point number).

The number we all know and love – 3.1415926535… – is a float of (theoretically) infinite length. The longer your approximation of pi, the more accurate (and time-consuming) your maths will be.

42 as a float is 42.000…

If you don’t care about the precision, you can cast floats into ints but it is probably not a great idea.

myFloat = 3.14159265
print(int(myFloat)) # 3

Here is a whole nerdy discussion about casting floats to ints for those who want to do that sort of nonsense.

Complex (skip if confusing)

Complex numbers are a fun part of maths that can make certain operations faster. For example, real-time radar. You might want to use them for making Mandelbrot fractal images.

In regular mathematics complex numbers have a real and a complex part like this 5+2i. The complex value i is used. the number i is what you would get if there was an answer to what is the square root of -1 (minus one).

In Python for reasons I am yet to work out, complex examples use i for the real part and j for the imaginary part. It is like someone read about the quaternions but only half remembered it.

The complex is two numbers together and can be generated by the function complex() like this:

myComplexNumber = complex(1,2) # 1+2i
myComplexNumber = complex(1j) # 0+1i
myComplexNumber = complex("9i+1j") # 9+1i

For most of us, complex numbers are things we will not have to deal with. Unless you are doing some serious science or intensive recreational mathematics.

Are lists arrays?

Remember when I told you about arrays? Ah, the days of easy stuff. Get ready for some Python-specific confusion. This is where I trip up coming from PHP to Python.

Allow me to introduce you to list, tuple, range, dict, set and frozen set. Yeah, I see that look. I had that same look on my face because I thought I would instantly understand this stuff.

x = ["apple", "banana", "cherry"] # a list
x = ("apple", "banana", "cherry") # a tuple
x = range(6) # a range
x = {"Name" : "Bob", "ID" : 22, "TelephoneNumber" : '01843 123456'} # a dict
x = {"apple", "banana", "cherry"} # a set
x = frozenset({"apple", "banana", "cherry"}) # a frozen set

Choose the wrong one and it will not behave how you were expecting. For me, I still think of these as types of arrays. It is probably better that you do not copy me.

Let’s look at them one by one.

List

This is what other languages would call a numerically index array. List items are ordered, changeable, and allow duplicate values. They are indexed numerically from 0. This is where you can try for a negative index and get not what you thought you would get. At least I did.

x = ["apple", "banana", "cherry"]
print(x[0]) # apple
print(x[-1]) #cherry
print(x[2]) # also cherry
print(x[1]) # banana

Did you want to add a new item to your list? Sorry, you will have to make a new list that is one entry bigger.

Tuple

Tuples are a bit hard to explain. Python is the only place I have ever encountered them.

After a bit of reading, I can tell you this.

A tuple is like a list in that they are ordered and allow duplicates except the order cannot change and the values inside cannot change. You use round brackets to make them.

x = ("apple", "banana", "cherry")

Here’s a link if that was a bit unclear.

Range

The range is probably not really meant to be here. It is an ordered range of numbers.

The range function takes up to three arguments (values needed to use it). Like this: range(start, stop, step) – unless you only supply one – let me explain that.

x = range(6) # 0 1 2 3 4 5 - stop given
x = range(3, 6) # 3 4 5 - start and stop given
x = range(3, 20, 2) # 3 5 7 9 11 13 15 17 19 - start, stop, and step given
  • start: Where you start from if you only give one argument, it will not be this one.
  • stop: Where you stop (not included)
  • step: Defaults to 1 but can be anything. To use this you need three arguments.

Another example. Say you want all the multiples of seven less than one hundred.

x = range(7,100,7)
for n in x:
  print(n)

That prints only the numbers we want.

I guess you get a sort of ordered tuple?

Dictionary aka dict

This is what I, as a PHP programmer, would call a string-indexed array. As of newer versions of Python dictionary types are also ordered (they have a numerical index).

Dicts (try saying that out loud at work) are key-value pairs. Like field and value on a form. Each key must be unique.

Bob = {
    "Name" : "Bob", 
    "ID" : 22, 
    "TelephoneNumber" : '01843 123456'
} # make the dict
Bob['xp']=400
# you can also have more than one value by adding a tuple or a list or another dict
Bob['awards']=['Best Coder','Worst Farts','Employer of the year 1066'] # this list is now an entry in the dict

Note: there is no comma after the last entry in the initial dictionary definition.

In my opinion, if you need an arbitrary blob of data, dicts are usually what you want. That said, you will discover custom classes soon enough and you may want to use those.

Sets

As I write this, I haven’t a clue what sets are but I really hope they relate to set theory or are numerical random access changeable array things.

Nope, sets are more like set theory than data theory.

A set is an unordered unchangeable grouping. You cannot edit the items but you can remove items and add items. So, get item, remove it, make changes to the got item, and put it in again.

x = {"apple", "banana", "cherry", True, 99}
print(len(x)) # 5
x.discard("banana")
print(len(x)) # 4
#There is also a remove method but it throws an error if the thing is not there.
x.remove("banana") # you just crashed the program noob

You can do some other stuff with sets. Popping for example.

offering = {"space", "adventure", "really wild things"}
x = offering.pop()
print(x) # you will get one of the things in offering.
fixedIt = x.capitalize()
offering.add(x) # put it back

We can also add other listy groups into a set

offering = {"space", "adventure", "really wild things"}
avoiding = {"milk","cookies","an early night"}
offering.update(avoiding)
print(offering) # {"space", "adventure", "really wild things","milk","cookies","an early night"}

We can add those tuples and lists in the same way.

offering = {"space", "adventure", "really wild things"}
avoiding = ("milk","cookies","an early night")
offering.update(avoiding)
print(offering) # {"space", "adventure", "really wild things","milk","cookies","an early night"}

Pay close attention – those last two may look nearly identical but they are not the same even if the output is. These things look like other things issues will trip you up if you are not careful.

Frozen sets

x = frozenset({"apple", "banana", "cherry"}) # a frozen set

A frozen set is like a set but you cannot change it. I’d have called that a constant but no one asked me.

And now we get into the weeds

Here we look at four odd fellows – bytes, bytearray, memoryview, and NoneType sounds a lot like The Null Hypthoisis if you ask me.

Each of these I learned about so I could write them down. They were all new to me.

Bytes

For some reason, you want the string as raw data (make sure you pick the encoding). You cannot change data of this type.

This is the type you get if you convert a nice well-behaved string into a specific encoding. You might want to do this to save a string in a format that is not UTF-8 because the people giving you the data are unrefined noobs or something.

Bytesarray

Yes, at last, an honest-to-goodness array. This is an array of bytes. You can change the array.

I haven’t a clue what you would do with one of these. Maybe manipulate some strangely encoded text?

Memoryview

This is a memory-safe way of looking into memory. NGL, this is all new to me. Here’s a post about it.

NoneType

It turns out that NoneType represents the distinct lack of anything. This SE answer explains it better than I could.

It is a good idea to check a return object against NoneType before using it.

obj = myUnreliableFactoryMethod(foo,bar)
if obj is None:
    # throw an error or something
else:
    # do something clever

And that’s a wrap

We have looked at all the built-in variable types and the functions that make them. I half-arsed a few of the more esoteric ones at the end because my brain is melting.

I think I learned something. I hope you did too.

Feel free to pass judgment, offer corrections, or expand on something. I’m here to learn. Also, please ask questions if I was unclear or if you want to know more. If I can answer, I will. Otherwise, I will go away and learn the answer for you.

Welcome to your new life as a Python geek.

I tried to buy stationery online (looking for better alternatives to Amazon)

September 24, 2024 in business by Matthew Brown

Today, I decided I needed some office bits. I checked a bunch of sites to see if any were better than Amazon. The results both pleased and surprised me.

Methodology

I tried to select as similar a product from each site as possible. They did not make this easy on me. Wildly different brands and variable unit sizes mean the comparison is not exact but as close as I could go.

The results are shown in the order I tried each site. The last one is my control reference – Amazon.

The shopping list

  • hole punch
  • lever arch file
  • 10 report holders (floppy folders for punched paper)
  • 2 sets of folder dividers (punched card tabs)

The results

The online shopEase of usePriceOverall
Argos
argos.co.uk
Searching was a nightmare. I did not find what I wanted and gave up.n/a0/10
Fail
The Range
therange.co.uk
Runs a bit slow. I found everything in the search results for hole punch.Items: £12.06
Delivery: £4.99
Total: £17.05
7/10
Could be worse
Ryman
ryman.co.uk
Challenging to find what I wanted. Items: £17.97
Delivery: £3.95
Total: £21.92
3/10
Must try harder
Stationery Shop
stationeryshop.co.uk
Did not mark or hide out-of-stock items in search results.Items: £12.50
Delivery: £4.95
Total: £17.55
6/10
Similar to others
Office Stationery
officestationery.co.uk
UI is ugly and slow but easy to use. Had to substitute for alternatives.Items: £7.25
VAT: £2.26
Delivery: £5.99
Total: £15.86
7/10
Inexpensive but limited
The Works [a]
theworks.co.uk
Due to no multipacks, to get what I wanted, I had to buy 10 single premium folders.Items: £37.00
Delivery: free
Total: £37.00
4/10
Meh not great
The Works [b]
theworks.co.uk
Managing my expectations and getting one premium floppy folder.Items: £10.00
Delivery: £3.99
Total: £13.99
8/10
Good value
Staples
staples.co.uk
Quirky search. Selected larger unit sizes.Items: £15.61*
Delivery: £4.99
Total: £15.62
9/10
brought more; paid less
Amazon
amazon.co.uk
Powerful search; many options; sortable search results.Items: £21.71
Delivery: free
Total: £21.71
2/10
Surprisingly expensive
* I put much more into my basket

Findings

The assorted report holders (floppy folders) was where a lot of shops fell short. Without them, the hole punch seems like an over-spend as I have loads of plastic wallets I could use for the lever archive file.

Argos failed out repeatedly. I am sure these are things they sell (or they did once) but as I could not find them, I could not buy them.

The Range made it far too easy for me to put all sorts of extras in my basket from the first search. I was put off by the shipping price but, otherwise, The Range ticked all my boxes.

Ryman, in comparison to The Range, was much much worse. When I was done, I closed their tab. Too expensive and not really what I wanted.

Office Stationary started out strong but did not seem to understand why I would want a bunch of cheap folders for punched documents. I replaced 10 assorted report holders (floppy folders) with some touch box slim to approximate.

The Works was a mixed bag. The things I wanted that it had were much cheaper but the floppy folders only came in single units of premium product. That said, If I buy a whole bunch of stuff, I’d get free shipping and a lot of things for my money.

Amazon was not as clear a winner for me as I thought it might be. The first few hole punches I looked at required me to order more than one which pushed me on to more expensive choices. I had the same problem with archive files too.

Staples was an odd one. I searched for floppy folders every which way I knew how. I found none. Then I searched for folder dividers and found a whole bunch of options. Oddly, I could not find the dividers in the search. Thus the quirky descriptor. I finally found folder dividers (and a lot of other stuff) by searching for tabs. Whoever wrote their search algo needs to add a synonym layer or something.

I ended up selecting a 25-pack of floppy folders which was cheaper than some 10 packs elsewhere.

Once I was done shopping on Staples, I was a few quid short of free shipping. I spent £3.86 on an extra item and saved £4.99 with free shipping. Win.

A surprising outcome from this project was that Amazon is actually quite expensive. With free (prime) delivery, it still exceeded most other stores. With any element of bulk purchase, any of the others could easily be a better choice.

The Winner(s)

The winner (in my book) was Staples. While not the cheapest and with questionable search, they had everything I wanted and free shipping was within my shopping budget. Staples were less expensive than Amazon. Amazon wanted more for every item type even when I opted to upgrade to a tougher hole punch (on Staples).

Coming in a close second was The Works. Their unit cost was lower but the range of goods were not quite there.

Office Stationery and The Range tied for third place.

Conclusion

Amazon is far from the cheapest, the lack of quality control and third-party sellers is just not as dependable. Overall, I am glad I shopped around. Amazon’s position as the default place to buy seems unwarranted in this test.

I would be happy buying from any of the four winners. I feel like they would all deliver items that are fit for purpose. However, Staples gets my custom this time. Their range of goods were comparable to Amazon but with far better prices and a gut feeling of trust.

Even factoring in free shipping, most other stores offered better value than Amazon. Buy every metric that matters to me, Amazon fell short of the competition.

Where do you buy your stationary and office stuff?

Upgrading OpenMentions.com

September 17, 2024 in coding-and-development by Matthew Brown

Some of you may know that I help run OpenMentions.com. And by help I mean it is my baby and so all the work is mine too.

For a while now a few shortcomings and missing features have been bothering me. Today, I set out to fix or improve them.

Trending topics

The trending topics section is not exactly responsive. In fact, “trending” might be a bit of an overreach.

The old way was to just grab the most recent 50 comments, replies, and mentions count the number per permalink and sort by that. This lacks subtlety and it takes forever for old topics to stop “trending”.

My first fix was to limit by age – nothing older than a secret number of weeks (I’m still playing with the number). This stops old topics from outstaying their welcome. It took some serious Google-fu to even work out how because the get_comments date arg was not especially well documented. Still, there are enough of us nerds writing about WordPress so I found what I needed.

The second part of this fix is a trick that Facebook once used in their Edge Rank algo. Instead of scoring +1 for each comment, reply, and mention that a topic has, I take the inverse of the age in hours. That caused a division by zero error.

Yes, that crashed the front page.

It turns out those replies that arrived in the last hour are zero hours old. A quick check for that which sets the age to 0.5 solved that error. Also, new comments cause trading topics to trend hard for 60 minutes. (The inverse of 0.5 is 2).

So now the trending topics are actually topics that are trending.

Win!

Reply and mention targets

Another shortcoming was that replies and mentions do not link back to the source of said reply or mention.

At first, I hit a brick wall. The comment object where the ActivityPub replies and WebMentions live does not store a useful URL.

That was when I had a brainwave and checked the comment metadata. Here I found that both replies and mentions store a URL. Not in the same field because that would be too easy.

A few if statements to check for something useful and a fallback of skipping things worked well. Now the date of each entry under a topic is a link to the reply or mention permalink URL.

I then rejigged the link that covers the text of each reply/mention/comment to link to the source of said entry.

Another win.

An easy win

The name of the writer posting the comment/reply/mention has always had a note telling me I forgot to add the author’s name as an attribute. I fixed that using esc_attr.

That’s three wins if you were counting.

Another quick win

While debugging my other stuff I noticed a div tag with the closing pointy bracket missing. An easy fix that does little other than make the HTML valid again.

Display avatars on the front page

Oh boy.

This one was a digging expedition. I identified five places to look for an avatar.

  • WebMention Metadata
  • ActivityPub Metadata
  • WordPress user-id
  • Anon email hash
  • A catchall for when those all fail

Each of those five potentialities gives (or doesn’t give) something to make an avatar from. WebMention was the worst with avatars only being given sometimes. ActivityPub seems to always play nice. email and WordPress user ID (the default ways) fail if they have nothing to work with.

For that last one, I did not have the email to hash so I went with the user name. The gravatar get function seemed to play nice with this as I hoped. After all, once you hash something, there is no telling what you hashed.

Some of those blogs not giving avatars with WebMention are mine (or I admin them) so I will have to look deeper into why the WordPress WebMention does not send avatars sometimes. Before then, at least each name has a cute generated image.

Still to do

After five wins I needed to take a break. I’m happy with today’s coding adventure. I think the IndieWeb discovery promise of OpenMentions is closer to reality and the font page is a bit more honest.

When I have seen more entries from Bluesky via Bridgy Fed, I may be able to do something nicer display-wise. Probably the same thing I do with likes.

I think there are some design improvements that I can add to the individual topic pages. They probably won’t happen today. I’m still thinking about the best approach there.

Take a look. Let me know what you think.

That is all.

Blog Activity