Recent Gout Attack

On the Wednesday morning of April the 14th, right after I took out the garbage, I noticed that I experienced some tightness when I was bending my left knee going up the stairs. As time goes by the knee begins to swell. By lunch time, it was swollen to the point that I can no longer bend my knee and I can feel a continuous throbbing pain around my left knee. I can also feel that the temperature around my knee has also been elevated. When I took some measurements with a touchless temperature sensor for measuring fevers, my left knee is like 2ºC more than my right knee. This is not my first gout attack, but it has been very long since my last one that I couldn’t even remember when I had it.

I decided to document my current experience, so that next time, I personally have something to recount. Therefore, this blog entry is more for myself than you the reader if you are reading this already.

I have had swollen joints due to gout in my ankle and my knee, always on my left side for some reasons. I wasn’t sure whether I should take Allopurinol or wait until the attack subsides. I seem to recall that in the past that I should not take any Allopurinol during an attack, but the recollection was pretty murky, and doctors are hard to come by these days, so I read the following article: Allopurinol Doesn’t Worsen Acute Gout Attacks, and decided to take Allopurinol in my medicine cabinet. Later on I found out from my family doctor and my local pharmacist that I may have been better off not taking it. What I can tell you is that it started to heal even with the taking of Allopurinol during the attack, so there is some truth to the above article.

I also decided to take Ibuprofen which is available over the counter to reduce the inflammation. The Ibuprofen worked within a couple of hours and really helped with the throbbing. In the end, there is not much to do but to wait and drink lots of water and let my system dissolve and eat away at the uric crystals in my knee.

I got some diclofenac sodium topical cream, which I applied on the affected area overnight. Unfortunately, I felt some skin irritation, and an over tightening or stretching of the skin situation. I had to wash it out in the morning and stuck to Ibuprofen. A single does of 400mg Ibuprofen didn’t do the trick. I had to double the dosage to 800mg.

My hope of the swelling going away in a few days was dashed on the first weekend when I knew that it was getting worse and not better. It was not until the second weekend (approx. 10 days into the ordeal) when I can finally begin to bend my knee. At this point I stopped taking the Ibuprofen and let it naturally take its course.

By the third week, I can bend my knee for most daily activities but going down the stairs and simple things like putting on my pants still created a sharp pain sensation.

This has been the longest gout attack that I have experienced. This time around, I noticed significant muscle atrophy in my left thigh and calf. I also noticed pull tendon or cramping sensations when going down the stairs. Fortunately these sensations went away as I started to do more walking in the latter part of the third week.

On day 22, I still have minor pain on my knee cap but I was able to walk so I did a 3.5 km walk with my wife in the evening of May 6th. Since there were no additional swelling the following day, I decided to do an indoor bike ride of 20km. Yesterday was another 3.5 km of walking and today another indoor ride.

As you can see from the Strava statistics, I am improving, so back in the saddle and back on the climb. Slowly but surely.

Checking for Vaccine Schedule Availability

It looks like York Region is beginning to ramp up our vaccine schedules. We are now awaiting our postal code to be eligible so that my wife and I can make an appointment. At the time of writing this post, unfortunately, our postal code is still not eligible.

We know some of our neighbours are checking the website, https://york.ca/covid19vaccine on a regular basis. Obviously, this is very tedious and frustrating. I decided to embark on a small project to detect our postal code from the web site. My goal is to write a script that can be executed from my NAS server every 30 minutes to see if it can find our postal code on the website. My first attempt was to use Python and Selenium. The API was a bit clunky and I found it to be somewhat unreliable and fraught with timing issues. I gave up on this approach.

I thought I give it another shot, but this time using Puppeteer. This was much more simpler to use, and I found it to be more friendly especially if you’ve worked with Browser based Javascript to begin with.

I wrote this simple node script called scrape.js:

#!/usr/bin/env node

const puppeteer = require('puppeteer');

const targetPostalCode = process.argv[2] || 'A2B';

console.log ('scraping for ' + targetPostalCode + '...\n');

(async () => {
  const browser = await puppeteer.launch();
  const page = await browser.newPage();
  await page.goto('http://york.ca/covid19vaccine');

  const anchorSelector = 'div#Y_accor div.new h3.Y_accordion span.trigger a';
  await page.waitForSelector(anchorSelector);

  console.log ('received...\n');

  const result = await page.evaluate((anchorSelector) => {
    let res = [];
    document.querySelectorAll(anchorSelector).forEach(function(elem){
      if (elem.textContent.match(/.*50 Years of Age and Older.*/i) != null) {
        elem.parentElement.parentElement.parentElement.querySelectorAll("p").forEach(function(elem){
          if (elem.textContent.match(/.*postal codes.*/i) != null) { 
            const postalCodes = elem.parentElement.querySelector("strong").textContent;
            postalCodes.split(", ").forEach(function(pc) {
              res.push(pc.trim());
            });
          }
        });
      }
    });
    return res;
  }, anchorSelector);

  console.log(result);

  let found = false;
  let regex = new RegExp(targetPostalCode, "i");
  result.forEach(function(postalCode) {
    if (postalCode.match(regex) != null) {
        // Postal Code Found!
        console.log("We found: " + targetPostalCode);
        found = true;
    }
  });

  console.log('closing...');

  await browser.close();
})();

I placed this script in the directory /home/xxxxx/gitwork/covidMonitor. Note that I targeted “50 years of Age and Older“, because this is the age group that I am personally interested in. The A2B is also not my real postal code. It is used instead of my own private postal code.

Before I run the program, I had to install puppeteer in my working directory.

cd /home/xxxxx/gitwork/covidMonitor
sudo npm i puppeteer

Running the above scrape.js produces the following:

scraping for A2B...

received...

[ 'L0J',
  'L4B',
  'L4E',
  'L4H',
  'L4J',
  'L4K',
  'L4L',
  'L6A',
  'L3S',
  'L3T',
  'L6B',
  'L6C',
  'L6E' ]
closing. 

Of course A2B is not in the list. If it was, another line like:

We found: A2B

will be in the output.

I supplemented the above with a shell script program which I can later use to configure cron to be executed every 30 minutes. The shell script’s job is to monitor the website using scrape.js and if the postal code is found, then send a notification email.

#!/usr/bin/env zsh

cd /home/xxxxx/gitwork/covidMonitor

if [ $(./scrape.js | tee /home/xxxxx/log/covidPostalCodes.log | grep "found" | wc -l) -ge 1 ]
then

sendmail xxxxx@gmail.com <<@
Subject: Covid Vaccine Can Be Scheduled

Goto the following site to schedule your vaccine:

https://york.ca/covid19vaccine

@

fi

I could have included the email notification logic in the node script as well, but I figure I may want to check manually on an infrequent basis, in which case I simply run the scrape.js script on the command line.

Now all there is to be done is relax and wait, a thing that we have been doing a lot lately during the pandemic.

Chinese Mauritian Roots

I recently received a YouTube video from one of my uncles on the topic of the migration of Hakka (客家) Chinese from Mexian, China to Mauritius.

My maternal heritage is from Mauritius and I have made previous postings in this regard. You can simply do a quick search in this blog on the term, Mauritius, and you’ll see other related postings.

For keep sake, I’ve gathered the videos here for easy reference to share this knowledge with other relatives. It is also pretty amazing what you will find when searching for “Chinese in Mauritius” on YouTube.

Below are four videos which I personally found interesting. The first three videos are from Jeanette Lan’s YouTube Channel, kudos to her for sharing these videos. They are listed in chronological order of production.

Commemoration of the 178th anniversary of the Arrival of Indentured Immigrants to Mauritius (November 2nd, 2012)

A Journey to Our Roots

The Cradle of Hakka Culture

Hakka History, Cooking, and Rhymes with the Toronto Hakka Heritage Alliance

Darci Door Bell

We have a cat named Darci. During the summer time she likes to take strolls through our backyard, checking out other frequent visitors like rabbits, chipmunks, squirrels, birds, and the like. She does this on an extended leash so to avoid her chasing these visitors and get lost into the wild. If you are curious, then visit her on Instagram.

We of course turn on the air conditioner on most days of the summer, so when Darci wants to come back into the house, she sits by the backyard sliding door and await one of us to open the door for her. If we are busy, she waits patiently for quite some time. My wife came up with the door bell idea. Instead of scratching the glass pane of the sliding door, which is mostly silent, we will train her to hit a door bell, which will alert us to let her in.

This is how I was assigned the Darci Door Bell project. This is another excellent opportunity to create a gadget. My first thought is to create a Raspberry Pi with a camera that uses an AI image classifier on the backend. I thought this would be a good opportunity to get my feet wet in AI. However, when dealing with a camera, and a Raspberry Pi, we are now talking about power and the need to be “plugged in”. We wanted a gadget that is wireless and battery operated. A battery based solution will severely restrict the power budget, so back to a WiFi based remote door bell idea.

After more research, I decided to use an ESP8266 MCU with WiFi and a simple step-down buck converter to convert 9V to 3.3V. I had worked with the ESP8266 before when I was attempting to use it to create my garage door opener. That was over six years ago. ESP8266 just came out and has yet to be integrated into the Arduino platform. Today, it is now much easier to work with the ESP8266. Using the Arduino IDE, one can simply program the ESP8266 natively as an MCU without even requiring an Arduino board.

From a previous project, I built a small circuit using an USB FTDI interface that will accept the ESP8266 ESP-01 board. This way I can plug the ESP8266 using USB to my computer and program it with the Arduino IDE. I wrote the following sketch, and programmed the ESP8266 ESP-01 board.

 #include <ESP8266WiFi.h>
 #include <ESP8266HTTPClient.h>

 #define SERVER_IP "192.168.1.111"
 
 #ifndef STASSID
 #define STASSID "myssid"
 #define STAPSK  "adsjfkdajfioeujfngjhf"
 #endif
 
 void setup() {
 
   WiFi.begin(STASSID, STAPSK);
 
   while (WiFi.status() != WL_CONNECTED) {
     delay(250);
   }
 
   WiFiClient client;
   HTTPClient http;

   // configure traged server and url
   http.begin(client, "http://" SERVER_IP "/IOTHandler.php"); //HTTP
   http.addHeader("Content-Type", "application/x-www-form-urlencoded");
 
   // start connection and send HTTP header and body
   http.POST("id=darciButton");
 
   http.end();
 
   ESP.deepSleep(0);
 }
 
 void loop() {
   ESP.deepSleep(0);
 }
 

The above program is pretty simple. When the board wakes up, it connects to my WiFi and then send an HTTP-POST request to my server that will handle the request based on the id, which in this case, it will be darciButton. As soon as the request is sent, the MCU will go into a deep sleep.

Completed Circuit

This way, the door bell will be a physical button that is hooked to the RST pin of the ESP8266 causing the ESP8266 to boot and send this POST request and immediately goes to sleep. The deep sleep is important, because while the device is in this deep sleep mode, the current draw from the 9V battery is negligible (<< 1mA). The only time the battery is used is when the button is pressed and released, and the ESP8266 is sending out the POST request. Using this power conservation approach, it is my hope that the 9V battery will last for the entire year of operation.

I used my 3D printer to print a little box for the whole thing and gave it some packaging padding, making sure the switch is on the top and properly supported. The final result looks something like this.

Packaged in a box

We then created a cardboard top cover that snugly fit the box, so that the top cover can freely move up and down the containing, plastic box. The switch itself has a little spring to it that allows the top cover to return back to its original position after being pressed. The finished product looks like this:

Finished Product

The top cover has a nickel on there so that Darci has a good target to train on.

Remember the server receiving the POST request? Well, I did some simple php programming on the server so that once the POST is received, I send out another HTTP request. This time to the Homebridge server with the homebridge-button-platform plugin installed. Homebridge is something that I already have and use to connect all non-compliant HomeKit accessories so that I can use those accessories via Siri. With this new plugin, I can connect this custom WiFi button to the HomeKit ecosystem within the house.

In effect, whenever this button is pressed, my HomeKit service will register an accessory button being pressed, and I can program a HomeKit scene that gets executed. I programmed a scene to play an audio file on all of my HomePods in the house. The audio file plays an audible door bell twice which I previously added to my Music library.

The final reward as shown by Darci herself. Watch the video below:

Darci Approves!

Of course with the button hooked up to HomeKit, we can now use this wireless button to do whatever HomeKit can do, unlock doors, turn lights on or off, etc. We will explore those possibilities in the future.

Going to Traffic Court During the Pandemic

I was ticketed during 2019 for a minor offence in my neighbourhood. I requested a court hearing at the time and had an original court date set in the spring of 2020. Of course this coincided with the beginning of the Covid-19 pandemic, when almost all provincial services have decided to shutdown to adhere to the pandemic closure.

Throughout the remaining months of 2020 there were many emails and phone calls with the court services for me to find out the rescheduled date. After more than three follow up calls and many emails I finally received a “virtual” court date for March 17, 2021, earlier this month.

Let me detail my experience of my traffic offence virtual hearing. Hopefully you will find this useful in case you have to go through a similar event.

The meeting was conducted with Zoom. I have used Zoom before so I was pretty comfortable with the format and functionality. I joined the meeting 15 minutes prior to my scheduled court appearance. After waiting for a couple of minutes a prosecutor appeared and pre-registered me and briefed me to what will happen. The most important information is to mute your mic when you are not talking, and unmute when you are talking. I also had to remind myself to address the “Justice of the Peace” as your Worship.

I learned something new with Zoom during the session. Zoom has the ability to create rooms and the prosecutor can move individuals from one room to another. When I first joined Zoom, I was automatically sent to a virtual waiting room. Once the court room is made available, I was then transferred to the virtual court room. I thought this was a pretty good coordination and worked very well.

Once in the court room, the experience is pretty standard. You get to hear in great detail all of the other hearings that were scheduled with the same court room. There were more than 10 other individuals that were scheduled within the same time slot. I had to wait for about 40 minutes before I was called up by the prosecutor. Her Worship was very friendly and accommodating and my session did not take more than 10 minutes to conclude our business.

We reached a mutually agreeable arrangement, and I proceeded to pay my offence on paytickets.ca the next day. Overall it was good to get this monkey off my back without having to visit a physical court during the pandemic. The experience was more streamlined than I thought, so kudos to the Ontario Court Services.

Windows 10 on Ubuntu 20.04 with VirtualBox

It is tax season again in Canada. In the past I had a VirtualBox virtual machine that I would only bring up for the purpose of running the Windows version of TurboTax because the member of our family who files the taxes dislike the too simplified online version.

Unfortunately VirtualBox refuses to come up on macOS BigSur due to new security considerations enforced by macOS. The new System Integrity Protection (SIP) disallows the kernel extension required for VirtualBox. Instead of going around SIP via the crsutil disable command, I decided to move all of my virtual machines that is currently sitting on my Mac to my Ubuntu NAS, since the Ubuntu box is up 24 x 7 and should be more convenient.

Below is what I had to do on my Ubuntu 20.04.2 LTS server.

Add the apt source where we can get VirtualBox.

sudo wget -q https://www.virtualbox.org/download/oracle_vbox_2016.asc -O- | sudo apt-key add -

echo "deb [arch=amd64] https://download.virtualbox.org/virtualbox/debian focal contrib" | sudo tee /etc/apt/sources.list.d/virtualbox.list

sudo apt update

Install Virtual Box and our user to the vboxusers group.

sudo apt install --yes virtualbox-6.1
sudo systemctl status vboxdrv

sudo usermod -aG vboxusers $USER

We then need to install the extension that enables RDP. The virtual machine is going to be hosted on a server without a graphics user interface, so we have to use a Remote Desktop Client (from Microsoft) on another machine (e.g. my Mac) to gain access.

VBOXVER=`vboxmanage -v | cut -dr -f1`
wget -P /tmp \
https://download.virtualbox.org/virtualbox/$VBOXVER/Oracle_VM_VirtualBox_Extension_Pack-$VBOXVER.vbox-extpack

vboxmanage extpack install /tmp/Oracle_VM_VirtualBox_Extension_Pack-$VBOXVER.vbox-extpack

I tried to import my existing Windows VM without much success, so I decided to create a new one from scratch and reinstalled Windows 10 Pro.

vboxmanage createvm --ostype Windows10_64 --basefolder "/home/kang/VirtualBox" --register --name "win10"

vboxmanage modifyvm "win10" --memory 4096 --nic1 bridged --bridgeadapter1 em1 --vrde on --vrdeport 3389

vboxmanage createhd --filename "/home/kang/VirtualBox/win10/win10.vdi" --format VDI --size 100000

vboxmanage storagectl "win10" --name "SATA" --add sata

vboxmanage storageattach "win10" --storagectl SATA --port 0 --type hdd --medium "/home/kang/VirtualBox/win10/win10.vdi"

vboxmanage storageattach "win10" --storagectl SATA --port 15 --type dvddrive --medium /home/kang/VirtualBox/en_windows_10_consumer_editions_version_2004_updated_feb_2021_x64_dvd_f42b7d6d.iso

vboxmanage storageattach "win10" --storagectl SATA --port 14 --type dvddrive --medium /home/kang/VirtualBox/VBoxGuestAdditions_6.1.18.iso

Note that I had to pre-download the Windows 10 ISO and VBoxGuestAdditions ISO files. The guest additions iso file was available from this site.

https://download.virtualbox.org/virtualbox/6.1.18/

For some reason my motherboard did not have the cpu virtualization mode enabled, so I had to do that with my BIOS settings. It was cryptically called AMD SVM (secure virtual machine).

I started the virtual machine with:

vboxmanage startvm win10 --type headless

However, I had issues with remote desktop. I had to set some permissions with the VirtualBox extensions. The following commands were executed to create a user and its password for Remote Desktop access.

vboxmanage shutdown win10 

vboxmanage setproperty vrdeauthlibrary VBoxAuthSimple

vboxmanage modifyvm "win10" --vrdeauthtype external

vboxmanage internalcommands passwordhash YOUR_PASSWORD
Password hash: 1ffc0406b9891fcd265a225e83a668fa045f1282588f80c8d11c029bad156d85

vboxmanage setextradata "win10" "VBoxAuthSimple/users/tax" 1ffc0406b9891fcd265a225e83a668fa045f1282588f80c8d11c029bad156d85

Now, I can access the VM through Remote Desktop from my Mac. I continue through the process of installing Windows 10, and the VirtualBox guest additions.

The rest is pretty simple. Install Chrome, Buy TurboTax for 2020 tax year, and we are all set!

One final note, I shared a macOS folder to the VM using normal SMB protocol, so that once my taxes are completed, this VM is a throw away, until next year!

The Day After: Installed a security update in regards to virtualbox-dkvm and VirtualBox now refuses to boot from any bootable iso. I gave up and used Parallels on my MacBook Pro. I may try kvm later.

Covid-19 Vaccine Appointment

Today marks the opening day at York Region where appointments will be taken for covid-19 vaccine appointments for people who are 80+ years of age. We were instructed to visit the following link (york.ca/covid19vaccine).

Since both of my parents are within this age group, I proceeded to the site this morning at 8am sharp to book their appointments. No surprise, the site was not available and I saw this:

At around 8:10am, the site was finally active. It was not immediately apparent to me how to book the vaccine, but after more reading, menu hunting, and a few clicks later I finally figured out. I had to choose the location first and then proceed to book an “activity” at that location.

At first, I was delighted to find out that there were hundreds of spots available at Richmond Green, a community facility just 10 minutes walk from our place. Unfortunately, when I proceeded with the booking, I had to create an account first. By the time I created the account, all the spots at Richmond Green were gone, and I had to book elsewhere. At around 9am, all spots from all locations were gone.

My advice is that if you don’t have a york.ca account now, go and create one before you make a booking.

Below is a video that may be useful to others showing how I navigated their web site to get to the booking. Good luck with your bookings!

The Objective Fascade

Objective, impartial, these are words that media outlets use to convince the readers or viewers that they are providing you with the facts. However, do not forget that the ones who is doing the reporting, in the West and East, performs a selection and interpretation on what they report. This may be intentional but is also natural. The selection of stories and their context is very difficult to get right even if they wanted to.

The only way to attain more objectivity is to broaden your own consumption of news media from multiple sources and with multiple perspectives, just like in the court of law. Placing any central trust in a single media outlet is misguided, in my opinion. Unfortunately this will require those of us consuming news to be critical, which I don’t believe as a population we are ready for.

One key area of critical thinking is your own personal knowledge base. This is of course your own experience but also your education. Just like many courts depend on precedence (history), as individuals we also need to continuously update ourselves so that we can be better judges ourselves. If we surrender this right of making our judgement then we become followers and at the mercy of other judges, like media outlets.

Weaponizing Social Media & Revolving Governments

If you asked me 10 years ago, I would be a strong proponent of democracy and how the Internet and social media will harmonize and amplify our inherent goodness of the majority and make the world a better place. Of course, I can see this is now totally incorrect. I now see modern mass media technology is being weaponized to promote ideas that benefits those who want to seek or stay in power. Perhaps I would further suggest that any communication advancements will ultimately be utilized in such fashion. Think about how consumer marketing has evolved with communication tech.

When you couple the power of what I described above with the modern liberal democracy ideals of, “everyone should have a voice”, you have a perfect storm fostering opposing, divisive, and influential views, which creates ever growing friction in the efficiency of governing within a democratic process. Decisions at the grass roots levels tend to be more emotional and less pragmatic. The current pandemic reaction from the liberal West can be viewed as a barometer of this effect. Also the leadership is representative of a mass emotional breakdown.

Recently I have become blasé to the instruments of government. Instead of focusing on how a government should work, we should treat it like a product which we the people all consume. Is it a good product and are we happy with it?

People are advocating or dear I say “preaching” one form of government as better than another instead of looking at the actual results of governing and people’s livelihoods. If you look at it from a high enough level, I come to the realization that modern advocacy of liberal democracy has become a religious crusade, one that seeks the conversion of all non-believers.

I am now toying with the realization that governments like all products will evolve or revolve on the changing needs of the consumer. I am not saying a simple change in leadership of a static system, but a massive reformulation of the government itself.

Perhaps we as a race have already figured it out, and the solution is already naturally practiced. Instead of our myopic planning horizons of every four years, or a life span, perhaps the fabric of governance is working through generations.

In essence every government is a crude form of true democracy. Everyone has the ability to vote, of sorts. When life gets too tough to tolerate and you blame the government and leadership for it, you vote by rebelling. This mechanism is of course called a revolution. Instead of an election that temporarily appeases the mass population, the mass population revolts and overturns the government and reinvents it. Social content settles to a new way of governing and the population is content until the next revolution. There is a natural social contract between leaders and those being governed. The votes will truly matter because they are being offered by sweat and blood, and not some, “going through the motion of an election turn out”.

So if you look at it from this granularity, it is somewhat immaterial to continue to debate on which type of government is a better or best government. The people will ultimately decides which government is best for them over the course of time.

In between revolutions, and we don’t feel like “voting / rebelling”, the best we can do is to play the current game that was established in the previous revolution.

Having said all of this, I do think a hierarchical structure of leadership properly established through merit vs a representation of a popular vote is probably more stable and beneficial. A party is in the depth of hypocrisy when it preaches for democracy that is infrequently practiced at intervals of spanning from 2 to 6 years, while we all goto work under a hierarchical structure with clear master/slave relationships for the majority of our working hours of our day.

Notes: I wrote the above in response to a Quora post here.

Trying out Apple Fitness+

I’ve switched to indoor cycling since mid-November when it got too cold and windy to perform an outdoor ride.

My indoor routine is to typically hop on my road bike which is affixed to a trainer (Kinetic Road Machine), and watched an Electronic Dance Music (EDM) filled with either English or Chinese dance mixes.

For each workout, I do my own HIIT sessions that usually last for about an hour or so. A typical session looks something like this recording on Strava. I try different things on different rides. Sometimes I do 1:1 intervals, sometimes I do 1:4 intervals on rest days, and other rides I do pyramid build ups, etc. I try to do an hour and at least for 45 min. The intervals can be between 30 seconds to 5 min depending on how I feel.

Yesterday Apple released their Fitness+ service. Since I’m part of their Apple One subscription, we get the service along with the subscription, so I figure I give it a go.

Today, I did two workouts, one 45 min with Emily and another by the same trainer for another 20 min. I think these workouts are nice for those who wants to get moving, but I personally found it hard to my liking.

The trainer is motivating, and upbeat. The workout is of a lower cadence than I am use to. The only lead in that you get is from the trainer, so there is no visual cue to help you with the next set of effort, or prep you how much rest you are going to get before the next hard effort. I also missed the power and cadence reading on the screen. For those measurements, I have to look down to my Garmin unit.

In short, at least for cycling, these programs are not going to replace Zwift and TrainerRoad. They are good for those who want to replace their typical gym classes. I may give other forms of exercises a shot later on.

Overall I think many will like the service. The integration with Apple Watch is pretty seamless and super friendly. However for cycling, I’ll probably continue with my EDM videos.