Counterstrike FAQs: Is it too late to start playing this game?

People ask this question because they believe games become more difficult for new players to join after the intiial launch. As if the skill level of the average player means new players can’t get to the enjoyable parts of the game, aka winning, without a soul crushing effort. In games such as Call of Duty and Battlefield where playtime and kill count unlocks better weapons its understandable people could miss the boat on new games.

For Counterstrike this isn’t true. There are no items or skills or weapons to unlock and the skins on guns are purely cosmetic, having no impact on fairness of the game play at all. Counterstrike isn’t a “pay to win” title and every in player in the game has the same potential.

“In Counterstrike, your player doesn’t get better… you get better”.

The Warowl

It’s never too late to join Counterstrike. The skill group based system can and will find a place for you in the ladder that will give you winnable games. It can find teammates and opponents of roughly your skill after only a few games and create an environment where you can contribute positively and enjoy the highs and lows of a game.

Where ever you start doesn’t determine where you end. Reddit is full of people who started in the absolute lowest skill group and eventually made it to the top. There’s always an active community of people learning CSGO on Reddit as the game spreads through word of mouth and from pro games people stumble across on Twitch.

Counterstrike FAQs: Wins are more important than stats.

As a programmer, I’ve always been interested in Counterstrike’s Matchmaking algorithm, that determines who plays who. I’ve spent years documenting the algorithm and participating in Reddit threads. Things changed about 6 months ago making that document obsolete.

Since it was first released the general premise that users had about the algorithm is that wining gives you ELO/Glicko points and that losing takes them away. The more you win, the quicker you rank up.

Now’er days, Reddit threads seem to converge on this idea that personal performance matters and that you can basically be a bad teammate, and still rank up.

A redditor once told me a story that he had created two new accounts. One for him and one for his friend. He then queued with his friend and cheated his ass off, ensuring both accounts won every game. However dispite only playing together after ten games the accounts ended up in different ranks. This creates a compelling argument that perhaps the K/D of the cheater was the difference maker.

Even though I can’t be sure either way, I still feel that there’s nothing you could do with this information which is useful. Should you kill a teammates defusing the bomb to steal the defuse and the MVP award? I mean probably not. Should you lie to your teammates and give false info that encourages them to die, or ended baited for you?

MVP and points on the scorerboard are linked, so I can’t imagine the algorithm would use both. And with many players not getting any MVP’s in a game, as a programmer I’m guessing it’d make more sense to use points, but I still can’t envision a scenario where any role that points plays, is greater than the result of winning or losing a game. It’s not great enough to overhaul the whole objective of the game, to win.

I think it’s a bad idea to tell that to Silvers they don’t have to play for the benefit of the team’s goal to win and it serves no purpose to propagate. It puts them in the wrong mental mindset and dissuades them from improving their team play. At worst, it causes them to lose faith that the algorithm has any semblance of fairness.

The copy and swap pattern explained to Scala developers

People are always asking about the benefits of immutability and why it’s a big deal for the Scala community. I learned about the copy-and-swap pattern from C++ before I learnt Scala and it’s why I’m grateful Scala won’t let me shoot myself in the foot.

Let’s look at a typical piece of Scala code from the Object-Oriented design world that embraces private mutable variables, believing that hiding state simplifies the design of the application:

class Person(name :String, phoneNumber :String = "") {
   private var mName :String = ""
   private var mPhoneNumber :String = ""
   
   def getName() :String = mName
   
   def setName(name: String): Unit = {
    mName = name
   }

   def getPhoneNumber() :String = mPhoneNumber
   
   def setPhoneNumber(phoneNumber: String): Unit = {
    if (phoneNumber.length < 8)
      throw new Exception("bad phone number")
    else
      mPhoneNumber = phoneNumber
   }

    setName(name)
    setPhoneNumber(phoneNumber)
}

val emergencyContact = new Person("robert", "9326489432")

println(s"emergencyContact name: ${emergencyContact.getName()}")
println(s"emergencyContact phone number: ${emergencyContact.getPhoneNumber()}")

This class maintains a name and a phone number, providing a getter and setter for each. Let’s look at how it might be used inside an application


def updateEmergencyContact(newName :String, newPhone :String) = {
    emergencyContact.setName(newName)
    emergencyContact.setPhoneNumber(newPhone)
}

updateEmergencyContact("mark", "7384")

When you run the code above it explodes because the phone number isn’t 8 characters long. You can capture the exception but you cannot handle it gracefully.

scala> println(s"emergencyContact name: ${emergencyContact.getName()}")
emergencyContact name: mark

scala> println(s"emergencyContact phone number: ${emergencyContact.getPhoneNumber()}")
emergencyContact phone number: 9326489432

What’s happened here is that the setName change worked, so now it says “mark” but the phone number wasn’t updated, it’s still robert’s phone number. In an emergency you’d phone Robert and ask for Mark, and Robert responds, sorry bro, wrong number.

This class of error is deeper than just poor error handling. The internal state of the application is corrupted. If you caught the bad phone number exception .. you still can’t recover from the error without a deep internal knowledge of the order to setXXX functions and what the state was before.

In C++ if a variable called a is the same type as a variable b then a = b; cannot fail. It is also an atomic operation – it happens instantly or it doesn’t. All you are doing when you say a = b is updating a pointer.

If your program works like this…

  1. Copy the initial state (var `b = a.copy)
  2. Modify b however you want: b.setName(...)
  3. Overwrite the reference at the end: a = b

..then your application will always maintain a valid state. If it crashes before the third line, a stays exactly how it was, which is at least consistent. If the final line executes, it’s also consistent. Let’s look at using wholistic objects in our approach:

val newPerson = new Person(newName, newPhoneNumber) // explodes
emergencyContact = newPerson                        // if reached, cannot fail

C++ uses copy constructors like many other object oriented languages do. In Scala we also have the benefits of using case classes which give us a copy function for free.

By designing the way you update data in your application to be around “whole classes and copying things” you simplify the error handling for your application. Extending the use of immutability everywhere allows you to trust the application more. You could draw comparisons between “copy and swap” with how databases implement transactions that are either committed or rolled back.

You may consider this a case of bad programming and not handling a validation issue correctly, you presumably don’t make this example mistake in your own code, but network/file exceptions are common and unavoidable. This pattern is more about graceful failure, retaining consistency easily being able to continue when things do go wrong. It works well on larger object hierarchies where you are scanning and updating multiple things at once.

Applying immutability everywhere, or using libraries like cats effect to help eliminate side effects are natural extensions to this principle. It may take some time to fully warm to however.

Monads for OO Programmers

I’ve been writing Scala for 5 years (At time of writing this post). Let me explain in my own layman terms without category theory what a Monad is.

A Monad is an object instance which contains another object instance and adds some context to it.

The word “context” here means to add other information to something in order to give it meaning. If you saw the word Drisenburg in a story book it’s meaning wouldn’t necessary be apparent out of context, but in the context of the book, you would come to understand as you read the whole book it is a name for a character or a location or treasure of something.

Context is new information that changes the meaning of something. A joke might be objectively funny but it might not be a funny thing if said at someone’s funeral.

We may know a Royal wedding is on TV at 5pm in UK Time but we need to know our own timezone or location, for that time to be relevant to us. In this example the time is the thing or object and the timezone is the context that makes the time relevant for us.

As a general phrase many people say “to put things into context…” and in the Object Oriented design world it makes exactly the same sense to model this context as something that wraps something else.

case class UKWeddingEvent(
   dayOfYear :Int,
   hour :Int,
   minute: Int
)

case class LocalTimeUKWeddingEvent(
   ourOffsetFromUKTimeInHours :Int,
   weddingEvent :UKWeddingEvent
)

Here I have a UKWeddingEvent and a LocalTime which I’m calling the Context in this example.

We could arguably model our solution by using a Tuple to attach our timezone to our wedding event

val ukWeddingEvent = UKWeddingEvent(364, 12,00)    // thing
val localOffsetFromUKHours = 4                     // context

val myLocalisedWeddingEvent = (localOffsetFromUKHours, ukWeddingEvent)

Or we could just have some sort of Context object to pair them

case class Context[A, B](mainThing :A, extraData :B)

The last two proposed solutions aren’t ideal as they allow tinkering with the mainThing outside of its context, without the full facts about what’s changing.

If the UK Wedding is pushed back two weeks, you don’t want to tamper with the UKWedding directly outside of the context of the localising information as you will cause a bug. The clocks go forward an hour in the summer in the UK one week before the Americans’ put their clocks forward so this would introduce a bug into the system. This is why the best approach was the original design, one that controls the object to restrict it’s access, which was very close to our first example:

case class UKWeddingEvent(
   dayOfYear :Int,
   hour :Int,
   minute: Int
)

class LocalTimeUKWeddingEvent(weddingEvent :UKWeddingEvent, offset :Int) {
   private val weddingEvent :UKWeddingEvent        // thing
   val offsetHoursFromUK :Int = 6                  // context
}

We still need to be able to change the wedding event in a controlled manor and in a way where the change can be captured. One way to do this is to allow people to provide an update function which changes a UKWeddingEvent into a new UKWeddingEvent, mapping it from an old value into a new value and allowing us to handle context changes:

def map(function :UKWeddingEvent => UKWeddingEvent) = {
   val newEvent = function(weddingEvent)
   
   val wasBST = weddingEvent.dayOfYear > 65 && weddingEvent.dayOfYear < 135

   val nowIsBst = newEvent.dayOfYear > 65 && newEvent.dayOfYear < 135

   val newOffset = (wasBst, nowIsBst) match {
        case (false, false) => offset
        case (true, true) => offset
        case (false, true) => offset - 1
        case (true, false) => offset + 1
   }
   
   new LocalTimeUKWeddingEvent(newEvent, newOffset)
}

So the function above allows users of my Context class to manipulate the inner object is a way that allows the context to retain control safely. Callers may use it like this:

def delayWeddingByTwoWeeks() = {
    localWeddingEvent.map(event => event.copy(dayOfYear = event.dayOfYear + 14))
}

This has safely pushed back the wedding whilst letting the context stay accurate and relevant. Whilst these next two examples may seem a little contrived for our code, it’s time to step back a little a look at the big picture.

I’ve been calling a Monad a generic context object so there’s little surprise we are going to make this UKWeddingEvent use the generic terms that monads use.

I’m going to eventually make this UKWeddingEvent in a Monad. Two other common things we want to do with our context object apart from map over it, is change the context by simply taking an update to itself it:

def flatMap(function :LocalWeddingEvent => LocalWeddingEvent) = {
   val replacementForWholeContext = function(this)
   this.offset = replacementForWholeContext
}

Flattening a monad is a way of merging contexts. In our example, it would be applying two timezones to the event. Convert a UK Time to French time, and then on to German (providing a new context and thing).

So lets look at our LocalUKWedding object and talk about those few operations

class Context {
   def pure(in)   // put a thing into some context
   def map(f)     // apply a function to a thing
   def flatMap    // replace a thing + context
   def flatten    // reduce to a single context
}

someOtherFunction   // get something out of the monad and realise it's value.

A Tour of real Monads.

Future

Functions return values and the Future Monad abstracts away the details of how functions are turned into values. Understanding the context of running code on this thread or that thread and have a slightly irritating need to refer to ExecutionContexts.

So Futures provide values and allow you to manipulate values that may not have even been generated yet by exposing it’s map function to say “apply this function to this value when it becomes available”.

// code example required.

I’m going to talk about Futures again when I get near the bottom. For now understand it is a Monad that provides an execution context.

Options

The context is whether something can be missing. map() here takes a function but runs it if the thing exists, thus your code can be ignorant of null pointers and missing variables and run safely regardless because it provides the context of whether or not those commands would fail.

What’s nice about abstracting away whether something exists or not is that you can write really terse code with practically no if statements.

You can think of Option’s implementation as a list of 0 or 1 items. If you can write a LinkedList collection class in Java, you can easily write your own Monad for Option. map takes a function and only runs it if the item exists.

Either

An either is two values bundled together. Either the left is empty and the right is populated or the right is empty and the left is populated. A little surprising thing about Either is that it’s “right biased”. map() takes a function that applies to the thing on the right. map does nothing to the left. Scala developers put good values in the right and errors in the left and map works like a “if this is successful, continue with this…”.

Getting things out

There’s no secrets or cheats here but it seems to be a point of frustration or confusing for people. You can put things into Monads, operate on them in context (whilst ignoring the context) and then pull them out. Every monad allows you at runtime to realise it’s value in a concrete way. Even future. You simply “Await.result”. Every program using a Future either has one await.result in it or it prematurely ends. No Exceptions. In Play framework the framework does it. Akka and http4s too. You should avoid it completely and chain your operations using map and flatMap. This will give you an application that has flexible concurrency and little chance of deadlocks. But there is no magic, eventually the whole app is flattened into one future per event handler on which await.result is invoked. The function isn’t in Monad category theory language but is called Await.result.

Programs using Option either eventually call .get or .getOrElse or they use if statements to control the flow but somewhere they are realised.

Next steps

Once you’re familiar with the four operations of a Monad. Put it in (pure), apply a change to the value safely (map), replace one (flatmap) or flatten nested Monads (flatmap) then you’re ready to look at some of the other guides with more confidence and experiment!

Scala has a very nice set of keywords that allow you to write a series of maps followed by a single flat map in a pretty style. It’s a syntax variation on a for loop called a for-yield loop.

You are probably going to want to explore that at some point but it’s beyond the subject of this blog post and frankly is just pretty boilerplate that shouldn’t deter you from using Monads directly. Hopefully this guide compliments your understanding of Futures and Monads from other articles and you can play with them having more confidence.

I believe in Findology

I believe in science. I believe in psychology. I believe in Findology!

There is a science and method to looking around your house for things that once you’ve learnt will make your life more enjoyable and less stressful.

The first rule of Findology is that you cannot find something unless it’s you acknowledge it’s missing. You need to move from panic, into a productive state. Go into your front-room and loudly proclaim “My house keys are missing and I can only find it, if I look for it”. Once you’ve done this, stand still for 10 seconds and contemplate emotionally that you have a small, easy task to perform. A quick search.

Here are some simple methodical steps

  1. The missing item is in the place you think it is. Why wouldn’t it be? Statistically it is probably within 18 inches of where you think it is. It has fallen behind something. Something is draped over it.
  2. No? That’s fine. It’s in the last place you saw it. You memory is the problem here, not the item. The item is not lost, you need to find your memories.
  3. Everything has a home. Every piece of sellotape, every pen, every ornament. There’s a “default” place you would put it, had you bought it home new. Your brain is a database and there’s also an algorithm to put new things in new homes. If your memory fails, your algorithm to assign something a home should select the correct place. Its where you think it should belong.
  4. You’re now going to have to adopt “the algorithm”. The algorithm is to search your house. You are going to search each place thoroughly, so that you only search it once. You will search things in the likely-hood of it being there. Think about your house having “hotspots” and “coldspots” of activity. A table is a hotspot. The bathroom is a cold spot (typically).
  5. Consult Dr. Solomon’s advice, using the link below.

With practice and discipline, you can become fast, organised and committed at performing a single thorough house search. It no longer becomes a chore. It is a simple, quick and reliably successful exercise you have to do, comparable to taking the bin out. Searching is easy.

As you accept Findology as your belief system, you more consciously consider the “homes” of your items. You pick up, fondle and lovingly gaze upon things like Glue sticks and say

“hello mr glue stick, you live in the draw, let’s put you there now”.

As you adopt Findology life is less stressful.

I didn’t invent Findology, it was invented by a real scientist. What I’ve written is an experience based variation of the original and more respectable official Findology advice. Please see this article for the genuine, and more hilarious, truth to happiness.

https://www.dailymail.co.uk/femail/article-1301444/12-tips-worlds-findologist-help-lose-again.html

Some excerpts:

Sometimes, in fact, you are looking right at it. That’s Solomon’s sixth principle. ‘It is possible to look directly at a missing object and not see it,’ he says.

‘This is due to the agitated state of mind that often goes with losing something – especially when you’re in a hurry. Go back and look again. It may be staring you in the face.

‘Sometimes, not only do we overlook an object – we forget what we’re looking for. To avoid this, repeatedly murmur the name of the object.’

Counterstrike’s raison d’être

The little CSGO team at Valve work on making CSGO the best game everyday. It’s their job to. With that said.. Valve is the platform business. It’s biggest and most important product is Steam. To make Steam attractive, to encourage adoption and retention of game developers Valve release many products that tie games to Steam. CSGO exists, for the larger company, purely to advertise those Steam features:

  • Making a competitive game? We offer a matchmaking service using Glicko. Look at how matchmaking increases retention rates and players invest to make it to the top.
  • Worried about cheaters using free 2 play accounts? We’ve got Trustfactor spanning multiple games so we can look at a gamer’s history to see if they’re likely to cheat.
  • Need anti-cheat? VAC bans thousands of CS players and you can enable it with 2 shakes of a lambs tail
  • AI Anticheat? Look at how CSGO detects and bans aimbots.
  • Want an overlay, with web browser, chat and want your gamers to share game screenshots on the community? Just hit F12 on any Steam game and get it free!
  • That’s not all. We got desktop SDK, Valve Index SDK for VR games and a host of other services you might want to enjoy.
  • Community market? Check out Counterstrikes loot boxes, even operating in France (with a novel legal interpretation)!
  • Look at Counterstrike running on a “steam deck”. Pointless but respectable from a technical standpoint none the less. (also, some poor soul did this knowing that CS2 was also being developed at the same time)
  • Want the community to build your product for you? How about Steam Workshop. Our millions of Counterstrike users are upvoting the same poorly designed aim-maps for decades.
  • Want to target the Esports arena? We’re the experts with Counterstrike. Check out Steam TV where gamers watch streams together and we collect the metrics and sell them back to you like Adsense for your game.
  • Worried about going free 2 play? We did it with Counterstrike.

We love and are invested in Counterstrike and I certainly believe the devs are too. CSGO has to dance to the tune of those selling Steam as a platform. Those below Gaben who want to milk the product and use it as an advertising tool for the rest of Steam. That’s why CSGO is getting Steam deck support even though we all know a controller isn’t as good as a mouse. Ho hum, tis the world of business.

How I stay organised using Vim

I spend all day in VIM. Either editing configuration, writing plans or using it as a full blown IDE.

I use nvim-metals to get IDE features like showing variable types when editing Scala code.

Whilst every morning I give a standup update, through out the day I keep all my notes in a text file. Its just a text file and looks roughly like this

Where ever I am in Vim or whatever I’m doing, I can immediately open the file with `G I’m using the feature called “marks”. In short m will mark the current cursor position so ma will remember the cursor position and associate it with the letter a. Typing` awill take you to the line your mark was on. (The quote character is under escape on a UK keyboard).

It’s an amazingly useful feature. I use it the most when I’m half-way through writing some code and I need to jump to the top of the file to add an import. I mark the cursor position, jump to the top and then return once I’m done. Lowercase letters are local to your file so you can store 26 unique positions per file. Using an uppercase letters operate at the global level opening my notes file regardless of where I am, or if the notes file isn’t opened yet. It just opens it and puts me in.

If I need to write an essay on a particular topic or the notes get long and ugly, the second trick I use is to create a specific text file for that thing and keep the filename in my notes file. Using gf in vim opens the file path under the cursor, so it takes me hardly anytime to navigate through my collection of notes, drilling in and out when necessary.

Vim’s Ctrl+o feature helps me move back to where I was when I’m finished with the notes, speeding up navigation. I also have this bind in my vim rc:

noremap <silent><leader>bd :MBEbd<CR>

When I type \bd the file I’m looking at is close and vanishes. This is my trick to keep my workspace clean and tab list short and focused. It’s not uncommon for me to spend a minute every now and again closing all the unused files like this, just as you might also do when you periodically close those browser tabs you weren’t using.

Finally, the benefit of just using a text file instead of some plugin solution is the flexibility. It’s in my sync’d cloud files so it’s backed up and can be opened in other programs. Sometimes i open it in Kate if i’m not in vim at that particular moment.

Open In JIRA – 2021 Edition

If you’re developer who uses Linux for work and has an appreciation for command line tools, it’s likely you spend all day in apps like IRC, Mutt, use Vim, emacs, and git commands. All of which, are probably littered with references to your project management code. My company uses Jira but yours may very. 6-7 years ago I “hacked” KDE’s Konsole to add an “open in Jira” link to the Konsole and it was like enriching dozens of programs at once! Now IRC, Vim, git all benefited at once from a single change. See the image for screenshots

Konsole augments email
Konsole augments bash
Konsole augments IRC Chat
Konsole augments git log command

Checking out the latest dev version of Konsole on my path to reimplement the feature again I spot a new feature. The feature allows selected text to be used to open a URL:

KDE Konsole’s new search option

It appears to have a simple configuration for building simple urls

The feature is called Web Shortcuts and appears in Konsole 20.12.2 (and possibly earlier)

Huge thanks to the KDE Konsole team for this awesome feature! As a Debian Stable user I have no idea how long this has been around, but I love it! I don’t know how much publicity Konsole gets but I wanted to share!

As a serious command line user, like many Linux users, Konsole’s 3 killer features for me are:

  1. This open in JIRA thing
  2. Infinite scrollback
  3. Search output

Tour of my working environment

User interface: Tiling window manager DWM

Resizeable windows that you drag around the screen, that overlap helps people using a computer for the first time to recognise that opening a new window doesn’t lose the old one, and that the computer can do multiple things at once, and so can they.

Once you know that however, moving and resizing windows is fiddly and unnecessary. DWM manages and resizing windows for me and means I use the mouse less which makes me more efficient too. Essentially I have 9 workspaces. If I have one app per workspace then each app is full screen. I keep my webbrowser on Alt+1, my editor on Alt+2, chat on Alt+7. If I open a second window I get a vertical split which helps me do things side-by-side if I need to, and if I open more they stack up on the right hand window, automatically sized and I can still cycle between windows with Alt+j and Alt+k like a Windows user might switch between windows with Alt+tab.

The DWM development team has some quirks in that DWM provides no separate configuration. You edit the source code, apply and patches directly to the source code and compile it into a binary yourself, keeping the size and complexity of the window manager small. The custom config I’ve applied (clients per tag, some colour changes and some keybindings) were first committed to a git repo I created in 2013 and still use to this day.

Operating System: Debian Stable

I don’t have much to say about Debian Stable. It’s stable and care is taken by the Debian team to make sure things don’t break. Aptitude is straight forwards, the documentation is good. Many people complain that Debian Stable isn’t very “up to date” but whatever is released brand new today will be in Debian in 2 years. After 5 of these 2 year upgrade cycles in my ten years of using Debian, there’s nothing new or looming that makes me feel like I’m missing out.

Vertical tabs instead of horizontal ones

One thing that’s important to keep up to date in Debian is your web browser. I downloaded Firefox directly from Mozilla, unpacked the tar ball into ~/opt (~/opt is in my home directory) and because it lives outside of root’s permissions it can keep itself up to date and doesn’t damage the stability of my machine. I use the tree-tabs plugin since it provides cleaner visibility when you have 30+ tabs open at once.

To keep my machine clean in other ways I use docker heavily to build applications I develop. I haven’t installed perl, nodejs, mongodb onto my system (which I need for work). Instead I maintain a bunch of docker images that can be thrown away or reset whenever I fancy.

Spotiamb

One thing that will no doubt stick out as odd or niche in my setup is my music player. Created as a little treat by the Spotify team in 2013 this Winamp clone connects to Spotify to play music and has a lot of nice functionality. Yes, including the visualisations you may remember. Winamp made them remove the “amp” hence it’s now “Spotiamb”. It’s not been very easy to maintain this application but I love it so much I persist. It’s only written for Windows and it’s a 32 bit application. To keep it alive I’ve held on to the original installer and milkdrop plugin all these years. I tracked down a docker image designed to do X11 and audio forwarding and so I didn’t have to add 32 bit architecture support to my main desktop. I hope to share this in a blog post soon.

Terminal: Hacked KDE Konsole

I still use a patched copy of KDE Konsole that has hardcoded regex’s embedded inside it so it ingrates with JIRA, the program that tracks the work I do, or should be doing. Read the full post for more information but I feel like it’s a win for open source if end users can make their little changes.

Editor, IDE: Vim / Neovim

Neovim with Scala-metals

I wrote Python and Perl professionally from like 2008-2018 and honestly vim is a fantastic editor. I used to believe in the slogan “Unix is my IDE”, often using Ctrl-Z to put vim into the background, returning to bash and using find, grep etc to help me develop the code. For those lightweight languages that don’t benefit from large IDEs, vim had become the editor I use all day. I had to adopt JetBrains IDEA when I learnt Scala just because of the complexity of the type system. I had tried and failed to readopt vim when working Scala but it didn’t really happen until scala-metals came out a year ago. To be honest I only really wanted accurate “go to definition”, “find references” and “show type” and it gives me those. I use a separate install of neovim as an IDE to keep open all day and use the regular lightweight default vim for quick editing sessions everywhere else.

Physical Setup

Desk with Chair, light, background Bookcase for show
Work laptop on desk, Gaming desktop underneath
So much more keyboard and comfort when a monitor stand is replaced with a mount. Get one!
  • Monitor: 24″ Asus 144Hz Gaming Monitor, 1080p
  • Programming Keyboard: Steel Series M400 UK – Blue Switches
  • CSGO Keyboard: HyperX Origins Alloy Core – Red Switches
  • Mouse: Roccat Kone Pure
  • Gaming Desktop: Core i7 6700K (4GHz) + Geforce 1660Ti
  • My desk arm gives me tons of space to push keyboard around and be comfortable. I literally get the whole desk. See before/after pictures. I couldn’t recommend it enough!

One thing I want to draw attention to (the pictures are too old to show) is a Usb-C hub costing £20. My mouse, keyboard and monitor are connected to the usb-c hub and so is a power charger. It means I have just one cable to put into my laptop and it connects to all the devices and even charges from the same cable. I can just freely come and go between my desk and my living room with only a single cable to connect/remove. Super convenient

16TB Synology Diskstation, Fibre Internet Terminator, 1Gbps Switch

Supporting Equipment

I use next-cloud sync to my self-hosted next cloud instance to backup a dozen files and folders, although I don’t backup the operating system itself. My work laptop is a Dell Inspiron 13 7000 2 in 1 I bought in 2018. I’ve upgraded constantly from Debian 9 without issues and if I need to reinstall so be it, but it’s likely I’d be moving to a new machine at the same time anyway since my environment seems to be very reliable. In my house I have a Synology diskstation with 2x8TB disks (mirrored) and also backed up using the Synology cloud backup service. That provides 3 copies of my important files.

How I got banned from Reddit’s r/Linux forum

I wake up one morning to find this drivel “stickied” to the top of r/Linux. A post from the moderators stating:

  • Readers should stop using social media (such as reddit)
  • your usage of social media spreads mis-information even if you don’t share misinformation

The headline alone is confusing for me. I’ve been a Reddit user for 14 years and actually considered it a “news aggregator” rather than social network. I don’t have any friends on the platform, it’s just a good place to see critiques of news stories. In fact if anything it’s THE place to ensure you don’t swallow misinformation.

I’m not on Facebook, Instagram or Twitter. I stopped using What’s App after Facebook bought it. It’s always interesting for someone on social media to tells others to drop it, but why Reddit allows a moderator to have such an anti-reddit views is a bigger question.

So the author wants to stop people using Reddit, stop people using Social Media and they want to control misinformation. Why then suggest people use decentralised channels to communicate where misinformation is harder to control?

In a moment of not caring I drop this insignificant comment into the chat:

Then I receive my ban

Pathetically authoritarian if you ask me. You do decide what’s appropriate for linux, I just threw out an opinion. Suspecting this was a single mod acting in bad faith I try to appeal my ban but it seems to be the same person

When you ban people for no reason and act like this you embarrass yourself and destroy the community. I think Reddit has a problem with these sorts of moderators who don’t actually contribute to the community, have no investment in a community and rate their own contribution by the number of bans they hand out.

One week later they sticky a “read the rules” post with this gem:

Top violations of this rule are trolling, starting a flamewar, or not “Remembering the human” aka being hostile or incredibly impolite.

I’d classify calling someone “a waste of time” as incredibly impolite. I’m feeling very much like I’m the forgotten human at the end of this ordeal.