Wednesday, April 29, 2015

Automating Code Deployment with GitHub Webhooks and Node

Do you push a "pull" button?
I've been pushing updates to my webcomic's code repo on GitHub for over a year now. My workflow has gone something like this:
  1. Make code changes.
  2. Test locally.
  3. Push changes to GitHub.
  4. Log on to production server.
  5. Pull changes from GitHub.
I'm trying to automate steps 4 and 5. I'd like to have my production server automatically update itself whenever I push code to the "main" branch of the repository.

This week I've been experimenting with using GitHub's Webhooks to automate my code deployment. Webhooks are a cool idea - set one up on your repo and every time an event occurs (push, pull request, fork, etc.) GitHub will send you some data to a URL of your specification which describes the event. All you need is something to process the data!

I set myself up a simple Node application to process the data using the githubhook package. It was very easy to use.

var githubhook = require("githubhook");
var exec = require("child_process").exec;

var github = githubhook({
    port: 8082,
    secret: "your-secret-code"
});

// listen to push on github on branch master
github.on("push", function(repo, ref, data) {

    var branchName = ref.substring(ref.lastIndexOf("/")+1);
    if (branchName === "master") {

        var repoName = data.repository.name;
        if (repoName === "comic") {

            child = exec("/home/comic/update_comic.sh", function(error, stdout, stderr) {

                if (error !== null) {

                    var e = new Error("exec error: " + error);
                    console.log(e);

                } else {

                    console.log("pulled update for " + repoName);

                }

            });

        }

    }

});

// listen to github push
github.listen();

My application will listen on port 8082 for GitHub events, which will be HTTP POSTed in JSON format (when you select that option later). When setting up, the value for secret (line 6) is important. You'll want that to match the value you'll set up in GitHub. Once you create the object, specify callback functions for the events that interest you and start listening.

I am just looking for the "push" event. When that event happens, I check to make sure the push was to the master branch and that the repo was my comic (I might use this for other repos later). If both of those are true, I exec a script that will pull the updates and restart the app if necessary.

Once you have your app running, you can set up your GitHub repo with the Webhook. Just go to your repository page, and click on the Settings link. Then click on "Webhooks & Services" and then on the "Add webhook" button.

Now specify the URL where you are listening with the app. My URL happens to be http://caseyleonard.com:8082/github/callback. The port is obviously the same one I specified above, but the path of /github/callback is the default used by githubhook (you can change it if you want - see the docs). Set the Content Type to be "application/json" and type in the same value for Secret that you used in the app. If these don't match, GitHub will receive a 403 response code when it sends you data and your listener will not be called. You can also select which events of which you want to be notified. It defaults to just "push" which is fine for my use.

It's simple and it works for me, at least so far. The less time I spend updating the code for the comic, the more time I can spend making the comics themselves. Today is the last of the Canterbury Tales parody, a set which took me a very long time to create!

Monday, April 27, 2015

The Moral of the Story

If you've been reading Amphibian.com for the last week, you'll know that I've been doing a parody of the Canterbury Tales. Today's comic is the third story told by the frogs, and it happens to be Business Frog's tale.

Business Frog is a weird character for me. He wasn't part of my original comic idea (I created him just for this shirt I made for my brother), but he gets a lot of screen time in the comics (he was the central character in the 5-part Christmas poem and the star of my GitHub Game Off entry). He is also the most upbeat of all the frogs. I've only shown him frowning once, and that was more fear than sadness. And today his story is the only one to have a "real" moral. Like most of the tales told by Chaucer's pilgrims, there was some moral - but before today they've just been silly. I think I use Business Frog for the deep stuff as a contrast to the lack of moral integrity I see in the real business world. Business Frog learns and gets it right because I want business humans to learn and get it right.

Too often, humans get it wrong.

I don't have any cool code tricks to showcase today because last week I didn't do much coding. On Thursday I did something infinitely more important and adopted the foster child who's been living in my home for the past 2 and a half years. She is a wonderful child, now 15 years old, who's been hurt by a broken world and is on a slow road to recovery. I am responsible for her now, but in a sense we're all responsible for what happened to her. We live in a world where we see our leaders put profits before people and teach us that self-interest is the best interest. We celebrate financial success and absurd narcissism.

That's the kind of stuff I think about when I make a comic using a frog wearing a necktie. Actually, I think about that stuff pretty much all the time. It's just that sometimes I am making a comic using a frog wearing a necktie. Am I crazy?

Absolutely.

Amphibian.com comic for 27 April 2015

Friday, April 24, 2015

Meetups are Better Than Meetings

I admit it, I don't work well in crowded and noisy areas. I can't set up my laptop at the coffee shop and get anything done. I like silence. Unlike many people, I can't focus when there is music playing. Does that make me strange? Probably. I need solitude to really accomplish much of anything.

Despite that, I went to a Meetup tonight in a local co-working space where I tried to work on an issue with my webcomic framework. There were lots of people around having lots of conversations. I frequently stopped what I was doing to talk to someone about what they were working on or what I was working on. Even though I didn't really get much done, it was still a positive experience.

Why? Because it exposed me to new people and new ideas outside of what is typical for me. For example, I have been curious for some time about algorithms that procedurally generate terrain in games, but I didn't know anyone who had actually worked on something like that. Tonight, I met someone who had made a game with randomly-generated areas and he told me about Perlin noise and how it is used. It was great!

So in this short post today I'd like to encourage you to find a similar group in your area and participate in it. Sites like Meetup.com are good places to look for them. If you can't find one near you, maybe you should start one!

In other news, my parody of the Canterbury Tales is still going at Amphibian.com. Today, Science Frog tells his story:

Amphibian.com comic for 24 April 2015

Wednesday, April 22, 2015

Simple DOM Collision Tracking

Back on the 15th, I had this awesome frog dodgeball game right in the third frame of my Amphibian.com comic. While today's Chaucer-inspired tale told in Middle English is amusing, it lacks the technical complexity of the dodgeball game. One of the many pieces that came together to enable a game inside a webcomic was simple collision detection between DOM nodes.

Frog Dodgeball
The comic frames, even in the dodgeball comic, are just "regular" DIV tags. I didn't use an HTML5 Canvas or anything like that. The frogs and balls are just IMG tags. To determine if a ball hits a frog, I had to come up with some reasonably efficient way of detecting the collision between two elements in the DOM and then taking some action based on a possible collision.

I used a class-based detection strategy similar to what I learned while using Crafty to make my entry for the GitHub Game Off 2015. Any element that should be checked for collisions with other objects should have the "collision" class applied to it. There isn't necessarily any special CSS associated with that class - it just has to be on the element. The element should also define a value for the field "collidesWith" that will be the name of another class. Only elements that have that class will be checked for collisions. I used a simple circle-based intersection formula for speed, so elements that can collide with other should define a value for the "collisionRadius" field as well. Finally, the elements should specify a function, hit, to be called if a collision is detected. The function will be passed an array of objects that are in collision.

Here is an example of how I set up the ball elements.

var ball = $('#ball');
var newBall = ball.clone()[0];

$(newBall).addClass("collision");

newBall.collisionRadius = $(newBall).width() / 2;
newBall.collidesWith = "frog";
newBall.hit = handleHit;

All balls are clones of a master ball element (line 2). I add the "collision" class, set the radius, specify what kinds of elements with which the balls collide, and specify the function to call if there is a hit. Here is an example of the handleHit function:

function handleHit(elemArray) {

    $(this).removeClass("collision"); // this ball won't hit anything else

    // make the element hit (assumes only 1 in this case)
    // semi-transparent for half a second
    $(elemArray[0]).css("opacity", "0.5");
    setTimeout(function() {
        $(elemArray[0]).css("opacity", "1");
    }, 500);

}

So that's the setup. But of course I had to add the collision-checking code to the comic framework. I already had a function that handled the animation, so I added a call to checkCollisions after each position update.

function checkCollisions() {

    $("img.collision").each(function(idx, elem) {

        if (elem.collidesWith) {

            var cx1 = Number($(elem).css('left').replace('px', ''));
            var ox1 = cx1 + ($(elem).width() / 2);

            var cy1 = Number($(elem).css('top').replace('px', ''));
            var oy1 = cy1 + ($(elem).height() / 2);

            var hits = [];
            $("img." + elem.collidesWith).each(function(idx2, elem2) {

                var cx2 = Number($(elem2).css('left').replace('px', ''));
                var ox2 = cx2 + ($(elem2).width() / 2);

                var cy2 = Number($(elem2).css('top').replace('px', ''));
                var oy2 = cy2 + ($(elem2).height() / 2);

                var distX = (ox2) - (ox1);
                var distY = (oy2) - (oy1);
                var magSq = distX * distX + distY * distY;
                if (magSq < (elem.collisionRadius + elem2.collisionRadius) * (elem.collisionRadius + elem2.collisionRadius)) {
                    hits.push(elem2);
                }

            });

            if (hits.length > 0 && elem.hit) {
                elem.hit(hits);
            }

        }

    });

}

My function iterates over all images that have the "collision" class. If those elements have a "collidesWith" defined, I get the X and Y coordinates for the center of the image. I'll need these for the collision check. Then I iterate over all the image elements that have the class specified by the "collidesWith" field and get their centers. The collision check starts on line 22. Basically, it makes two circles at the center-points of the images with the specified radii. A collision is detected if the circles overlap at all. If they do, I add that element to the hits array. At the end I call the hit function, passing the array, if there were any hits.

It all worked pretty well, and now I'll have it all ready for the next time I want to add a pointless game to a comic!

Amphibian.com comic for 22 April 2015

Monday, April 20, 2015

Using Your Own Custom Web Fonts

Olde Geoff coude telle a goode tale.
It is the month of April, and you know what that means. Yes! The Canterbury Tales! Geoffrey Chaucer's most famous work of Middle English literature was set in April near the end of the 14th century. I loved reading the Tales as part of my high school literature requirements and have never forgotten them.

As a tribute to Chaucer some 600+ years later, Amphibian.com will be written in the style of the Tales for the next week and a half. It starts out with an unnamed narrator meeting up with a group of frogs in an airport. They're all travelling to the Moscone Center in San Francisco for a conference and agree to tell each other stories to pass the time. In the Canterbury Tales, it was a group of pilgrims travelling to Canterbury. If you've never read Chaucer's original, you can find it here: The Canterbury Tales.

I say all that as an introduction to the real topic of the today's post - using your own custom fonts on web pages via CSS.

I had to do this for the comics to get a font that looked Middle English. The font I'm using is, oddly enough, named Canterbury. You may be familiar with using Google Fonts to add a custom font to web pages, but they don't actually offer one in the Middle English style. That's why I had to do it on my own. It's not hard to do, and is the same method used by Google Fonts and font-based icon utilities such as Font Awesome.

The first thing you need is a font. There are many places on the web to find fonts, but make sure you are adhering to the license agreement. Some are public domain, others you have to pay for, and some are provided under one of the Creative Commons licenses. Here are some popular font sources:

Besides just having a font, you need to have that font 4 different ways. Each browser has its own set of supported formats, so if you want complete functionality across all browsers you'll need to have the font in EOT, SVG, TTF, and WOFF formats. You can usually find fonts in TTF or OTF formats. What if you don't have the rest? There are some free utilities on the web that can convert to the other formats for you. I used Font2Web but Font Squirrel has a similar service that I used once in the past.

Once you have all those font files, you need to define the font in your CSS. You do this with the @font-face declaration. In it, you give the font a family name and specify the URLs for the various file formats. Here is the CSS for the Canterbury font:

@font-face {
    font-family: 'Canterbury';
    src: url('../fonts/Canterbury.eot');
    src: url('../fonts/Canterbury.woff') format('woff'), url('../fonts/Canterbury.ttf') format('truetype'), url('../fonts/Canterbury.svg') format('svg');
    font-weight: normal;
    font-style: normal;
}

Note that if you use relative paths in the URLs, they are relative to the location of your CSS file. I keep my fonts in a directory named fonts which is sibling to my css directory.

Once you have your font defined, you can use it in styles by referencing the font-family name you gave it above.

.olde-text {
    font-family: 'Canterbury';
    text-align: left;
    font-size: 1.3em;
}

As you can see, it's not that hard to use your own custom fonts in web pages. It was easy to make my text use a Middle English font. What's not easy is reading Middle English and understanding what it means. But give it a try anyway in today's comic.

Amphibian.com comic for 20 April 2015

Friday, April 17, 2015

Publish/Subscribe with jQuery

The frog dodgeball thing from Wednesday's comic was probably more fun for me to create than it was to play. Embedding a simple game in a comic, even a SVG/CSS/JavaScript comic, was not the easiest thing to do. But I used some very effective design patterns to make it easier.

Not a Sub, a Pub/Sub
The comic has supported simple animations since the beginning, but for the game to work I needed to add a custom module to just that one comic which could take additional actions when the animation state changed. I certainly didn't want to tightly couple the general-purpose animation code to this one comic, and also I didn't want to duplicate the most of the animation code in this module just to add one feature. Since I may want to do similar things in the future as well, I wanted a solution that would be flexible.

I decided to use the Publish/Subscribe Pattern. A derivative of the Observer Pattern, a Publish/Subscribe model allows me to completely decouple the event generator (my animation code in this case) from any other components that may wish to take action on certain events (the game code).

The Publish/Subscribe pattern has three parts:

  1. the publisher (creates the events)
  2. the subscriber(s) (want to be notified of events)
  3. the controller (takes events from publishers to subscribers).


My animated comic objects will publish events at certain points in their animation cycles. It doesn't matter if no one is subscribed to those events or if 100 other objects are subscribed. The general contract is that the subscriber says to the controller, "call my notify method when event X happens" and the publisher says to the controller, "event X just happened" the controller will pass the message on to every subscriber by calling the notify method. The publisher doesn't have any idea who is subscribed.

Fortunately, jQuery provides the controller. In jQuery-speak, this system is called custom events. Basically, the .trigger(event) method on jQuery objects invokes a controller that notifies any other objects that may be subscribed to that particular event on that object.

Consider the following example.

<!doctype html>

<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Pub/Sub</title>
</head>

<body>

  <p id="publisher">I have something to say.</p>

  <p id="target">Nothing here.</p>

</body>

<script src="https://code.jquery.com/jquery-1.11.2.min.js"></script>

<script>

$(function() {

    // subscribe to events named "myEvent" from #publisher
    $("#publisher").on("myEvent", function(event, data) {

        $("#target").html(data.text);

    });

    // using setTimeout to simulate an asynchronous event
    setTimeout(function() {

        var myData = {
            text: "This is my event text"
        }
        // publish a "myEvent" event, with some custom data
        $("#publisher").trigger("myEvent", [myData]);

    }, 5000);

});

</script>

</html>

As soon as the page is loaded, it sets up a subscriber function to "myEvent" events that may come out of the P element named "publisher." I used setTimeout to simulate an asynchronous event that may happen sometime on your page. When it does, the "publisher" publishes its "myEvent" along with some data. The subscriber function is called, and the P element named "target" changes its contents to be whatever was provided as data.

If you execute this code yourself, you'll see that the text "Nothing here" is replaced by "This is my event text" after 5 seconds.

I used this pattern on IMG tags to have them publish events at certain points in their animation cycles, so I am now able to make comic-specific code that can take special actions on general-purpose animations. All I had to do was add a single line with a call to .trigger() to my animation function! That means comic-cell games will now be even easier for me to create! There will be more!

But not today. It's just a normal comic with a little animation.

Amphibian.com comic for 17 April 2015

Wednesday, April 15, 2015

Sounds Good

Today's comic was a lot of fun to create. If you haven't seen it yet, go there right away. You won't regret it. It's much more entertaining than this blog.

If you're still reading, it means you've either already looked at the comic or you just ignored my advice in the first paragraph. Let's move on.

So the third frame in the comic is a frog dodgeball game. Every time you click (or touch) it launches a ball at the frogs. If they get hit, their agility score goes down. It's really pointless. But still, throwing red balls at frogs as they hop past is strangely entertaining.

There's a lot of good programming topics that came up while I was making it. I added animation event emitters so that I could use a listener pattern for the frogs' paths. I added animation that changes the image of an object as it moves around on the screen. I added collision detection that uses jQuery selectors. All good stuff.

Creative Commons Licensed Sounds
But the one thing I would like to mention here today is where I get the sound effects. The sound the page makes when you successfully hit a frog is the same sound I used in my GitHub Game Off 2015 game entry for when Business Frog gets hit by an apple. I got it and all my other sound effects from Freesound.org.

Previously, I've mentioned how I sometimes get SVG clipart from OpenClipart.org. Freesound is like the same thing, but for sounds. All of the sound effects on Freesound are licensed under one of the Creative Commons license agreements. Many completely free, having been donated to the public domain. Most are licensed by Attribution, which means you just need to give credit to the creator. There are vast amounts of sound effects that are perfect for the kinds of small web-based games that I like to create.

You'll need to create an account in order to download the sounds, but you can listen to them right on the web until you find the perfect one. Unlike with OpenClipart, I'm not really capable of creating any kind of audio files that anyone would want - so I don't upload my own work. But if you do make your own sound effects, by all means share them! The world will be a better place for it!

One final thought. The sound files on Freesound.org tend to come in a variety of formats. Typically I need them in .mp3 or .ogg format for my games. I've found Audacity to be a great tool for my simple audio conversion and editing needs.

Here's another link to that comic, in case you missed it.

Amphibian.com comic for 15 April 2015

Monday, April 13, 2015

Goodbye, GitHub Game Off 2015

And so today the GitHub Game Off 2015 has ended. The last four weeks have been busy, but I'm happy with my entry this year. Even though I didn't get to write a game completely from scratch like I did back in 2013, learning the Crafty framework was worth it.

Learning to use a new framework is good in itself, but what I've really liked about Crafty is that I've found such interesting things while looking at its source code. I wrote last week about how it is able to make read-only fields on JavaScript objects, but here's another neat trick I found.

One feature that Crafty offers is the ability to draw the game entities with either Canvas or the DOM. You can even mix the two in your game, like I did in mine (it was done that way in Octocat Jump originally). All "2D" entities have a .flip() method which, you guessed it, flips the entity's image backwards. I thought I knew how this was done for Canvas entities, but it also works on DOM entities. I had to look in the code to see how the flip was performed.

When I saw it, I said to myself, "Of course! Why didn't I think of that?"

You can flip any element in the DOM using the CSS3 2D transform scale methods. Just set the scale to a negative number.

<div id="flipMe" style="transform: scaleX(-1);">
    this will be backwards
</div>

You can do it programmatically with jQuery just as easily.

$("#flipMe").css("transform", "scaleX(-1)");

I knew you could scale DOM objects this way but it never occurred to me that a scale of -1 on the X or Y axis would just flip the object!

Flipping a comic cell. The one on the right has had a transform of  scaleX(-1) applied.

Just another reason that I love looking in open source code, and you should too! Hopefully GitHub posts a list of all the Game Off 2015 entries soon, so we'll all be able to learn new techniques by looking at other people's code.

You know what else you should love looking at? My frog comics! Here's a link to today's...

Amphibian.com comic for 13 April 2015

Friday, April 10, 2015

Listen to the Spring Peepers

This week I was able to hear one of my favorite sounds again - the Spring Peepers. Not some weird hipster music group, but the small chorus frogs Pseudacris crucifer.

I love listening to the chorus of these tiny amphibians every spring here in central Pennsylvania. When I was a child I lived next to the Tuscarora Creek where it was easy to listen to them every evening. Now I am a bit more removed from a suitable habitat and don't get to hear them nearly as much as I'd like. And they don't seem to last as long as they used to. It seems like I only get to hear them for a week or two in April, although they supposedly will call until June.

If you don't live in the eastern United States you may have never heard these little frogs. Listen to these audio files and hear what you've been missing.

The sound of a single frog: 

The whole chorus of frogs: 

If I hadn't told you they were frogs, you might mistake them for some kind of insect or something. Maybe even a bird, if it called at night. But most birds don't call at night. Only owls.

They might not be spring peepers, but my comic frogs can also entertain you today. For a few minutes at least.

Amphibian.com comic for 10 April 2015



Wednesday, April 8, 2015

ALTER comic DROP MySQL

I've decided to migrate my comic away from MySQL. I have my reasons. Lots of people have reasons.

Some people complain that MySQL isn't truly open source anymore. It's true that it does have closed-source modules now. And Oracle is not exactly forthcoming with test cases or security patches. But these things don't bother me that much, since I'm just looking for a free, easy to use database.

Some people say that MySQL is not standards-compliant. Well, this is not my main reason but certainly a factor. I've been doing SQL for a looong time, and MySQL's is weird. I've always just dealt with it. But it would be nice to not have to think about is this the MySQL way or the normal way when I'm working on something.

Some people say that the performance doesn't scale as well as other RDBMS software. I don't know. I only ever use it for basic, low-performance stuff.

Some people say that MySQL has become stagnant. Ah, this is certainly a factor for me. It seems as though Oracle doesn't have a lot of interest in making MySQL better. And why would they? It completes with their classic RDBMS, which makes them big money. Honestly, up until this point I've just been happy that they haven't killed it off altogether. Some people have forked MySQL, like MariaDB, to move the product forward.

PostgreSQL. I'm going back.
But it's the new features in PostgreSQL that really have me wanting to change. Specifically the native JSON support. Since I store and work with my comic data in JSON, it makes sense to use a database that treats JSON as a first-class data type. I know that many of the popular NoSQL databases do this, but I don't have other use cases that drive me towards a NoSQL solution.

I once used Postgres for all my projects. It was my go-to RDBMS product back around 2001. But then I hopped on the MySQL train with everyone else and rode it to Disillusionment Town. Now I'm heading back.

I'm currently working with the node-postgres client pg to convert my comic. Thanks to my prior design decisions, it is fairly easy to swap one product for another. I use a module I called data.js which encapsulates all the database details. I've swapped it out for a new pg-data.js which implements all the same functions and I'm working through the issues. The Node pg module uses a fairly different design pattern than the mysql module does, particularly for pooled connections. That's really my biggest hurdle.

And now for the comic! They haven't been very deep lately. I've been putting too much time into the GitHub Game Off for the past 2 and half weeks. But I am working on a very interesting set for later in the month.

The Game Off ends Monday! Remember to play my game: http://caseyleonard.com/ggo15!


Amphibian.com comic for 8 April 2015

Monday, April 6, 2015

Cross-Site Scripting (Legitimately)

This weekend I completed one of the major features that I wanted to add to my GitHub Game Off 2015 game - the high scores list. While it may sound mundane, it has one feature that I don't use a whole lot - JSONP.

JSONP, or JSON with Padding, is in my opinion a technique that has a very misleading name. It's really about bypassing the same-origin policy that web browsers use to prevent cross-site scripting hacks. And it works by having the server respond with full JavaScript instead of just a JSON string. The JavaScript is typically a function call with the JSON string directly in the call. I guess that's where the "padding" part of the names comes from - the data is "padded" with the function call. Odd if you ask me, but whatever.

Here's a basic example. For it to work, the client defines a function to process the data it wants to request from the server.

function processData(data) {
    console.log(data); // or do something more useful, whatever
}

Now the request can be made. By injecting a <script> tag into the DOM, the browser will make a remote call to any server you want - it doesn't have to be the same as the one serving the original page. As part of the URL in that script tag, the name of the local function is typically passed as part of the query string. The script tag would look like this...

<script type="application/javascript"
     src="http://www.example.com/giveMeData?callback=processData"></script>

On the server, the data is then prepared for the response. Instead of just sending a JSON string, the server creates a string response that looks like a regular JavaScript function call. The function being called is the one specified in the script tag URL, and the JSON data is directly in the call. This is what the server response text looks like:

processData({"field1":"value1","field2":"value2"});

The browser treats the response just the same as any static JavaScript file requested from a server and executes it. Your data processing function gets called, you get the data, and everyone is happy.

For this to work, the server obviously has to be set up for this. You can't just pass a "callback" query string parameter to any random web server and expect a usable response. This pattern is most useful for creators of data services who want to make their product available on other peoples' web pages. Like the Facebook buttons, for example.

I found myself wanting to use this pattern because I put my game on caseyleonard.com, but that site just serves static content via Nginx. To maintain the high scores web service, I'd have to run an application somewhere else. Without the JSONP pattern, my game wouldn't be able to send and receive high score data. It was also useful to allow me to test updates to my game locally and still access the high scores on a remote server.

As it turns out, this pattern is common enough that jQuery includes some utilities to make it easier. They have a really nice API that makes performing a JSONP request almost the same as a "normal" AJAX request. Here's an example from my game code.

function processHighScores(data) {
 
    var $tbl = $("#scoreboard");
    for(var i=0; i < data.length; i++) {
     var n = data[i].name;
     var s = data[i].score;
        var $row = ("<tr><td>" + n + "</td><td>" + s + "</td></tr>");
        $tbl.append($row);
    }

}

function populateHighScores() {

    $.ajax({
        type: "GET",
        url: "http://amphibian.com/scores",
        jsonpCallback: "processHighScores",
        contentType: "application/json",
        dataType: "jsonp",
        success: function(json) {
            console.log(json); // don't really need this
        },
        error: function(e) {
            console.log(e.message);
        }
    }); 
}

The processHighScores function above is the one that receives the data from the JSONP request. The populateHighScores function makes the call. As you can see, jQuery makes it easy by allowing me to specify just the URL and then the name of the JSONP callback as another field (line 18). When it builds the script tag for me, it automatically adds the "?callback=processHighScores" to the end of the URL.

I wrote the high scores application using Node. All of the routes I set up are designed for JSONP callbacks. In each one, the response is built as a string using the callback parameter. One thing to note is that the proper content type for a JSONP response is "application/javascript" not "application/json". It is legitimate JavaScript, pretty much like you'd have in a static .js file. The only difference is that you are generating it dynamically. Here is the server-side route that handles the client request from above:

app.get("/scores", function(req, res, next) {

    var fn = req.query.callback;

    var data = JSON.stringify(scores);

    var js = fn + "(" + data + ");";

    res.setHeader("Content-Type", "application/javascript");
    res.send(js);

});

Dynamically generating JavaScript based on URL parameters in the request is nothing new. I was doing it back in the '90's as part of ASP web applications. But back then I never thought about it as a way to bypass the same-origin policy. I'm not even sure I even knew what the same-origin policy was back then. It was a simpler time...back when I drew these frogs by hand.

Amphibian.com comic for 6 April 2015

Friday, April 3, 2015

Stay Out Of My Objects!

While working on my game for the GitHub Game Off this week, I was looking in the code for Crafty.js. Crafty is the JavaScript game engine used by the game I forked for the contest, and I was curious about how it did some things. I noticed some JavaScript features it in that I don't see used very often and I thought it was interesting enough to share.

Have you ever wanted to make a field in a JavaScript object read-only? Consider this example:

var o = {
    answer: 42
};

console.log(o.answer); // prints 42
o.answer = 84;
console.log(o.answer); // prints 84

Typically, you might not care that you can reassign answer to some other value. Perfectly normal, right? Sure. But what if you were making a library that you want to share and be used by other people in other projects? You might not want them accidentally (or on purpose) messing with your object internals.

So try this:

var o = {};

Object.defineProperty(o, 'answer', {
    value: 42,
    writable: false
});

console.log(o.answer); // prints 42
o.answer = 84;
console.log(o.answer); // prints 42 again! ha!

Now you'll see that the answer of 42 prints out both times. The reassignment had no effect. You've created a read-only field on the object!

The JavaScript function Object.defineProperty gives you much more control over the properties on your objects. In addition to writable, you can also specify if a field should be enumerable. Being enumerable means that the property shows up during property enumeration of the object. Look at this example:

var o = {};

Object.defineProperty(o, "answer", {
    value: 42,
    writable: false,
    enumerable: false
});

Object.defineProperty(o, "whatnot", {
    value: 33.3,
    enumerable: true
});

Object.defineProperty(o, "here", {
    value: "there",
    enumerable: true
});

for (var i in o) {
    console.log(i);
}

The example above will output "whatnot" and "here" but not "answer." The answer field does still show up if you console.log(o) in modern Chrome, however. It will also be visible in the debugger, so this is more about hiding things from other code that it is from people.

The answer can be seen here, but not enumerated.

There's another neat trick you can do with Object.defineProperty, which is create getter and setter functions. Instead of just getting or setting a field's value in your code, defining a custom getter or setter means that a function is invoked which can take other actions. Here is an example:

var o = {
    theAnswer: 42,
    answersGiven: 0
};

Object.defineProperty(o, "answer", {
    get: function() {
        console.log("giving an answer");
        this.answersGiven++;
        return this.theAnswer; 
    },
    set: function(a) {
        console.log("changing the answer!");
        this.theAnswer = a * 2;
    }
});

var myAnswer = o.answer;
console.log(myAnswer); // prints 42

o.answer = 15; // changes the answer, but not to 15!

var myNextAnswer = o.answer;
console.log(myNextAnswer); // prints 30

console.log(o.answersGiven); // prints 2

In the code above, the special getter function is called and an internal counter is incremented each time o.answer is invoked. Similarly, assigning o.answer to a value calls the setter function which has its own ideas about what value should really be set.

I don't know if these things will ever be useful to you, but at the very least I hope you found them as interesting as I did. Always look in the code for open-source libraries! You never know what cool tricks you'll see in them.

Remember to try out my game at http://caseyleonard.com/ggo15 and give me some feedback. I still have over a week left to work on it!

There's one thing that bothers me now, though. Why is there a w in answer?

Amphibian.com comic for 3 April 2015

Wednesday, April 1, 2015

April Fools!

Today is the first day of April, but I have no tricks or hoaxes here in my blog. I do have one on my webcomic, however.

I have too many things going on right now, which troubles me a bit. I'm having difficulty making sure the comics get done along with my GitHub Game Off 2015 entry while at the same time making sure I keep my day job and not neglect my family.

Here are my latest updates.

Amphibian.com April Fools' Day


I had to do something foolish for the 1 April comic. It's a technology company tradition to release phony products, absurd announcements, and generally silly ideas. The frogs had to join in. So I replaced the comics with text today - to finally make the site compatible with Internet Explorer 5. But of course, that's not really possible. I used the jQuery plugin Typed.js to create the manually-typing-the-comic-transcript-in-a-terminal effect that graces the site today.

In general, I liked Typed.js better than the alternatives but it was not without flaws. I was a little disappointed that I couldn't get the cursor to work the way I wanted, and you can see parts of the HTML tags appear briefly as it types. Still, I like how it turned out.

1980's terminal? Or today's Amphibian.com?

Game Off 2015 Jumping


Over the last few days, I also found a couple of minutes to add a critical path bonus to the frog jumping game. Since the game is supposed to represent Business Frog jumping through a Gantt chart, I decided that the red platforms should represent the critical path. Hitting several of them in a row results in an additional bonus multiplier at the end of the game. Jump on every red platform in the order in which they appear and you can get really crazy multipliers which lead to really crazy scores.

Critical Path!
My wife, who has never been subjected to a Gantt chart, constantly reminds me that she wants the high scores to work at the end of the game. I'm going to try to get to that this weekend, but it means adding a server-side component. I'll probably try to make something really lightweight using Node. She also suggests I replace the hamburgers with coffee. I'll probably do that too. I still have to fix the frog jumping sprites too, but the game is coming along well. The competition ends on April 13th.

Unfortunately that's all I have to talk about today. And there's no picture of a comic at the bottom here, because the comic has to picture today. But I'm sure there are plenty of other fun things to find on the Internet.