stephenwoods.net » Stephen http://stephenwoods.net !important Thu, 28 Jul 2011 21:52:28 +0000 en hourly 1 http://wordpress.org/?v=3.2.1 Making a histogram with canvashttp://stephenwoods.net/2011/07/28/making-a-histogram-with-canvas/ http://stephenwoods.net/2011/07/28/making-a-histogram-with-canvas/#comments Thu, 28 Jul 2011 21:52:28 +0000 Stephen http://stephenwoods.net/?p=192 A histogram is a very common tool used for editing photos, in photoshop and lightroom it gives users a quick view of how their photo’s values are distributed (some digital cameras also display a histogram).

The image histogram actually just displays a graph of how many pixels with each value appear, usually split into all three colors. Using the canvas imageData method its very easy to create a histogram. Basically its a matter of looping through the pixels, keeping track of how many appear at each value and then rendering out a graph.

I did it here. (only tested in webkit). In this example I never actually display a canvas, I use it to extract image data and then pass the dataUrl to image nodes. Canvas is awesome.

]]>
http://stephenwoods.net/2011/07/28/making-a-histogram-with-canvas/feed/ 0
Less bullshit, more hackinghttp://stephenwoods.net/2011/07/20/less-bullshit-more-hacking/ http://stephenwoods.net/2011/07/20/less-bullshit-more-hacking/#comments Wed, 20 Jul 2011 17:23:42 +0000 Stephen http://stephenwoods.net/?p=182 Under the Gate

One time at a boat show I met sailboat designer Tom Wylie, famous for the Wyliecat, an unusual boat design. I asked him what the theory behind the design was. Was it faster? More efficient? He answered: “less bullshit. more sailing”. Which is to say that it may not be the fastest or best (or maybe it is) but it doesn’t matter, because the point is that there is a lot less work to sail the boat. Easier to reef, easier to tack, etc.

The point of all this is that aside from possible real, excellent uses of node.js I love hacking on it because it delivers the same thing for me. I can throw together a proof of concept really quickly, because there is no bullshit. No server config, no incomprehensible documentation. It uses the same language I use every day at work, so no context switching. If I have an idea I can get it running fast, easily and with less fuss. Less bullshit, more hacking.

]]>
http://stephenwoods.net/2011/07/20/less-bullshit-more-hacking/feed/ 1
Flash? We don’t need no flash! I don’t have to show you any stinkin’ flash!http://stephenwoods.net/2010/10/26/flash-we-dont-need-no-flash-i-dont-have-to-show-you-any-stinkin-flash/ http://stephenwoods.net/2010/10/26/flash-we-dont-need-no-flash-i-dont-have-to-show-you-any-stinkin-flash/#comments Tue, 26 Oct 2010 17:18:23 +0000 Stephen http://stephenwoods.net/?p=180 This week I overdid an on-site marketing banner. Rather than a bunch of images, or god-forbid a flash animation, I through this together with CSS and teeny tiny bit of javascript. The clouds and buttons are pure html/css, as is the animation. Animation is only visible in Chrome/Safari/FF4, but everything degrades in a nice way for other browsers. (IE < gets a fallback gif.

Here it is, more or less.

]]>
http://stephenwoods.net/2010/10/26/flash-we-dont-need-no-flash-i-dont-have-to-show-you-any-stinkin-flash/feed/ 1
From the archiveshttp://stephenwoods.net/2010/08/20/from-the-archives/ http://stephenwoods.net/2010/08/20/from-the-archives/#comments Fri, 20 Aug 2010 18:04:51 +0000 Stephen http://stephenwoods.net/?p=176 This is the earliest JS written by me I could find on the internet archive (from my student web site at usc, circa 1998):

function gotothingy(selection) {
var selectedplace, tempIndex
tempIndex = selection.selectedIndex
selectedplace=selection.options[tempIndex].value
parent.content.location.href = selectedplace
}

Not as bad I thought it would be.

]]>
http://stephenwoods.net/2010/08/20/from-the-archives/feed/ 0
10k?http://stephenwoods.net/2010/07/30/10k/ http://stephenwoods.net/2010/07/30/10k/#comments Fri, 30 Jul 2010 17:52:20 +0000 Stephen http://stephenwoods.net/?p=170 So these guys have a contest something like the classic 5k contest. Except the rules are stupid lenient (library and FONTS don’t count). The whole fun of the 5k contest is that the limitations are so strict it causes some real creativity.

Worst still, the first entry, by this guy, is 141.04kb with 12 requests and just shows ‘hello world’.

So, because I was up at 6 with the baby this morning I re-did the example (without pretty fonts) in under 5kb and one request. (actually only 2.2k gziped)

Doesn’t actually meet the rules, because css transitions don’t work in IE 9. Also I kind of cheated by making a document that isn’t technically valid and using a much crappier image. And I double cheated by requiring Firefox 4, chrome or safari.

]]>
http://stephenwoods.net/2010/07/30/10k/feed/ 0
New Jobhttp://stephenwoods.net/2010/04/16/new-job/ http://stephenwoods.net/2010/04/16/new-job/#comments Fri, 16 Apr 2010 23:47:55 +0000 Stephen http://stephenwoods.net/2010/04/16/new-job/ Hey all. I work at flickr now.

]]>
http://stephenwoods.net/2010/04/16/new-job/feed/ 3
I’m just a simple hyperchicken from a backwood asteroid…http://stephenwoods.net/2010/03/09/im-just-a-simple-hyperchicken-from-a-backwood-asteroid/ http://stephenwoods.net/2010/03/09/im-just-a-simple-hyperchicken-from-a-backwood-asteroid/#comments Tue, 09 Mar 2010 07:51:54 +0000 Stephen http://stephenwoods.net/2010/03/09/im-just-a-simple-hyperchicken-from-a-backwood-asteroid/ …but I don’t think ORM is very useful. I would say that for hacking together a very simple crud interface in rails/django/whatever its really nice. But in the end, if your app has a database you ought to be writing your own queries.

UPDATE: This is a great answer to this post.

]]>
http://stephenwoods.net/2010/03/09/im-just-a-simple-hyperchicken-from-a-backwood-asteroid/feed/ 0
Run-time Code Generationhttp://stephenwoods.net/2010/03/03/run-time-code-generation/ http://stephenwoods.net/2010/03/03/run-time-code-generation/#comments Wed, 03 Mar 2010 19:30:55 +0000 Stephen http://stephenwoods.net/?p=159 I was speaking with my colleague Matt about refactoring Javascript. One of the most common “smells” in code, or at least in my code, is duplication. A really common one for me to see several event handlers or callback functions that all do the same thing, but in ever so slightly different cases. This came up most recently when I was hacking together a routing module for a node.js project.

Because js is functional I had the idea of routes actually being an array of functions that took a request object and returned a route object. Pretty powerful, you could have routing based on anything, not just urls. Anyway, what actually ended up happening was this:

var routes = [

    /* / */
    function(request){
        if(/^\/$/.test(url.parse(request.url).pathname)){
            return {
                controller:'index',
                action:'index',
                data:{}
            };
        }else{
            return false;
        }
    },

    /* /about */
    function(request){
        if(/^\/about$/.test(url.parse(request.url).pathname)){
            return {
                controller:'index',
                action:'about',
                data:{}
            };
        }else{
            return false;
        }
    },

    /* /news/story/[0-9] */
    function(request){
        var test = /^\/news\/story\/([0-9]+)$/
                    .exec(url.parse(request.url).pathname);

        if(test){
            return {
                controller:'news',
                action:'showStory',
                data:{
                    storyId:test[1]
                }
            };
        }else{
            return false;
        }
    }
];

As you can see, I’ve written the same function twice at the top, more or less. Now there are a couple of ways to refactor this. The obvious one of course is to have the function which acts on this array check if the input is an object or a function and act accordingly, so that the route could just be an object with a regex and info about the action and controller. I decided not to go with this option because I like to avoid code with lots of switching and cases if possible, just running the function seems much cleaner to me.

So instead I created a function that would create the most common case functions. That way I could write my routes like this:

var routes = [

    /* / */
    r(/^\/$/, 'index', 'index'),

    /* /about */
    r(/^\/about$/, 'index', 'about', {foo:'bar'}),

    /* /news/story/[0-9] */
    function(request){
        var test = /^\/news\/story\/([0-9]+)$/
                    .exec(url.parse(request.url).pathname);

        if(test){
            return {
                controller:'news',
                action:'showStory',
                data:{
                    storyId:test[1]
                }
            };
        }else{
            return false;
        }
    }
];

Much cleaner, just as flexible, and to the caller it looks exactly the same, because the function ‘r’ returns a function that looks like the one I created for the news story, like so (I also added the feature that query variables would be added to the data object):

function r(regex, controller, action, data){
    var exp = regex,
    d=data || false,
    ret = {
        controller:controller,
        action:action || 'index'
    };

    return function(request){
        var uri = url.parse(request.url, true);
        if(exp.test(uri.pathname)){

            //get the query string and add it to the data
            var retData = uri.query || {};
            if(d){
                for(var i in d){
                    retData[i] = d[i];
                }
            }

            ret.data = retData;

            return ret;

        }else{
            return false;
        }
    };
};
]]>
http://stephenwoods.net/2010/03/03/run-time-code-generation/feed/ 0
Timepicker on the YUI bloghttp://stephenwoods.net/2010/03/03/timepicker-on-the-yui-blog/ http://stephenwoods.net/2010/03/03/timepicker-on-the-yui-blog/#comments Wed, 03 Mar 2010 18:54:39 +0000 Stephen http://stephenwoods.net/2010/03/03/timepicker-on-the-yui-blog/ I have a post up on the YUI blog. Check it out.

]]>
http://stephenwoods.net/2010/03/03/timepicker-on-the-yui-blog/feed/ 0
Automatically Erase Data from your iPhonehttp://stephenwoods.net/2010/02/23/iphone-security-basics/ http://stephenwoods.net/2010/02/23/iphone-security-basics/#comments Tue, 23 Feb 2010 19:14:22 +0000 Stephen http://stephenwoods.net/?p=151 (This is in response to the rash of iphone thefts)

People like to steal iphones. Its a fact of life. For the most part they just want to sell the phone without your sim card or your data. However, if you are like me you keep a lot of stuff on your phone…a contact list of course, but more importantly you keep your email on it. Also of course a thief could use it to call their best friend far away for free. To prevent this phones have always had the feature of a passcode, which you should be using already on your iphone. At some point in the recent past apple added an even more useful feature: you can set it so that the phone erases itself after 10 incorrect passcode entries.

To enable this setting follow these steps:

Go to general settings:
step1

Click on “Passcode Lock”
step2

Enter a passcode you won’t forget, then set “Erase Data” to on.
Turn on Erase Data

Then you should be pretty much only out an iphone when it gets stolen. Still sucks, but not as bad.

]]>
http://stephenwoods.net/2010/02/23/iphone-security-basics/feed/ 0