Image from https://commons.wikimedia.org

Something was Missing

The very first Apple laptop I’ve ever owned was the 2015 Macbook Air. This machine was great as a student and it provided me with everything I needed at the time. There were times when I would need to reboot the system, especially after a major update and I would be greeted by the startup chime. This is no longer present in the new Macbook lineup beyond 2016 (touchbar era).

This quick hack/fix can be found here by 9to5mac.

By saving you time, here’s the tl;dr. Open up terminal and enter the following:

sudo nvram StartupMute=%00

Assuming your audio isn’t muted, you’ll be once again greeted by the startup chime after your machine has been rebooted.

Digging Further

After the discovery of this command, there were no clear answers of how this came about. I initially began to investigate this by visiting the man page.

nvram(8)                                                                          nvram(8)



NAME
       nvram - manipulate firmware NVRAM variables

SYNOPSIS
       nvram [ -p ] [ -f filename ] [ -d name ] [ -c ] [ name [= value ]] ...

DESCRIPTION
       The  nvram command allows manipulation of firmware NVRAM variables.  It can be used
       to get or set a variable.  It can also be used to print all of the variables or set
       a  list  of  variables  from  a file.  Changes to NVRAM variables are only saved by
       clean restart or shutdown.

       In principle, name can be any  string.   In  practice,  not  all  strings  will  be
       accepted.   New World machines can create new variables as desired.  Some variables
       require administrator privilege to get or set.

       The given value must match the data type required for name.  Binary data can be set
       using  the  %xx  notation, where xx is the hex value of the byte.  The type for new
       variables is always binary data.

OPTIONS
       -d name
              Deletes the named firmware variable.

       -f filename
              Set firmware variables from a text file.  The file must be a list  of  "name
              value"  statements.  The first space on each line is taken to be the separa-
              tor between "name" and "value".  If the last character of a line is  \,  the
              value extends to the next line.

       -x     Use  XML format for reading and writing variables.  This option must be used
              before the -p or -f options, since arguments are processed in order.

       -c     Delete all of the firmware variables.

       -p     Print all of the firmware variables.

EXAMPLES
              example% nvram boot-args="-s rd=*hd:10"

       Set the boot-args variable to "-s rd=*hd:10".  This would specify single user  mode
       with the root device in hard drive partition 10.

              example% nvram my-variable="String One%00String Two%00%00"

       Create a new variable, my-variable, containing a list of two C-strings that is ter-
       minated by a NUL.

              example% nvram -d my-variable

       Deletes the variable named my-variable.



                                     October 28, 2003                             nvram(8)

As you can see, the man page was created a long time ago, 17 years from this post. This is the 8th section and there doesn’t seem to be other sections for the nvram command. The options that displayed the firmware variables only displayed variables currently in use by the EFI firmware.

This is what is displayed when I ran sudo nvram -p.

bluetoothInternalControllerInfo	%bluetooth%controller%info)
fmm-computer-name	MacBook Pro
bluetoothActiveControllerInfo	%active%bluetooth%controller%info)
backlight-level	D%01
gpu-policy	%01
StartupMute	%00     <-- THIS IS WHAT I RECENTLY ADDED TO ENABLE THE CHIME
HW_BOOT_DATA	%01%00%00%00%01%00%some%foobar%0000%00

I assume StartupMute used to be enabled in older versions of MacOS and was promptly extracted or hidden from the system and someone decided to re-enable it out of curiosity which fortunately still works in Catalina. I also assume most critical NVRAM variables are closed-source and are hidden away by Apple.

First Impression

Prior to using the HHKB, I had currently been using the Keychron K2 on Gateron blues with 0.5 o-rings. I really liked the bluetooth connectivity and tactile switches but the stabilizers were still a bit too sluggish.

When the HHKB arrived, I went ahead and adjusted the DIP switches so I can activate the function modifiers in MacOS. I was aware of the changes I needed to overcome when working with a 60% keyboard. I knew what I was getting myself into from the get-go. Since I do a lot of code development, it took some time for muscle memory to set in-tune with the new keyboard layout.

DIP switch configuration table.
DIP switch settings for MacOS.

About 10 minutes in, every key press I made felt very satisfying. Every action was very smooth and tactile. There was an initial bump followed by a very smooth glide throughout the remaining key press. Even though the keyboard is completely made out of plastic, there is no flex at all and it feels very sturdy. The key caps are made out of PBT except for the space bar which is made out of ABS. After a while, I finally understood why this keyboard is beloved by many mechanical keyboard enthusiasts. It is, if not the best keyboard I have ever used up until now.

Design & Layout

At first glance, this keyboard is pretty small. In fact, it contains 60% of keys that are contained in a full keyboard layout. The function row, arrow keys, numpad, caps lock, and special keys are all gone. Now you may be asking, “why would anyone do this?”. Simply put, most of these keys are hidden behind a secondary function layer which can be activated by holding down the function key (Fn). As for myself, the Fn key is in the best location for my right pinky which I use to access all the function modifiers without breaking a sweat. The key side labels indicate the usage of the Fn key. The longer I use this keyboard, the better I understand its awesome design.

Control and caps lock.
Arrow keys.

After a while, I begin to notice myself having to re-adjust the keyboard back to its original position on my desk. It turns out that there are only two working rubber feet on the bottom of the keyboard. This sliding problem was quickly mitigated by super glueing two thick rubber washers in place of the plastic bumps.

Addition of a rubber stopper to prevent the keyboard from sliding.

The rubber washers created the perfect height and angle for my typing preference. Even though there are two levels of feet adjustment under the keyboard, I find that both levels are still too high without use of a wrist rest.

Side view of the HHKB.

The Topre switches found in the HHKB are rated for 45g of actuation force. Apparently this is known to be the “sweet spot” in terms of tactility. The tactile feedback that this keyboard produces is from the rubber domes bottoming out when a key a pressed. Before moving forward, this isn’t your ordinary rubber dome you find in a stock HP keyboard, these switches have their very own patent.

The topre switch that resides under the key cap.

TL;DR

This is my very first 60% keyboard with Topre switches. It has been an enjoyable experience so far with minor modifications made to it and I plan to lube the Topre switches in the near future. For more info on the HHKB, it can be found here.

Projects come in all shapes and sizes, but there exists a project that fits the bill in every way. An application that is robust and secure throughout its development life cycle. Just because.

Who needs an overly-engineered application when you are provided a system that:

  1. Delivers on time
  2. Is always up-to-date
  3. Requires no maintenance
  4. Doesn’t require a core team ever again

Perfection. /s

Link to GitHub Project

A safe way to clean the boot partition.

Suppose that one day you are routinely performing a maintenance update or wanting to install a new package and suddenly be greeted by the following:

username@ubuntu:~# sudo apt install yourpackage 
Reading package lists... Done
Building dependency tree       
Reading state information... Done
You might want to run 'apt-get -f install' to correct these:
The following packages have unmet dependencies:
 yourpackage : Depends: libyourpackage1 (>= 1.x.x) but it is not going to be installed
 linux-image-virtual : Depends: linux-image-4.x.0-xxx-generic but it is not going to be installed
E: Unmet dependencies. Try 'apt-get -f install' with no packages (or specify a solution).

Problem: /boot/ is 100% full and/or apt is not working

Check the current version of your kernel

$ uname -r

It will show something similar to the following:

4.4.0-130-generic


List the old kernels

$ dpkg --list 'linux-image*' | awk '{ if ($1=="ii") print $2}' | grep -v `uname -r`

It will show something similar to the following:

linux-image-4.4.0-116-generic
linux-image-4.4.0-121-generic
linux-image-4.4.0-124-generic
linux-image-4.4.0-127-generic
linux-image-4.4.0-128-generic
linux-image-4.4.0-133-generic
linux-image-4.4.0-148-generic
linux-image-virtual

Get ready to craft a remove command to delete the old kernels.
Please be sure to keep the current and the last two versions of the kernel.

$ sudo rm -rf /boot/*-4.4.0-{116,121,124,127,128}-*

Time to cleanup apt, remove orphaned kernel images, and update grub

$ sudo apt-get -f install ; sudo apt-get autoremove ; sudo update-grub

Finally, you can now update and install packages again!

$ sudo apt-get update

*Usage of any "The Division" name, logos and/or images are registered trademarks of Ubisoft.

This is a fun little project built for my group of friends and I to pull up each other’s player stats on Discord. All it does is collect data from a target website and parses the values in standard output, in this case channel messages.

The bot has been written in Python and many of the guides found on the internet were quickly out-of-date with the current discord library.

Here are some changes that I came across while building the service.

Updating the Bot’s Presence in the Discord Channel

Old:

...
client = discord.Client()

@client.event
async def on_ready():
    await client.change_presence(game=discord.Game(name="This is a bot."))
...

New:

...
client = discord.Client()

@client.event
async def on_ready():
    activity = discord.Game(name="This is a bot.")
    await client.change_presence(status=discord.Status.online, activity=activity)
...


Updating the Bot’s Channel Messages

Old:

...
@client.event
async def on_message(message):
    if message.content == "Hello":
        await client.send_message(message.channel, "World")
...

New:

...
@client.event
async def on_message(message):
    if message.content == "Hello":
        await message.channel.send("World")
...

In the end, the bot runs reliability on most low-end hardware since the only thing it does intensively is parse contents from a webpage.

Note: It is assumed that you have OAuth2 already setup on Discord’s developer portal.

Download Project (.zip)