Sunday, December 31, 2017

Tunnel Video - Free Highlight Reel Creator for YouTube is Live!

Tunnel Video - Free Highlight Reels for YouTube

I'm thrilled to return to blogging after a crazy few months working on my web app for YouTube videos: Tunnel Video. The Beta is live so head on over and you can create free highlight reels from YouTube videos.

Tunnel Video is the simple alternative to video editing. Whether you're looking to highlight the best parts of a tutorial, put together the best moments of various videos (e.g., sports), or just create a kid-friendly playlist without comments, ads, or recommended videos--it's easy, free, and doesn't require any install. 

Once you've created your highlight reel or mashup of YouTube videos, you can quickly share the results with a public view URL. Send it via social media, email, or whatever, it's just plain easy.

Check it out! I'd appreciate any feedback.

My GitHub heat map for 2017 tells the story pretty clearly--I started the project in April.

Cawood Tunnel Video GitHub heat map

This new project is under the umbrella of my software startup: Second Marker.

Tuesday, July 11, 2017

Second Marker Software

My next project has begun. I’m working on a software startup called Second Marker.

Second Marker Software

Our first solution—and the inspiration for starting the company—is a free and easy alternative to video editing: Tunnel Video. If you want to make a highlight reel of YouTube videos, this will be the simplest solution.

There are endless possibilities for why someone would want to create and share a playlist of YouTube video with start and end times, but some use cases include:

Update: try the Beta for free at!

Wednesday, June 21, 2017

Google Cloud SQL Proxy on Same Machine as MySQL

As a web developer, it makes sense that you'd want to connect to my Google Cloud SQL instances running in Google Cloud Platform (GCP) via Cloud SQL Proxy and also have MySQL running locally on your machine. Unfortunately, the default configurations for these two systems will cause an error when you try to run the proxy: "bind: address already in use."

One clear reason to run the proxy is that it allows you to securely connect to your Cloud SQL instances with MySQL Workbench. You can get the IP (hostname) and port from GCP no problem, but to connect, you need to be running Google's proxy. (You also need to create a JSON credential file from GCP and add your IP to the Authorized Networks BTW.)

The reason for the error is that both the proxy and the local default install of MySQL will try to communicate on port 3306. When you try to start the proxy, this is the result:

doom:project cawood$ ./cloud_sql_proxy -instances=instancename-9999:us-west1:instance=tcp:3306 -credential_file=CredFileName-dflkjal.json &

doom:project cawood$ using credential file for authentication;
2017/06/05 23:51:24 listen tcp bind: address already in use

To resolve this error, one solution is to create a config file for the local MySQL server and change the port.

One thing to note (as per the MySQL documentation) is that the installer for macOS will not create a config file: "Note As of MySQL 5.7.18, my-default.cnf is no longer included in or installed by distribution packages." If you don't have a config file already... to create the config file, simply run these commands.

$ cd /etc
$ sudo nano my.cnf

This is all you need in the file:

port = 3366

port = 3366

Once you're done use CTRL + o to save and exit Nano.

It's worth noting, that I used to see this error before I installed MySQL locally. The reason was that there was another Cloud SQL Proxy process ("cloud_sql_proxy") already running. The solution to that is simply to kill the process.

Wednesday, April 12, 2017

Node.js Authentication Error Connecting to Google Cloud SQL Proxy

I was receiving this error trying to run a local instance of a Node.js API against a Google Cloud Platform (GCP) database.

Error: ER_ACCESS_DENIED_ERROR: Access denied for user ''@'cloudsqlproxy~' (using password: NO) at Handshake.Sequence._packetToError (/Users/cawood/GitHub/project/node_modules/mysql/lib/protocol/sequences/Sequence.js:52:14) at Handshake.ErrorPacket (/Users/cawood/GitHub/project/node_modules/mysql/lib/protocol/sequences/Handshake.js:103:18) at emitOne (events.js:96:13) at Socket.emit (events.js:191:7) at readableAddChunk (_stream_readable.js:178:18) at Socket.Readable.push (_stream_readable.js:136:10) 

The solution was quite straightforward, but when I first googled the error, I couldn't find anything about the access denied error showing no user--the username should be in the error (i.e. 'username'@'cloudsqlproxy).

I thought the error was the GCP Cloud SQL Proxy, but I was initiating it correctly and with a valid credential file for a service account:

$ ./cloud_sql_proxy -instances=name-111111:us-central1:instancename=tcp:0000 \ -credential_file=serviceAccountCreds.json &

The problem was actually with the environment variables for my local instance of the Node.js API. I hadn't exported them. Of course, the error was correct, I wasn't trying to connect with any user at all.

$ export MYSQL_USER="username" 
$ export MYSQL_PASSWORD="password" 
$ export MYSQL_DATABASE="test" 
$ npm start

To check if you have set these correctly, you can output them to the console when you start the server: console.log(config);

cawood$ npm start 
> projectapi@0.0.1 start /Users/cawood/GitHub/project
> node server.js 
 { user: 'username', password: 'password', database: 'test' } 
App listening on port 8000 Press Ctrl+C to quit.

Friday, March 10, 2017

Google Acquires AppBridge Software

At the Google Cloud Next conference yesterday it was announced that Google has acquired AppBridge. I've been at AppBridge for just over a year and I'm thrilled to be a part of this Vancouver software success story.

AppBridge is a tremendous addition to the Google solutions because the founders designed the AppBridge Transformation Suite from the ground up for performance and the cloud. AppBridge is already handling the world's largest G Suite and Google Drive migrations.

Here is a quote from Google's announcement:

"Migrating to the cloud can be complex. It's not just your files that need to be moved; permissions also need to map correctly; content likely needs to be reorganized, and some data probably needs to be archived. To address that challenge, today we are announcing the acquisition of AppBridge, an enterprise-grade, G Suite migration tool that helps organizations seamlessly migrate from their on-prem, cloud-based and hybrid solutions to Google Drive.

With AppBridge, your organization can migrate files effortlessly to G Suite from your existing file servers or content management systems like SharePoint, or from many other cloud platforms you might be using. File permissions are also brought over when you migrate, which means your team's file access remains unchanged and your data stays safe. We’re working together with AppBridge to bring them into the G Suite team. Stay tuned for more information in the near future."

As for me, I'm going to take some time to think about what I want for my next adventure, but this one was certainly memorable.

TechCrunch Article: Google acquires AppBridge to help enterprises move their files to its cloud services

Wednesday, February 15, 2017

Google Sheets Split into Columns

I'm very much appreciating Google Sheets' split into columns feature. Ya, I know, it's not like it hasn't been done before, but man it's nice to have when you need it.

To split text into columns using separator options (including space, comma, custom, etc.):
  1. Open a spreadsheet in Google Sheets.
  2. Paste the data you want to split into columns.
  3. In the bottom right corner of your data, click the Paste icon.
  4. Click Split text to columns. Your data will split into different columns.
  5. To change the delimiter, in the separator box, click Comma to open the dropdown of options.

Wednesday, January 18, 2017

Building Video Games with My Daughter and Lego

I asked my (then) 4-year-old daughter if she wanted to make a video game, and her response was exactly what I expected, "We can't make a game." "Actually, " I said, "we can! Want to do it?" She emphatically said yes, so we set out to make an iOS game. Of course, I had already done some playing around with Unity 3D, so I knew that a 2D game wouldn't be too much work.

I wanted her to have the best experience possible, so I devised a plan to take her ideas and convert them into the game without changing much along the way. I used a sample 2D game as a starting point so we wouldn't have to spend too much time writing code before she saw her creations in a working game. Note that if you don't deploy your app to the store, you can do all of this for free (plus the cost of Lego of course).

We started by drawing out the main elements of the game by hand. Here are the villain and hero characters as my daughter drew them.

After that, it was off to the Lego store so we could get enough 2x2 pieces to build whatever we wanted. Here's the villain Lego version my daughter created from her original drawing.

We designed the rest of the game elements including a tree and an egg, and then I used photos of the Lego concepts to convert her creations to simple sprite versions. Here's another character before reducing the pixels down to a simple sprite.

My daughter building Lego versions of the game sprites.

This is a screenshot from the first build I deployed to my iPhone (just for fun, I threw in a photo of my daughter as the player). Not bad for a 4-year-old with some Lego!

We had a great time on this project and I was promoted to write this post when she recently asked if we could play the game again.

Wednesday, December 28, 2016

How GitHub Shows My Second Child Arrived

I happened to notice this funny visual representation of the 2015 birth of my son on my GitHub profile. When anyone asks me questions about having kids, I'll have to show them this.

I'm pasting in a screenshot of my profile page below. The heat map is pretty clear about my son arriving in September. There's one outlier green square after his arrival--which I assume was me just committing every change I had made before his birth.

Tuesday, November 01, 2016

BIA Woman Indiegogo Campaign is Live!

Two of my friends have set out to create the perfect pants for female athletes. Today they launched their Indiegogo campaign for BIA Woman's perfect pants. Check it out and help support female athletes everywhere!

biawoman perfect pants

"We took it to other athletes – our clients, training partners, friends, and competitors. We listened to the problems they were struggling with and then asked ourselves the most important question of all: How can we make a difference?
BIA WOMAN ATHLETICS was born. We partnered with a team of ingenious fabric and design experts, recruited high-performance women athletes across multiple disciplines to test our products and came up with the best line of workout clothing designed by and for athletic women."

Saturday, October 15, 2016

My Blog's Most Popular Search Term: Microsoft Bob

This goes into the wacky Internet category. I just happened to glance at the "Search Keywords" stats for my blog in the Blogger admin console and noticed the single most popular search term (since I started the blog around 2005) that has led people to the geeklit blog is "Microsoft Bob."

What's possibly even more bizarre is that number two is "barcelona aquarium." Really? Out of all the pages out there, people are searching for an aquarium and thinking, "ya, geeklit sounds like the right site for that."

Very strange people...

Sunday, September 18, 2016

Why I Just Bought a MacBook Pro

I wrote a post in 2014 entitled, Why I Just Bought a Chromebook, so it may seem odd that I'm now writing this post. To be clear, I'm not backing off my favourable position on Chromebooks at all. They're great and they can be a lot more affordable than other laptops... like the MacBook Pro, for example. MacBooks are overpriced; I feel that's a pretty defensible comment. So why would I buy one?

The answer is actually quite simple and surprisingly non-technical. I have spent my entire career working in software, but I've never bought an Apple computer of any type. I've been using my wife's old MacBook for years, but I've never experienced the best that Apple has to offer and I always wondered what I was missing. If you combine that with the current popularity of Macs--especially amongst web developers--and I just decided it was time. I've run many versions of Windows. I've used FreeBSD and some flavours of Linux (including Ubuntu on my Chromebook), but it's not until now that I can say that I've really had the full Mac experience.

Unfortunately, this version of the MacBook is missing some of the hardware niceties that I enjoyed in the older MacBook I used. For example, the MagSafe connector for the power cord is gone, there is no SD card reader, no light to show the battery is charging, and no external lights to show how much of the battery remains. Those were all useful. Most people have heard about the lack of ports on this new laptop--I've given a nod to that controversy by including a dongle in the image above. Almost everything requires a dongle which is a pain. One notable exception is the headphone jack. Until the iPhone 7, the MacBook Pro actually does have a headphone jack which is nice. I'll have to see how much of an issue this is (or isn't) for me. So far, I've only purchased one dongle--for USB devices. That will cover a lot for me. If I really have issues, I'll get one of the third-party adaptors that adds ports to the machine. (Update: I saw a pretty cool "HyperDrive" one that adds an SD card reader, USB port and HDMI port.)

Of course, there are lots of improvements as well. The screen is much better, the battery life is improved and everything just generally runs faster on the newer processor and RAM. I also really like the keyboard. It has a very satisfying click which reminds me of a mechanical keyboard.

I haven't had the machine very long, so this isn't a proper review. At this point, I'm feeling good about the purchase. Yes, I do miss some MacBook features, but the Pro machine is much faster than my old one and allows me to project to Apple TV. The other one was too old to offer that feature--which gives you an idea of just how big a step us this was in hardware. 

Sunday, August 14, 2016

Angular 2 ng serve or ng build Permissions Error

Update: If you're running macOS, you should just use Homebrew from the start and you'll likely avoid these issues.

If you grab an Angular 2 project from the web, you might find that you run into permissions errors after you install it.

For example, these commands are a common example of a simple project install. (This example uses yarn, but NPM would have similar results.) The addition of 'sudo' is common on Macs, but it can cause the permissions problem.

$ sudo npm install -g angular-cli
$ sudo npm install -g yarn
$ sudo yarn install

The problem occurs when you try to run $ ng serve (or $ ng build); you see an error such as this one:

EACCES: permission denied, open '/Users/cawood/GitHub/test/node_modules/arr-flatten/index.js'
Error: EACCES: permission denied, open '/Users/cawood/GitHub/test/node_modules/arr-flatten/index.js'
    at Error (native)
    at Object.fs.openSync (fs.js:640:18)
    at Object.fs.readFileSync (fs.js:508:33)
    at Object.Module._extensions..js (module.js:578:20)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)
    at Module.require (module.js:497:17)
    at require (internal/module.js:20:19)
    at Object. (/Users/cawood/GitHub/mix/node_modules/arr-diff/index.js:10:15) 

The error occurs because the install ran as the admin user. The quick solution is to give the current user sufficient rights to the folder structure in your project. This example is heavy-handed, but it's fine for prototypes. These commands change the permissions recursively for everything (files and folders) in the test directory which is the one that contains the Angular 2 project.

$ sudo chmod -R +rwx test 
$ cd test 
$ ng serve

Tuesday, July 05, 2016

Switching to Google Cloud Platform Storage

After staring down an upcoming bill for website hosting, I quickly decided to switch my website content (including most of the images on this blog) to Google Cloud Platform (GCP) storage buckets. GCP storage buckets for static websites are much cheaper and I liked the idea of having all my content being managed by Google's cloud services.

To setup static content in GCP storage buckets, follow the steps outlined in the Google Cloud article, Hosting a Static Website.

To serve content from your custom domain, you'll need FTP access to upload a file to your current hosting storage. This is how Google verifies that you own the domain.

Once you've verified your domain, you create a storage bucket named the same as your domain (e.g., and then upload your files to the storage bucket. There are two ways to upload content, you can use the dead easy Storage Browser web interface, or you can use gsutil. gsutil is a Python app that enables command line access to GCP.

Even if you use the web UI to upload your files, you'll probably still want to use gsutil for some additional actions. For example, to set files as public, you have to go into every folder using the UI (it's labourious to say the least), but gsutil provides a simple command to accomplish the same thing extremely quickly. This one command recursively sets every file in the bucket to public read: gsutil -m acl set -R -a public-read gs://bucketname

After you've got your files uploaded and set to public, you can test the links from the Storage Browser and then your bucket is ready to go. The last step is to go to your domain registrar's site and add a CNAME entry for GCP storage. For example, points to After adding the alias, you can verify it's working by using the free CNAME lookup tool on

That's it! You're now saving money and your files are being managed by someone else. Very nice.

Note that if you're moving from Windows hosting to GCP, you might be switching from an IIS web server on Windows to a Linux backend. This means that your new Linux driven URLs will be case sensitive. This actually broke some of my image links because I hadn't matched the case of the file path exactly in the HTML and IIS doesn't care about such details.

Update: I saved over $120 by not renewing my hosting plan and my first Google Cloud Platform monthly bill was 0.08c.

Friday, June 17, 2016

Google Celebrates "Lady Day"

"Ms. Porat is the CFO, not the lady CFO." -  Danielle Ginach 

The women of Google have come up with a clever, tongue-in-cheek way to raise awareness about gender equality after an investor made a sexist remark at the company's annual shareholders meeting last week.

As my daughter grows up, I have become more and more aware of the issues women face in the workplace. Please read the Business Insider article about Google's Lady Day for the full story.

Wednesday, May 04, 2016

Spam iCloud Calendar Event Ads

Arggghhhh, now some waste of skin has figured out how to spam people by sending iCloud calendar invites to random email addresses. I just got an ad for Ray-ban sunglasses in my calendar. I like to refer to Spam that's sent by real people to the wrong address as "Spork." I'm not sure what to call this new type. Maybe "Spam Lite" or "Spam Singles"--both of which are real things BTW. Ya, Spam Singles sounds good, but moving on...

Thanks to user duozmo on for the solution. To prevent this type of spam:
Log into iCloud on the web, open your calendar and go to ⚙  > Preferences. Under Advanced, you’ll find an option to receive calendar invitations by email instead of straight into your calendar.

This should allow you to delete calendar spam like regular email spam.

The other annoyance is that you can't delete or modify these since only the organizer can do that. To remove any spam you get this way.

1. Open the Calendar app from your Mac (not the iCloud web interface)
2. Create a new calendar (e.g., called "Junk")
3. Right-click the spam event and choose the Calendar option. Select "Junk" from the list of calendars and the malicious event will be moved.
4. Delete the Junk calendar entirely (without notifying).

Tuesday, April 26, 2016

Chromebooks to run almost every Android app?

Oh let it be true... please let this be true: Chromebooks may soon be able to run almost every Android app.

From the article, "Chromebook users will soon get access to the 'more than a million' games and apps on the Google Play Store."

This would be huge. I've already written about how much I enjoy my Chromebook, but having full access to the massive Google Play store would be unbelievable. As more and more software is written in app form, 'old school' operating systems are becoming less and less relevant. ChromeOS is a fantastic bridge between having to do everything on a tiny screen and running a heavy O/S on a larger machine.

Wednesday, March 30, 2016

Why I Switched from Apple Music to Google Play Music

When Rdio was shut down, I successfully used Move to Apple Music to copy my playlists into a free trial of Apple Music. However, after using Apple Music for a few months, I've run into more snags than I can handle, and I've decided to migrate to Google Play Music.

Google Play Music

Fortunately, just like my previous switch, there is a way to get my playlists over to the new platform. To copy playlists from Apple Music to Google Play Music, I'm using Although it seems to have the same issue I encountered in the last move--not choosing the same recording of the songs--it's certainly better than redoing all that time intensive work of creating the lists. The premium version costs a few dollars, but it's worth it.

So why go through the hassle of switching streaming services again? Here are the "why not" reasons:

  • The cost is the same for the family plan, so price isn't an issue.
  • I can copy over my playlists (with a bit of clean up required)
  • I thought Apple Music would work seamlessly with iTunes. For example, I expected to be able to freely mix my content from iTunes and the streaming service. That's not the case. There appears to be no synergy there.

The deal breaker was the flexibility of Apple Music--or rather, the lack of flexibility. I simply cannot use Apply Music on enough devices in my house. Here are the devices/options I tested:

  • Windows PC: works via iTunes
  • MacBook: works via iTunes
  • iPhone 6: works via Apple Music App
  • iPhone 3 (my daughter plays with it): no app, does not work at all
  • Android Tablet (Kindle Fire): no app, does not work at all
  • Nexus 5x: works via Apple Music App
  • Chromebook: does not work at all

Obviously, some of these are more important than others, but the fact remains that Google Play Music works fine on every one of these devices. Furthermore, it does not require any install to run on a PC/Mac/Linux/ChromeOS browser; I really miss the web listening experience that I had with Rdio and I want that back. In the end, it was an easy decision to make the switch and go Google.

Saturday, February 06, 2016

Google Drive API JavaScript App Running in App Engine

I worked through the JavaScript quickstart guide of the Google Drive V3 API and modified it slightly so I could host and run the whole thing in the Google App Engine . I suggest you work through the quickstart once (following all the steps) before you read on--unless you're already familiar with App Engine and the Google Cloud Console, it may be difficult to follow what needs to change. The quickstart is a simple one-page app that allows the user to authorize access to their Google Drive and then shows ten files and/or folders in that Drive.

Why would you want to do this? It's great to be able to create your app that uses the Google Apps APIs, but even better is to host that app within the Google App Engine so that you don't have to worry about maintaining any of the infrastructure that runs your app. You also get the benefit of sophisticated App Engine features such as performance scaling.

The steps in the Drive V3 quickstart ( will get you most of the way, but with a few changes, you can serve the app from the Google App Engine, which is super powerful and a more modern mechanism for running a web application.

One thing you'll have to change is the URL that your client ID will accept. The quickstart expects you to host and run the app on your local machine, and therefore use http://localhost as the URL. You can enter that when you work through the tutorial, but you'll have to change the URL for "Authorized JavaScript origins" later to the URL for your particular app. However, you won't have that URL until you try running your app from the Google Cloud Shell.

Your client ID should look something like this (I've edited it so as not to disclose my client ID):

Here are some notes to clarify how to get the quickstart running in Google App Engine from the Google Developer Console:

  • You'll likely want to create your own GitHub repo and clone it to your local machine.
  • When you get to the step in the tutorial, you can connect your app project to your new Git repo. You'll have to authorize Google App Engine to use your repo. By connecting the two, it is super easy to manage (and even edit) your code from within the Google Developer Console.
  • Create the sample file (with code provided) in the local repo and push it to master that is synching with GitHub.
  • Don't forget to change your client ID in the sample code: var CLIENT_ID = '';
  • Once you have everything ready. Make sure you have your new quickstart project selected and then open the developer cloud console. The console is a Linux based shell.
  • Change directory (CD) to the src directory for your quickstart project.

cawood@definite-destiny-999999:~$ cd src/definite-destiny-999999/master

  • Start a web server using Python to host your application: python -m SimpleHTTPServer 8080

cawood@definite-destiny-999999:~/src/definite-destiny-999999/master$ python -m SimpleHTTPServer 8080
Serving HTTP on port 8080 ... - - [12/Jan/2016 00:11:56] "GET /?authuser=0/ HTTP/1.1" 200 - - - [12/Jan/2016 00:11:58] "GET /quickstart.html HTTP/1.1" 200 -

  • Open the Web preview from the console window in port 8080. When you navigate to the quickstart.html file, you will get the URL you need to add to your client ID credentials. The Web preview option is in the top-left corner of the cloud console. 
  • Find your client ID in the credentials section of the dev console and edit it to add the URL you just opened in web preview. (To stop the app (quit the web server), press Ctrl+C.)

That's it! You should now have the quickstart running in Google App Engine! Sweet.

Note: I do not cover deploying your app for production use. Perhaps that can be a future post.

Note: If you've made a change and pushed it from your local machine, but the file isn't updating, try closing and reopening the console. I've found that it doesn't pick up changes to the files unless I do this.

I've made the project public on GitHub:

Wednesday, January 13, 2016

I AM CARDBOARD VR Url Not Recognized Setup Error

For Christmas, I picked up a Google Cardboard viewer. It's the easiest (read: cheapest) way I know to get a virtual reality headset for home use. When I co-wrote Augmented Reality: A Practical Guide for the pragmatic programmers (in 2006), headsets for augmented reality or virtual reality were expensive and bulky.

That certainly has changed. Google cardboard devices are literally made of cardboard. There are lots of choices. I got the I AM CARDBOARD® 45mm Focal Length Virtual Reality Google Cardboard. So far, I'm impressed with the inexpensive device. Enabling clicking in the virtual user interface by moving a magnet on the side of the device is ingenious.

Unfortunately, I quickly ran into a problem with the set up. When asked to use my phone's camera to grab the QR code on the cardboard, I received the error "URL not recognized" or "Problem in parsing the Url." QR codes represent a URL and if that URL changes, they can break. The solution was to find the manufacturer's website and search for a QR code there. In this case, I found a working QR code for the I AM CARDBOARD. Now I'm looking forward to trying out more of the apps with my daughter.

Update: My daughter loved it! I shot a video of her reaction that I'm sharing with family. So cool.

BTW: from the site -- "Calibrate your VR headset using the QR code found in this listing images. To do so, open the Google Cardboard app, select "Configuration" menu option, click on "Switch viewer" and scan the QR code."

Friday, December 04, 2015

My Brother's D&D Kickstarter Campaign

The World of Myrr is a Kickstarter campaign that my brother put together. It's a detailed and play tested campaign world for Dungeons and Dragons Fifth Edition

If you know any D&D fans, let them know this new campaign is out there.

He even gave me credit in the video for helping with the World of Myrr Wordpress site and various other technical questions. :)