Map CAPS Lock to Control Key in Windows

Windows version: 10

If you use the control keys a lot for keyboard shortcuts, it makes sense to have the control key where the caps lock key is. Why? Because while the fingers are resting in the home position (ASDF row), you have the pinky finger under the “A” key and right beside it will be the “Control” key. It’s easy on the pinky and ergonomic.

The early keyboards used to have the Control Key beside A:

Here are three ways I recommend (I prefer the registry edit):

Both Power Toys and Ctrl2Cap are fine in my opinion as both are officially listed on the Microsoft sites.

However I like the registry edit solution better as there is no software to install and it’s just a single line of edit. I used to be scared editing the Registry Editor but the procedure below is tested and safe. Just carefully type in the values (you won’t be able to copy/paste them).

1. Open the Registry Editor, you can hit the “Windows” key and start typing regedit and it will show you suggestions for opening the Registry Editor:

2. Navigate to the entry:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout

3. Right-click “Keyboard Layout” and add a new “Binary Value” with name: Scancode Map

4. Type in the following values:

00 00 00 00 00 00 00 00 02 00 00 00 1d 00 3a 00 00 00 00 00

You can’t copy / paste them, so type them in carefully 😊

5. Click OK, close the Registry Editor and restart your computer. Your CAPS Lock key should now be mapped to the Controls Key.

Windows Firewall Rule for Go Web Development

If you do Go web development on Windows, then you are likely to come across the Windows Firewall – Security Alert whenever you build and run the Go app. For example, here I am trying to build and run a sample Go web server program “main1.exe” that wants to run on port 4000:

Windows Defender Firewall – Security Alert

This can be annoying when you create a lot of throw-away small apps for learning; you end up with hundreds of these “allow” rules in the Firewalls ruleset. Here’s a small glimpse of all the rules that got created running an experimental web program “multiple_handlers.exe”:

I am not sure if hundreds or even thousands of these junk rules slow up the system. To me they are junk for sure as I am not likely to run these again after the learning and testing is done. So my solution is to create a single inbound rule for port 4000 and always try to stick to the same port when developing web programs in Go. Here is how to do it in Windows:

1. Press the Windows key (start button) on your keyboard and start typing “firewall”, click the Windows Defender Firewall link as shown below:

2. Next click on “Advanced settings”

3. Then right-click on “Inbound Rules”, which will bring up a pop-up menu, then click “New Rule…”

4. Select “Port” then click Next

5. Type the port you want to allow. I choose 4000 for local development, so that’s what I specify and click Next.

6. Select “Allow the connection” and click Next

7. I work from home, so I choose “Private” only and click Next

8. Give the rule a friendly name, I gave it “4000 for local development” and click Finish

9. The rule should now be created and can be seen as below.

Now I can happily run my Go web programs on port 4000 and never receive a Windows firewall security alert ever again 😀

How to Run Simply Scheme on Windows

Goal: To be able to run Scheme on Windows, particularly the flavor “Simply Scheme”.

There is a great computer science book called Simply Scheme by Brian Harvey and Matthew Wright. Professor Brian Harvey also taught a great class CS61A at the University of California, Berkeley. Our goal is to be able to run Simply Scheme so that we can follow along the book and its exercises.

Illustrated by Polly Jordan, from page 4 of the book Simply Scheme

Simply Scheme uses custom Scheme commands to teach some important programming concepts. These commands are not available on regular Scheme but their value cannot be undermined in helping to learn more easily concepts taught in the book like recursion, higher order functions, composition, abstraction and more.

The best and easiest way to run scheme on Windows is via DrRacket from the Racket language site. Racket download provides a nice integrated learning environment DrRacket and it can be extended to run Simply Scheme via a package “Danny Yoo’s Simply Scheme”.

1. Download and install DrRacket from here

2. Start Racket, then click on File -> Package Manager

3. Click the tab “Available from Catalog”, then type “simply” in the filter. You should see “simply-scheme” listed. Select “simply-scheme” and click the Install button.

4. After installation, close the dialog box and restart the DrRacket

5. Choose Language -> New Language from the menu bar. Then select Simply Scheme as shown below.

6. You should be able to run Simply Scheme programs now. Here is an example program that implements “Pig Latin”.

7. Bonus: If you like Emacs Key bindings then enable it in Edit -> Preferences -> Editing. Make sure the option is “unchecked” for Enable keybindings in menus.

Enjoy Simply Scheme!

I remind myself: It can be easy to learn new languages and syntax. Then tedious to keep up to date with endless frameworks. But great programming concepts are timeless, so it’s a good idea to learn them well.

Install and Configure Apache and PHP on Windows

This post explains how to install and configure Apache and PHP on Windows. Sure, there are convenient options like: Bitnami WAMP Stack, WampServer or XAMPP. But over the years I found that installing each stack separately is more reliable and provides greater flexibility. You will probably also want MariaDB for a database which you can download and install from here: The database itself doesn’t have to be configured directly with either Apache or PHP so there are no steps provided here for the database. You only need to enable a line in PHP ini for PHP to provide the database functions.


  • Windows 10, 64-bit
  • PHP 7.4.x
  • Apache 2.4.x


Download PHP from the Windows download page. We will use PHP as an Apache module, so make sure to get the Thread Safe version.

After downloading the zip file, unzip it to a convenient location on your hard drive. I usually keep all my stand-alone programs that I use under ~/bin folder. So the location of my unzipped PHP folder is: C:\Users\sanji\bin\php-7.4.27-Win32-vc15-x64

Copy the file php.ini-development and rename it to php.ini, then edit it:

# The default input vars, upload and post sizes are small 
# so I make sure they are big enough
max_input_vars = 5000
post_max_size = 100M
upload_max_filesize = 100M
max_file_uploads = 50
# Only for local development machine, I set the max execution time at 120 seconds
# instead of the default 30 seconds, because some PHP application updates fail 
# locally without a high enough timeout threshold
max_execution_time = 120

# I usually set the full-path because sometimes just specify "ext" doesn't work
extension_dir = "C:\Users\sanji\bin\php-7.4.27-Win32-vc15-x64\ext"

# I have the following extensions enabled which 
# is also good for WordPress development
extension=exif      ; Must be after mbstring as it depends on it

I also added the location “C:\Users\sanji\bin\php-7.4.27-Win32-vc15-x64” to the Path in my Windows Environment Variables under System Properties.

Nothing more needs to be configured for PHP. Let’s get Apache installed and configured.


Apache binaries are not provided by the official Apache HTTPD project. You can can get either from ApacheHaus or Apache Lounge. Here is the download page screenshot of the binary for Apache 2.4.52 x64 on ApacheHaus:

After downloading the zip file, unzip it at a convenient location on your drive. The full path on my machine is: C:\Users\sanji\bin\Apache24. For convenience, I also added to the environment Path variable “C:\Users\sanji\bin\Apache24\bin” via Windows System Properties.

The file “Apache24\conf\httpd.conf” needs to be edited.

# Change the following to the location where you 
# unzipped the downloaded Apache zip file
Define SRVROOT "/Users/sanji/bin/Apache24"

# I use port 8080 instead of the default port 80
Listen 8080

# I use virtual hosts, so following needs to be enabled 
# and the httpd-vhosts.conf file included
LoadModule vhost_alias_module modules/
Include conf/extra/httpd-vhosts.conf

# The following modules are also enabled
LoadModule rewrite_module modules/

# The following settings enable PHP
LoadModule php7_module "/Users/sanji/bin/php-7.4.27-Win32-vc15-x64/php7apache2_4.dll"
<FilesMatch \.php$>
    SetHandler application/x-httpd-php
PHPIniDir "/Users/sanji/bin/php-7.4.27-Win32-vc15-x64"

# I also had to add the following line to get curl working with PHP 
# (aside from enabling curl in php.ini)
LoadFile "/Users/sanji/bin/php-7.4.27-Win32-vc15-x64/libssh2.dll"

ApacheHaus uses “extra/httpd-ahssl.conf” for SSL configuration. I use the port 4430. Here is my “Apache24\conf\extra\httpd-ahssl.conf” change:

# I changed the default port 443 to 4430
Listen 4430 https

Finally here is my vhosts configuration file (located in Apache24\conf\extra\httpd-vhosts.conf).

# I serve all my sites from the folder "C:\Users\sanji\pdn"
# So the following entry affects all my development sites
<Directory "/Users/sanji/pdn">
    Options Indexes FollowSymLinks
    AllowOverride All
    Require all granted
    DirectoryIndex index.html index.php

# I use port 4430 for SSL
# Here are settings for a site called viaye.san, you can create your own by 
# editing the C:\Windows\System32\drivers\etc\hosts file
# To generate and self-sign SSL certificates, please see 
# I like to keep my docroot under "www" and the 
# access and error logs under the "logs" folder
<VirtualHost *:4430>
    SSLEngine on
    ServerName viaye.san
    DocumentRoot "/Users/sanji/pdn/viaye/www"
    ErrorLog "/Users/sanji/pdn/viaye/logs/error.log"
    CustomLog "/Users/sanji/pdn/viaye/logs/access.log" common
    SSLCertificateFile "/Users/sanji/_pepper/_ssl_local/viaye.san/cert.pem"
    SSLCertificateKeyFile "/Users/sanji/_pepper/_ssl_local/viaye.san/server.key"

That’s it for configuration. The final step is to add httpd as a Windows service. Head over to C:\Users\sanji\bin\Apache24\bin and run:

httpd -k install

You can now start, restart the Apache HTTPD server from the Windows Services panel as seen below:

The following video shows how to install Apache, PHP and MariaDB on Windows using the steps above.

Create a Self-signed Certificate on Windows for Local Development

We need to a create self-signed certificate for local development so that the local development server behaves similar to a live production server. Additionally the certificate must not generate warnings in the browser (Chromium based browsers only) that the certificate is self-signed and can’t be trusted.

Developing locally with plain http is just fine. But sometimes we need to mimic development with production so that TLS encryption via https is available also on our development machines. We also don’t want to see ugly security warnings from browsers. The following article shows how to create self-signed certificates on Windows that doesn’t generate browser warnings on Chrome and other Chromium based browsers.

The article is a bit long but please grab a coffee and follow along. The result is worth the effort as you only need to generate the certificate once in a very long time. I set the expiry date 10 years in the future for the domains I create for local development.

Goal: Create an imaginary domain pdb.oak.san with a self-signed certificate that works on major browsers (except Firefox) without generating a warning. Works great on Chromium based browsers like Chrome, Canary, Microsoft Edge and Opera, IE.

Step 1: Setup hostname

  • Open Notepad in Administrator mode: Click Windows Start icon in task bar and start typing Notepad, right click the Notepad icon and click Run as administrator
  • Inside Notepad, open the file: C:\Windows\System32\drivers\etc\hosts
  • We want to create an imaginary domain: pdb.oak.san, add the following line to the hosts file:    pdb.oak.san
  • Save the file and close

Step 2: Create a client-side self-signed certificate

  • Open PowerShell in Administrator mode: Click Windows Start icon in task bar and start typing PowerShell, right click the PowerShell icon and click Run as administrator
  • Type the following to generate a self-signed certificate for domain pdb.oak.san with friendly name pdb.oak.san that expires after 10 years:
New-SelfSignedCertificate -CertStoreLocation Cert:\LocalMachine\My -DnsName "pdb.oak.san" -FriendlyName "pdb.oak.san" -NotAfter (Get-Date).AddYears(10)
  • You should get the following output

Step 3: Copy the certificate created in Step 2 to Trusted Root Certification Authorities, then export it

  • Open Management Console for Certificates: Click Windows Start icon and start typing certificates, click Manage computer certificates
  • On the left panel, click Personal -> Certificates, you should see the client-side certificate for pdb.oak.san created above in Step 2
  • On the left panel, open the tree for (but don’t left click the folder) Certification Authorities -> Certificates
  • With the right mouse button, drag and drop the certificate to the location opened in the previous step
  • Now export the certificate: right-click the certificate, All Tasks -> Export…
  • Welcome screen appears, click Next
  • Select Yes, export the private key, click Next
  • Keep the default values for .PFX, click Next
  • Type a password for the private key, click Next
  • Browse for a location and give the certificate a name (cert.pfx), click Next
  • Finally click Finish
  • You will get a notice that the export was successful

Step 4: Create the server-side certificate and key

  • Pre-requisite: you need to have OpenSSL installed. Since you are a developer and on Windows, it’s highly likely you already have installed, so you should also have OpenSSL installed. Otherwise we recommend installing Git for Windows with Git Bash support – this will automatically also install OpenSSL.
  • Open Command Prompt and change directory to the location where you exported the certificate with .PFX extension cert.pfx in Step 3 above.
  • Type the following commands in the Command Prompt one by one. When prompted for password, type the password you used in Step 3 above when exporting the .PFX certificate.
$ openssl pkcs12 -in cert.pfx -nocerts -out key.pem -nodes
$ openssl pkcs12 -in cert.pfx -nokeys -out cert.pem
$ openssl rsa -in key.pem -out server.key
  • You should now have the following files in the folder, we will be using the cert.pem and server.key files. You can delete the other files if you want to.
cert.pem    --> KEEP
server.key  --> KEEP

Step 5: Test

  • You can use Apache or Nginx to test the https connection for the pdb.oak.san domain. We will create a simple Go server as it can be created really fast with a few lines of code. Create a file called main.go and type the code below. Make sure cert.pem and server.key is in the same folder as the main.go file.
package main

import (

func handleHome(w http.ResponseWriter, r *http.Request) {
    _, _ = fmt.Fprintln(w, "Home page to test the TLS cert and secure https connection")

func main() {
    http.HandleFunc("/", handleHome)
    _ = s.ListenAndServeTLS("cert.pem", "server.key")
  • Build and run the Go server: go build main.go, then run the resulting executable program main.exe
  • Now if we visit https://pdb.oak.san/ in a browser, we can see the home page with the following content: “Home page to test the TLS cert and secure https connection”
  • We can also check the certificate by clicking on the lock icon in the browser address bar:

For Nginx Users

To test on Nginx instead of writing Go code, you can use the configuration below.

  • Make sure to copy your cert.pem and server.key to the locations for ssl_certificate and ssl_certificate_key.
  • Folder paths like C:\Users\sanji\pdn\pdb.oak.san\www should of course match the locations in your own computer.
server {
    listen          443 ssl;

    server_name     pdb.oak.san;
    root            C:\Users\sanji\pdn\pdb.oak.san\www;
    access_log      C:\Users\sanji\pdn\pdb.oak.san\logs\access.log;
    error_log       C:\Users\sanji\pdn\pdb.oak.san\logs\error.log;
    index           index.html;

    ssl_certificate     C:\Users\sanji\pdn\pdb.oak.san\ssl\cert.pem;
    ssl_certificate_key C:\Users\sanji\pdn\pdb.oak.san\ssl\server.key;

The video below shows the steps I took to setup SSL on an imaginary domain on my local machine. The video is 20 minutes; maybe I could have been done the video in 10 minutes or less. But here I am showing the actual problems I am running into and the steps I am taking to solve them.

Setting up domains, servers and certificates in real-life is not without problems. This is not a scripted video. It shows the problems I face and how I resolve them.

This a scenario where you have created personal certificates and digitally signed them on your own and now you want them available and trusted on another machine.

Turn Off Windows Sound Notification Banner

Operating System: Windows 10

In an earlier article I posted how to How to Disable Windows Volume Popup, but that required a small 300 KB program to be installed.

In my opinion the real-offensive element is actually the browser notification banner that gets attached to the media control popup. This is what I mean:

Both Chrome and Firefox notification banner attaches to this volume popup. Disable it like this:


  1. In Chrome address bar, type chrome://flags/
  2. Then find the setting Hardware Media Key Handling and set it to Disabled.


  1. In Firefox address bar, type about:config
  2. Then set media.hardwaremediakeys.enabled to false

Enjoy just the volume control bar without the ugly offensive banner!

Add Gitignore in Visual Studio

Objective: You have multiple Visual Studio projects (using the same technology stack) under a single git repository and you need to manually add a .gitignore file.

Instead of copy/pasting an existing .gitignore file, let Visual Studio generate it for you.

2 Steps to Add the .gitignore File via Visual Studio

  1. Inside Visual Studio, open your solution and click the tab “Team Explorer”
  2. Then click “Add” under Ignore & Attributes Files -> Ignore File
Steps to add .ignore file in the Team Explorer tab
After successfully adding the .gitignore file

This will add the .gitignore file in your root git repository folder. So you should not need to repeat the projects for other Visual Studio projects in the same folder (provided they are all using the same technology stack).

Upgrade Phoenix Framework

The following shows a minor upgrade within version 1.5.x. If you need to upgrade 1.4.x to 1.5.x, please see:

To upgrade a Phoenix project, edit mix.exs, look for the line (was upgraded from 1.5.1 to 1.5.4):

{:phoenix, "~> 1.5.4"},

To upgrade the Phoenix installer itself, run in the terminal (example shows upgrading phx_new 1.5.3 to phx_new 1.5.4):

> mix local.phx
Resolving Hex dependencies...
Dependency resolution completed:
  phx_new 1.5.4
* Getting phx_new (Hex package)
All dependencies are up to date
Compiling 10 files (.ex)
warning: redefining module Mix.Tasks.Local.Phx (current version loaded from ~/.mix/archives/phx_new-1.5.3/phx_new-1.5.3/ebin/Elixir.Mix.Tasks.Local.Phx.beam)

Generated phx_new app
Generated archive "phx_new-1.5.4.ez" with MIX_ENV=prod
Found existing entry: ~/.mix/archives/phx_new-1.5.3
Are you sure you want to replace it with "phx_new-1.5.4.ez"? [Yn] y
* creating c:/Users/sanji/.mix/archives/phx_new-1.5.4

> mix --version
Phoenix v1.5.4

Finally, if you updated mix.exs file for any project, run:

> mix deps.clean --all
> mix deps.get
> mix

XAMPP Upgrade Tasks

I usually have 3 simple and separate tasks for a XAMPP upgrade or any general development environment migration (for example when moving to a new Windows or Mac hardware).

  1. Moving the source codes, files and assets: copy the www folder with all the project source codes local virtual host domains
  2. Apache configuration: edit the httpd.conf and httpd-vhosts.conf files
  3. MySQL migration: migrate the database

Source files

Usually I have a separate www folder configured with vhosts.

Apache Configuration

I only change the following line in httpd.conf because I like to develop on port 8080.

Listen 8080

And as a habit (Debian and FreeBSD) check if the vhosts file is included:

Include conf/extra/httpd-vhosts.conf

The httpd-vhosts.conf file has multiple entries (for each project or local domain name):

<VirtualHost *:8080>
    ServerName client1.san
    ServerAlias www.client1.san
    DocumentRoot C:/xampp/www/client1

MySQL Migration

A fresh copy of a pristine MySQL installation with PHPMyAdmin has the following databases:

  • information_schema
  • mysql
  • performance_schema
  • phpmyadmin
  • test

So when migrating I try to avoid copying over those five databases / schema.

Preview(opens in a new tab)

While it might be OK to dump the database via PHPMyAdmin, it’s not a good idea to restore it via a web interface. For example my combined database size is almost 1 GB.

So ensure you have a decent max_allowed_packet size in specified in my.ini:


Then run the database restore command manually from the command line. For example:

mysql -u root < databases_to_migrate.sql

Using URLSearchParams in IE 11

Microsoft Edge has been around for a while, but IE 11 is not dead! There are people in the real world who still use IE 11, so the development process especially JavaScript implementation has to account for it.

While there are many Github projects and NPM packages providing Polyfill for URLSearchParams, the easiest way to use it is using a CDN link to one of the Polyfill implementations. Here is one from:

Then link from your code like this:

<script src=""></script>