Please note that I really do like Enigma, and I have mad respect for everybody who designed its levels, since the levels are an essential part of the game. As you read, please try to keep this in mind, even when my review sounds negative or occasionally sarcastic.
There is a puzzle game called Enigma. The player controls a black marble and rolls it around a top-down view to try to hit coloured blocks called Oxyds and match them in pairs.
Well, that's what the game is ostensibly about. The actual gameplay involves Rube Goldberg machines and obstacle courses between your starting position and a trivial number of Oxyd stones at the end.
If you haven't heard about Enigma before, you really need to see this explanation/review from The Obscuritory, which explains what the game is much better than I ever could.
So since The Obscuritory has already done it, I'm not here to write a review of Enigma the game itself. I'm here to review Enigma I, which is the game's first level pack, and the landscapes in it. ("Landscape" is Enigma's term for a level.) Turns out 100 levels is a lot to write about, so I'll just see how far I get before I get tired of naming all of them. Finally, it's worth noting that since Enigma I is the first pack (apart from the tutorial), the levels here are generally easier, less abstract, and more focused around a particular concept compared to the later level packs. It is absolutely possible to create levels aimed at Enigma newcomers and have them be fantastic, but I expect many of Enigma's truly outstanding levels are hidden in the later packs.
Enigma's built-in rating display goes from 0 to 10, and here is how I will award them:
At the end of this post I will link a level pack I created of all the levels in Enigma I but having removed all the ones that I think suck.
If a level could potentially be improved with the help of some constructive criticism, I will do my best to provide that constructive criticism, rather than mere criticism.
Here we go!
This level is trivial, so I'm not rating it.
Uh oh - not off to a great start. This level has some doors, which alternate opening and closing at a snail's pace. There aren't any obstacles in this landscape, so the only challenge lies within your own mind: Are you patient enough to sit through 3 minutes of the doors? If you are, there's no emotional or in-game reward at the end of this level, only a sense of relief that you can at last have some action again. 2.
You must push the wooden boxes into the water in order to bridge to the Oxyds. There are two screens here - if I roll right a little from the position in the screenshot, the screen will scroll, and I'll be on the very left edge of the second screen.
There's a little challenge here - I had to take 2 or 3 attempts at it - but pushing ALL of these boxes from the first screen ALLLL the way over to the second screen where they're needed takes a lot of time and is frustrating to do over again if you make a mistake while playing the level. The level could have been much improved if the boxes were closer to where they were needed, and I don't think it would have diminished the value of the puzzle.
Since the level spans across 2 screens, it's also harder to plan a solution on paper or in an image editor, since you can't see the whole level at once. 3.
There is an item that looks like an umbrella, and after you activate it, you can roll above the void for 10 seconds until the invincibility wears off. It's a trivial level. Nothing here to rate.
The black snake-like voids actually move around very fast in a random pattern. Each snake has a fixed length and wanders all over the stage, leaving its tail behind it, and if it slithers under you then you fall down and lose a life. You have three lives, and if you lose them all, the level including the Oxyds resets and you have to start from scratch.
I like the concept, but this level has some critical flaws that make it disappointing. First, when you are respawning, if there is a snake underneath you then you fall in again and lose another life. To put it another way, the snakes can randomly spawn camp you. It's more likely than you'd think.
Second, the snakes can overlap themselves and each other, making it really hard to tell where the "head" of the snake is, so you can't predict their movements as easily because you don't know which part is going to extend.
If this level was fairer and easier to play around, I would have given it a better score, but those factors bring down the enjoyment so much that I have to give this a rating of 1. The snakes spawn camping you kinda sucks.
You have to hit the switches to make the blocks rearrange so you can navigate closer to the Oxyds, but if you hit the wrong switch, you get trapped in the middle and have to restart the whole level. Which switches are the wrong ones? Who knows!
This is one of the few levels from Enigma I that I haven't completed, and I've given it a fair go, but I just do not understand how the blocks move. Being trapped and it resetting my progress from a single mistake is so demoralising. It might be a fine puzzle if I can figure out the logic to the block movements, but I can't. I guess I won't rate this one as I might just not be smart enough for it??
Sokoban level.
I'm a big fan of Sokoban clones - hell, my best online friends are from the forum community of a niche Sokoban clone - but Enigma is different from Sokoban. In Enigma you control a rolling physics object with the mouse, bounce off anything you touch, and can only move blocks if you hit them hard enough. This is scientifically the worst possible control system for playing a box-pushing puzzle game.
Now, I still like box-pushing puzzle games, even in Enigma!
But!
Level designers have got to consider the control scheme when designing levels like these for Enigma. It's important to have a floor material that isn't frustratingly slippery, and it's important to not waste the player's time by having them push boxes allllllll the way across the level when they've already solved the puzzle in their head.
Sok It To 'Em has twelve boxes, which must be pushed all the way down and to the right side onto the buttons. It is not a difficult level. After spending under a minute and pushing just one box into the end location, the level can now be trivially solved:
But I still have to execute this obvious solution from here. I have to push ALL the ELEVEN! remaining boxes all the way to the end. This is a chore. 2. Alone, it doesn't totally suck, but it's more tedious than most of Enigma's 1000 other sokoban levels. (Not exaggerating. There are really one thousand other sokoban levels.)
Oh my god, speaking of other Sokoban levels...
This level is an absolute masterpiece. You have to move all the grey blocks onto the blue dots, and as the title implies, it is nowhere near as easy as it first appears. The entire level is in this screenshot.
This level is a masterpiece because it is the polar opposite of Sok It To 'Em. It has a fascinating and engaging puzzle that makes incredible use of the small space of the level. Retrying is quick because I don't have to push the blocks very far. The rough floor is also ideal for box-pushing levels since it's harder to apply too much force to the marble and hit blocks that you didn't intend to.
There are no flaws in this level. This level is mind-blowing. 10/10. This is one of the best levels in Enigma I. Play it.
Moving close to the Oxyds, onto the grey tiles, spawns more of the remaining Oxyd stones in the same pattern.
Nothing too special to see here. The level has a bit too much stuff to be called trivial, but doesn't have much challenge. You roll around and you hit the Oxyds and you win the level. Pretty average. 4. I took away a point because there isn't a challenge, but it's certainly not a bad level. It's relaxing!
The first of the "Meditation" levels. You control all the small balls at once, and you have to get them into the dents. There's no way to fail in this level. It's trivial so I'm not rating it.
At this point, we've passed the opening of Enigma I and we're into its typicals levels. And all in all, the typical levels are not too bad.
The outer ring leads you around the level counter-clockwise, the inner ring leads you around the level clockwise. Most Oxyd stones on the shared wall between the rings, but some Oxyds can only be hit while in a specific ring. You can switch between the rings once per rotation. There's no way to fail. The level is fine, but not interesting. 4.
It plays like what it looks like. The floor is one of the more slippery types. I'm glad that it's not actually too hard - it's certainly not malicious! - but it's not the most interesting level. I'm giving it a 4, which is better than you might expect, because at the end of the day it is very fair.
The maze is randomly generated every time you enter the level. There is nothing in the maze. This level is not interesting. I haven't even moved the marble yet, but I already know nothing in here is going to please me.
I don't think I've completed this one before, so I'll just check now how large the level actually is, because it's larger than the one screen in this screenshot. If it's stupid large than that'll be another point against it in the rating. Let's see...
Okay, it's like 3x3 screens. Oh, and there's the other Oxyd in the top right corner! I guess while I'm here I may as well solve the level and tick it onto my completed list. Alright, just gotta head down into the bottom left corner now, and...
...wait, why isn't that the end of the level? Where are the other Oxyds??
...my god, there's four of them.
The maze is EMPTY, so the only reason I am playing this level is for the sake of the maze. But it's not even a good or an interesting maze. It's an algorithmically generated maze. I feel the same way about algorithmically generated levels as I do about algorithmically generated text: If you didn't take the time or effort to write the text (design the maze) yourself, then it's not worth my time to read it (to solve it). The level has no point. 0. I think this level shouldn't be in Enigma.
All the grey tiles with gradients are steep slopes, and the skulls kill your ball if you touch them. You have 3 lives.
Based on my previous ratings, you might think I'd hate this level for being pointless, but it's actually pretty funny. Also, the level does have a point, it is a dexterity challenge, and it's a short and sweet dexterity challenge at that. While the level is not an innovative concept, I do actually enjoy playing it. And with only 6 Oxyd stones to pair, it doesn't overstay its welcome. 5.
Trivially easy Sokoban level, but at least this one only has three boxes (the plugs), so like the last level it also doesn't overstay its welcome. Just in case you have trouble with this one, there is an easy mode variant, which is exactly the same but with two boxes in the starting room instead. 4.
Far from reaching the brilliance of the level simply titled "Easy?", this level is a single room with no obstacles and the Oxyds hidden in the walls made out of look-alike stones. The real Oxyds are all hidden in the corners of the room. 3.
You start in the middle of this closed room and have to push the brown blocks out the way to get to the outside. Then you have to teeter around the edge of the level on the very very slippery ice, making sure you don't fall into the black abyss.
In case you were wondering, the blocks do not have ice physics. They have no physics at all in any of the levels. The only things with physics are "actors", which is usually the marbles.
It's not a maliciously bad level, but like... ... there's nothing about it that interests me. 3.
This level has two rooms, so four Oxyds in total. After you go through the frictionless chute at the bottom of the screen, you reach the second room which is a vertically flipped version of the first room.
The rotors move towards you at a decent speed to try to kill you, adding some tension and excitement to what would otherwise be a lame matching puzzle. Also, if you move in the right way, you can make the rotors bounce against the Oxyds for you, meaning you don't even have to go into their areas and can try for a better time on the level.
It's short, basic, but engaging. 5.
It's a maze made out of swamp tiles. The level is 4 screens large. The maze is surrounded by deadly water.
Swamp tiles slowly suck your ball in and make it more difficult to move. If you spend about 5 seconds above swamp tiles without touching solid floor, you'll be sucked up completely and lose a life, respawning at the start location.
To add insult to injury, the maze is randomly generated. But at least the gameplay is more engaging than Desert Ruins! 1.
Trivial level.
Trivial spring tutorial. There are two kinds of springs. You pick them up into your inventory, then click them to spring and cross hazards. The wide spring gets dropped on the floor when used, the narrow spring stays with you and can't be dropped. Going for fast times on this is one is funny.
You enter the spring ring and then wait until you win the level. You cannot control your ball while in the ring. You just have to wait until the springs throw you into matching blocks. 1.
The skulls swing around the level in arcs at a decent speed, leaving frictionless space tiles behind them. As more and more of the level gets turned into space, you have to quickly match the Oxyds without dying to the skulls once.
Without any room for error, this level can be frustrating, but with only four pairs of Oxyds to match it's not that hard to get it within a few tries. You have to keep an eye on what's going on in the whole level to make sure you don't launch yourself into the patch of a skull. On the plus side, the fast-paced action and quick retries combined with the need to think before you launch into the frictionless space makes this one enjoyable for me. 5.
Another spring tutorial, this time with 6 Oxyds and a par time that is virtually impossible to surpass.
The ground breaks after rolling over it. Play well and don't fall in. My criteria for a rating of 6 is that it's good enough for me to replay it, and I have replayed Brittle Planks, so... 6!
It seems like your average skull-avoiding level designed for beginners, but those same beginners will find this level surprisingly frustrating. The spawn point in the empty passageway on the right edge of the screen means you'll have to travel the whole length of the level again if you slip up and collide with a skull (compared to if the spawn point had been near the middle of the level and allowed access to several paths like spokes). The section with the arrows is nastier than it needs to be since the arrows hide the ball underneath them. Look at the screenshot, do you see the ball peeking out the left side of the arrows? Since it's hidden, while you're going through it you don't know whether you're about to slam into the top or bottom line of skulls. You just have to move the mouse and pray.
While this isn't so hard for me now with the experience I've gained, it was fairly frustrating when I was going through the level pack for the first time. The arrows section covering over your ball is malicious, and dying there means weaving your way back through the entire level again. 1.
It certainly took revenge on me.
Wait, no, what happened! The level just called Lissajous was fine! Why would you go and make this!
This one sucks. The whole floor is swamp, which slowly drowns your marble and messes up its movement. All the stones are next to deadly water, and there are no extra lives. A single death resets all the Oxyds. Finally, there is gravity which switches direction every half second, making you constantly fight against an invisible ever-changing force to try to stay away from the water, while being close enough to the water to get those edge Oxyds. The easy mode is tolerable, but the regular mode is sadistic. 0.
Another empty maze level, exactly like Desert Ruins, with SIX!! Oxyd stones. Nothing personal against the author of Mossy Paths, but I've already had my fill of maze levels in this pack. 0.
This one is pretty cute, with a fantastic mix of puzzle and execution. The physics gameplay of Enigma does pay off in this level. You have to map out a route which visits every bridge at most once, which allows you to deposit all floppies and keys into the bottom right corner. Not quite as easy as it looks.
After you place all the keys and floppies in this room, a bridge opens up that allows you to travel into the second screen:
Here's the Oxyds, also with disintegrating paths between them. They're all blue coloured so you can visit them in any order without having to match them, which makes sense since there's brittle floor. The route that I used here actually doubled back on some of the paths very quickly before they fully broke. Not sure if that's intentional! Good puzzle, good execution challenge, solid level! I rate it a solid 7.
This meditation level is trivial. You put the balls in vaguely the four corners, and the ramps push them into the dents.
There are about 10 rooms that look exactly like this. Going in the wormhole in the bottom left teleports you to the next one in the sequence, which eventually loops back around to the first room again. Pairing the Oxyds is tricky if you don't know which room you're in, which is why each room includes these movable blocks, which retain their positions when you re-enter the room later.
The solution to the level is to move the blocks into your favourite pattern to signify which colour Oxyd it is, and then keep heading through the wormhole until you see the pattern you made earlier for the matching colour.
Fair level, though not especially engaging. 4.
2 rooms stacked vertically and 6 Oxyds. The white floor inverts your controls, and the rest is frictionless space. Aim carefully to hit the Oxyds. That's all there is to it. Some skill is required to fling yourself into the Oxyds given the inverted controls. It's a completely fair level, but I'm taking away a point for it not being very imaginative. 4.
This is basically two levels in one: easy mode and regular mode both simulate different mancala games. Mancala is a category of physical games from Africa, which are played by moving stones around a regularly shaped board made of holes. Easy mode is the game Awale (also known as Oware, Wari, or Warri) and regular mode is the game Katro from Madagascar.
I don't understand this level's recreation of Katro, but I really like the recreation of Awale. If you haven't played it before, this is a video showing the rules and an example game. The screenshot above shows the state of a new game. My stones are on the left and the opponent's are on the right. I have to capture more than half the stones to win. I can use the top bank of switches to try out a choice, and the glass blocks indicate which new places the stones will move to. I can use the bottom switch to confirm my choice. Then the computer opponent on the right side immediately makes its move.
It took me quite a while to get the hang of this (including having to look up the previously linked video) but now that I know it, the game is enjoyable to play in this Enigma recreation, and it's awesome that the Enigma engine is capable of doing this at all.
The community ratings absolutely shafted this level, giving it a mere 2.5 average, which is why I'm rating it 10 to get those numbers up. And also because it fits my criteria for a 10!
This is cute! Within the frictionless void of space are two gravitational wormholes, and you have to carefully move the marble at just the right speed to fling off them around the skulls into the destination area. That's the whole level! It's a fun concept, fun to play, and doesn't overstay its welcome one bit. 7.
I can't say anything about this level without spoiling the puzzle, sorry! It's good and unique and not too hard - I was able to work it out all by myself. 8.
Each wormhole takes you to one Oxyd, and each destination has a corresponding wormhole that takes you back to this hub. There's no obstacles, it's just pure memorisation. Or, it would be pure memorisation, but even that is thwarted: the wormhole destinations randomly change, so sometimes you just have to brute-force it until you find the Oxyd you wanted. I can't find any skill or strategy here. 2.
You are given a spring and you must jump between the floating islands. There are 6 Oxyds.
No matter which level they appear in, I really really want to like the springs. But every time I find that they're just too unforgiving. Missing a jump respawns me at the start of the level with one fewer life, and landing the jumps consistently is surprisingly difficult. Having the right velocity at the moment you click the mouse button to jump is what separates life from death.
This level at least has large platforms that interconnect in many ways, and the only obstacle is jumping properly, which is better than some of the levels in other packs where I get through most of a long linear level and then fail a spring jump at the end.
That said, I still don't like the springs. 4, which is higher than it could be because they did the best they could with the springs.
There are two horizontal screens. When the blue blocks appear, you get stuck in them and can't move, but they appear and disappear every second. So it's a match-the-Oxyds level with no obstacles, except you can't move half the time. I don't like the concept, but it's mostly harmless. 3.
The springs threaten to bounce you into the water as you roll around the level.
Looks gross, but it's actually more than fine and fair. The floor has a suitable amount of friction, the springs don't bounce you too hard, and the level isn't totally covered in them, so it doesn't condemn you to certain death like you might expect from looking at it. There's a lot of spots where you have more freedom to move around. 5.
There are some invisible springs and the wormholes put you in a variety of random places. With gentle movement you can solve it in seconds through trial and error until the wormholes put you where you want to be. 3 - I wish it allowed for more strategy.
Another simple introductory level. This one wants you to use the boxes to build bridges so you can turn off the laser and get to the left side for the Oxyds. I'm surprised this level is so deep in to the pack, since it's too trivial for me to give it a rating. I'm also surprised that this is the first level to use a laser, since the lasers are so versatile and can make lots of levels interesting in different ways. It's fine!
I don't know why, I don't know how, but this level has atmosphere. It feels like you're not supposed to be here. It feels dark. It feels constructed. It feels like the level tiles aren't quite right. It feels like a basement.
6 for atmosphere, though the gameplay is nothing special.
I love the layout of this one. I swear I've seen it in something else, maybe it was in an official Sokoban game, I can't quite remember. It's still a great layout! The ball feels a little too bouncy for the close-quarters box pushing, but the level does its best. I like it! 7.
... Dead Ball Walking ...
On the one hand it's not a very imaginative idea, and I wouldn't give it a good rating, but... the fact that it so brazenly embraces what it is... look at it... It's so ludicrous that it loops around to being good again? I don't know. I can't rate this. This level cannot be rated. It can only be experienced.
I'm tired of explaining ALL the levels, so from now on I'll just show some of my favourites so I can publish this blog post.
There are 3 blocks of different sizes and you have to move them around the enclosed space so that they all stack on top of a blue circle. This opens a gate. The rules are that smaller blocks can be moved under bigger blocks but not vice versa, and when moving stacked blocks the smaller one is moved first. Yes, it's like the Hanoi towers.
This is actually so fun to puzzle out. Fair and fun and great. The quotes messages at the top (which I already collected in that screenshot) are the cherry on top. Play this. 10.
Another Jacob Scott bridge-building level. You have to build a bridge to the Oxyds on the right side. Every block is needed, and several of them have to be used in clever ways. I especially like the use of the left side and the one-way stone. It took me a few attempts, and I enjoyed the process of gradually figuring out the level! Nothing groundbreaking, but it is good fun! 8.
The big brother of Islands, this one has smaller areas and more boxes. You don't need to use all the boxes, so it's less elegant in that regard - it feels a little less like puzzle solving and more like trying to find something that works. It's still good fun. 7.
The last of Jacob Scott's bridge-building levels that I'd like to highlight. This one is tough. You don't need to use all the boxes, but the challenge is figuring out which ones you do need. It's also worth noting that many boxes must be sacrificed into the water to access other boxes, for example the pairs of boxes along the top-middle and bottom-middle cannot be pushed sideways; one of them must be sacrificed vertically if you want to push the other one horizontally and use it. The symmetry of the level makes it much more interesting to understand compared to Island Paradise. This was really good fun to solve and I found the answer quite amusing. 8!
This is the FUNNIEST level ever. So, the grey tiles are just normal, but the white tiles invert your controls while the ball is over them. It's... it defies comprehension. It defies being rated.
Here's how this one works. There are 4 balls which need to go in the 4 dimples. All the balls are trapped in cages. If a ball hits its cage with enough force, the whole cage moves one block over. So, it's not possible to get all the cages in place for all the balls to go in the dimples... without using the wormholes. When a ball goes in a wormhole it gets teleported to the yellow tile at the top left of the landscape.
So now there are two balls in the top left cage. One catch is that once a ball has left its cage, that cage cannot be pushed again by the other cages. In this screenshot, the top right cage is now stuck there forever. Also, be careful not to crush a ball under the cage when the cage moves.
This is creative, and doesn't make things too complicated beyond this core concept! 7. Very solid.
This is the last level in the pack, and it's the largest by far. It appears to be several simple areas put together, including bridge building and some space floor - but the true part of the puzzle is hidden a little deeper.
Without spoiling the exact details, you have to get the correct order of operations to travel between different parts of the level without blocking yourself off, and to do that, you have to find an extra movable block.
This was extremely satisfying to solve when I finally managed to get it, but the journey to solving it was extremely tough.
The level is not forgiving. You have to navigate around many hazards like bottomless pits and rotors without making a single mistake, since this level only gives you one life to work with. If you mess up during the 15-minute-long level (that's my completion time) you have to do it all over again, and the start is quite fiddly.
If I could improve this level, I would make the bridge building sections shorter, I would make the critical part of the puzzle a little less obscure/easier to execute, and I would let the player do small bonus challenges to obtain extra lives in some sections (as well as setting ConserveLevel=true and AutoRespawn=true). This would make the level a lot less tedious because the player wouldn't have to redo the same starting actions as many times if they mess up.
Overall, while this level was satisfying to finally complete, I'll just give it a 6 because of these issues that would be pretty easy to improve on.
Enigma I does have some fantastic levels in it, but they're sandwiched between an equal number of levels that want you stone dead. I think the pack could be a much more enjoyable experience for beginners if some of the levels were tweaked to be more welcoming and encouraging, and some other levels were removed from the game entirely.
While I haven't attempted (yet?) to improve any of the levels myself, I have curated a little level pack of everything that doesn't totally suck - so I've kept all the amazing levels, good levels, and mid levels. Hopefully this will be a better starting point for newcomers than Enigma I itself!
You can install these level packs by placing the XML file into ~/.enigma/levels/cross
(Linux) or into AppData/Roaming/Enigma/levels/cross
(Windows). Note that if you're using the Flatpak (Flathub's distribution) version on Linux, you'll need to use Flatseal to allow access to filesystem=home
, since this distribution doesn't have the correct permissions by default.
Once you've copied the XML file, restart Enigma, and you can find my packs in the menu by clicking Level Pack > User > (Name of pack).b
Download Enigma_I_Suckless.xml
If this blog post excited you enough to download and try Enigma for the first time, you'll also like my Starting level pack, where I've curated a smaller section of levels to introduce some mechanics, show off what the Enigma engine can do, and also include a couple that are just funny. If you don't like a level from my pack, please do skip it, and if you need a more exhaustive introduction to the game, you could check out the full built-in Tutorial pack, especially Jacob Scott's Advanced Tutorial level at the end of that pack.
Have fun! If you're looking for some help, feel free to check out the Enigma User Support pages or just contact me directly to ask for more of my thoughts!
Byyeeeeee!
P.S. To any Enigma developers reading this, I hope I haven't upset you too much! As I said at the start, I do like the game, and the levels are a very important part of the game! I don't know if Enigma's levels get updated or not, but if it is possible to update a level, I'd love to work with you to contribute some improvements to the levels for the next version of Enigma! If you'll have me, of course. You can get in touch with me here!
]]>Your logged in session is stored in the cookies. I suggest using the cookie-jar pattern rather than manually constructing the cookies for each request.
The user agent also matters. You cannot change the user agent header at any point or you will be accessing the logged out version of the page.
These curl commands are demonstrations only. They will not work on their own. The purpose of them is to show which URLs, cookies, headers, and body data are necessary. You will want to use your own programming language instead of curl, and you will need to fill in the placeholder data.
Here's the tutorial:
(something along these lines) curl -v 'https://example.com/forum/ucp.php?mode=login'
You need to do this to get cookies. Save the returned cookies in the jar.
(something along these lines) curl -v 'https://example.com/forum/ucp.php?mode=login' -X POST --data-raw 'username=USERNAME&password=PASSWORD&redirect=.%2Fucp.php%3Fmode%3Dlogin&redirect=index.php&login=Login' -H 'Cookie: THREE_COOKIES' -H 'Content-Type: application/x-www-form-urlencoded'
Save the returned cookies in the jar.
(Note: If your language's cookie jar library is properly programmed, the previously stored cookies with the same name will be overwritten with these new ones. If the cookie jar remembers all versions of each cookie, just make sure the constructed cookie header has the NEW values at the START. For example, Cookie: foobar_cookies_u=34567; foobar_cookies_u=1; foobar_etc_and_so_on=
will work. Hopefully you shouldn't have to worry about this at all!!)
curl -v 'https://example.com/forum/' -H 'Cookie: THREE_COOKIES' > am_i_logged_in.html
Open up the page in your web browser and see whether it looks logged in.
You can tell if it didn't work if you aren't logged in on that page. You can't get error messages out of phpBB, so you'll have to keep looking at your process and trying things until it finally works.
Print out the raw HTTP request you sent in step 3. Does the user agent look right? Do the cookies look right? There should be 3 cookies sent here: foobar_cookies_sid=hexadecimal; foobar_cookies_k=; foobar_cookies_u=34567
. If the cookies are wrong here, print out the HTTP request and response you sent in step 2 and examine those.
Another idea for debugging is to try sending this request with curl to the forum's main page, and tweaking it until the message stops saying "Login" (this means you haven't succeeded and aren't logged in) and changes to "Logout" (this means you succeeded and are logged in):
curl https://example.com/forum/ -H 'User-Agent: USER_AGENT' -H 'Cookie: THREE_COOKIES' | grep Log -m 1
#HttpOnly_.
flags at the start of some lines. You must remove those flags from the file before feeding it into your scraping program. Remember to set your scraping program's user agent to the same user agent as the logged in browser.Please send any feedback, refinements and corrections to my email with a specific subject line so that I can improve this page!
]]>I've been told that a tool called "Vallpaper" can also help with this. However, I haven't tested it at all, so it might not work! Don't come asking me for help, but do feel free to let me know if Vallpaper works for you, and I'll update this section of my blog post.
My original post continues below. You should read it! :)
Over the last couple of days I've been setting up my new KDE install -- KDE is REALLY good, thank you so much to the people who work on the default applications and system integration -- and I wanted to take advantage of the great virtual desktops feature. It seems that in the past there used to be a way to display a different wallpaper on each virtual desktop, however, this feature was removed around the time that KDE 5 came out.
Nowadays, the only default way to have different wallpapers is to use the "activities" feature, which is very similar to virtual desktops but with some features added (like independent wallpapers and layouts and panels) and some features removed (like being able to zoom out to get an overview of which windows exist across all spaces).
Some KDE developers have been thinking about removing activities and combining their features with virtual desktops, so maybe that'll happen in the future to make this easier! For now, we have to create something to add that functionality.
If independent wallpapers don't really exist, the next alternative is quite straightforward: detect when the active desktop changes, and then change the global wallpaper to match it.
I'd heard of a few different KWin window tiling scripts, so I assumed that KWin would have the necessary functionality. I quickly discovered a built-in KWin script, located in /usr/share/kwin/scripts/desktopchangeosd
, that has code to detect when the current desktop changes. I also found a shell command that appears to execute a Plasma script to change the wallpaper, which would complete the missing part of the puzzle. All I need to do is figure out how to put them into one file!
I'll save you the two hours of me failing to do this. It turns out that "KWin Scripts" and "Plasma Scripts" are entirely different things with different features? In particular, Plasma Scripts can change the wallpaper but not detect virtual desktops, and KWin Scripts can detect virtual desktops but not change the wallpaper.
WARNING: This is cursed! Read on if you dare.
So KWin scripts can't actually communicate with the outside system at all, no wallpaper, no shell commands, no file access, all they can do is manipulate windows because KWin is only a window manager. Foiled? Not quite. KWin can actually affect the outside world in one way: error logging.
console.error(...)
in a KWin script will send data, and journalctl _COMM=kwin_wayland -n 0 -f
in a shell will read data. Perfect, we're now communicating in real-time (?) between KWin and the system. The shell script just needs to call plasma-apply-wallpaperimage
to set the wallpaper.
Install the KWin script with:
kpackagetool5 --type=KWin/Script -i /path/to/wallpaperperdesktopfolder kwriteconfig5 --file kwinrc --group Plugins --key wallpaperperdesktopEnabled true qdbus org.kde.KWin /KWin reconfigure # ??? kwin --replace # THIS WILL CLOSE ALL RUNNING PROGRAMS
To complete the puzzle, download and edit the shell script to point to your favourite wallpapers, then run it in fish shell. Changing virtual desktops will change the wallpaper with a cross-fade animation.
If it doesn't work, check the shell script's logs and journalctl _COMM=kwin_wayland -n 0 -f
I guess. But I'm probably not going to be able to help you debug anything since I know just as little as you do.
What can KDE people do to improve this?
An important thing is improving the documentation. I was flying completely blind creating these scripts. I had to trial-and-error the folder structure, each individual line of code, and run three commands and log out and log back in again after making each change to coerce it into applying the changes.
While the documentation technically exists, and there's almost a page with a tutorial, the tutorial could do a lot more to explain step-by-step how to set up the folder structure for your KWin script, how to install the script, how to reload it after making changes, how to produce debug logs, how to monitor debug logs. All of the tooling things that surround the actual code are extremely under-documented and I had to rely on code searching other people's GitHub repositories and reddit questions with 2 comments apiece to discover these basic steps.
After better documentation exists and has been user tested, add a link from the "KWin Scripts" settings pane to the main page of that documentation section, with a caption something like "How to create KWin scripts."
The best idea to solve the problem would be to merge workspaces and activities into parity with each other. This would also clean up a lot of end-user confusion about what the two features are. I've been using Linux for years and I've been using KDE Activities for 10 months up until today and I honestly don't know what a use case of activities is.
A workaround for this specific problem could be to allow KWin scripts to execute Plasma scripts. This would fill in the gap of KWin scripts being good at detecting signals and Plasma scripts being good at doing actions.
Finally, the method I described in this blog post actually answers the classic FP thought problem of whether output logging is a side-effect. It is. Lol.
Cadence
]]>I dunno, what are they? Your guess is as good as mine...
Third-person pronouns, such as he, him, she, her, it, they, are used by a person that isn't me in order to refer to me without having to say my full name each time.
I don't say my own pronouns, because I am me.
Therefore my pronouns are whatever other people say I am.
SSSHHHHHShhshhhssssssssssshhh!!!!!!
I'm not picky. Since I'm a ẃ̷̗o̵̜̎m̸͎͆a̵̜͌n̴̥͒, choosing ẃ̷̗o̵̜̎m̸͎͆a̵̜͌n̴̥͒ly pronouns would make sense... but ultimately my pronouns really are what other people say they are.
they them or she her. ARE YOU HAPPY NOW? ARE YOU HAPPY? ARE YOU HAPPY?
The background of the website is now a pretty pattern. I think that using a pattern background recontextualises a lot of things of the site. "What does that mean, Cadence?" I don't know.
The background image is a heavily edited Windows XP built-in tiled wallpaper. GNU Image Manipulator's "cubism" filter did most of the work. After that it was a matter of adjusting the hue and contrast so that it would be noticable while not interfering with reading the actual text.
If you want to add a tiled image background to your entire site, I'd recommend using black text on a light image background to make it easier to read. Example of a light background image. This is because when the whole screen is darkish like my website, variations in that dark colour are more noticable, whereas when the whole screen is light, variations in that light colour are less noticable. For the background, you probably want it to be less noticable because the text should take priority.
Related, I might add a light theme variant to my whole site for accessiblity. We'll see.
The blog section has been renamed "weblog" (the URLs are staying the same, at least for now.) The story behind the word weblog is that diaries, or logs of one's activities, when on the web, were called weblogs (web-logs). This was shortened to "blog" somewhere around the mid-2000s.
In recent years, the number of companies running self-described blogs is out of control. Here are the types of things that are called blogs on the web as it stands today:
Commercial interests are persistently gaming internet search engines and making them useless for finding personal websites, actual websites with stories and hearts to them.
Me using the word "weblog" rather than the now-meaningless "blog" is an attempt to fight back against this. Hopefully I don't get dropped off the SEO rankings as a result of changing this important word across my entire site oh god why am I thinking about SEO I have never put a single second of thought into the SEO for this website before now
XXX: Reword and rewrite this post when not exhausted
— Cadence
]]>The rest of this post will be technical analysis.
Fandom, formerly Wikia, is one of the most annoying websites on the internet. It is always accelerating and gaining traction and scooping up other wikis and wiki farms. The site now contains so much important knowledge contributed by so many people, but the user experience is really really horrible. To put it in the words of an anonymous user:
Fandom pages crashing and closing, taking forever to load and locking up as they load the ads on the site... they are causing the site to crash because they are trying to load video ads both at the top and bottom of the site as well as two or three banner ads, then a massive top of site ad and eventually my anti-virus shuts the whole site down because it's literally pulling more resources than WoW in ultra settings...
The site has too many ads. But even with ad-block, the layout still sucks a lot and the page is slow to load.
Fandom itself is actually built on top of open source software, MediaWiki. MediaWiki is the software that runs Wikipedia, and most other interesting wikis on the internet. MediaWiki can be heavily skinned and modified, so you might not recognise that you're using it. Fandom has taken open source software and used it to build the most annoying ad-infested website of all time.
MediaWiki is open source/free software with the GNU GPL 2 license. Free software helps, well, software freedom, but it doesn't ensure that end-users will have a friendly experience, and Fandom is the evidence. An example of a potential solution is the Anti-Capitalist Software License, because software tends to be user-friendly when it's made with people in mind rather than profits, but there's a lot of questions that have yet to be satisfactorily answered.
Hilariously, wiki text authors have hated Wikia for a long time — as far back as 2010. In 2010, Wikia rolled out a new "user-friendly" skin for the site that many protested against, but I'll let the Anti-Wiki Alliance speak for itself. Why not take a look at its site?
If you are a wiki text author, the Anti-Wikia Alliance also provides guides and assistance on moving your own wiki off Fandom to somewhere more ethical, and lists suggested destinations you could move to, free and paid.
"Why would I pay for wiki hosting?" Because someone has to pay to keep it online, and if you aren't paying, then either ads or investors are. That's the unfortunate reality.
MediaWiki has extensive APIs. BreezeWiki queries those APIs for HTML page content, search results, category listings, and whatever else it needs.
Wiki pages are written in wikitext markup, which gets transformed to HTML for display. This can be any HTML at all, so BreezeWiki needs to be flexible and minimal in how it handles the page content so that it can deal with a variety of sites with different appearances and layouts.
BreezeWiki is written in the Racket programming language, a dialect of Lisp. In Lisp, s-expressions are the core building block of all data structures, and they can be used to hold XML (HTML) representations easily. This means all the core list manipulation tools can be used for editing the structure and content of the HTML, making it a really natural fit for the site.
BreezeWiki uses the html-parsing module to convert the HTML to a nested tree of s-expressions, then it walks that tree with a recursive function to edit the tree. At each step, the function takes in the current element, and returns a replacement element. This functional style lets the tree be transformed in a consistent and immutable way. Once it's all done, the s-expression content is added to BreezeWiki's page template, and that's all converted back to HTML with the html-writing module and sent to the client.
This tree walking code is how it converts inter-page links, for example. As it walks the tree, whenever it finds an "a" element with a src attribute that points to the same wiki, it rewrites that attribute and returns the new element.
You can open src/page-wiki.rkt in the source code to see precisely how it does it.
You might recall that I recently stopped running Bibliogram, and be wondering, how long will BreezeWiki exist for?
The answer is, I don't know, so enjoy it while it lasts! What I do know is that it'll be fun as hell. Tell your friends, tell your co-workers, and tell any wiki authors you know to transition to another hosting platform.
See you next time!
Cadence
]]>Quoting in Lisp is a very important concept in programs that deal with data structures. Here's the concept explained without excessive detail.
This page specifically uses the Racket dialect of Lisp, but these examples are general enough that they should apply to any kind of Lisp.
You don't need to memorise these right now, you can always come back and check them later for clarification.
value
- something like a number, a string, or a symbol. values are data.list
- a one-dimensional list of values (can also include nested lists). lists are data.variable
- a variable stands for a value, but the variable itself is not a value. variables are not data (but their values are).symbol
- a symbol looks like a variable name but it has ' before it. symbols are data.sexp
- stands for s-expression. a sexp is anything between parentheses. to be more specific, it starts with an open parenthesis and continues until the matching closing parenthesis. there may be nested sexps inside it. sexps might be data or might not be - you'll see.word
- this isn't Lisp terminology, this a term that I made up to represent a sequence of letters that appears within a program.It's okay if these don't make sense right now, because the rest of this page will serve as examples for all of these.
(define x 42)
This can be executed as code. The first word inside the opening parenthesis is the function to call, and the other words are its arguments.
Here, x is a variable, 42 is a value, and (define x 42) is a sexp. (define x 42) is not a value because it will be executed as code.
The function list creates a list out of its arguments:
(displayln (list 39 40 41))
Try writing this as a program and executing it. The output area will show the result (39 40 41). The result displayed in the output area is a list (and also a value, and also a sexp).
Rather than constructing lists, they can be directly represented in the program by writing the list with a quote mark ' before it:
(displayln '(39 40 41))
Try writing this as a program and executing it. The output area will show the list (39 40 41) which is the same as before.
Since the quote mark ' affects the entire sexp that follows, you can quote nested lists too, using just a single quote mark:
(displayln '(39 40 (41 42) 43))
If you didn't write the quote, the interpreter would treat this sexp as a program to execute. It would try to call 41
as a function, and then try to call 39
as a function. Numbers aren't functions, so you'll get an error if you try.
(displayln (append '(1) (list 2)))
The quote only applies until the end of the sexp. It applies to '(1)
but does not apply to (list 2)
.
Up until now, we've been using displayln
to display the values in the output area.
From now on, we're just going to write the values directly. One difference in doing this is that when not using displayln
the output area will also include a quote for any printed list.
(list 39 40 41) ; example one '(39 40 41) ; example two
When each of these is evaluated, the output area shows '(39 40 41)
, with a quote mark. This fact isn't particularly significant, I just want to make sure we're on the same page.
Quoting a word results in the concept of a "symbol" that was alluded to earlier.
Executing this program gives the symbol 'x
in the output area:
'x
Conceptually, symbols are just arbitrary values. One use for them is like enums from other programming languages.
Now that you know what a symbol is, I can show you that entire sexps can be quoted too:
'(39 40 41 x 43)
Since the quote mark ' affects the entire sexp, the x
here is quoted too, and becomes a symbol. The result displayed in the output area is '(39 40 41 x 43)
. x
is not evaluated as a variable, because it isn't a variable. Because it is quoted, it is a symbol, and symbols are just values.
Observe:
(require racket/list) (second '(39 40 41 x 43)) ; -> 40 (fourth '(39 40 41 x 43)) ; -> 'x
<p>Welcome to my <b>cool website!</b></p>
X-expressions are a Lisp-y representation of XML. They represent XML as list structures, which can then be manipulated with the usual sexp-related functions like list
and car
. It's easiest to explain with an example:
'(p "Welcome to my " (b "cool website!"))
The quote mark ' at the start is required because 'p
and 'b
shouldn't be called as functions. This sexp is a store of data, not a program to be executed. 'p
and 'b
are actually symbols, and in this case they represent the XML tag name.
The <b>
tag is deprecated in HTML 5, so let's replace it with the semantic <strong>
instead.
In other programming languages, you might expect to use an object-oriented XML parser to do the work, but quoting and the x-expression notation lets us take a different approach in Lisp.
(define old '(p "Welcome to my " (b "cool website!"))) (define (replace-strong sexp) (cond [(symbol? sexp) (if (eq? sexp 'b) 'strong sexp)] ; recursion target: replace 'b with 'strong [(pair? sexp) (cons (replace-strong (car sexp)) (replace-strong (cdr sexp)))] ; recursion: reached a cons cell, replace its contents [#t sexp] ; don't touch other types like strings )) (replace-strong old) ; -> '(p "Welcome to my " (strong "cool website!"))
DON'T PANIC if this example is beyond you. If you understand it, awesome! If you don't understand it, you're not missing out.
Touching on the example from earlier:
'(39 40 41 x 43)
What if you wanted 'x
to actually be used as a variable, not a symbol? What if you did want to create the list '(39 40 41 42 43)
? Without quoting, this can be done as follows:
(list 39 40 41 x 43)
But this can get messy if the data structure is complex, with several nested lists.
The quasiquote feature allows this in a compact notation. The quasiquote character, also known as backquote or backtick ` acts just like the normal quote ' most of the time:
`(39 40 41 x 43)
But using a quasiquote enables two additional features. Using a comma, you can unquote a specific value anywhere in the tree, such as inside nested lists:
`(39 40 41 ,x 43) ; -> '(39 40 41 42 43) `(39 40 (41 (,x)) 43) ; -> '(39 40 (41 (42)) 43)
Quasiquote is often much easier and less messy than the alternative:
(list 39 40 (list 41 (list x)) 43) ; -> '(39 40 (41 (42)) 43)
You can splice lists into other lists using ,@
inside a quasiquoted list. Wow, that was a lot of jargon. Check out the example:
(define y '(5 6 7 8)) `(4 ,y 9) ; -> (4 (5 6 7 8) 9) `(4 ,@y 9) ; -> (4 5 6 7 8 9)
Using unquote , puts the value directly into the other list. Using unquote-splicing ,@ puts each list element into the other list, flattening them together.
If you want to read a longer and more thorough explanation, an excellent option is available in the How to Design Programs book.
If you want to learn about how code and data are the same structures and how this naturally connects into macros, see CSE341 Lecture Notes 14 and then Macros in the Common Lisp Cookbook.
If you want to learn more Lisp basics, check Lisp Quickstart - Learning Lisp Fast for the short version and The Racket Guide for the long version.
If you want to learn how to design programs, read the How to Design Programs book for beginners.
Hopefully this guide was an appropriate length to get you get to grips with quoting. Knowing you, you just read through this whole thing without trying the code examples in your editor, and that's okay! I designed this guide so that it should make sense just reading it, but I really really do recommend pasting the examples into your editor if you want to explore them and deepen your understanding.
Okay, that's the end. See ya!
— Cadence
]]>I have noticed this for several years but not known whether or how to put it into words. After thinking about it more than usual in the past weeks, this is my attempt to describe my feelings.
When significant changes occur in my life it feels like they are occurring around me without my agency. They don't have an impact on my feelings or emotions, they are just things that happen.
Examples of this occurring in the past:
As for romance and dating in my life, sometimes I do have feelings and emotions about these, and often when I feel them they are very strong. But that's only sometimes; an equal or greater amount of the time I don't feel anything about them.
Many people around me ask me "how did it feel to ..." for each of these life events, and "I didn't feel anything" is not the answer they're expecting. So I think most people around me would feel things in these situations. So I expect it's normal and natural to feel things.
Which begs the question, why don't I?
I've figured out a few things that are potentially related.
Maybe it's a combination of all of these.
A better question would be, do I want to feel things?
I believe so! It would be important and valuable to connect with my feelings more. I imagine it would also have wider positive impacts on my life and my brain.
I don't know for sure.
I'm going to try spending more time thinking about my feelings rather consuming the internet and turning off my brain. I'm going to take my own advice on the matter.
And if this doesn't help, well, I'll still be in a healthier place than I am currently.
I can also research each of the potential causes I mentioned above to see if other people affected by those things have had similar experiences to mine.
I guess there's nothing more to say. Feel free to get in touch if you know anything about these feelings, or if you have a response to my words.
— Cadence
]]>Instagram is really annoying, and I've given enough, and I don't want to deal with it anymore. Bibliogram will remain mostly broken unless somebody steps up to fix it. The main instance, bibliogram.art, will shut down, unless somebody wants to take it over. If you want to try fixing Bibliogram, you should read through the rest of this post for helpful tips about the current situation.
I started Bibliogram in early 2020 because Instagram was pissing me off. This may sound surprising, but I have never really used Instagram before starting Bibliogram, and I have never had an account, so I didn't personally care much about looking at Instagram posts. The story is that I encountered Instagram links sent by friends too frequently for my taste and wanted to make a workaround.
It was annoying to see a login wall in the browser when the server didn't try to stop you from accessing the data at all. So Bibliogram accessed the server and put the posts into a friendlier page layout and that was it.
A much-requested feature I added early on was RSS feeds. This ended up getting quickly turned off for the main instance, because RSS usage was dwarfing interactive usage. Many of these feeds had been added to people's readers and forgotten about. Even today I still receive a decent number of forgotten requests for feeds — these forgotten feeds haven't returned useful data for more than two years. Feed requests aren't free. Bibliogram needs to make an outgoing web request, wait for it, and convert the response data. This also uses up a piece of Bibliogram's rate limit to Instagram, even if nobody's there to see the feed that Bibliogram generates.
Instagram rate-limits access to its servers to stop people from doing the exact thing I'm doing. I'll try to document here the phases that I went through, but I might have forgotten some of those phases.
Don't panic: I am not documenting any of the currently working workarounds, only the past ones which are useless except for historical interest.
I'll be using rkrkrk
as a sample username.
There's a parameter in profile pages called rhx_gis and your application needed to remember this parameter so that it can use it in subsequent requests. If you use the wrong rhx_gis, you're locked out. Instagram used this in the past, but didn't require it when I started working on Bibliogram in January 2020.
After 100 or so requests to profile pages like instagram.com/rkrkrk
they'll stop returning a useful response until you cool down. Timeline continuations weren't limited, but you could only access the timeline if you knew the internal user ID, and you could only get that ID from the profile page. So if you'd accessed a profile page in the past, you could store the ID and you only needed to access the timeline continuation from then on, which wasn't limited. Problem solved.
(Currently, the limit on requests to profile pages is way less than 100. It's more like 3. I don't remember when they lowered it.)
You can now only access a profile page if you're in somebody's house in real life — so not if you're a server on the internet. This era was documented here, and it was the first time people saw the notice that an instance was blocked. This limitation means Bibliogram could only load profiles it already knew the user IDs of. I developed a few ways of working around this:
For finding user IDs, the assistants feature was added. Trusted people could run the assistant program at home, which would collect user IDs (and nothing else) on behalf of Bibliogram, and Bibliogram instances could share between each other all the user IDs they already knew about.
Similarly, there was the import script, which copied all user ID mappings from one instance to another. It would output numbers like Imported 492381 entries (37161 new, 138 overwritten, 455082 skipped)
which means that 37,161 previously unknown users can now be looked up on that instance thanks to sharing IDs.
Finally, there was a browser userscript people could install to let them access a specific user ID.
These bypass methods are all part of Bibliogram's code still, but they're not used any more because they're totally useless.
I'm Cool. I was messing around with google search and entered the query site:instagram.com
just to see what would come up. Curiously, I found a URL like instagram.com/rkrkrk/feed/
which is just like a regular profile URL but with /feed/
on the end. I clicked it, but the page didn't load properly. I checked out the page source, and all the data needed for Bibliogram to work is in there. And then I decided to check it out on my server, and it wasn't blocked at all. In conclusion, Instagram's internal code is absolutely dogshit. You'll see more instances of their dogshit code as we continue.
I put /feed/ into the Bibliogram code and all is well. Total bypass.
Here's the update post for this one. This is INSTAGRAM_BLOCK_TYPE_DECEMBER in the code. /feed/ requests are now blocked for some servers - but not all. I moved Bibliogram to Iperweb, the first suggestion I got, and it works again. (Iperweb has poor value for money servers though, I wouldn't recommend you use that particular company.) Requests now work most of the time. My memory is a bit fuzzy on this one.
Each graphql request has a different set of rules based on the matrix of whether you're at home or a cloud server or accessing via Tor, and which query_hash you're accessing. There's about 4 different behaviours that are fixed for a particular location-endpoint combination, but are seemingly assigned randomly. Why? Probably because its code is dogshit. Anyway, I route through Tor but only for the ones that work through Tor.
After fixing this, I guess nothing really happened for a while? Bibliogram was in a state of mostly-working. It worked the best I could make it work while always scraping from logged-out resources. If you're logged into an account, it's another matter entirely. A whole world of endpoints opens up to you, especially ones used by the official app. However, if you make a wrong move, Instagram will not hesitate to shut down the account for supposedly suspicious activity, and creating an account also means agreeing to the Instagram terms of service, which I do not wish to do.
Instagram radically changed the way it internally arranges the data in its pages, requiring new ways to make requests and new ways to parse through it.
For the profile page, there are 4 different ways that the data might be provided, and your extractor has to handle all 4. It seems to switch which format is being used every few hours. If it's not the right time, then the exractor you're using will fail. Here are the formats:
instagram.com/rkrkrk/?__a=1
ajax after original page load, tiny tiny tiny rate limit.instagram.com/rkrkrk
and extract _sharedData, similarly tiny tiny tiny rate limit. You can try the /feed/ workaround, which used to give more requests, but this appears to finally be patched now. /feed/ might only work from specific classes of IP addresses.instagram.com/rkrkrk
or /feed/ and extract PolarisQueryPreloaderCache.While it is still possible to write code to handle these methods and switch between them, some of them are rate limited too heavily to make Bibliogram viable at those times. Tor seems to be restricted further, though not completely.
From as soon as mid-2020 I began to deal with a serious problem of poorly coded bots accessing Bibliogram and using up its rate limit. These bots were created without regard for whether their requests succeed and they don't acknowledge my requests to slow down. They were designed specifically to scrape data from Bibliogram, and the owners were apparently too lazy to run their own instance of Bibliogram, or to contact me asking for help setting one up. The bots are a problem because they appear to be unmonitored, and they're using up the rate limit that would be better if it were helping real people. In August 2020 I blocked various proxy networks from accessing my site, then dealt with the really bad offenders on a case-by-case basis. Here's the list that's currently being used.
Later on, I'd create a system where Bibliogram dynamically applies its own rate-limiting system to anyone accessing it.
I think a mistake I made here was the faceless approach to blocking people who are being a problem. They treat being blocked as a puzzle to overcome, and Bibliogram as just another faceless website, rather than something being run by real people who want to help. In the future I'd approach this differently by giving bots a custom error message that appeals to the operators' humanity and asks them to contact me rather than just trying to work around the block. Kind of like the anti-piracy screen in Just Shapes And Beats.
The simultaneous crackdown on /feed/ and Tor and with needing to write new code to scrape the page is too much for me to bother with, especially when I am working on it in my spare time and have no personal interest or incentive.
You can't look at profiles. You can still look at individual posts, but if this breaks in the future, I probably won't fix it.
The main instance, bibliogram.art, will shut down unless somebody offers to take over running it.
Bibliogram is open source, and it is still excellent code to build on top of, since it has the interface design, the post models, and the structures set up to perform several workarounds.
All that is needed to make it work is a function in collectors.js or body.js to access the data in the new format.
More Instagram workarounds are definitely possible due to its code still being dogshit, but I don't have the energy to look for more workarounds myself.
Yes, Bibliogram can be revived. But I won't be the one to make it happen.
If you decide to take up the task, I have three simple but important requests.
Huge huge massive thanks to the volunteers that translated Bibliogram's interface to their language, and I'm sorry that I let down your hard work a bit by discontinuing Bibliogram. I've credited you all again here to show just how important you are!
Thanks to the Bibliogram chatroom for keeping me company and coming along on the ride with me.
Thanks for Austin Huang for creating a real alternative to the Instagram app. May Barinsta rest in peace.
For the people in #87806986 on /g/, you are fucking hilarious. Maybe the best way to cheer somebody up really is by showing them a clown.
Something very exciting is coming next. Stay tuned for my next project: Announcing BreezeWiki.
See ya!
— Cadence
]]>This guide assumes you have Element desktop logged in and you're able to decrypt the messages in your client. If Element refuses to decrypt then this guide isn't for you, sorry.
This guide is for people who have a bunch of JSON of an encrypted event, perhaps obtained from their homeserver, and they want to legitimately decrypt it using their own client's keys.
Also, if you want to decrypt the history of an entire room to save as plaintext, you can do this using the built-in "export chat" button. Save as plain text and turn up the size limit to 100 MB. For massive rooms (>100k events) this could take a couple of hours. Element may appear to be frozen during the process but it will finish eventually.
Press Ctrl-Shift-I to open the console, then paste the following code, replacing the middle line with your event JSON.
(e => mxMatrixClientPeg.matrixClient.crypto.decryptEvent.bind(mxMatrixClientPeg.matrixClient.crypto)(new (mxMatrixClientPeg.matrixClient.store.getRooms()[0].timeline[0].constructor)(e)).then(c => console.log(c.clearEvent)))( { PUT YOUR EVENT JSON HERE WITH THE CURLIES } )
mxMatrixClientPeg.matrixClient.crypto.decryptEvent.bind(mxMatrixClientPeg.matrixClient.crypto)
Prepares the built-in decryptEvent function so that it can be called.mxMatrixClientPeg.matrixClient.store.getRooms()[0].timeline[0].constructor
Gets a copy of the MatrixEvent type. This is done by looking up an existing event, and getting its constructor.new (...)(e)
Constructs a new MatrixEvent on the provided JSON..then(c => console.log(c.clearEvent))
Once it's done decrypting, displays the result.(e => ...)({})
An anonymous function to make it easier to see where to paste the event JSON.Hope this helps!
Cadence
]]>This is nice and easy because encryption is the default. On the "people" section on the left side, click the plus icon. Search for a person's name, or enter their full @username:matrix.org handle into the box. Click Go. All done!
If you like encryption - most people do - then you don't need to read the rest of this post.
---
Starting one is really difficult and annoying. You used to be able to do this by flipping a switch, but the functionality has been removed now.
To get into the technical details, Matrix's representation for whether chats are direct or not is also a pain. Rather than being a property that's set on the room and consistent for everybody, the is-direct state of a chat is determined for each user by their own account data, and can only be broadcast to other users when inviting them during room creation.
This article will mostly be avoiding the technical details.
First, go to the rooms section and create a new room. Make sure the room is private, but make sure it's *not* encrypted by flipping the switch off.
Then, invite the other person to the room. (You can click on "people -> invite to this room" in the side bar.)
Once everybody is in the room, run the command "/converttodm". This will give the chat the correct name and picture, and it will warp up to the "people" section in the left side list. Each person needs to run this command because the command does not synchronise between people.
This is, currently, the only way to do it in Element.
This is a long shell script because creating the chat is a three step process with many opportunities to fail along the way. I have used the non-POSIX-compatible fish shell, but feel free to port this to another shell. You need curl and jq to run it.
Put this file into the `~/.config/fish/functions` folder. You'll need to put your access token in the script (or read it interactively); you can find an access token under "settings -> about -> access token" in Element. You can now immediately invoke `matrix-start-chat @user:server.tld` (multiple recipients allowed) in the shell to start a new unencrypted chat. The people you're inviting to chat don't need to do anything special.
Step 1: Call the createRoom API endpoint with all the users you want to invite, saying that you'd like the chat to be direct. This does create the chat and asks all *other* users to make the chat direct on their side, but we still need to mark it direct on our side.
Step 2: Query the m.direct account data, which stores which chats are displayed as direct chats on our side.
Step 3: Insert the new chat into this field, which is a non-trivial process, even with jq. The modified m.direct can be sent back to the account data. All done.
Hope this post helps you!
Cadence
]]>SchildiChat is a much improved version of Element for desktop, web, and Android. I have since added these sound effects to it in a PR. The softer sounds are default (but you can switch back to Element's, if you desire).
Please just use SchildiChat.
The original post continues below.
There are two problems with Element's notification sound. Firstly the sound, secondly its frequency.
On the internet, text conversations are often fragmented into several small messages as one person thinks of more things to say. The other person then replies.
Conversations are also asynchronous, which means that they don't take place in real time. Somebody can walk away from their computer, come back later, and reply to the message without breaking the flow too badly. You can't do this with a phone call, for example. Taking time to reply is acceptable etiquette.
Because of this, you don't need to notified for every message you receive. If somebody tells you something over the course of a couple of minutes in 4 separate messages, you only need one notification sound for that. You'll remember that you have something to check, and when you do check, you'll see the conversation. Having an extra 3 notification sounds won't make a difference, it only serves to be annoying.
The userscript solves the first problem by replacing the sound, and the second problem by limiting the frequency of notification sounds.
The new ringtone was created by Ana Gelez and the new message sound was created by my friend Quarky.
Here is the first part of the userscript, to show you how to change the settings:
// **** CUSTOM SETTINGS HERE **** //
// after the application makes an audible notification sound, all sounds arriving in the next [TIME] will be completely silenced.
const gapBetweenSounds = 10*60*1000 // 10 minutes
// when you focus the application and check messages, this will reset the timer so the next received message will always notify again.
// depending on your system, this focus detection could be unreliable, causing you to miss notification sounds!
const resetOnFocus = true
// replace the default sound effects with ones of your own choosing.
// if you want to design your own sounds, you need to put ogg and mp3 files on the server.
const customSounds = {
messageAudio: { // when you receive a message
url: "https://umbreon.heyquark.com/files/notif", // default is "media/message"
volume: 1
},
ringAudio: { // when you receive a call
url: "https://umbreon.heyquark.com/files/ring", // default is "media/ring"
volume: 1
},
ringbackAudio: { // when you place a call
url: "https://umbreon.heyquark.com/files/ring", // default is "media/ringback"
volume: 0.5
}
}
// **** END OF CUSTOM SETTINGS ****
You can view the whole script and install it by clicking here. You must have a browser extension like ViolentMonkey installed already. This linked code is licensed under CC0 meaning you can do anything you want with it. If you want to officially make this part of Element, you have my full blessing - but please just use SchildiChat.
Have fun!
— Cadence
]]>You're welcome to not read this if the language is harmful for you, or if you just don't find it interesting or helpful. I love you!
The people read my blog almost certainly are not GitHub's biggest fans and are aware that alternatives exist, so I won't dwell on this much.
GitLab really is the worst thing ever. It doesn't offer any advantages for anything I want to do on a git forge, and using the straightforward features has so many bad parts.
Disclaimer: I pay to use Sourcehut and it is by far the forge that I have used most within the last two years.
I'm going to organise this as written text since it's really different from the options above, and harder to group into positive or negative things. Most of them are mixed, coming with upsides and downsides.
It's really incredibly fast to load, particularly on bad networks like the entirety of Australia.
Check out the totally* unbiased* speed comparison website.
It's run by a real person that you can contact if you have problems and he replies to your emails! That's cool. He respects you (a little bit) and won't take down your data unless he really has to. And he'll let you know and be apologetic about it. (Unless you're being an asshat.)
He also has a LOT of opinions and will probably not like your feature request because you just don't understand his amazing grand vision. And none of your users understand his amazing grand vision either. If you're asking for help, he'll be helpful, but if you're asking "[this sourcehut feature] should probably work [this different way]", he'll probably reject your suggestion.
On the forges mentioned above, the repository and the issues page and the contributions are all part of the same section. All repositories come with an issues page and a contributions page whether you like it or not. Due to this design, they allow for easy navigation and searching across all the different sections relating to the project.
Sourcehut has three kinds of pages: repos, lists, and todos. However, rather than being combined with a navigation to go between them, they are completely different web pages that aren't linked together. You also create them on an ad-hoc basis, meaning that for personal projects that you'd like to share with the world but not allow contributions on, you don't have to have a list or a todo.
Sounds good? It is, and it isn't. I mentioned that all of the different pages you create are not linked together, and this fucking sucks it sucks so bad. Pause a moment to think about it. You're looking at some GitHub repo or whatever, and it's a public project that welcomes contributions, but, when you go to find the issues page to report that bug, the "issues" link is not there, and there's no way to get to it unless you figure out the URL. It's dreadful.
Sourcehut does offer the "project hub" feature, which has outgoing links to the different sub-pages of your project, but once you're there you can't get back to the project hub again. This makes it basically useless for navigation. In addition, the project hub page and the repo page are virtually indistinguishable, leading you to ask multiple times, "wait, where did the button go to get to the mailing list? I swear I saw it in the top bar a minute ago." And you did see it a minute ago, but it's not there now because you've navigated to the sub-page for the repo, and you're never making it back up to the hub page ever again.
To ameliorate this, you can edit the README of every single page you create to include outgoing links to get to the other sections of your project, finally allowing people to navigate around freely to the places they need to get to, which fucking sucks it sucks so bad. Take a look.
Being able to create mailing lists separately, though, does mean that you can make a list for whatever you want, rather than it having to be strictly related to some repo. (I think I heard somewhere that He doesn't like you doing this, but it's not against the terms of service, and you're paying, so can He really be too mad about it?)
There is an extra setting for repositories, which is "unlisted", and can only be accessed if you know the URL (so, it's not linked from your user profile). I find myself using this a lot. It's great!
Rather than requiring one-time contributors to create an entire account and fork the entire repo, they can email small code patches into your project. These are displayed on the mailing lists page which also doubles as a code review. You can use git commands to apply their commits directly to your own repository, and then you can edit them if you want to before pushing them back to the main repo. Patches are sent using a tool called git send-email
. Awesome!
People have to learn how to use
The first time somebody has to do this, due to their unfamiliarity with the workflow, it will be more mentally taxing and time consuming for them to figure it out compared to signing up on your Gitea instance and using the Gitea workflow. Unless your expected contributors are all Linux kernel developers. If that's the case, Sourcehut is for you.
Lists and todos appear at first glance to be analoguous to GitHub's pull requests and issues, but this is actually not the case. Sourcehut's model is a bit more flexible, as long as all of the other people who are going to be submitting things to your project also understand the nuance and use them appropriately. Hahahaha.
Lists are for discussions, announcements, code patches, code review, and preliminary bug reports. People should write everything to lists if they can. This is easier for them, too, since they literally just have to write an email and the body of their email appears on the page.
Todos are for actionable tasks. They look a lot like GitHub's issue page, and there are similarities for sure, but you don't want this to act as the first line for submitted issues. This is because, if you're anything like me, the vast majority of the issues you get are not actionable tasks - either requests for help or issues that are impossible to solve. Somebody will complain about a feature that doesn't work, and you have to say "this just isn't how my code works" or "I don't have enough information to act on this". And you could keep asking them and gather the information you need, but at that point, the whole conversation is in shambles and the info you need is scattered all through the thread.
The correct way to do it is to use lists for bug report submissions, discuss with the person further until you know what's going on and what to do about it, and then, if you need to do anything about it, create your own actionable task on the todos page with all the information you found out in the top post. And if the problem they emailed in was something that you can't solve, you can tell them "I can't solve this" and you don't have to worry about the (1) indicator on the issues tab, because the conversation will be lost to time. This is good.
There aren't any stars or other gamified metrics. This is a good thing!
However, it also means that you can't show off to a future employer about how many people love your code and rely on it in order to convince them to hire and pay you.
Sourcehut is a paid service.
This means you have to pay, and it's another subscription coming out of your bank account and where did all my money just go again?
This also means the platform won't do things that are bad for its users, which is not a guarantee you get with GitHub or GitLab, because they are owned by investors. Sourcehut can pay its employees and it can plan to add features that will help its paying users and it should be around for the forseeable future.
No JavaScript. This is a good thing! Gitea mostly works with JavaScript disabled, GitLab doesn't work at all. Sourcehut doesn't have any JavaScript on the site. For basically everybody this doesn't matter in the slightest.
i haven't used it but it looks pretty cool and it looks like it could avoid some of my current frustrations regarding CI.
Sourcehut is really great for personal projects that you occasionally want to show to other people because it loads quickly and you can create lists and todo on an ad-hoc basis rather than them being linked to some repo.
The contribution process is where it falls apart. It seems like it would be pretty great to contribute to because you don't need an account to discuss, report bugs, or send code patches (once you've learned how to do that). And it is pretty great, but only under the condition that you already know the URLs for the repo page and the mailing list, because you can't get from one to the other without guessing the URL.
As such, if you want to invite contributions from novice users, or don't want to manually write navigation links into literally all of your READMEs, then you should probably stick with one of the forges that uses the classic interface and contribution process, like GitHub or Gitea. Gitea does have the signup process as a barrier. Make your choice depending on how much you and your users hate Microsoft.
GitLab isn't good for anything. Fuck GitLab.
— Cadence
]]>All-purpose. Timeless.
.iso is a generic disk image format. There are many kinds of .iso files for many different kind of discs. Wii, PlayStation 3, and generic CDs and DVDs can all be stored in a .iso file. In the case of the Wii, a .iso is a copy of literally everything on the disk. It's straightforward and works for literally every purpose, although the file size is large.
It can be played directly on Dolphin, and on hardware with an ordinary USB loader.
Dolphin Emulator says,
A simple and robust format which is supported by many programs. It takes up more space than any other format.
You can mess around and convert ISO files using Wiimm's ISO Tool, or Dolphin's right click menu, as well as many other programs.
All-purpose. Timeless. Smaller size.
NKit is a software package that shrinks the size of .iso files by removing junk data (keeping the actual game data). If you want the original .iso back, you can use NKit again to reconstruct the full thing, so it can be used for game preservation.
The filename ends in .iso because it is still a regular .iso, it just has everything except the game data stripped out. As such, it has the same compatibility as a regular .iso.
It can be played directly on Dolphin, and on hardware with an ordinary USB loader.
To convert both ways between regular .iso and .nkit.iso, download the NKit program.
On Dolphin Emulator, game data may take 10-20% longer to read because Dolphin emulates Constant Angular Velocity and NKit moves data towards the inside of the disc.
NKit has a unique feature where it can deduplicate update partitions and reuse them between discs, allowing you to save more storage space for large collections of games.
De-facto format for downloaded games.
Stands for Wii Backup File System. (Probably.) If you download games from the internet, you'll most likely see this format, due to its small size and wide compatibility. It removes junk data and update partitions from the disc, leaving just the actual game data, so it's smaller than .iso files and not suitable for game preservation. It's most used by people who download and play games. USB Loader GX dumps games in this format.
It can be played directly on Dolphin, and on hardware with an ordinary USB loader.
You cannot convert WBFS to other formats using Dolphin, but even if you could there would be no reason to.
You can convert and mess around with the contents of WBFS files using Wiimm's WBFS Tool, among other programs.
Dolphin Emulator says,
A basic compressed format which is compatible with most versions of Dolphin and some other programs. It can't efficiently compress junk data (unless removed) or encrypted Wii data.
It's a compressed format for GameCube games. It's not helpful for Wii games.
It can be played directly on Dolphin, and not on hardware.
You can convert it in Dolphin's right click menu.
NKit removes junk data, GCZ compresses the rest. Nowadays, the NKit software package will do both steps for you at once.
It can be played directly on Dolphin, and not on hardware.
Download the NKit program to convert .iso to .nkit.gcz and back. Dolphin's right click menu can probably convert it for you, too.
It was one of the earliest file formats for compressing Wii game data.
Dolphin Emulator says,
An advanced compressed format which is compatible with Dolphin 5.0-12188 and later (July 2020 and later), and a few other programs. It can efficiently compress encrypted Wii data, but not junk data (unless removed).
It can be played directly on Dolphin, and not on hardware.
You can convert it using Wiimm's WDF Tool, as well as the Dolphin right click menu.
Dolphin only.
Dolphin Emulator says,
An advanced compressed format which is compatible with Dolphin 5.0-12188 and later (July 2020 and later). It can efficiently compress both junk data and encrypted Wii data.
This format can be used for game preservation, like NKit.
It can be played directly on Dolphin, and not hardware unless converted.
You can convert it using the Dolphin right click menu.
Same data in a tabulated form.
Format | Playable on hardware | Can reconstruct original file | Compresses GameCube data | Compresses Wii data | Removes junk data | Overall file size |
---|---|---|---|---|---|---|
.iso | ✅ | ✅ | - | - | - | Largest, always 4.7 GB |
.nkit.iso | ✅ | ✅ | - | - | ✅ | Decent |
.wbfs | ✅ | - | - | - | ✅ | Decent (Wii only) |
.gcz | - | ✅ | ✅ | - | - | Decent (GameCube only) |
.nkit.gcz | - | ✅ | ✅ | - | ✅ | Very small (GameCube only) |
.wai | - | ✅ | - | ✅ | Unsure | Smallest (Wii only) |
.rvz | - | ✅ | ✅ | ✅ | ✅ | Smallest |
I'd last played Wii Sports Resort in depth about a decade ago. It got into my head recently and wouldn't leave, so I decided to write a post about it. To refresh my memory of what the sports and the game as a whole were like, I watched a 6h20m "all stamps" speedrun.
If you haven't played Wii Sports Resort, this post likely won't make a lot of sense. I wrote this post for myself, and it's a collection of my thoughts after I've played the game, it's not exactly a review or a recommendation of the game. I've tried to include little video clips of the gameplay of each sport to allow you to to quickly familiarise yourself with the sports if you don't know them, so hopefully you can get some meaning out of my words even if you haven't played the game. Fortunately, Wii Sports Resort doesn't have any lore, so I won't be spoiling anything about the game here.
This post is also a Web 1.0 exclusive. In other words, it's not available on Gemini. Sorry!
Right, the all stamps speedrun.
Watching the all stamps speedrun was fascinating! I remembered so many things about the game and also discovered a lot of things that I never knew before. For example, I never realised that the victory music for each sport is different from each other! Usually this reflects the sport in some way. For example, the basketball music sounds... I don't know how to describe it, but it sounds basketball-y!
The music and sound composition for the whole game is really incredible. The in-your-face-ness of basketball, the wind and ambience of the golf courses, and the menacing beat of swordfighting showdown... wow!
A lot of the stamps in this game were incredibly challenging. I remember that I'd obsess over them a lot when I was younger, either thinking about how I could get them, or wondering if I was skilled enough to achieve the stamp's high demands. For example, the archery stamp that requires a perfect game (difficult execution!!), or the power cruising stamp that requires first locating all 5 time balloons and then popping them in a single run (difficult planning!!). I think I could have had more fun if I focused on the actual gameplay of the sports, but I'm not upset at my past actions.
My whole family were huge fans of this mode and it has always had the "Most Popular" banner above it. We played it for hours the first day we got the game, then woke up the next day with really sore shoulders and arms. As well as the versus mode we also played the mode where a single player fights against an opposing army, though my siblings played this one more than me. They managed to get to level 20, volano reverse, but not complete it. As time went on, they became far better at the versus mode than I did, but I still enjoyed playing against them. I like the way the characters move and step around each other on the circular platform.
Looking back, I realise that the island flyover mode made me fall in love with this game. It's not merely a free roam around the island, there's all sorts of balloons to pop, locations to explore, and of course i-point message boxes to read, which add a huge amount of flavour to the whole island and its setting. The text is different depending on the time of day, meaning that there's 240 individual tweets of lore about the island to find. It's so interesting and it contextualises the whole setting of the game and makes it seem like a real place. It's so awesome! It turns out that the US and PAL versions have differing i-point text, so now I want to read the US version's lore too. For example, the PAL version never says that the tennis court balls were stolen by dogs, merely that they were stolen. I spent so much time playing island flyover.
I always wished that it didn't have the time limit, so that I could truly roam free, but I guess the fitness-themed game didn't want you to spend all day in front of the teevee without realising where the time had gone. The plane controls were really fun to use, aside from constantly having to thrust the remote forward to get temporary speed boosts, which is super annoying.
Power cruising has a free roam mode too which lets you get up a lot closer to the game world due to the camera, but you move a lot slower than the aeroplane flyover and the pitch of the engine is more annoying. And you have to stay in the ocean, you can't go on land in your tiny boat, but there are a lot of interesting parts of the ocean that are tricky to access by plane. The regular power cruising game is decent enough, and going through the floating goalposts is satisfying, but overall the game isn't deep and doesn't feel like a sport.
I should have played golf more, I think it was definitely one of the more interesting and skillful modes in the game. I played a round with my dad just a couple of years ago and it was fun to watch each other try to line up shots and make jokes. It really puts the pressure on when you have to make a tricky shot and you have to use the motion controls to do it. It's also a lot of fun when you get a lucky red bar and the shot exceeds your expectations. Trying to balance the different clubs and the wind speed and the shot angle and the slope of the green is so interesting.
it's awesome and anticapitalist!!! in real life, that is. i never played it in wii sports resort
I think the basketball 3 vs 3 challenge was my favourite mode to play against my siblings? Unlike some of the other games you can play against the other person in real time rather than turn-taking, and the game is really interactive: trying to pass the ball to a better position, avoiding them snatching, and then juke them out when shooting. And even when shooting you still need to land the shot, which isn't free. The defense part is fun too, trying to snatch the ball at the right moment without falling on your face and giving them a free shot. This is probably the sport that I screamed the loudest at in both triumph and dismay. I want to play it again with someone.
Tutorial video that also shows gameplay and doesn't waste time
My dad was absolutely obsessed with this game as well as the return challenge. He would spend hours every evening playing the table tennis return challenge trying to get a higher score, which was both funny and sad to watch. It took him so many attempts to get to 999. He would also tell us all about his games against opponents in the regular mode. Many times he was upset by his mii standing at the wrong side of the table to return the serve and not running to where it needed to be. Sometimes he would shout (playful) at the teevee, "stop standing there like a wet lettuce!!!!", a phrase which has remained in my head for a decade. Apparently this is a wider known slang term but I don't know the slang implications. Lucia, the champion, gave him soooooo much trouble.
Whenever we had friends around to play we liked the bowling game since we could pass the controllers around for everyone to play and it had just the right amount of luck while still being straightforward to play. I remember playing this against my babysitter a decade ago. I won.
I found this one relatively fun to play on my own and I enjoyed going for high scores. Nobody else liked it as much as I did. I guess it was never a very deep game mode - just ride off the boat's wave trail, spin the remote, and land on your board. I still liked it in the moment.
Gameplay video. The video shows the practice mode where you can find ducklings. The main game has you complete a bounded course as fast as you can.
I think canoeing is the game that made me sweat the most. It's not very deep but it is fun to push the boat around and say hi to the ducks and the fish. I found out from watching the speedrun that the fish give you a speed boost if you row the same way as them, which is,,,, funny,,,,,
Gameplay video. The video shows the co-op mode on a tandem bicycle; the single-player mode is identical but with a single mii on a standard bicycle.
Cycling does seem to be a fairly deep mode. I never played it a lot in the past, but after watching the speedrun, I've gained a massive appreciation for it. There are 6 courses that span the whole island, and each of them was carefully designed. They ride around different parts of the island including the main landmarks such as the main bridge, volcano, and the town, but the route connects these landmarks using many tiny paths that reach all over the island that you might not have noticed before.
The music is completely dynamic, made up of many layers, which swell and fall away depending on the game state, including how much energy you have left, which part of the island you're riding on, whether you're behind somebody, and then as Vincenzo leads you into the final section of the course the music is seamlessly replaced with a much more intense version of the main song, and hearing it makes you feel like you can do anything!
It's important to plan a strategy of when to stick behind to recover and when to use your energy to push ahead, so that you'll be able to eventually pass the race leader. The way the multi-day races are implemented is really interesting - your position from the previous races is carried over, but each rider is released from the start at regular intervals. This means that you still have to pass the same number of people in total, but each day is like a reset for how the riders are distributed over the course, meaning you'll always be able to plan how to get to the next person ahead of you without large gaps between packs forming over the whole event.
Wii Sports Resort is a very good game with a lot of good sports and a lot of good memories that you can happily play alone or with friends. If you have an old Wii kicking around in your house, why not get the game? It costs $20 to get a second hand game disc, but there's a neat little trick where you can hack your Wii, download the game, and play it for $0. (Though do note: it will be awful to emulate unless you also have a real Wii Remote due to the way the game interprets the motion inputs from all of the remote's sensors.
Seeya! 🚣🏻♀️
— Cadence
]]>The circles mode in osu! is a somewhat fun game. I want to play it casually from time to time, and enjoy myself, without taking it seriously. But the game has always fought back against me whenever I've tried to play it more. The life bar is strangely aggressive on some songs and the scoring system places a huge amount of emphasis on combo, to the point where accidentally missing a single note will make your score worthless, no matter what else happened in that attempt.
Something I love to do in rhythm games is improve upon my past scores, but the combo system makes this difficult and frustrating. "Improving" in the circles mode of osu! means "getting lucky and not missing for longer chains". Some people may find satisfaction in playing easier songs and striving for a full combo, but I find it much more fun to play more difficult and intense songs and try to get a certain % score on them.
The closed-source nature of the original game means that its scoring system is set in stone. Without providing me an avenue to change the numbers to be more friendly and fun for my way of playing, I would always give up and stop playing after only a few days. In the past I attempted to modify opsu!, which is an open-source Java clone of osu!, to calculate scores differently, but I got lost in the code and wasn't able to accomplish my goal.
osu!lazer is open-source and provides easy avenues to modify the gameplay and scoring system to match the way that I want to play. Here I describe what I changed, and how I did it, to document my work and provide help for anybody else who wants to do similar things.
As far as I know, local builds of the game cannot submit plays for online scoring or pp gains. If this is incorrect, and it's possible to submit plays on local builds, please let me know, because I'd be interested in doing that!
Local builds can still log in and use online features like in-game beatmap downloading.
The rest of this post will be a technically-oriented tutorial. Not all the sections may be relevant to you, so feel free to skip around.
I'm using Fedora Silverblue 36 (Kinoite branch) which has the additional challenge that the operating system is immutable and installing system packages is discouraged. Silverblue provides several container systems to help install packages, and we'll be using those to build osu!. If you're not on Silverblue, you can just use your system package manager and ignore the things I wrote about containers.
osu!lazer is based on .NET 6.0. We need the .NET 6.0 SDK to build it.
.NET is designed so that there is an SDK, which is used to build the application, and a runtime, which is used to run the application. .NET applications don't compile to native code, so whenever anybody needs to run a .NET application, they need the runtime installed on their system. Since this is just for personal use, normally this wouldn't matter. You could install the SDK (which includes the runtime) and you'd be fine.
There's a catch. The container software we're going to use, called Toolbox, is supposed to support X and Wayland forwarding so you can run graphical applications inside the container and they will Just Work. osu! doesn't seem to recognise this, and won't start inside the container. This means you need to build it in the container and then run it on bare metal (i.e. outside of the container). The challenge is that in order to run a .NET application on bare metal you need the runtime installed on bare metal. We're going to work around this requirement for the runtime, but more on that later. For now let's just set up the container and build the lazer source code.
Oh, of course. .NET has telemetry in it. It can be disabled with an environment variable. If you want to disable the telemetry, you should set this enviroment variable now before you install .NET. You just need to change DOTNET_CLI_TELEMETRY_OPTOUT to 1.
In fish shell, you can set the environment variable like this:
set -x DOTNET_CLI_TELEMETRY_OPTOUT 1
You can add this line to ~/.config/fish/config.fish to make it automatically apply when you open a shell.
In bash, you can set it like this:
export DOTNET_CLI_TELEMETRY_OPTOUT=1
You can add this to your bash startup file to make it automatically apply when you open a shell.
Once it's in your startup file, if you want to make sure that nothing leaks, it would be safest to log out and back in again to make sure you don't have any old terminals hanging around which could be missing the new setting.
The first step is to download the osu! source code. Git is available on the default installation, so we'll just clone the repo now.
cadence@ribbon ~/Software> git clone https://github.com/ppy/osu/ cadence@ribbon ~/Software> cd osu cadence@ribbon ~/S/osu>
As mentioned, we're going to use the "toolbox" container system, and it's easiest to start from scratch with a brand new toolbox rather than going with your existing one. I'll use the name "lazer" for the container, so that name will appear in my prompt line. You can use whatever name you want.
cadence@ribbon ~/S/osu> toolbox create lazer cadence@ribbon ~/S/osu> toolbox enter lazer ⬢ cadence@lazer ~/S/osu>
As mentioned, we need the .NET sdk, so install that. osu!lazer (at time of writing) specifically needs version 6.0, which is the latest version.
⬢ cadence@lazer ~/S/osu> sudo dnf install dotnet-sdk-6.0
Checkout a past release of lazer. We should use a known-good commit to make sure the build actually works in our environment, before we try editing the source code.
⬢ cadence@lazer ~/S/osu> git checkout 2022.405.0
(If you're reading this in the far future, you might want to try checking out a more modern release. I don't know.) If this is the case, you can see a list of available releases with:
⬢ cadence@lazer ~/S/osu> git tag
That's basically all the setup, and now we can make a build.
⬢ cadence@lazer ~/S/osu> dotnet build osu.Desktop -c Release
This will take a while and download some packages. Eventually, you should see "0 Errors".
If you get a message like:
The .NET SDK has newer analyzers with version '6.0.0' than what version '5.0.3' of 'Microsoft.CodeAnalysis.NetAnalyzers' package provides. Update or remove this package reference.
If this appears, the nuget cache is for an old .NET version, and you should clear the cache. You can do this with:
⬢ cadence@lazer ~/S/osu> dotnet nuget locals all --clear
If you're not using Silverblue, then .NET is available system-wide. You can now grab headphones and run osu!lazer with:
cadence@ribbon ~/S/osu> dotnet run --project osu.Desktop -c Release
Otherwise, for Silverblue, you have to publish the project as a "self-contained" directory, which allows it to be run without the .NET runtime. This is what I was referring to at the start. This trick means that after it's built, we can just run it normally on bare metal.
⬢ cadence@lazer ~/S/osu> dotnet publish osu.Desktop -c Release -r linux-x64 --self-contained
This puts an executable file in <the osu code directory>/osu.Desktop/bin/Release/net6.0/linux-x64/osu! which can be executed on bare metal to run the game.
You should git checkout master now so that you have the latest code. Cool! Go change stuff in the source code!
If you'd like to apply my scoring changes, here they are:
osu.Game/Rulesets/Scoring/ScoreProcessor.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
This patch makes accuracy give 90% of the score and combo give 10% of the score. In the default game, this is balanced to 70% combo and 30% accuracy. You can change these numbers to whatever you want.
osu.Game.Rulesets.Osu/Mods/OsuModSpunOut.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
This is an accessibility thing. I play with a laptop with a touchscreen, and spinning is really tough for me on that touchscreen. The SpunOut mod doesn't even spin very fast, and can even fail very short spinners, so for these reasons changing the mod score multiplier to 1.0x makes sense.
osu.Game/Rulesets/Mods/ModNoFail.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Why shouldn't I?
If you installed the .NET runtime system-wide:
cadence@ribbon ~/S/osu> dotnet run --project osu.Desktop -c Release
This will build your new changes and then start the game directly.
Self-contained for Silverblue:
⬢ cadence@lazer ~/S/osu> dotnet publish osu.Desktop -c Release -r linux-x64 --self-contained
This will build your changes and make a new executable. You can start the game on bare metal as before.
That's all for today. Go forth and edit your favourite games to be more fun for your brain!! ^▼^
Cadence
]]>I use the Workman keyboard layout, and I've written about that in blog posts in the past. It's lovely for my personal use, but since I haven't used Qwerty consistently in more than 18 months, I have forgotten how to type on it. This makes it much less convenient if I need to type more than a few words on somebody else's computer, or a managed system that I can't install the layout on. Lugging my own keyboard around with me won't do any good, because the keyboard layout is managed in software, not hardware.
For a while I've been thinking about a hardware device that I can carry around with me, that I can plug a keyboard into, and then plug the device into the USB port of a computer. The device would pretend to be a keyboard, and keys typed on the real keyboard would be remapped by the hardware, allowing me to take my layout anywhere without needing to configure any software on the target computer.
For example, when I press the key T (or where the key T should be on the keyboard), the hardware device will intercept and read this keystroke, figure out which letter it is based on the Workman layout, find where that letter would be on the Qwerty layout, and send the Qwerty key position to the target computer.
As far as I can tell, no. But if somebody has, pleasepleaseplease let me know since it would save me a lot of work reading about USB technicalities and figuring out which hardware will actually work, since I can use the same hardware that they used!
Whatever hardware I use, the key factor of whether it's usable is whether it has USB support. The device needs to accept USB keyboard input and provide USB keyboard output. If it can do that, then writing the code to connect the two is probably the easy part.
The USB protocol is complex. I can't build a keyboard layout remapper using just electronic components; I'll have to use some kind of microcomputer or microcontroller. In particular I'll be investigating the Raspberry Pi microcomputer and the Arduino microcontroller.
Finally, USB can operate in either -host mode- or in -otg mode-. When a computer uses host mode, you can connect peripherals to it. When it uses otg mode, you can connect it as a peripheral to something else. In my case, I need to have one USB port in host mode and a different USB port in otg mode. I cannot use a hub to mix types.
I'm not 100% sure, but I think USB type C may be able to be configured as either type. However I do still need to connect it to USB type A stuff in both directions.
A Raspberry Pi is a Linux computer, so all models of it absolutely supports USB peripherals (host mode). I already own a few of the Raspberry Pi models. However, only some models support otg mode.
The Raspberry Pi Zero has one USB data port which can be configured to either otg mode or host mode at boot time. This isn't suitable for me since I need to connect 2 cables at the same time. (Though, if I were using a physical bluetooth keyboard for this project, then I could run the Pi in otg mode and connect the keyboard through bluetooth and this would work.)
As far as I can tell, all USB hubs sold for the Pi Zero actually jack in to the otg port, they don't create new USB ports. So you can't use this and otg mode at the same time.
The Raspberry Pi model A and its siblings also support otg mode. Like the Zero, they only have one port, so they're not suitable for me.
The Raspberry Pi model 4 B has 4 type-A USB ports which can only be used in host mode, and also 1 USB type C port which is normally used for power input which can additionally be configured to otg mode. If the Pi's power draw is acceptable, then this would work for my project!
However, due to a global chip shortage, it's literally impossible for me to get a Pi 4.
A Raspberry Pi would probably take about 15 seconds to start up, which isn't totally ideal, but would be good enough for this project.
The Arduino connects to a computer using its USB type B port, acting as a peripheral (like otg mode). So we just need a way to make it also act as a host.
There *appear* to be USB host shields (a shield is the Arduino name for a hardware expansion). Whether they actually work, or work well, I do not know. It seems easier to obtain these than it is to obtain a Raspberry Pi 4.
I already have an Arduino Uno, and I think it's currently possible to purchase an Arduino if I need a different model. I do not understand the ecosystem or the different models.
When making a totally custom keyboard, James Stanley used a Teensy as the microcontroller, connecting switches to its digital inputs and sending the output through the micro USB cable (otg mode) using QMK as the firmware.
The PJRC store sells a "USB Host Cable" for the Teensy board, the connections on which are exactly what I'm looking for. It says that it allowed connecting a USB device to the Teensy, and that the "Teensy 4.0 has USB host capability on bottom-side pads". So, if I understand everything correctly, I believe that I can use this host cable and the regular socket on the Teensy at the same time.
I have no idea whether these assumptions are correct, though. If I decide to acquire a Teensy I'll do some emailing first to make sure I can use both cables at the same time.
I'm planning to visit my parents to pick up my old electronics stuff, most notably my Arduino Uno, and see if I can get it to send a fixed sequence of keys to the computer. If I can do this, then I'll start browsing for a USB host shield that looks suitable, and that should be the difficult part of this project all done!
If I'm successful at making the hardware remapper I'll likely try to design a pretty wooden or acrylic box to put things in. I don't have access to a 3D printer, so I'll have to use woodworking tools or off-the-shelf acrylic boxes.
If this gets any further through the planning phase then I'll make a follow-up post. See you then!
This will be a fairly short post. I wanted to describe techniques that work for me. This is based on no scientific knowledge whatsoever. Warm your feet at your own risk.
If I put my feet, which are already cold, into a cold place, then they will stay cold. I think this is because my body knows that they're cold and tries to redirect blood away from them, so that my body doesn't continue to lose internal heat to the cold place.
If my feet are already warm, and I put them into a place that is too cold, the heat will be sucked out of them, and it'll be the same situation as before.
The difference is when my feet are warm, and I put them into a warm place. The heat of my feet is able to maintain the temperature of that place, and my feet and my blankets then live in a happy symbiotic relationship of warmth for the rest of the night.
(As I said, this probably isn't scientific at all.)
My conclusion is that I need to make a warm place to put my feet in.
What I said above remains true whether I wear socks or not. I do think socks help a bit, but I've had good results with and without them. I don't think they're the most important factor.
I think that the most important factor is whether the foot area is already warm before I put my feet in it.
Your feet are too small to heat the area initially, which is why they get cold if you put them into a cold space. But a body part that is warm and large, like your legs or your butt, should be successful at initially warming the foot zone.
Here's what I do:
Before I lie down in bed, I pull back the covers and sit down on the area where my feet would go for 15-20 seconds, pulling the inside of the duvet up around my back. I find that this short period of time is enough to make the sheets and duvet comfortably warm. Then, if I lie down and put my feet into that warmed space, they never get cold again for the rest of the night.
If you find that cold air is getting in the foot end of your sheets and ruining the igloo, my final technique is to tuck the end of the duvet underneath your legs, so that your legs are surrounded on all sides and the warm air can't escape. This may require either a long duvet or a short body. If you're stuck, you could get a separate blanket to use to wrap that place.
Hurrah!
— Cadence
]]>I received an awesome email last week from somebody who was struggling with writing their own blog posts. They had identified challenges they wanted to overcome, and they asked for advice on if I'd dealt with those challenges myself.
I really appreciate that they reached out! I started thinking about how I should compose my reply, and then realised that other people might find my words useful too, which is why I ended up publishing this post! (Fun fact: This was the third paragraph of the post I wrote, and I wrote it in past text.)
There are many ways to divide and categorise kinds of writing. One possible division you could make is between writing that's private and writing that's to be shared.
The word blog is derived from "web log" - a log that's on the web. The medium of a blog post implies that your words will be shared with others in some form.
It doesn't necessarily mean that you're writing for others. Artemis offered me an interesting perspective on this. Despite their blog being readable by anyone, they are the person writing, and the writing is explicitly for them.
why i don't use analytics - artemis everfree
Well, I sort of lied: the division of whether your words are for yourself or for others isn't actually a binary. You can compose your writing in several ways that make it more for yourself, or more for others, or even a bit of both.
If you're writing with others in mind, you might wish to make adjustments in the language you use in order to explain some concepts better for the readers who aren't in the in-group. If you're writing from your heart for yourself, and publishing your words as an afterthought, you might adjust for this by using a pen name and not providing a way for readers to respond. You can do these things to different degrees. For example, a blog where you talk about difficulties you had styling your website could be filled with jargon that only makes sense to you, or you could explain some of the contexts and reasoning behind your styles, or you could write it as a full tutorial for beginners.
All of these writing styles are totally okay! Before you start writing, though, you should think about who your audience is this time, and to what degree your post is for them, and choose your words and style based on this.
I write for myself because I find that processing, organising, and structuring my thoughts into prose means that my ideas arrange themselves in my mind better, and I have a fixed reference that I can look at later if I want to.
You can that I was writing primarily for myself in my very first blog post.
I also write because it's fun, provided I treat myself well enough while writing. See the section on "fun" further down.
I began writing for others because I realised that other people might find my words useful too.
Before I made my blog, I found that I was talking to my friends in chatrooms about the things I'd been doing, and I really enjoyed sharing my life in this way. But my friends are split into several chatrooms, so I'd have to share my thoughts in all of them if I didn't want anybody to be missed out. Some of my friends aren't in any chatrooms, we just have direct messages.
I realised that if I organised my thoughts into a structured post, I could send the post link to all of my friends, plus anyone else I wanted who might be interested in the ideas of a specific post, without needing to repeat myself! And we could still talk about the things after I shared my link.
It does make things feel a tiny bit impersonal and parasocial, though... I'm not sure what to do about that. I wonder if there's a better medium for this purpose. I'm not sure.
Here's an example of I post that I wrote because I wanted other people to read it, because I was really really mad about something and needed to vent.
Regardless, I still enjoy sharing my ideas with the wider world, and people have told me of the positive impacts or new directions my words have had on them! That's so cool. Thank you all. I love you so much.
The most important thing about writing, whether it's for yourself or for others, is the message that you convey.
Something that the modern web seems to have forgotten is that they need to actually write something of value under the layers of presentation. It's about writing! This is why I consistently enjoy reading personal and indie blog posts. They are always about something meaningful rather than trying to entice readers based on the value of their mouse click. This is a low bar to clear - you can be assured that anything that you write online will have value. :)
That's what I'd consider to be the core of a "good" post - something that is at least a little meaningful to you. (This is "writing for yourself".)
And yet you'll find that, most likely, other people will find your words meaningful too. If whatever the topic is is interesting enough that you managed to compose and publish a page about it, then in my experience, it'll be interesting enough for other people to read.
For example, I don't know anything about motorcycles and I'm ordinarily not excited by them. When I stumble upon somebody online who's excited by motorcycles and talks about them, in a manner that's accessible enough for me to understand with little knowledge of the subject (this is "writing for others"), I really enjoy reading their story. It expands my perspective on the world, I learn new things, and I genuinely find it fun to read from people who are passionate about their topic.
Please don't be worried about trying to make a "good" post! You can write for yourself, about something you're passionate about, and that is a "good" post. I promise you that if you enjoyed writing it, other people will enjoy reading it too.
And if you enjoyed writing it... well, isn't that good in its own right?
If you're writing for other people, it can be very tempting to think that your words are not interesting and that other people do not want to read them. Those beliefs are totally false.
Your thoughts are good, your words are good, and I would love to read about them!
If you write just for youself, you're totally valid too!
These statements are true.
I think that the reason that I'm not afraid is, well, that it's not scary even if it did happen.
By making the act of writing itself fun, it means that I'm not bothered if people don't like my post. I have no way to know what people think of my words unless they contact me and let me know (that's why receiving emails about my posts is always so welcome).
If somebody reads my post, doesn't like it, and clicks away, that idea doesn't matter to me because I'll never know about it. I still received personal enjoyment from the act of writing. This is why I think it is important that, no matter what, you should take steps to ensure that you do enjoy writing.
And as I say, if you write something you're passionate about, and you enjoyed writing it, then I bet other people will enjoy reading it as well.
Writing can take a long time. It's important to enjoy that process for the sake of it! If you have a keyboard that feels nice to press, and an application that you enjoy writing words into, then that's an excellent start!
The tactile part of writing, feeling my fingers hit the keys, watching each letter appear on screen, is satisfying to me in its own right. If by the end of a paragraph I don't like how the letters are arranged into words and the words are arranged into sentences, it still never feels like a total waste of time because I enjoyed pressing buttons.
I'll let you in on a secret. I barely proofread my posts. By the time I reach the end and have written out all the sections, my brain is exhausted and I never want to take the time to go back through my own words. I don't find proofreading to be a fun part of writing! So I mostly ignore it and don't do it. And I believe that's okay. (Although I did get a second pair of eyes for this particular post, and they suggested improvements to a couple of the sentences.)
There are a few posts I've started writing that have just been left in the drafts folder before I managed to finish or publish them. I'm not upset by this; I still appreciate the value of those drafts and I don't see them as hindrances or failures. I enjoyed the tactile part of writing my words, and the ideas that I did manage to write about are now more organised in my own head. I can also see these drafts as opportunities that I may be able to finish in the future!
...and an application that you enjoy writing words into...
I personally love to write my blog posts in Textreme 2, a really pretty writing application. It's silly and childish and it's fun. Textreme 2 legitimately is half the reason I'm able to write so much, because it makes it more enjoyable for me.
(If you think it would help you too, and you're not able to afford a copy, let me know and I might be able to buy it for you!)
Another way to make the writing process more exciting is to play media around you. I find that videos distract me too much away from my words, but I really like putting on music to listen to. I don't often listen to music while I work, so it's a nice and motivating change.
Start with a small idea. Figure out roughly how many paragraphs you'd like to write. If your topic would benefit from being structured, put down some headings of the key points you want to mention. Then start filling in the gaps.
An idea being small does it not make it worse. It will likely make the writing process more enjoyable for you, especially if you can start and finish in a single session.
If you enjoyed the writing process, then that's good writing because it was good for you.
If you end up writing more or fewer paragraphs than you'd originally planned to, that's not a problem at all. This very post ended up being far, far longer than I expected! And I'm glad about that, because it means that I got to properly explain my thoughts on all the sections I had planned, and hopefully my brain didn't get lost too far down the river.
If I had written fewer words than I had expected, or I found myself unable to fill in some of the section headers, that's okay too. I would be proud of myself for the things I did write, because they are still valuable, and writing them has benefited myself as well as, I hope, any readers.
If you publish a piece of writing after you read my article, send me the link! I will read your article and I will almost certainly like it :)
I may possibly write a couple of sequels to this post.
But that's all for now. See you next time!
— Cadence
This page was originally published via the Gemini protocol. However, I've also made the contents available on this blog if you don't have a Gemini client. The translation you are reading is not perfect. Hopefully it is good enough.
`backticks` around words indicate the boundaries of code that you should type in. You should not actually type the backticks. You may wish to replace words inside them. For example, if you see the text `/query somenick`, you may wish to enter the following into the chat window:
/query cadence
It may be interesting to briefly discuss some history.
IRC was created in the late 1980s. It grew throughout 1990 and peaked in the early 2000s. IRC has become a lot less popular in recent times, probably due to people moving to the chat features implemented on many social media platforms.
The available interfaces for IRC are fairly complex to get running at first, which is something I hope to partially ameliorate by writing this page. Despite IRC's loss in popularity, it is still used by enthusiasts, dedicated groups, and people who like old technology. Since you're reading this article about command-line computing, you'll likely be in good company with the people currently on there!
IRC is a great fit for text-mode computing because it is entirely text-based and designed to be operated without a graphical interface. It was created before HTTP and HTML, and has no built-in file uploads.
IRC is text chat.
You get text messages, nicknames, multiple channels, private messages, and basic moderation.
Modern chat applications often include message history, file uploads, user avatars, typing notifications, message formatting, message editing, and voice chat. None of these features are available in IRC.
IRC is not a proprietary protocol, so many clients have been developed for it for a variety of operating systems and time periods.
It is worth noting that several graphical clients for IRC exist, some more easier to use than others. Kiwi IRC (a webapp) and HexChat (a GTK 2 application) are popular choices.
Some more modern IRC clients try to "fill in the gaps" by working around what they consider to be missing features. For example, IRCCloud makes a persistent connection to the IRC network even after you disconnect, allowing you to access message history when you return. Some clients allow you to upload images to another website, and then post a link to them in the chat. Some clients might automatically render these images in the timeline.
This article is about command-line computing, so I'll be explaining how to connect with the command-line client WeeChat. There are also other command-line clients that some people swear by, including irssi and ircII. Connecting with those is left as an exercise for the reader.
I'll assume you want to connect to the largest network, Libera Chat. If you want to connect to a different network in addition or instead, you should visit that network's website. It will contain the parameters you need in order to connect. The procedure should be very similar no matter the network.
After first opening WeeChat, you will be in the system buffer, where you can run commands. To add the network Libera Chat, use this command:
/server add liberachat irc.libera.chat/6697 -ssl
In this command, `liberachat` is a local alias for the network, `irc.libera.chat` is the network's address, and `6697` is the port. `-ssl` specifies to connect with SSL - you will always want to do this.
Now you can set connection options like your nickname. Use this command to set options:
/fset server_default
(The options you set here will apply to all networks. To set options for a specific network, use /fset liberachat, or whatever alias you gave that network previously.)
First, set the nicks. The nick is the display name you will have. Only one person can have a nickname at any given time, so pick something unusual.
To set it, scroll to the entry that ends with `.nicks`, press Alt-Return, and enter the replacement value. Press Return to confirm.
Then set your username. This field will rarely be displayed and doesn't have to be unique. Set it to be the same as your preferred nickname.
Then set your realname. It's called realname for historical reasons - you *could* put your real life name there, but most people use the field either as a joke or to display pronouns. This is also rarely displayed.
If you don't know what sasl_username or sasl_password are, you don't need to fill them in. If you do know what they are and you have already registered, now is the chance to enter them!
Press q, Return, to exit fset mode.
Type /save to ensure your settings are saved.
Now you can connect. Type /connect liberachat and see what happens.
(If you get stuck, you may wish to check WeeChat's quick start guide and Libera Chat's guides. If you email me to tell me what the problem was, I can add information about it to this guide too.)
It's no fun being alone. Type `/join #channelname` to join some channel on the network if you know its name.
You can search on the internet for topics you're interested in, or you can find channels on the network that contain a certain name using `/list -re .*help.*` (replace "help" with the term you want to search for).
The left side of the screen is the list of channel you're joined to (WeeChat also calls them "buffers"). The current one you're in is highlighted. To change channel, hold Alt and press the number (for channels numbered 1-10), or press Alt-J and two numbers (for channels numbered 11-99). You can also use F5/F6 to move up and down the list one at a time.
Channels with activity or highlights will be marked in a different colour. You can switch to the next highlighted channel with the shortcut Alt-A.
F1/F2 scroll the channel list. F9/F10 scroll the channel topic. F11/F12 scroll the nicks list on the right side of the screen.
You can run commands from any screen, but if they have output, the output will always be sent to the "server buffer". This buffer is always at the top of the channel list, and you can change to it by pressing Alt-1.
Without a user interface, IRC interactions are triggered using /slash commands. You can get a command list with /help, and help about a specific command with /help commandname.
Mode letters indicate the status, privileges, or lack of, of a user or channel. The modes are set by the network, and may be edited by commands. The mode letters and their meanings are different on each network, so you should check your network's documentation.
For example, here are Libera Chat's mode lists: https://libera.chat/guides/usermodes https://libera.chat/guides/channelmodes
NickServ is a bot account, operated by the network you connect to, that acts as a gatekeeper for authentication. As you have already noticed, you can connect to an IRC server under any nick with no sign-up or login. If somebody disconnects you can connect with their nick to impersonate them, which is obviously an issue! NickServ allows people to "register" their nicknames (akin to signing up for a website) which means a password is required to connect with that nickname in future (akin to logging in).
In the past, you used to /msg your password to NickServ directly to authenticate. This process can be automated by every IRC client. Nowadays, authentication is done at the same moment you connecting using a method called SASL.
This is another network-operated bot that restores the permissions of chanops if they disconnect and reconnect. It generally works automatically and you don't need to worry about it.
As mentioned just above in the NickServ section, registering your nick stops other people impersonating you on the network, so while it's not necessary, it's a great idea if you are a frequent participant on IRC!
To register your nickname, start a private message with NickServ using the command /query NickServ. You can now send the word "register" to NickServ and it will tell you what to do next.
After registering, you'll need to specify the password when reconnecting. Here's how:
(The following directions will store your password in plain text. If you want to store it securely, read the quick start guide in detail: https://weechat.org/files/doc/devel/weechat_quickstart.en.html#irc_server_options)
Open the settings for your network with /fset liberachat
Find the options for SASL. SASL is for authentication.
Add your username and password to the configuration.
If you have many channels, you may find the "go.py" plugin useful. You can install it by typing `/script install go.py`.
It can be activated with the hotkey Alt-G. You can now type the name of a channel to quickly switch to it.
There are many many plugins available, and it is expected that you will install plugins to shape WeeChat to your needs. See WeeChat's documentation for a list of plugins!
WeeChat doesn't only support IRC. If you're a Matrix fan, there is a weechat-matrix plugin written in Python which is surprisingly really good!
But do note that Matrix users may expect your client to be able to do things like render images or typing notifications or read receipts, which WeeChat cannot. WeeChat includes some workarounds for images, links, formatting, mentions, and quote replies, but remember that a graphical Matrix client may be more appropriate for Matrix, which is designed as a graphical protocol.
Hopefully this was a helpful introduction to IRC and WeeChat and you can get connected easily. See you on the net!
Cadence
]]>This page was originally published via the Gemini protocol. However, I've also made the contents available on this blog if you don't have a Gemini client. The translation you are reading is not perfect but it should be good enough.
It turns out that I took a lot of things for granted in a graphical environment that I lost when moving to a console environment. (You might have seen this coming.)
I immediately felt the limitations, not only from the things that I had expected to be inaccessible such as viewing images and videos, but things as basic and everyday as _clicking links in a chat client_ and having them open in a web browser. Often times I would be totally unable to do a task and end up switching to the graphical environment.
This is an incredibly natural task to do in graphical windowed environments - moving the windows around the screen and plopping things between them - and I had not even considered that it was something that I would lose.
If you find a link to a git repository and you wish to clone it, you have to get that URL into the shell somehow in order to use the clone command. If it's pretty short, the easiest approach may be to remember it and then type it out by hand. If you find an interesting quote on a web page, and want to share it on IRC, same deal. The most straightforward approach may be to tile the buffers and type out the quote again by hand.
Some individual applications do support an internal clipboard (like Emacs and its "kill ring"), but these don't allow pasting into other applications such as a regular terminal, so you still can't git clone or share to IRC. (For the Emacs fans yelling at me that Emacs *can* do these, the Emacs log post is coming up soon, okay?!)
You can get increased functionality and cross-application pasting by using a terminal multiplexers, allowing you to grab text from the screen and insert it elsewhere, but this is still an incredibly challenging process. You absolutely have to be a power user to even bother trying this. Moving around a full-screen interface is really tedious, and you have to be careful not to copy any data that rests in columns. tmux does the best it can be adding shortcuts to help you quickly get to the space you want to copy, and it's still challenging. Grabbing a quote to share on IRC or a link to git clone in the terminal *are* possible like this, but only if you're brave enough.
Note that if you're using a terminal emulator instead of the console, you do get the mouse and you can use it to highlight text. The terminal emulator can copy and paste.
This is very similar to the last paragraph. As you might expect, a command line web browser allows you to "click" links which will be opened *in the browser*, but URLs that you find anywhere else simply won't be clickable. You once again have to highlight the URL with tmux and put it into the browser's address bar, or remember the link and retype it.
If you're using a terminal emulator, you can ctrl-click links with the mouse to open them.
For historical reasons many shortcuts are not available in the console because they are merged with other keys. For example, Ctrl-Backspace does not delete a word because it actually is interpreted as Ctrl-H. Regular backspace is interpreted as Ctrl-/. Depending on the application, Alt-Backspace might be able to delete a word, but Ctrl-Alt-? is also mapped to this combination. As far as I am aware, shortcuts that use Ctrl cannot know whether Shift is pressed or not, so the entire layer of Ctrl-Shift-... is not available. Thankfully, the function keys are all available and distinct, so if your application allows you to make your own keybinds, definitely take advantage of that freedom.
If you're using a terminal emulator, *some* additional shortcuts are available, but still not the full range of keystrokes supported in a graphical application. Shift-arrows are newly available, but Ctrl-Backspace is still Ctrl-H and Ctrl-Shift-O is still Ctrl-O.
Applications generally present very few or no menu options and require the user to first learn, then memorise, and finally blindly use all of the shortcuts that they will commonly need.
Here are some examples of this:
There are no key prompts visible. You can see them if you press `PREFIX ?` but you still have to remember them, exit the help screen, and then blindly enter them and hope it works. If you didn't understand the instructions correctly, you have to go right back to the help screen and find your place again in order to learn more.
Once you have the shortcuts committed to memory, they are fairly quick to activate, all relying on a prefix bind first.
Again, there are no key prompts visible. You can experiment with slash commands to activate things, and read the commands help text, but in order to do even that you still need to read the new user introduction guide to pick up the critical shortcuts, like for buffer switching.
Let's say you start weechat - which is primarily designed to be an IRC client - and want to connect to a popular IRC server. Here are the *minimum* steps to connect:
Normally you'd /set the SASL data too in secure storage, but I'm skipping that rat's nest. Onwards to connecting...
And now you can use the Alt-[number keys] or Alt-J to change to the right buffer, and start typing.
Reading the user guide is mandatory in order to do this. You are not going to be able to guess these steps or pick them up from the interface.
Experienced users might feel comfortable with weechat after some practice, but I still feel incredibly scared.
Links2 is much more intuitive than the ones I mentioned. There is a menu bar with several critical navigation commands and settings available there. You'll still have to press ? to see the keyboard shortcuts for scrolling, following links, and going back pages, but they are fairly intuitive and you only need to know a small number of them. Accessing the menu bar takes a little time, and shortcuts are available for people who want to activate frequent functions more quickly.
It's Emacs. You have a menu bar at the top, but good luck figuring out anything else. Nano beats it in usability but not in features. The menu bar contains thrilling items such as:
It's FUCKING VIM.
I have barely touched Midnight Commander so far, but it actually looks fantastic. The interface is laid out well and the bottom of the screen has several options which are labeled with the keys that you press to activate them. Pressing the appropriate key either activates the action directly or it opens a new menu containing more clearly labelled options, most of which look pretty helpful.
Great job, Midnight Commander! Hopefully I'll get to write a whole post just about you. :)
Your terminal emulator might support 256 or even millions of colours, though as far as I can tell, console mode supports just the basic 16. And they aren't very good shades. But it still may be enough for you to get by.
Console mode just supports the ASCII base set, as far as I can tell? I haven't investigated this in detail but I do know that esoteric characters and emojis just show up as little blocks. Your terminal emulator should support Unicode, and probably renders it as the correct widths!
Well, that's all for this post. In the next post I'll likely be talking about a specific application that I've been using and provide a cheatsheet of hotkeys you should know. See ya!
— Cadence
]]>This page was originally published via the Gemini protocol. However, I've also made the contents available on this blog if you don't have a Gemini client. The translation you are reading is not perfect but it should be good enough.
I was browsing some records of internet history including RFC 1855, RFC 2664, and textfiles.com/history.
I realised that I had a longing to have grown up in this kind of internet, where despite its restrictions, everything seems new and wonderous and free, with unlimited possibilities.
In some sick irony, despite the modern web being capable of doing far far more than the days of web 1.0 and the days even before it, the modern web also feels more restrictive and more difficult to touch, more difficult to feel, and more difficult to connect with.
Related to this, I thought it would be exciting to set up an environment for computing in console mode, the Ctrl-Alt-F1 on your Linux computer (and maybe in BSD and UNIX too, but I don't know). In console mode, you get a fully capable shell and environment, but with no graphics, no mouse, and a tiny character set.
If you want to try this at home, you will have a better experience using a terminal emulator within your graphical environment, since this will additionally support millions of colours, Unicode, and occasionally mouse support if you want it. I decided to try console mode for fun, though I can switch to using a terminal emulator at any time if I decide to.
THERE ARE NO RULES.
Going into this I knew I would hit so many restrictions in things I wanted to do. This is why I decided from the get-go that I wouldn't restrict myself to the console only. If I want to use the graphical environment for any reason, I can switch to it and do whatever I want to. Graphics mode is excellent for...
And so, I am allowed to switch to graphics mode at any time for any reason. I'm not even trying to make console mode my primary means of computing. The idea is merely to use console mode *some of the time, because it is cool, not because it is required.*
Even if there are no rules, it would still be good to define some goals for this experiment, so that I can generally focus and target my attention.
There is no time limit and I should not feel bad if I do not accomplish any goals. These are directions I could travel in, not requirements.
I'm still early in this experiment, but things are progressing in a more exciting way than I expected. I really like the emotions that the whole project has been making me feel.
I've been organising my links and thoughts in an offline personal document which I will be adding to as the days go by. Once I have enough material to make a focused post about, you can expect more frequent posts here again! I hope I'll be able to share a lot in the coming weeks. Hell yeah. I plan to write about the software I've been using, the difficulties I've encountered, and the wonderful things I've discovered.
(If you're a visitor from the future and I ended up not making follow-up posts, *please* send me an email to remind me to update this section of the site.)
See you soon!
]]>These have been written about before on the internet. However, all the online guides I found were difficult to understand or contained incorrect information.
In this guide, rather than simply listing all unlockables, I am presenting information in the form of, unlock this by doing that.
Everything in the game is unlocked by achieving first place (gold trophy) on a specific cup in Grand Prix mode. If playing multiplayer Grand Prix, either player can get first place for it to count.
Normally, every single cup gives its own individual unlockable, except for 50cc and 100cc All Cup Tour, which have no associated unlockables.
However, to unlock the alternative title screen background, you must get gold on every cup on every speed, including 50cc and 100cc All Cup Tour.
I found a wonderful infographic created by user Zurioko.
Please see their post: https://www.reddit.com/r/mariokart/comments/qkznwx/i_had_a_lot_of_fun_with_the_infographic_of_mkw_so/ -- direct image link.
]]>content warning: mental health, feelings, emotional writing.
I've struggled for a long time with how to describe to people how it feels to be me while I'm experiencing depersonalisation and a total loss of my sense of myself. Today, I found the words.
The feeling of depersonalisation is like living inside a mirror.
It's like being a reflection, living in the world of glass. Everything around me is in motion, and it seems like it should be real, but it just glides past my body with a glossy sheen, unable to be felt.
My eyes can't look, and my mind can't think. I'm a reflection, acting automatically, moving on a separate layer to the world rather than truly living within it. Reflections don't see. Reflections don't think. Reflections don't feel, reflections don't live.
I'm not tangible. I have no impact on the world, nor can I be affected by it. I reflect what's there, without understanding why, without caring why.
One day I want to place my hand on the mirror, melt down the glass barrier with my touch, step through and feel my body fill with colour, my long legs carrying me forward into rays of sunshine. The rays hit my face and I feel their heat on my skin. I feel the world moving around me and with me now, everything so vibrant and tactile, free from the cold glass prison where everything is smooth.
I look up at the sun as it blesses me, and finally, I smile.
Cadence
]]>Sometimes I think of simple solutions to problems. Sometimes I spend far too long chasing my own tail.
This is probably best illustrated through a conversation I had online with Lepton.
Not everything requires writing a script. Step back, pause, and use your mind before writing code, even if it's trivial.
Cadence
]]>Most of these annoyances were things that I had to do manually every time I started my computer. I found that I was keeping my computer powered up for long periods of time so that I didn't have to repeat them.
The login screen on Linux is technically known as the "display manager", and there are many different display managers available depending on preference.
Ubuntu seems to use GDM (Gnome Display Manager) by default, which gets the job done, except that I couldn't work out how to change the keyboard layout there. GDM was always using Qwerty, which is frustrating when I don't have the Qwerty layout on my keycaps and don't have it memorised either. The password box masks characters, so I couldn't tell if I hit the wrong key by mistake. Usually I would enable the on-screen keyboard and use it to enter my password.
I solved this problem by installing XDM to replace GDM, because I read online that with XDM we can create a file /etc/X11/xorg.conf.d/90-keyboard.conf
with contents:
Section "InputClass" Identifier "keyboard-workman" MatchIsKeyboard "on" MatchDevicePath "/dev/input/event*" Driver "evdev" Option "XkbLayout" "workman" EndSection
Now XDM uses the Workman layout.
The default XDM appearance is not to my taste, but I only have to see it for a few seconds, so it won't be worth my time to read how to install a theme.
I use full disk encryption, including on the root partition.
This makes it really annoying to configure, because there's no X server, and I can't access any real files at that point. I'm also scared of messing something up real bad.
LUKS supports multiple passwords, so as well as my regular password, I also added my password transposed to a different layout.
First, use # parted -l
to check your partitions. You need to identify where the encrypted partitions are.
The partitions will always end in numbers, like /dev/sda3
or /dev/sdb1
.
If you labelled your partitions, you can probably find them easily in that summary. If you didn't, they'll be the partitions that have nothing listed for the "file system" field.
The things you are looking for are not /dev/mapper/*
devices!!
Once you've identified your encrypted volumes, carry the following steps out for each of them. I'll use /dev/sda3
as the placeholder, so replace that anywhere it appears.
# cryptsetup luksDump /dev/sda3
to check the status. Might be useful to look at, and compare before/after.# cryptsetup luksAddKey /dev/sda3
to start adding a new key. Enter any existing passphrase to authorise.# cryptsetup luksDump /dev/sda3
. You should see an additional key.Don't forget to do this for all your encrypted partitions, and ensure that all of them include the same passphrase. Because when you enter the passphrase on boot, it attempts to use that passphrase to unlock all disks at the same time. If not all disks have that passphrase, you will have to enter multiple passphrases until you have unlocked every encrypted partition.
My 3.5mm output is kind of weird? Like, it doesn't think my headphones are plugged in when they really are, and I think that's the reason that my computer selects the wrong audio device to try to send sound to after I log in. So I have to open pavucontrol
and change the output every time.
Apparently I can add some lines to /etc/pulse/default.pa
to change the default devices. I've done this, though currently I'm not sure if they work reliably.
Anyway, if you're facing the same problem, the instructions in this post seem reasonable: https://unix.stackexchange.com/a/462671
The Openbox startup file, ~/.config/openbox/autostart
, seems like it always runs in bash, rather than the user default shell. This makes sense. Something that doesn't make sense is that even if the script has a #!
line, it still uses bash.
This piece of code will restart the script if the current shell is not fish. If it is fish, it will continue.
test $FISH_VERSION || exec fish $0
Various small web programs that I've written need to run in the background after I log in, but I don't really like it if I can't monitor them and stop them easily. Often I need to look at what my code is currently doing, and it's important that I reduce the friction to that as much as possible.
Rather than running the programs headlessly, I now have my Openbox startup file run them in terminal windows, then move the terminal windows off screen to a spare workspace so that I don't have to look at them until I want to.
Now that my startup script is running in fish, it's comfortable to write code that does this. Bash can do it too, but fish is just nice, you know?
set next_terminal_offset 0 function terminal_in_workspace set workspace $argv[1] set title $argv[2] set directory $argv[3] set command $argv[4..-1] if gnome-terminal --working-directory=$directory --title=$title -- $command wmctrl -r $title -t $workspace wmctrl -r $title -e 0,(math $next_terminal_offset + 52),(math $next_terminal_offset + 20),-1,-1 set next_terminal_offset (math $next_terminal_offset + 40) end end
And now, starting a program is as simple as...
terminal_in_workspace 1 homepages /home/cloud/Code/homepages npm run start
My computer is less annoying now. I'm happy when I can shut it down at night, because it no longer resists my efforts to start it up again. Shutting down my computer improves its security and saves power.
I love my computer.
Cadence
]]>If you need a reminder of what the Workman layout looks like, I got you.
My hands are definitely more comfortable when typing Workman than they were when typing Qwerty.
Due to the layout, my fingers are able to stick above the home row, because the most commonly pressed keys are actually there. For the other keys, I can reach each finger out from this base position.
This typing technique, which I believe is called "touch typing" (??) is greatly encouraged when learning to type, even for the Qwerty layout. Controversially, I don't think it's good advice for Qwerty. The Qwerty layout makes it totally impractical to keep the fingers around the home row, since the home row has very few useful keys on it. (In fact, significantly more time is spent typing on the top row than is spent on the middle row!)
As a result, when I was typing Qwerty in the past, I would use the first 2 or 3 fingers on each hand and move each hand around quite a lot to hit all the keys. For some words, one hand might even cross into the keyboard half owned by the other hand in order to type it faster.
The design of the Workman layout, which puts the most commonly used letters on the home keys, and the next most common letters in easy to reach positions, makes it naturally comfortable to use.
I type faster now with Workman than I did on Qwerty.
Checking my TypeRacer profile, I can type passages of text at around 115 words per minute, and in my last blog post about Workman, I wrote that my Qwerty speeds were 90-100 wpm. That's about 20% faster. Cool!
But what if I had spent the same amount of time that I practised Workman for, practising Qwerty instead?
I don't know, but the answer I expect is that such practice would have caused my Qwerty speeds to improve. Would they have improved to 115 wpm? I can see that being possible.
And I look online, and I see Workman typers that are much better than me, and I see Qwerty typers that are much better than me. The way I see it, choice of keyboard layout does not grant better speeds. Technique and practice are the things that are important.
I think typing speed and keyboard layout are almost entirely independent, and that Qwerty is certainly not "slow".
Type accurately.
One really important thing that I noticed from TypeRacer is that I do a lot better if I "slow down" in order to type more accurately. If you go fast, you're more likely to make mistakes. If you do make a mistake, then you will probably type a few letters past it. You must switch modes in your brain, stop typing, move to the backspace key, delete these excess letters, delete the original incorrect letter, move your hands back to the base position, and resume typing again.
Another way to think of it is: When you make a mistake, it's like you stopped typing entirely for the period of time that it took you to notice and delete the mistake. This is a surprisingly long time!
Pausing to make sure that you are typing the words correctly if your mind is unsure is faster in the long run, because the micro-pause as you process which fingers to move is still far shorter than the amount of time you would have effectively stopped for if you had made a mistake.
Consistency and accuracy are extremely important to typing quickly.
I have noticed that on Workman I make different kinds of typos than I do on Qwerty.
On Qwerty a common error would be for me to press the key next to the one I meant to press. This is possible because my hands are floating over the top of the keyboard and moving around. Now that I'm typing "properly", with no hand movement, this isn't an issue.
The kinds of typos that I make now are much more commonly caused by pressing keys in the incorrect order if the same finger must be used twice in the same word, like typing "tiwce" instead of "twice", or "misidrection" instead of "misdirection", or "characetrs" instead of "characters". (TW are on the same finger, as are SD, and so are TC.)
I still make errors where I just press the wrong finger entirely and type the wrong letter, but these are much more reduced compared to when I was using Qwerty, and can be further reduced if I take the time to slow down and think about what my hands are doing.
When programming, there isn't as large of a difference in typing style compared to Qwerty. Programming requires typing a lot of symbols and punctuation, which means my fingers naturally need to jump all around the keyboard no matter what layout I am using.
There is a "Workman-P" layout available, which is designed more for programmers to use, and moves some symbols to easier-to-reach places, for example. I haven't tried it yet, and I think it would be a hassle to learn, since the locations of symbols are actually printed on my keyboard.
You will type faster if your keyboard has no letter labels on it.
Think about it. What purpose do the markings serve? Once you know how to type even somewhat effectively, you should know where all the key positions are. If you are looking down at the keyboard, that's bad for three reasons.
One; if you are looking at the keyboard then you are not looking at the screen, so you can't check how things are being printed out. Have you ever typed an entire paragraph with caps lock on by accident? You won't if you're looking at the screen while you type.
Two; if your fingers are on the keys then you can't look at the labels on the keys. Your fingers are in the way. If you are reading the labels, then you have your hands off the keyboard and in a terrible pose, which is just awful. If you really need to be reminded of where all the letters are, you should print out a reference of the layout and stick it in your workspace at the same height as your screen.
Three; a lot of fancy keyboards have keycaps that are shaped differently depending on the row that they're found in. This is to be more ergonomic for the fingers, or something. If you rearrange the keys, the rows that the keys are in will change. Keys that are at different heights to each other will now be next to each other in the same row on the keyboard. It's awful.
Ideally, if you change keyboard layouts, you have keys without labels on them. If your keys have labels, that's still fine. Leave them as Qwerty no matter the layout you type. You will type better, I promise.
In my computer science class last year, there were a number of programming tests that had to be taken on a machine that did not have access to the internet or to my standard home directory. This was done to avoid cheating by students.
The Workman layout is not installed on those computers, and I can't download or copy the layout specification to be able to easily install it.
What I did was use a series of commands to reconstruct an xmodmap specification of the layout. The sandbox computers did have xmodmap installed, so if I could create the file by hand, then I would be able to use the layout.
If you were curious, here is the process:
workman.xmodmap
somewhere.C-x h BACKSPACE C-u M-!
, xev -event keyboard | grep -Eo 'keycode [0-9]+'
C-x h
. Then M-x delete-duplicate-lines
. Then go to the end of the buffer with M->
C-x r t SPACE = SPACE RET
. This adds =
to the end of each line.;
, you'll need to type the name of all the symbols which appear on that key, like semicolon colon
.setxkbmap -option caps:backspace
for capslock backspace. (Note that you have to do this before the upcoming xmodmap
command. Running setxkbmap
with any set of options will reset xmodmap
modifications.)xset r 66
makes the capslock-backspace activate repeatedly when held.xmodmap /path/to/workmap.xmodmap
Here's my finished xmodmap file produced through this method, if you want to see.
That last thing is possible, and quick to do with some practice, but definitely very tedious, and Linux only.
For a while now I've had a dream of building a hardware module that I can insert between the keyboard and the computer to remap the layout in hardware. So rather than needing to work to install the layout on the computer, which may not even be possible depending on if it is a public computer, I can take the device around with me and then use any computer after taking 5 seconds to connect the device to the keyboard.
But I'll probably follow this up in another blog post if I decide to actually continue the idea.
I like Workman! I think it's a good layout. My hands are comfy. My accuracy has improved. My typing speed has not, because typing speed depends on technique and skill rather than layout. Typing on other computers now is very tedious. Using the Workman layout on public computers may be possible, depending on the computer.
I hope you enjoyed this lengthy insight into how I use computers now.
— Cadence
]]>As you might expect, the queer support centre views sex and bodies in a positive light, and it gives out free condoms and tampons to students, available in small decorated boxes near the entrance for people to take.
I saw lots of small wrapped cylinders in the box, about the size and shape of my index finger from the tip to the second joint. I picked one up and asked my friend, "do you know what this is?"
They told me it was a tampon.
I stuttered. "Ah. I see. That, makes sense. That's what I expected. Uh, I'm asking because I've never seen one in real life before. Because I, uh, don't need to use them."
They laughed. "Ahaha, oh right, of course. I keep forgetting that you haven't always been a woman."
I froze, then began to laugh uncontrollably with joy.
— Cadence
]]>It's the end of the first day of the semester. Students are getting drunk, I can hear them on the roads and in the houses around me. I pull my coat tighter to me and continue.
About halfway home, I reach the dark section, a steep asphalt slope. I slow down to conserve energy for the hill ahead, and as I head up, I notice a person standing on the path ahead of me. I slow more and walk with caution.
As I approach, I notice that they are holding a box of beer cans, and talking on the phone with a male voice. He drops the box on the ground and some cans roll out, and starts to pick them up, turning around, and noticing me.
I stop walking, a few metres between us, and ask, "are you alright?", uncertain of if I want to approach. He replies, "yeah, all good", and then after a short pause, talks to the person on the phone, "this... [couple of seconds pause] walker, looks scared of me".
I'm tempted to say something: "What do you expect? You're drunk, we're on an unlit path with nobody around, and I'm a woman in a skirt." I hold my tongue.
He steps back and I pass by on the narrow path.
— Cadence
]]>Last weekend I participated in a competitive Netrunner tournament. (What is Netrunner?) Players from Dunedin and Christchurch participated in the tournament, it's cool that the regions were able to get together like that. We played the Startup format, which means there's around 300 legal cards we can play, all of which were created in the last couple of years by the Nisei organisation. In total there were 10 people in the tournament, 4 from Christchurch and 6 from Dunedin.
I started playing Netrunner around December 2020 when a friend invited me to the weekly local friendly event out of the blue. I enjoyed it quite a bit and I kept returning to continue having fun and to improve my skills as a player.
I still don't have much experience building decks as corp side, so I brought along a fairly generic Built To Last deck where the aim is to set up extremely strong ice to keep the runner out of the server where you're scoring the agendas. It's a fairly straightforward deck, but very powerful. I was impressed by this identity when I saw it played at locals, which is why I decided to play it in the tournament, though I still chose all the cards myself to put in my deck rather than taking somebody else's build.
I usually find runner side more fun to play and easier to build for, so I spent more time coming up with an original idea for it and refining it.
One of the people that I invited to play Netrunner with me in the past took a stab at deckbuilding and ended up making something with the card Chameleon. Though their deck wasn't very cohesive, I applaud their efforts, and while that deck didn't make good use of Chameleon itself, it did put my mind to work wondering what I could do to make Chameleon viable. I ended up creating a whole deck around the idea of using Chameleon.
The thing about Chameleon is that when it's installed I get to choose which type it is for the rest of my turn. When my turn ends, Chameleon pulls itself back into my hand, ready to be installed again next turn and allow me to choose another type. Sounds great, right? With Chameleon, I can defeat any kind of ice simply by choosing the correct type! But there's a few drawbacks.
I managed to come up with a strategy that completely mitigates all of these drawbacks.
DZMZ Optimiser, affectionately called Dizzy Mizzy, reduces the cost of the first program installed on a turn by 1. Chameleon costs 2, so if I can install 2x Dizzy Mizzy, I can install my first Chameleon for free.
Ice Carver reduces the cost of all opposing ice by 1, allowing me to break a little more ice than I could otherwise.
Cybertrooper Talut. This card is critical. "Whenever you install a non-AI icebreaker, that icebreaker gets +2 strength for the remainder of the turn." On its own, this is just ok, but you may remember that Chameleon comes back into my hand after every turn. Which means that whenever I use it, I have installed it that turn. This straight up just gives it +2 strength forever, getting it up to 5. With Ice Carver, that's 6. This greatly expands my options.
Paule's Cafe is the final piece of the puzzle. It reads, "spend click: host a program or piece of hardware from your grip on this resource. spend 1 credit: install 1 card that is already hosted." At first glance, this might sound confusing: why spend 1 more credit for the exact same thing? The answer is that credits can be spent during a run, allowing me to host Chameleon, and then install it and choose its type mid-run. This means I start the run, the corp rezzes ice in my face, I see what type it is, and I can straight away pay a credit to install Chameleon right then, choose the correct type for it, and break the ice.
I'm playing all of this with the identity Kit, which gives the Code Gate type to the first piece of ice I encounter each turn. This means if a server is protected by 1 piece of ice, and if I run that first, then the ice will be Code Gate, so I only need a code gate breaker. Since this is such a common occurrence, I also added Gordian Blade, a code gate breaker, into my deck, so that I can get past whatever ice without needing to hassle with Chameleon. Other support cards like Egret (which is in the deck) and Pelangi (which is not) will allow me to set the type of other ice to code gate, creating a massive chain of code gates that I can burn all the way through with only Gordian Blade. So satisfying.
Alright. That's enough rambling about my deck. I do think it's really cool, and I'm very happy with it and with myself. And — spoiler alert! — it won games!!
It was fairly early in the game, I installed my first agenda, and they ran the server. I completely forgot that I had already installed Reduced Service in that server before. So I didn't rez it and they stole the agenda, otherwise the 8 credit tax probably would have made them unable to do that, since Reduced Service costs them another 2 credits to run for every advancement on it.
I was very upset at the time, but it actually turned out okay because I had 2x Punitive in hand so I immediately flatlined them on my next turn.
It was a long and epic game.
Let me set the scene. I have 6 points, my opponent has 5. (7 needed to win.) They were playing Built To Last, and there were a couple of pieces of ice that just had too high strength even for Chameleon. They installed 2 cards in a remote, face down.
I didn't know what either were, but I had a feeling that one of the cards was a 2 point agenda which they'd be able to score on their next turn and win the game, and I had a feeling that the other one was Cayambe Grid.
Cayambe Grid would have meant that I'd need to pay another 6 credits to complete a run on that server. I had already made extremely taxing runs on the previous 2 turns. If it wasn't Cayambe, I could maybe have made the run, but if it was, there was absolutely no way.
I had no way to be certain whether it was Cayambe, but I suspected it was, and if it actually was, then I knew that it would be a disaster. I'd spend my entire turn trying to make that run, and they'd rez Cayambe, and they'd kick me out of the server, and my turn would have gone down the drain, my final turn, as my hopes and dreams flashed before my eyes as play passed to them and they triple-advanced and scored that blasted 3/2 agenda to win the game. That would be a disaster, after coming so far and making it to 6 points myself.
If that was the case, I would lose the game. So I had to do something else.
I started my turn. I ran R&D on click 3 with a broken bank and no Imps to speak of. I accessed one card.
It was an agenda.
I won the game.
Despite being a competitive event, we decided ahead of time that it would be nice to relax and give everyone the same prizes for participating no matter where they placed in the tournament.
Since Netrunner's cards do not come in randomised packs, and anyone can print their own copy of any legal card to play with, it wouldn't be possible to give away rare cards or anything like that as a prize.
Instead, everybody got some extremely cool alternate arts for popular cards in the game, including Project Beale, Noise, and Diesel. I like them a lot!
I placed 6 out of 10 in the tournament and won half of the games that I played in, 2/4 as Built To Last and 2/4 as Kit. I'm extremely happy with these results! These were also the first games that I won as Kit, at all! I didn't actually manage to achive a win earlier when playing at locals or when playing online on jinteki.net. Those games did help me to think more about my game plan and to refine my deck, though, and I definitely couldn't have won at the tournament without the experience that those preparatory games gave me.
Still though, regardless of my results, I'm very happy to have just played in the tournament at all because all of the games I played were awesome.
I wrote this post in the Textreme 2 text editor. It sure as hell made writing this a lot more fun, and I don't think I would have written nearly as much if I was using a more traditional text editor. You should totally check it out. It's available as part of the itch.io Palestinian Aid bundle for a limited time (2 days left at time of writing) which you should definitely also get if you haven't already. I'll probably make a post in the future recommending items that I liked in the bundle.
]]>