Friday, January 30, 2015

The Super Bowl - The Only Use For Roman Numerals!

Alright, so today's comic is my poor attempt at humor combining Super Bowl advertising with online advertising. The Super Bowl is a big deal. I had to at least mention it in the comic.

The Super Bowl is actually the only sports program I watch. I hardly watch any television at all. I gave it up a few years ago and don't regret it. The only thing I really miss is seeing interesting and funny commercials. Fortunately, the Super Bowl rarely disappoints in that category.

But why would the frogs run a Super Bowl ad? Even they aren't sure what their company does, but it seems to be related to the latest trendy technologies. Tech companies have a long history of running Super Bowl commercials, going all the way back to 1984 with Apple's famous ad.

This year, a 30-second spot is said to cost $4 million. Any "normal" company would have a hard time justifying that much marketing money for one commercial. But for today's super-successful technology businesses, $4 million is nothing. Why not have some fun with a Super Bowl ad? Do something really creating and people will be talking about it for weeks. Apparently, people have already started talking about one of GoDaddy's ads...

What I find really interesting is how television commercials for things like web hosting companies have become so mainstream. I remember when the Internet was just for nerds. Nerds who never watched the Super Bowl. comic for 30 January 2015

Wednesday, January 28, 2015

I Won't Stand For This

A Standing Desk
I sit a lot. Most of the day really. I sit when I drive to work. I sit at work when I write software. I sit when I eat lunch. I sit when I drive home from work. I sit when I eat dinner. I sit after dinner when I write blogs and comics and sometimes other software. Always sitting.

In today's comic, the frogs are picking a new chair of the board, which to them means a new thing to sit on when they have their meetings. Frogs also sit most of the time, but they aren't bipedal. Humans are designed to stand up on two legs. So why do we sit so much?

It turns out that sitting all the time is probably taking years off my life. The sedentary lifestyle that so many of us have is dangerous. I need to sit less. Could a standing desk be the answer?

If you are unfamiliar with standing desks, they're basically just really high desks. Instead of a chair in front of it, you stand up to use it. You can write or type on it. Supposedly they are better for you than sitting at a normal desk all day.

I found this article on Lifehacker than can help me find the perfect standing desk:
Five Best Standing Desks
Then I found this other article on Lifehacker that can help me deal with pain caused by standing all day:
Take the Pain Out of Standing All Day
Draw your own conclusions. comic for 28 January 2015

Monday, January 26, 2015

Your Browser is Lying to You

There's a little trick I do on my comic to make sharing easier. Since the content changes three times per week, if you send someone the link to "" and they don't click on it until 2 days later there's a good chance they'll see a different comic than you did. That's why as soon as you navigate to I re-write the URL to include the id of the latest comic. Then when you copy the contents of your browser's location bar into the "share" field on Facebook, everyone will see the same thing you did - even if they don't click on it for a year.

And speaking of Facebook, you may have noticed this trick there as well. When you click on a picture, it will show up larger and cover most of your news feed. If you take note of the URL in your browser, it will change to a direct link to that picture. Copy that URL and use it later, or give it to a friend, and it will take you right to that picture.

You are looking at
...but click on that picture and the URL changes!

But technically speaking, your browser never left the page it was on before you clicked on the image. Just like doesn't redirect you to a new URL when you first visit the site or even when you navigate around using the "Previous" and "Next" links - the URL bar can lie to you!

Doing this yourself is fairly simple. Look at this code:

var newPath = "whatnot";
if (history.replaceState) {
        nowShowing: newPath,
        yourData: "whatever you need",
        storeIt: "in this object"
    }, "page title not really used", newPath);
} else {
    // you are using an old Internet Explorer

The history.replaceState function is what makes the magic happen. You should check to see if it exists (I still hate you, IE 9) before calling it, but I haven't found a good fallback option or polyfill. There are some that try, but in my opinion they aren't worth the hassle. Anyway, let's unpack this a little. The replaceState function takes 3 parameters. The first is an object. Any object you want. More on this later. The second parameter is the page title for the new URL. Nothing is really done with this, but it may be used someday according to the browser documentation. Just put some text in here and forget about it. The third parameter is the new path. In my example it's "whatnot" - so if you were to execute this on, the URL would change to

Alright, so what's up with that generic, whatever-you-want, first parameter object? It comes into play when the browser's back button gets used after you've changed the URL. To have consistent behavior, you need to handle what happens when the user wants to return to where they were before you changed the URL. For example, I change the URL to, based on something on which the user clicked. Then I change it to when they click on something else. Then they hit the back button. The browser takes them back to - but they didn't really never left the page. I have to know how to re-create what I had on the screen when I made up the /whatnot path in the first place.

To handle situations like this, bind a function to the "popstate" event on the window object. This function will be called whenever the back button is used. In it, you can access that object you made when you replaced the URL. Just put enough information in there to recreate the user experience you created the first time you changed the URL. Here's an example which uses jQuery for the even binding:

$(window).bind("popstate", function(event) {
    var s = event.originalEvent.state;
    if (s && s.nowShowing) {
        console.log("welcome back to " + s.nowShowing);

Your object that you passed in to replaceState is now available via the event.originalEvent.state object. So when /whatnot becomes the URL again, you'll know as long as you put some identifying information in that object. In my example, the field nowShowing contained the path.

These tricks are often useful when developing something like a single-page web application and you want to gracefully handle the back button, but clearly they have other applications as well. Just another browser/JavaScript feature to think about when you are looking for creative solutions to web-based problems. comic for 26 January 2015

Friday, January 23, 2015


Not since the spork has a portmanteau been as beloved by the tech industry as the acqui-hire. These days, it seems like the best way to get a job at a big-name Silicon Valley company is to start your own small, insignificant company and wait to get acquired.
For Sale: Team. Used but in good condition.

There is some debate over whether or not the practice of buying a company just to get its employees really works. I think the biggest benefit has to be the fact that the larger company can immediately get a team of people who already work well together. If they can keep that team together and redirect them to some other (possibly related) project, it could be much easier than trying to put together a new team. The downside is that they may be paying more for the team that it is really worth.

I believe team dynamics have been overlooked for too long when explaining why some projects succeed and others fail. But think about your own experiences. I know when I have been forced to work with people who just didn't get along, it didn't matter how talented each of us might have been individually. The project fell apart. That doesn't mean that anyone in particular was to blame, but the team as a whole just wasn't right for the task.

But when I am able to pick my own team, or when I work with friends on a project, it seems like nothing can go wrong! Or at least, nothing that we can't overcome.

Getting the right team together is difficult. When a company is small, the team grows by current employees getting their friends to come join them. Thus the team tends to work well together. At a large company, a team can be formed by a manager picking people out of a database of names and skills. It doesn't have to be like that, however. If the manager had access to some sort of personality profiles along with skill profiles, algorithms could be used to select better teams. It would be a bit like online dating - employees fill out profiles and get matched up with other employees with whom they would work well. I am not aware of any companies that have tried this, although there may be some.

The frogs have their own unique take on this practice today. comic for 23 January 2015

Wednesday, January 21, 2015

The Origin of

Today's comic got a little complicated. So some sinister-looking toad has started a new company to compete with and has hired away all the worker frogs. Since everybody's over at the other company today, the comic is actually at the toad's company website -

I thought it would be simple to point to the same server as and have the application just use a different stylesheet when the toads URL is detected. As it turns out, it wasn't really that simple.

One of the things I forgot about was how picky browsers can be about cross-domain loading. While there's no issue with sourcing images or JavaScript from other domains, I ran into a minor issue with Font Awesome loading font files cross-domain.

If you haven't heard of Font Awesome, you should check it out. By creating a custom font of pictures (remember Wingdings? It's like that, but useful) it essentially gives you a library of scalable vector icons that can be customized with CSS.

Due to the way Cross-Origin Resource Sharing is designed, a server is expect to specify in a response header if the requesting domain is allowed to use a web font. The header is called Access-Control-Allow-Origin. If is hosting the font, by default only pages at can use it. But if I add the special header to the response when I serve the font, I can specify other domains that are allowed to access it.

My goal, therefore, was to set the "Access-Control-Allow-Origin" header to "" so my social media icons wouldn't be missing when viewed from Initially I wasn't sure how to do that, since all static content is served automatically by Express's static middleware. This is the only middleware that is still "built-in" to Express, but it is really just a wrapper for the serve-static module.

To add a certain response header to only some files, I had to supply a setHeaders function when I set up the middleware.

app.use(express.static("public", {
    "setHeaders": function(res, path, stat) {
        if (path.match(/\.(ttf|ttc|otf|eot|woff|font.css|css)$/)) {
            res.setHeader("Access-Control-Allow-Origin", "");

Personally, I think the name of the function is a little misleading. While the intention is certainly to give you a place to set headers, you can pretty much do whatever you want inside. You get access to the response object, the path of the request, and the file stat for the file at that path. There's a small caveat - because the function doesn't return anything, you can't really make any asynchronous calls that defer any processing. You have to do whatever you need to do synchronously. Set the headers you need to set and move on.

My method simply checks to see if the requested file ends with one of the font extensions, and if it does the special header gets set.

I set out to do something that I thought would be simple, and ended up learning something new. Not a bad deal. I hope those frogs got as good of a deal at their new jobs... comic for 21 January 2015

Monday, January 19, 2015

Do Crazy Perks Attract Crazy Employees?

At my job we get two perks in addition to our salaries. One, we get free coffee. And two, we get the privilege of working there.
I Love Free Coffee!
Photo by Nevit Dilmen

Once I worked for a guy who constantly reminded us that he shouldn't even really be paying us. We were learning so much from him, he said, that we should have been paying him to work there. I guess since he couldn't find people to take him up on that offer, he had to resort to paying me.

Needless to say, I'm really not accustomed to the crazy perks people get while working for Google or other trendy and cool software companies.

Still, looking at the list of benefits Silicon Valley software companies are offering makes me jealous at times. Free lunches. On-site barber shop. Massages on demand. Free dry cleaning. Free bus to work with on-board WiFi. Almost makes me wish I went to a better university so I'd have a chance at employment with one of those companies. I guess I'd have to be really smart too. And an amazing software engineer. Oh well...

The cynical side of me wonders if the companies really offer those perks because they want to make their employees so totally dependent on them that they can never quit. If you always get your hair cut at the Google barber and get all your laundry done at work, you seem pretty dependent on your employer for more than just your paycheck. The line between home and work is blurry. Your whole identity is wrapped up in the company for which you work. Could be dangerous.

But I don't have to worry about any of that. Perks are overrated. I don't have to pay my employer rent for my cubicle space, so I'm happy. comic for 19 January 2015

Friday, January 16, 2015

At Present, I Present to You This Present.

Venn diagram by Cmglee
Which, of course, means right now I'm giving you a gift. What is the gift? Knowledge!

Today's comic, while wrapping up the frogs' experiment with streaming music, presents you with some homographs that are heteronyms. Huh?

Jokes based on heteronymic homographs really only work in print. Homographs are words with different meanings but the same spellings. You need the context in which they are used to guess at the correct meaning, and I purposely used ambiguous context.

But if you were to hear the words spoken there would be no ambiguity - at least in this case. That's because the words used in this comic are also heteronyms (or sometimes called heterophones). That means that they are pronounced differently.

Homographs are either heteronyms or homophones, and if they are homophones they are also homonyms.

Homophones are pronounced the same but have different meanings - and depending on if they are spelled the same will be either homonyms (same spelling) or heterographs (different spelling).

I think the Venn diagram helps.

Puns, which I use extensively, usually involve homophones. Phishing and fishing, for example (and they're heterographs).

The downside of this comic is that it probably only works in English. Anyone using Google Translate will most likely be disappointed. Or confused. Perhaps both. comic for 16 January 2015

Wednesday, January 14, 2015

I Am Not Musical, But JavaScript Is

A while back I wrote about the Internet Arcade, a collection of classic arcade games that can be played in your web browser. They play without any special plugins because the games are being emulated in JavaScript. It's great, except that most of them have no sound. This got me thinking about how limited JavaScript is in terms of sound generation and I started looking around for some answers.

I have used SoundManager 2 for many years in order to play audio clips in web pages, but I suspect that would be of little use when emulating an old arcade game. I own two full-size classic arcade games (BurgerTime and Dig Dug) and I realize that most of their sounds are just playing some frequency for some time through some simple speaker. There were no MP3's stored in the memory chips on those old boards.

I don't understand any of this.
So why can't we make simple sounds with JavaScript? I could play sounds at whatever frequency I wanted using BASIC on an IBM PCjr back in 1989. Have we gone backwards?

No, it turns out that we can generate sounds using JavaScript, with quite a bit of complexity actually. The Web Audio API is an amazing toolbox for audio generation in the browser...but it is still just a draft. Fortunately, the draft specification has been implemented in recent versions of the major browsers, with the exception of Internet Explorer of course.

I read the specification Too much audio stuff for me to understand. I am not musical in the least. I played the saxophone for one year in elementary school and I remember absolutely nothing about it. I don't have an expensive sound system in my home or car, and I believe that the tiny cheap speakers that come built-in to most monitors are just fine for my listening needs. Not musical at all.

I needed to find some library that could simplify things a bit. I found Tone.js and started to play around with it. Sure enough, I could use JavaScript to create a terribly annoying sound that would not end until I closed the page.

My goal, however, was to make a page that could play a recognizable song of some sort. I found this great resource that has transcribed the music from the original Super Mario Bros. for the piano. But as I mentioned, I can't read music! Fortunately, my wife can. She even taught violin for a while. I had her look at the sheet music and tell me what the notes were. That's how I was able to make this:

//create one of Tone's built-in synthesizers
var synth = new Tone.MonoSynth();

//connect the synth to the master output channel

synth.setVolume(-15); // i have no idea

var index = 0;
var notes = ["E5", "G5", "E6", "C5", "D6", "G6"];

//create a callback which is invoked every sixteenth note
    if (index < notes.length) {
        synth.triggerAttackRelease(notes[index++], "16n", time);
    } else {
}, "16n");

//start the transport

This code uses Tone.js to reproduce the 1-UP mushroom sound from Super Mario Bros. There are 6 notes, which I put in an array there on line 10. On line 13, I set up a callback on the Transport that will be called every 16th note and will play the next note in the array for the duration of a 16th note. Once the Transport is started, on the last line, it will play through the notes and you should hear the familiar music. Here is a link to the demo page.

The one thing that I could not figure out is why I had to set the synth volume to a negative number in order for it not to blast my speakers (line 7). By default, it is really loud. According to the documentation, setVolume should take a number representing the decibels. My understanding was that anything below 0 could not be heard. I thought perhaps using a negative number meant turning down the volume by that many decibels, but setting the volume to -5 three times did not have the same effect as setting it to -15 once. So I don't know. If I use Tone.js more, I'll have to perform a more thorough investigation.

For now, enjoy some frog comics about streaming music. comic for 14 January 2015

Monday, January 12, 2015

The Internet is All Advertisements

Today the frogs try some targeted advertising with the help of a cookie. It may or may not work, depending on if you, the reader, have the cookie or not.

Advertising used to be about billboards - like this one.
In real life, I have to wonder how online advertising ever works. The Internet is a weird place. It costs a lot of money to operate, but everyone expects it to be free. Sites that put up "paywalls" are generally maligned. That leaves advertising as the only way to pay the bills, which means the online advertising industry has grown to enormous size and complexity. And you probably don't ever even think about it.

It's not just websites that are expected to be free. Look at the smartphone app marketplace. Paid apps are rare. It's just some global understanding that everything related to the Internet, even mobile Internet, should be free (except your mobile data plan! I'm sure that costs a fortune!).

Do you ever click on ads you see on websites? I rarely do, except in cases where the ad offers me a discount code or something on a product at which I looked but didn't purchase.

I've tried being on the other side as well. I will occasionally run ads for on Facebook. The amount of users on the Internet is so big it's just a numbers game. I have to get my ad seen by 10,000 people so 30 will click on it. Good thing Facebook has a billion users to see my ad! If get my ad seen by everyone on Facebook, I could get 3 million clicks. I think that would cost me close to a million dollars. And I don't even make any money from my comic! If I did, I'd probably have to put ads on it, like I have on this blog.

So the whole Internet is paid for by clicking on ads that send you to sites with other ads for you to click on.

And the smartest people in the world go work at Google and Facebook to build systems for better advertisement targeting.

Oh, well. Enjoy some ad-free frog comics! comic for 12 January 2015

Thursday, January 8, 2015

No Internet

It's hard for me to write a blog for today because there is no Internet connection at my house. It stopped working yesterday and Century Link won't even consider if the problem is on their end until after they send me a new DSL modem. We shall see.

I remember when I had a computer before the Internet, and it didn't seem as useless as my computer seems right now. comic for 9 January 2015

Wednesday, January 7, 2015

Games for Everyone!

Did you read any of the 2014 Google search trends stories? The one about Flappy Bird had some interesting things in it.

Here's the link, in case you missed it: Google 2014 Search Trends: Gaming.

The first take-away is this: a game developed by one guy in a few days was the number one searched-for game of the year. Proof that it doesn't take a multi-million dollar effort by a major game company over several years to make a popular game. A secondary thing to note here is that Flappy Bird went offline in February. Near the beginning of the year! And it was still the biggest search star of 2014! People were talking about that game for the rest of the year. It became a major element of popular culture.

Further down in the story, there are some more interesting things. Loom bands were big last year, and searches for them were up three times. I know my daughters spent a great deal of time searching for loom band designs and tutorials. The youngest even tried making her own loom band tutorial videos. It was great to see the kids using the Internet for learning, then being creative and trying to share their ideas back to the Internet.

We love this game. But we're partial to frogs.
Near the bottom, the "games for girls" search trend bothers me a little bit. It says that we search "games for girls" more than "games for kids" or "games for boys." In a week when my comics are concerned with tech company diversity, I would like to express my frustration with this. Have you ever searched for "games for girls"? My daughters have, and when I see them doing it I have to correct them. Why can't games just be games? Games for everyone? I don't want my daughters thinking that they are supposed to enjoy a certain type of game over other types. My daughter Alex enjoys Super Mario Bros. (she's actually playing right now as I'm writing this) but you won't find it listed under a For Girls heading. There is some whole website devoted to "girls games" and honestly they are all pretty awful. But what if they just called the site "Games for Kids" - would it change anything? Why not let boys play the game (and I use the term loosely) where you make a cake? And while I'm on that subject, I'm not even sure I would technically classify many of them as games. But then again, all of my daughters greatly enjoy playing Fayju's Amazing Frog? and that game defies all attempts at classification.

I would recommend you direct any child to the nearest Nintendo Entertainment System (or emulator if you don't still have one) to play a game before searching for "games for girls" on the Internet. Which leads to the final point, the last quote in the Google story.

"When games play well, they don't age, whatever their lack of gloss."

- Mike Diver
Which is why we'll always remember Mega Man and will still play Ms. Pac Man in 50 years. comic for 7 January 2015

Monday, January 5, 2015

STEM for Everyone!

My comics this week take a (hopefully) humorous look at a very serious problem. In STEM (Science, Technology, Engineering, and Mathematics) careers there is a very pronounced diversity problem. Women, who make up roughly half of the general population, do not have anywhere close to that level of representation amongst software engineers, the type of engineers with which I have the most familiarity.

So if you weren't aware of this, look at these statistics on technology company diversity: Diversity in Tech. You can find lots more information like that with a quick search.

Me and my daughter Alex. She loves frogs and science.
As my frogs search for the cause of their diversity problem, I'm trying to highlight the fact that there seems to be no good explanation of why so few women choose STEM careers. And there are plenty of people who try to explain it. All the time. One day not long ago I saw 3 links to articles in my Twitter feed, each offering a thorough analysis of why software engineering is dominated by men. One provided a great deal of evidence that it is the environment, meaning that current software engineering teams are filled with people who are hostile towards women. Another completely refuted the "environment" theory, insisting that the "pipeline" is to blame. Obviously, the author argued, our high schools and universities do a poor job of getting young women interested in science and engineering careers. The third article presented a balanced argument, which blamed both.

Here's an article that claims to have the explanation: The Shortage of Women in STEM Explained. Or maybe this one: Paving The Way For More Women in STEM. Have more time? Read this one: Why Are There Still So Few Women in Science? These aren't even the articles that I read originally - there are tons of writings on this subject in recent years.

And so this week's set of comics was written. Everyone has a theory, but nobody really knows where the problem is. Environment? Pipeline? Both? Something else? I certainly don't know, and I wouldn't expect the frogs to figure it out either.

I can offer only the following thoughts.

My daughter worked on learning Python on her Raspberry Pi for a few weeks, but lost interest. She told me that programming was too lonely. It was just her and the computer. This was a very strange concept for me. One of the things I liked best about programming when I was 10 years old was that it was just me and the computer. I enjoyed the solitude. But in the real world, software development is almost always a team effort. Today I spend much more time interacting with other people than I spend alone with the computer. If someone had explained that to me 25 years ago, I might have picked a different career. If I can explain that to my daughter now, she might again consider it as a career. She is currently planning on becoming an architect, another career I had considered for myself when I was her age. But for all I know, architecture is a lonely career (I don't know any architects to ask). And does her desire to pick a career that involves lots of teamwork have anything to do with her gender? I have no idea about that either. She's just a kid who loves to build houses out of giant cardboard boxes, play with Legos, and stack endless cubes of whatever in Minecraft. If picking a career that involves lots of human interaction is correlated with gender, do misconceptions of what STEM careers are actually like contribute to lack of interest among women? Again, I have no clue. Am I even asking the right kinds of questions?

I pretty much don't know anything. But I'd like to know more.

I'd like to live in a world where women have equal representation in all careers. Does anyone know how we get there? At least we're talking about it. Keep talking about it, and eventually we'll get it. comic for 5 January 2015

Friday, January 2, 2015

Wrapping it Up

Wrapping Paper. Really cheap right now.
I know, you are probably sick of wrapping after all those Christmas presents just a week ago. So today I'm talking about line-wrapping.

Today's comic lets you write a short message in the last cell, made out of those wooden letter blocks that little kids play with. Of course, space is limited in the cell and there's only room for about 10 letter blocks per row. To make a multi-word message fit, I had to use a line-wrapping algorithm to split up the text into lines that were no longer than 10 characters each.

There is a fairly good write-up of the process on Wikipedia. I needed a JavaScript implementation so the wrapping could happen in the browser after the user types in the message.

It was actually quite simple. Here is my function:

function lineWrap(text, len) {

    var lineWidth = len || 10; // if line length not specified, default is 10
    var spaceLeft = lineWidth;
    var words = text.split(/\s/);
    for (var w in words) {
        var word = words[w];
        if ((word.length + 1) > spaceLeft) {
            words[w] = "\n" + word;
            spaceLeft = lineWidth - word.length;
        } else {
            spaceLeft = spaceLeft - (word.length + 1);

    return words.join(" ").trim();


My version defaults the maximum line length to 10 (as you can see on line 3) but you could change that to any default you want. You can also specify another value as the second parameter to the function each time you call it.

To wrap the lines, the given text is first split into an array of words. I split using the regular expression for white-space on line 5. Then, go through the list of words and check if the length of the word plus 1 space will exceed the space available on the line. If it will, put a newline character on the front of the current word and set the space available to be the maximum line length minus the length of the current word. Otherwise, subtract the length of the current word plus 1 space from the current space available and move on to the next word.

After all the words have been checked, I use the join() function on line 17 to put the array of words back together with a space in between each word.

If you call the function like this:

lineWrap("this is some text that should wrap");

the resulting text should look like this:

this is
some text

But if you call the function with a longer line length,

lineWrap("this is some text that should wrap", 20);

the resulting text will look like this:

this is some text
that should wrap

Looks good, right? Now get wrapping! Lines, not presents. comic for 2 January 2015