2012-04-03 Walkstation

The finished product

Inspired by Neal Stephenson's REAMDE and reinforced by "Not Invented Here"'s http://notinventedhe.re/on/2012-1-17/regarding/Walkstation, I decided that a treadmill desk would make the perfect addition to my home office. So, armed with a garage full of underutilized tools and Craigslist, I set to work.

I had found a 48" round oak countertop on Craigslist about a year ago for another project that never quite came to fruition, so I was good to start with that. So my next step was to find a treadmill. I began by posting an ad for anyone wanting to get rid of a used treadmill for about $50 (or less). I got a few hits, but I guess that "you get what you pay for" hold true. I ended up with a $20 treadmill with some structural damage that I was confident that I could fix. Once I got the housing off and saw all the broken welds, I realized that it just wasn't worth it. So, back to Craigslist -- but this time anticipating to pay a bit more. So, this time, I just looked for what people were selling, and I ended up finding exactly what I wanted -- only $115 and 15 miles away.

So, I got it home and started mentally (and, soon after, actually) disassembling it. The control panel would come off pretty easily, although there was no way to unplug it -- the cables were fastened to the control boards at the motor and at the controls. So, it just kind of hung there. I then removed all of the plastic cup-holder segments, and also the fairly-heavy-duty metal back panel. Then, it came time to attach the table top. This fully-circular table top was a bit unwieldy, so, I cut about a 1ft segment off of what would become the back. Then I moved on to figuring out the ideal placement on top of my now-naked-looking treadmill. I underestimated how much work this would actually be, and probably should have just called someone to help. But I am nothing if not stubborn as hell, so I just muscled through it.

The control panel that originally attached to the vertical supports was at an angle. Therefore, the vertical supports had no reason to have a top surface that was conveniently parallel to the ground. This 45° slope was going to cause me some problems, since I was going to have to rig up a bracket to attach the desk top at its highest point. For this, I ended up getting some hinges and attaching them to the metal supports and the table top. This worked out pretty well, since I could either flip it up vertically (which I anticipated needing to do to get it in the house) or lay it down the slope of the handles of the treadmill while I was working on other parts. So, now for the trickiest part of the project: bracing the front of the desk up to being level with the ground (and being strong enough to hold 2  23" widescreen monitors).

I went down to my local Ace Hardware and after some chatting with the sales associates, ended up with 2 fairly thick angle irons and a decent handful of self-tapping sheet metal screws. Oh, and a hack saw. I proceeded to cut off a 1 1/2" segment from each side of the angle irons, bent it down, and those would be my cross braces for the front of the desk. So, I drilled the holes into the vertical supports of the treadmill, angled these braces as close as I could get to being positioned as I had envisioned them, and fastened them in place. They held remarkably well. So, I then taped two levels to the top of the desk, got it as level as I could, and marked the screw holes I would need to attach the braces to the underside of the table. So, I rigged up some 2"x4"s to hold it in place while my hands were otherwise occupied with drills and such, and it came together. Although the table was still not as sturdy from front-to back as I would have liked.

Fortunately, from my first treadmill, I had a long piece of steel that was appropriately-sized for me to attach to the underside of the tabletop. This shored up the surface just as I had hoped.

I spent the next few evenings sanding and staining the top. It came out really well, and I'm hoping that the polyurethane will protected it from all of the computer equipment that I will have sitting on top of it for the foreseeable future. The control panel was still hanging there, but if I was ever hoping to get it through the doors into the house, I would have to rig up something when I got it in place. So, after finally calling up a neighbor to help me out, we detatched the angle braces, flipped up the table top, and moved it into the house last night. Once I was sure it was where I wanted it to live for as long as I plan to own this new piece of productivity/workout equipment, I took the fairly-heavy-duty metal back panel, attached it to the underside of the now rather-inaccessible handle bars, and mounted the control panel back to it. Glad I had some self-tapping screws left over.

So, there it is. All-in-all, about a 10 hour job, about $160 in parts and equipment, and spread over a 3 week period (for no other reason than having other stuff to do). And, this entire blog post was written while walking on it. I guess the only problem that I have is that the desk is a bit tall for typing, so I'll probably mount a simple keyboard and mouse tray for it. Overall, I'm very happy with it, and I encourage all mechanically-inclined people who spend significant time in front of a computer to do it. It's amazing how easy it is to forget that you're walking at 1.5 mph while your brain is otherwise engaged.

Control panel removed Cutting the angle irons First cross brace attached to top Both cross braces attached Additional under-desk support Still dirty, but set up in the office

2012-03-06 Engineering Egos

Recently, I've been giving a lot of thought into how software developers and engineers react to criticisms, either about the work that they're doing or the work they've already finished. Of course, I'm talking about myself too. We developers have a lot invested in the product that we build -- both intellectually and emotionally. And why shouldn't we? The lines of code that we write or the look of that fancy new website... well, that's art to us. To the rest of the world, it's just something that "works" and doesn't need to be examined or scrutinized, but the fact is, we've agonized over every variable declaration, design pattern, and technology choice. We've ruined weekends and nights because of that weird "code smell" that we couldn't quite put our finger on. But what we ended up with is something to be proud of -- at least in our eyes.

So maybe that helps us to understand why when our code is questioned or criticized, or when our application is called out as "obsolete", we tend to take it a bit personally. That's okay. We have egos, and if we didn't, we would be much less effective at our jobs. Just as a painter's strokes are physical representations of what occurred in his mind's eye, the logic that drives our application is a direct manifestation of our thought processes. Not to put too fine a point on it, but it's an extension of us. Now I'm not saying that being invested in our work is a bad thing. I'm merely stating that we need to keep our egotistical tendencies in check. When our code comes under scrutiny, attack, or whatever the case may be, we need to learn to not take it to be a criticism of ourselves. Yes, it sounds ridiculous. But we all do it.

Of course, it's not enough that we recognize the reasons behind the way we react when our architectural decisions are questioned or when that snazzy new module you poured your last 72 sleepless hours into comes under the magnifying glass. We must also take into consideration that our team members, employees, and, yes, bosses are going to be in the same position as us. So, how do you tell these people the way you really feel about what they built? Well, It's far too easy to jump in and start throwing around "wrong" and "makes no sense" and "how did this ever work?". Stop. Stop trying to interpret the code, and start trying to interpret the programmer. The way the code is organized, the way the data is structured, and even the way conditionals are ordered all speak volumes to the way the developer intended for the program to execute -- even if you do find a line or a section that is "wrong". And what's the easiest way to understand how that developer thinks? Ask them. Don't have them walk you through their code (you can do that yourself... there's nothing that you're going to learn about the code or the engineer from that), have them walk you through their problem-solving process, or even the background behind the problem they set out to solve. Chances are, you'll be able to draw certain parallels and contrasts to how you personally would have approached it, and that's a great thing to push to that yet unallocated portion of your own memory for quick reference when you're later hunting through their code. But more importantly, you've allowed that person to exercise their own ego a bit and teach you. That's when you've got an opportunity to take what you've learned and do your job more effectively -- without making anyone else feel like you're there marking your territory.

I'll end with this: there was a fantastic engineer that I worked with a couple years back who, consciously or unconsciously, had mastered the art of understanding the developer behind the code. This particular developer was a sort of virtuoso at not only mimicking the styles set forth by the original authors, but also in following their trains of thought. I remember diving into that code base once and being able to tell from style alone who worked on what sections (as clear as if they had written "so-and-so was here" in their comments); but the amazing thing is that this certain developer could blend in and integrate seamlessly into what was laid out before him. While this person was clearly a talented developer, he [coincidentally] had his ego in check far better than any other engineer that I've ever worked with.

Maybe we should strive to be that guy for a change?

2011-05-15 Basic scratch MVC using node.js

Update: I have tweaked the interface a bit to allow for the encapsulation of Routes and Routers, and also added the ability to serve up static files. I have set up a GitHub account to host these various projects (see list on right). I hope that this is able to help some people out. Please feel free to comment (or even better, contribute)

I've personally found that the best way to truly dive into any web programming environment is to build a basic MVC framework from scratch. Yes, it's true that there are most likely MVC frameworks out there already, but building one from scratch presents the programmer with a an extensive cross-section of problems to solve. These include, but are not limited to:

  • Request parameter parsing and validation
  • Error handling
  • Code organization
  • Interface design
  • Class autoloading

So, I dove back into node.js tonight to see what I could throw together as a basic MVC framework. Since it's always a good idea to start writing code with the interface in mind, here's what I came up with for setting up your routes:

var mvc = require('./mvc.js');
var Router = mvc.Router;
var Routes = mvc.Routes;

var http = require('http');

Routes
    .add("/MySite/{controller}/{action}", function(data) { return this.exec(data.controller, data.action, data._qs);})
    .add("/{controller}/{action}", function(data) { return this.exec(data.controller, data.action, data._qs); })
    .addStaticDirectory("/includes")
    .addStaticDirectory("/content")
    .setDefault("/", function(data) { return this.exec("Default","Init", data._qs); });

http.createServer(function (req, res) {

    var router = Routes.getRouter(req, res);
        router.dispatch(req.url);

    res.end();


}).listen(1337, "127.0.0.1");

As you can see, once we have our webserver set up, we can start defining the patterns of the different URLs that will be accessing our site. You can use any placeholder terms you want (although I'd probably recommend {controller} and {action}, since those are pretty standardized). From there, the values that are extracted out of that URL (passed through as 'data'), can be passed along to the 'exec' method. Now, let's take a look at our mvc.js file:

/*
MVC ClassLoader
*/

var ClassLoader = (function() {

    var self = this;
    var CONTROLLER_PATH = "./Controllers/";
    var MODEL_PATH = "./Models/";
    var VIEW_PATH = "./Views/";
    var NODE_EXT = ".js";
    var DEFAULT_CONTENT_TYPE = 'text/html';

    var attachControllerMethods = function(className, instance) {
        instance._className = className;
        for(var name in BaseController) {
            instance[name] = BaseController[name];
        }
    };

    return {
        CONTROLLER_PATH : CONTROLLER_PATH,
        MODEL_PATH : MODEL_PATH,
        VIEW_PATH : VIEW_PATH,
        NODE_EXT : NODE_EXT,
        DEFAULT_CONTENT_TYPE : DEFAULT_CONTENT_TYPE,
        get : function(className, request, response) {
            try {
                var fileName = className + "Controller" + NODE_EXT;
                var constructor = require(CONTROLLER_PATH + fileName);
                    constructor = constructor[className+"Controller"];

                var instance = new constructor();
                attachControllerMethods(className, instance);
                instance.setServerVars(request, response);

                return instance;

            } catch(e) {
                console.log("Failed to open controller " + className);
            }

            return null;
        }
    };
})();

exports.ClassLoader = ClassLoader;


/*
MVC Base Controller
*/
var BaseController = {

    setServerVars : function(request, response) {

        this.Request = request;
        this.Response = response;
    },

    getModelConstructor : function(modelName) {
        var modelName = modelName || this._className;
        var filePath = ClassLoader.MODEL_PATH + modelName + ClassLoader.NODE_EXT;
        try {
            var constructor = require(filePath)[modelName];
            return constructor;
        } catch(e) { console.log("Failed to load model."); }
        return null;
    },

    getModelInstance : function(modelName) {
        var constructor = this.getModelConstructor(modelName);
        return constructor ? new constructor() : null;
    },

    getViewConstructor : function(viewName) {
        var viewName = viewName || this._className;
        var filePath = ClassLoader.VIEW_PATH + viewName + ClassLoader.NODE_EXT;
        try {
            var constructor = require(filePath)[viewName];
            this.Response.setHeader("Content-Type", constructor.ContentType || ClassLoader.DEFAULT_CONTENT_TYPE);
            return constructor;
        } catch(e) { console.log("Failed to load view"); }
        return null;
    },

    getViewInstance : function(viewName) {
        var constructor = this.getViewConstructor(viewName);
        return constructor ? new constructor() : null;
    }
}

BaseController.getModel = BaseController.getModelInstance;
BaseController.getView = BaseController.getViewInstance;

/*
MVC Routes
*/

var Routes = exports.Routes = new (function() {

    var routes = {},
        defaultRoutePattern = "/",
        defaultRouteHandler = function() {},
        parsedPatternData = {},
        staticPaths = [];

    this.add = function(pattern, func) {
        routes[pattern] = func;
        return this;
    };

    this.setDefault = function(pattern, func) {
        defaultRoutePattern = pattern;
        defaultRouteHandler = func;
        return this;
    };

    this.addStaticDirectory = function(path) {
        path = path || "";
        if(path.substr(-1) != "/") { path+="/"; }
        staticPaths.push(path);

        return this;
    };

    this.get = function() { return routes; };
    this.getStaticPaths = function() { return staticPaths; };
    this.getDefault = function() {
        return {
            pattern : defaultRoutePattern,
            func : defaultRouteHandler
        };
    };

    this.parseQueryString = function(qs) {
        var nv = {};
        var parts = (qs || "").split('&');
        var eqPos;
        for(var i=0; i < parts.length; i++) {
            eqPos = parts[i].indexOf('=');
            if(!~eqPos) { continue; }
            nv[parts[i].substr(0,eqPos)] = parts[i].substr(eqPos+1);
        }
        return nv;
    };

    this.parsePattern = function(pattern, url) {

        var patternData;
        if(!(patternData = parsedPatternData[pattern])) {

            var params = [];
            var result = pattern.replace(/\{(.*?)\}/g, function(match, sub1, pos, whole) {
                params.push(sub1);
                return "([^\/]+?)";
            });

            result = "^"+result+"(\\/?\$|\\/?\\?.*$)";
               parsedPatternData[pattern] = patternData = {
                regex : (new RegExp(result)),
                params : params
            };
        }



        var counter = 0,
            urlParts = null,
            regex = patternData.regex,
            params = patternData.params;

        url.replace(regex, function(match) {
            urlParts = {};
            var i=0;
            for(; i < params.length; i++) {
            urlParts[params[i]] = arguments[i+1];
            }

            urlParts._qs = Routes.parseQueryString((arguments[i+1] || "").replace(/^\/?\??/,""));
        });

        return urlParts;
    };

});

/*
MVC Router
*/

var StaticResourceHandler = new function() {

    var contentTypes = {
        '.json': 'application/json',
        '.js': 'application/javascript',
        '.gif': 'image/gif',
        '.jpg': 'image/jpeg',
        '.jpeg': 'image/jpeg',
        '.png': 'image/png',
        '.svg': 'image/svg+xml',
        '.css': 'text/css',
        '.html': 'text/html',
        '.txt': 'text/plain',
        '.xml': 'text/xml'
    };

    this.serve = function(path, resp) {
        path = path || "";
        var ext = path.substr(-4);
        if(!(ext in contentTypes)) {
            resp.statusCode = 500;
            resp.end();
            return false;
        }

        resp.writeHead(200, { 'Content-Type' : contentTypes[ext] });
        resp.write(require('fs').readFileSync(path));
        return true;
    };

};

var Router = exports.Router = function() {

    var self = this,
        request = null,
        response = null;

    this.exec = function(controller, method, data) {
        var instance = ClassLoader.get(controller, request, response);
        if(!instance) { return false; }

        if(instance[method]) {
            instance[method](data);
        } else if(instance.onActionUnavailable) {
            instance.onActionUnavailable(method, data);
        } else {
            throw new Error("Action Not Found!");
        }

        return true;
    };

    this.init = function(req, res) {
        request = req;
        response = res;
    };

    this.dispatch = function(url) {
        var url = url || req.url,
            result,
            verdict,
            routes = Routes.get(),
            staticPaths = Routes.getStaticPaths();

        //check static paths first
        var verdict;
        for(var i=0; i < staticPaths.length; i++) {
            if(url.indexOf(staticPaths[i]) == 0) {
                verdict = StaticResourceHandler.serve("."+url, response);
                if(verdict) { return };
            }
        }

        for(var pattern in routes) {
            // test the pattern
            result = Routes.parsePattern(pattern, url);

            // if the pattern was successfully matched...
            if(result) {
                //call the handler for that route, which will inevitably call 'exec'
                // if 'exec' was able to open the controller, the verdict will be 'true'
                // in which case we need to stop processing more controllers.
                // if the verdict is false, we should continue to find a route that works.
                verdict = routes[pattern].call(self, result);
                if(verdict) { return; }
            }
        }

        var defaultRoute = Routes.getDefault();
        result = Routes.parsePattern(defaultRoute.pattern, url);
        return result && defaultRoute.func.call(self,result);
    };


};

Routes.getRouter = function(req, res) {
    var r = new Router();
        r.init(req, res);
    return r;
}

First, let's talk about the Routes and Router. The 'Routes' object is a collection of all these url patterns the programmer has defined for the application. Encapsulated in this object are also the methods used for parsing out the regular expressions and url parameters. On the Router object, the 'dispatch' method is the one that will do the heavy-lifting upfront. This is going to utilize the Routes object and do its decision-making based on the output (mainly, "check each route and see if it matched the pattern"). Once the Router has determined what controller to load up, the ClassLoader jumps in to do its job.

The ClassLoader is configurable based on how your code base is organized and the file extensions you are using for your node.js files. Relative to the mvc.js file, I created three folders in the same directory:

- /mvc.js
- /Controllers/
- /Views/
- /Models/

I chose the convention that all files in the 'Controllers' directory would be of the format SomeNameController.js, and the objects that those files contained would be named similarly (SomeNameController.js). Views and Models do not need to follow that convention. Once the controller is instantiated, the "BaseController" methods are attached to the object (getModelConstructor(), getModelInstance(), getModel(), getViewConstructor(), getViewInstance(), getView()).

Soon to come... an MVC framework built in python on top of CherryPy!

2011-04-21 PHP Statics

PHP's use of static properties and methods not only require jedi-like mind tricks to grok, let's face it: they're just wrong. So, this post today is to help lay it out there. Let's take this first example:

class MyClass {

    /* helper methods */
    public static function helper1() {
        echo "Calling My Helper 1\n";
    }

    public static function helper2() {
        echo "Calling My Helper 2\n";
    }

    /* instance methods */
    public function instanceMethod1() {
        echo "Calling Instance Method 1\n";
    }

    public function instanceMethod2() {
        echo "Calling Instance Method 2\n";
    }
}

echo "Instantiating MyClass\n";
$myInstance = new MyClass();
$myInstance->instanceMethod1();
$myInstance->instanceMethod2();
$myInstance->helper1();
$myInstance->helper2();

/*
Results in:
Instantiating MyClass
Calling Instance Method 1
Calling Instance Method 2
Calling My Helper 1
Calling My Helper 2
*/

Okay, so even though we declare methods 'helper1' and 'helper2' as static, we can call them on the instance. That's fine -- PHP will dynamically check if they are instance methods first, and then fall back to the static methods that are available. That's actually handy, since the static methods won't have a dependency on an instance, why shouldn't we be able to use them both ways?

Now, let's take this one:

class MyClass {

    /* helper methods */
    public static function helper1() {
        echo "Called My Helper 1\n";
    }

    public static function helper2() {
        echo "Calling My Helper 2\n";
        $this->instanceMethod2();
        // so, even though we called this static method on an instance,
        // it doesn't understand $this.
    }

    /* instance methods */
    public function instanceMethod1() {
        echo "Calling Instance Method 1\n";
        $this->helper1(); //this should be allowed
    }

    public function instanceMethod2() {
        echo "Called Instance Method 2\n";
    }
}

echo "Instantiating MyClass\n";
$myInstance = new MyClass();
$myInstance->instanceMethod1();
$myInstance->helper2();

/*
Results in:
Instantiating MyClass
Calling Instance Method 1
Called My Helper 1
Calling My Helper 2

Fatal error: Using $this when not in object context in ...
*/

This makes sense. even though we're calling a static method on an instance, it prevents that method from having access to the instance ($this). This is preferred: we want our static methods to be useful in both a static and an instance context.

Now let's take a look at something far less acceptable:

class MyClass {

    /* helper methods */
    public static function helper1() {
        echo "Called My Helper 1\n";
    }

    public static function helper2() {
        echo "Calling My Helper 2\n";
        self::instanceMethod2();

        // This is absolutely wrong.
        // You should not be able to call instance methods statically!!!!!!
    }

    /* instance methods */
    public function instanceMethod1() {
        echo "Calling Instance Method 1\n";
        self::helper1();
    }

    public function instanceMethod2() {
        echo "Called Instance Method 2\n";
    }
}

echo "Instantiating MyClass and calling methods statically on the instance\n";
$myInstance = new MyClass();
$myInstance::instanceMethod1();
$myInstance::helper2();

echo "Using MyClass statically\n";
MyClass::instanceMethod1();
MyClass::helper2();

/*
Results in:
Instantiating MyClass and calling methods statically on the instance
Calling Instance Method 1
Called My Helper 1
Calling My Helper 2
Called Instance Method 2

Using MyClass statically
Calling Instance Method 1
Called My Helper 1
Calling My Helper 2
Called Instance Method 2
*/

So, a couple things here.... As of PHP 5.3, we have been given the ability to store a class name in a variable, and then call methods off of it. Such as $class="MyClass"; $class::myMethod(). This is cool, and actually quite handy. However, what I cannot fathom is why PHP gave us the ability to call instance methods statically off of an instance. It makes sense for methods declared statically to also advertise themselves as instance methods (as we covered previously), but for an instance method to advertise itself as a static one? That feels backwards. To that end, you'll see that there are even cases where this will throw an (albeit meaningful) error:

class MyClass {

    protected $myVar = "You found me!";
    public function getMyVar() {
        echo "MyVar: " . $this->myVar . "\n";
    }
}

echo "Instantiating MyClass\n";
$instance = new MyClass();
$instance->getMyVar();

echo "Using MyClass instance, but calling method statically\n";
$instance = new MyClass();
$instance::getMyVar();

echo "Using MyClass";
MyClass::getMyVar();

/*
Results in:
Instantiating MyClass
MyVar: You found me!
Using MyClass instance, but calling method statically
Fatal error: Using $this when not in object context in ...
Using MyClass
Fatal error: Using $this when not in object context in ...
*/

As you can see, 'getMyVar' is not declared statically, but PHP, for whatever reason, has given us the option of calling it as such. This feels sloppy; it's understood that static methods will NEVER have a dependency on an instance, but instance methods naturally tend to. As you can see by the error messages, this blatant mistake spews all over what used to be your nice, clean code; it throws a runtime error instead of a compile time error.

Inheritance. Now we get into an area where PHP has historically dropped the ball as far as statics go, but has begun to rectify with their new technique coined "Late Static Binding".

class MyClass {

    protected static $myVar = "Base";

    public static function getMyVar() {
        echo "MyVar: " . self::$myVar . "\n";
    }
}

class MyClassChild extends MyClass {
    protected static $myVar = "Child";
}

echo "Using MyClass\n";
MyClass::getMyVar();
echo "Using MyClassChild\n";
MyClassChild::getMyVar();

/*
Results in:
Using MyClass
MyVar: Base
Using MyClassChild
MyVar: Base
*/

What we're seeing here is that even though we're calling 'getMyVar' on the child object, the parent's use of 'self' will only look at the class on which it is defined. There must have been a public outcry or bloody coup since, as of PHP 5.3, the 'static' keyword was introduced to solve this problem. To quote php.net:

This feature was named "late static bindings" with an internal perspective in mind. "Late binding" comes from the fact that static:: will not be resolved using the class where the method is defined but it will rather be computed using runtime information. It was also called a "static binding" as it can be used for (but is not limited to) static method calls.

If we replace 'self::' with 'static::', no other modifications need to be made to make it act as we'd expect it to.

Here's another quirk -- if you call an inherited static method, and that method requires knowing on what type of object it is being called (yes, I know that's an anti-pattern, but hear me out), PHP's getclass() will report it incorrectly. This goes back to the Late Static Binding, where getclass is a compile-time regurgitation of the state of your objects, and getcalledclass is the runtime version:

class MyClass {
    public static $myVar = "You found me";
    public static function myFunction() {
        echo "You ran me\n";
    }
    public static function getClassInfo() {
        echo "Class Name: " . get_class() . "\n";
        echo "Called Class: " . get_called_class() . "\n";
    }
}

class MyClassChild extends MyClass {}

echo "Using MyClass\n";
echo MyClass::$myVar . "\n";
MyClass::myFunction();
MyClass::getClassInfo();

echo "Using MyClassChild\n";
echo MyClassChild::$myVar . "\n";
MyClassChild::myFunction();
MyClassChild::getClassInfo();

/*
Results in:
Using MyClass
You found me
You ran me
Class Name: MyClass
Called Class: MyClass

Using MyClassChild
You found me
You ran me
Class Name: MyClass
Called Class: MyClassChild
*/

This last example is a reiteration of a previous comment on "self::" vs. "static::". I only bring this up because it recently burned me, and I am hoping to save someone else out there the pain and suffering I experienced in trying to hunt it down:

class MyClass {

    public static function step1() {
        echo "Base Step 1\n";
        self::step2();
    }

    public static function step2() {
        echo "Base Step 2\n";
        self::step3();
    }

    public static function step3() {
        echo "Base Step 3\n";
    }
}

class MyClassChild extends MyClass {

    public static function step2() {
        echo "Child Step 2\n";
        self::step3();
    }
}

echo "Using MyClass\n";
MyClass::step1();
echo "Using MyClassChild\n";
MyClassChild::step1();

/*
Results in:
Using MyClass
Base Step 1
Base Step 2
Base Step 3
Using MyClassChild
Base Step 1
Base Step 2
Base Step 3
*/

As you can see, by using "self::", the parent step1() did not check to see if the called class (the child) had a more specific version of the step2() method, and it called its own instead. To fix that, we replace the "self::" with "static::" and it will work as we expect.

2011-02-24 PHP's register_shutdown_function

Personally, I'm not a fan of PHP. With 5830 functions defined in the global namespace as of right now, how could one ever make the argument that PHP is a well thought-out language? However, what the language is good at is giving you a bunch of tools that you never even thought you wanted. Case in point: register_shutdown_function.

This obscure, but fantastically useful, function allows you to execute a block of code whenever your script ends -- for any reason. Whether your page exit()s or die()s or just finishes, a developer has a hook to run whatever code he/she deems necessary. And not just one function either... you can use this call to register as many shutdown functions as you want, and they will get executed in the order that they get applied. But of course, you must be careful: PHP will happily give you more rope than you will ever need to hang yourself. A lot of people may consider the use of this function to be magic, and you'll want to be very clear that what you're doing is documented.

Use of this function is very straight-forward.

void register_shutdown_function ( callback $function [, mixed $parameter [, mixed $... ]] )

Now, something undocumented (but incredibly useful) is that you can pass a lambda function in for callback. The examples on php.net show that you should pass in a string (or array) representing a function to call. So, if the function that you wanted to call was named "bye", you would call register_shutdown_function("bye"). But say that you wanted to call a method called "bye" on a "Utilities" class. Well, then you must call register_shutdown_function(array("Utilities","bye")). Honestly, I find that incredibly unintuitive and hard to follow. I would much rather see this:

register_shutdown_function(function() { /* do something */ });

But then again, I love javascript, and oh do I miss functional programming....

Now, you might be asking yourself: why would I ever need to use that function?

register_shutdown_function(function() {
    Timer::writeAll();
});

class Timer {
    private static $events = array();
    public static function set($title) {
        self::$events[] = array("name" => $title, "time" => microtime(true));
    }
    public static function writeAll() {
        array_walk(self::$events, function($item) {
            echo $item["name"] . ": " . $item["time"] . "\n";
        });
    }
}

Timer::set("Test before 1000");
for($i=0; $i<1000; $i++);
Timer::set("Test after 1000");
for($i=0; $i<10000; $i++);
Timer::set("Test after 10,000");
for($i=0; $i<1000000; $i++);
Timer::set("Test after 1,000,000");

This highly simplified example shows a Timer class with two methods: "set" and "writeAll". Perhaps you were doing some performance testing and you decided to litter your code with Timer::set() calls. At the end of the script, you can print out all of your debugging information to show where any bottlenecks may be.

The output would look something like this:

Test before 1000: 1298609284.6236
Test after 1000: 1298609284.6237
Test after 10,000: 1298609284.6245
Test after 1,000,000: 1298609284.699

2010-09-18 The Two-of-Three Rule

In software development, I have found that there is a solid, albeit cynical, rule about the expectations we should be setting for our clients and customers. This rule states that anything you plan to deliver will have, at most, 2 of the 3 following characteristics*:

  1. It can be done quickly
  2. It can be done cheaply
  3. It can be done well

Of course, you don't want to list these rules in your negotiation process (sorry, but I feel I have to explicitly call that out), but you do need to keep them in the back of your mind. If the client is asking for all three, then at least one of those characteristics is going to eventually give. The first two items in that list are very tangible for you and for the client -- due dates and payments are going to likely be your customer's deciding factors in whether you get the contract -- but the third is much more subjective, and harder to quantify. And perhaps using the word "well" is a bit of a misnomer; we must not ship crap. But there are ways to cut corners that allow you to get your product out the door on time, as well as within your client's budget.

"We must not ship crap" means that we are not going to cut corners by cutting testing time. So if your testers say they're going to need a certain amount of time given your current project scope, perhaps it's time to revisit the scope. Does your contract say that you're building a website and that you need to support browsers back to Firefox 1.0, Safari 2, and Internet Explorer 5.5? How will it affect your timeframes for development time and testing if you were to bump that to Firefox 2.0 or 3.0, Safari 3, and Internet Explorer 7.0? And perhaps, in addition to this website, they want 3rd-party API support, a custom Content Management System, and integration into their internal intranet that was developed by some highschooler six years ago for his senior project? Respectively speaking, could you defer part of the scope until a later release, use an open-source solution that meets all of the client's requirements, or take the opportunity to pitch some new business (which may extend the timeframe, but see "defer")?

There are a new set of challenges around how to work with a "deferred" or "enhancement" project plan, but that's an article for another day.

One last thought: The characteristic of getting something done "cheaply" is not directly proportional to the financial responsibility to which the client is agreeing. If the customer agrees to a price that they believe is fair, but the developers, designers, and testers are keeping their noses to the grindstone nights, weekends, and lunch hours, you have assumed the extra cost; the project is no longer done cheaply. The return on investment that you will be getting from the people entrusted with building this product, if carefully quantified, will drive the overall price of the project shockingly higher.

*The initial "Two of Three" rule was outlined to me several years ago without much explanation by a professor. Over the years, I have had time to reflect on it, and it has not only held true in software projects, but also across other industries. I hope that you can find its applications in your own line of work.

2010-09-08 NodeJS

So, tonight I ventured into the realm of NodeJS, and I wanted to share what I have learned. I went into this process knowing virtually nothing about what I was getting myself into; so under the assumption that there are other beginners out there, I hope that I can make this overview very simple.

Before I even got into the installation portion of NodeJS, I stood up a VirtualBox to play around in. I've learned (many times the hard way) that it's always good to set up a sandbox to try out new tech. Therefore, if you screw something up, you can just trash the install and start over. Installing a VM of Ubuntu took about a half hour. Sharing a folder from the host to a mount on the guest took about 15 minutes longer to figure out. I've found that it's easier/safer to develop and save files outside of the virtual machine, just in case I irreparably damage it.

Once that was done, I downloaded NodeJS from http://nodejs.org/#download and saved it to my Home folder. I extracted the files, and navigated to that directory via the command line. Three simple commands later, and it was installed:

./configure
make
sudo make install

It does require that you have a C++ compiler installed (which was not available in my base Ubuntu installation), but installing that was simple enough:

sudo apt-get install g++

After "make install", you can test your installation by running:

make test

This will run through a battery of tests, and show you where your installation is lacking. I had two errors thrown back at me: "Error: node.js not compiled with openssl crypto support." and "Error: Command failed: /bin/sh: curl: not found". Each are simple to resolve:

sudo apt-get install curl
sudo apt-get install libssl-dev

And that did it. "Hello World" was incredibly easy to set up:

var http = require("http");
http.createServer(function(req, res) {
    res.writeHead(200, {"Content-Type" : "text/plain"});
    res.end("Hello World\n");
}).listen(8124, "127.0.0.1");

I saved that file as hello.js and executed:

node hello.js

Then, I went to a web browser, typed in the url http://localhost:8124 and saw "Hello World" appear as the webpage. Success!

So, I proceeded to create a more "real world" example, just to explore the framework a bit more. So, I set out to create a chat server and client. I've always been a fan of Javascript, due to its relative simplicity and flexibility, but I truly believe that NodeJS is where it shines. For the past several years, I have done much more work on the web than I have on desktop applications, so being able to apply the same event-driven coding paradigms is a very welcome sight. And thinking more about it, so much of what we build in interactive applications actually IS based on events, even if we refer to it as polling. So, here's what I came up with:

server.js:

var net = require("net");

var streams = [];
var server = net.createServer(function(stream) {

    stream.setEncoding("utf8");
    stream.on("connect", function() {
        streams.push(stream);
        stream.write("[System] Connection Established");
    });

    stream.on("end", function() {});

    stream.on("data", function(data) {
        data = data ? String(data) : "";
        for(var i=0; i<streams.length; i++) {
            if(stream != streams[i]) {
                streams[i].write(data.replace(/\s+$/,""));
            }
        }
    });

});

server.listen(8124, 'localhost', function() { console.log("server has been bound."); });

var commands = {
    "exit" : function() { process.exit(); }
};

var stdin = process.openStdin();
stdin.on('data', function(chunk) {
    var command = chunk ? String(chunk) : "";
    command = command.replace(/^\s+|\s+$/,"");
    if(command.indexOf(".") == 0 && (command.substr(1) in commands)) {
        commands[command.substr(1)]();
    }
});

client.js:

var net = require("net");

var username = process.argv[2] || null;
if(!username) {
    console.log("No username supplied.");
    process.exit();
}

var commands = {
    "exit" : function() { process.exit(); }
};

var connection = net.createConnection(8124, "localhost");

connection.setEncoding("utf8");
connection.on("connect", function() {

    var stdin = process.openStdin();
    stdin.on('data', function(chunk) {

        var command = chunk ? String(chunk) : "";
        command = command.replace(/^\s+|\s+$/,"");
        if(command.indexOf(".") == 0 && (command.substr(1) in commands)) {
            commands[command.substr(1)]();
            return;
        }

        connection.write("["+username+"] " + chunk);
    });

    stdin.on("end", function(){});
});

connection.on("data", function(data) { console.log(data); });
connection.on("error", function(exception) { console.log("[Exception] " + exception); });
connection.on("timeout", function() { console.log("[Connection Timed Out]"); });
connection.on("close", function() { console.log("[Connection Closed]"); });

So, to execute (each in their own terminal window):

node server.js
node client.js username1
node client.js username2

And that's it. Obviously it's not a terribly robust application, but it's amazing what can be done in so few lines of code.

Next I am going to attempt to install the CouchDB modules and build on top of this. Until next time...

2010-09-06 iPhone iOS4 Location Database

My good friend Chris Vance has been looking into the GPS data stored within iOS4 on the new iPhones. After pulling one of these databases from a phone, I have discovered that is nothing more than a SQLite3 database with a wealth of information*. I was tasked with making a visual representation of this data.

Digging in, I find two (very similar) tables: CellLocation and WifiLocation. In addition to the obvious Timestamp, Latitude, and Longitude fields (found in both tables), there are some other columns that could be interesting: HorizontalAccuracy, Altitude, VerticalAccuracy, Speed, Course, and Confidence. On the database that I had the opportunity to analyze, Confidence was the only one of these "interesting" fields that had values (integers) in it -- and the values were meaningless to me without knowing what kind of rubric came up with that number. The "Timestamp" field used in these tables is a variation of the epoch timestamp -- only instead of doing the number of seconds since 01/01/1970, Apple has chosen to use 01/01/2001. This makes the math pretty easy for converting to a human-readable date.

I chose to visualize these several thousand data points in Google Earth by generating a very basic KML file with Placemarks and Paths via Bash shell script.

I will post screenshots and (possibly) the script in the near future.

*SQLite Manager is a Firefox plugin that allows you to explore any SQLite database stored on your local computer. I found it very useful in digging into the file pulled from the phone.

2010-08-28 New Media Center PC = Ubuntu Awesomeness

I was hoping to report this weekend about my exploits with NodeJS, but my free time was commandeered by setting up my new media center pc. It was supposed to be built two weeks ago, but a faulty motherboard set me back. The box I am replacing was a 2-year-old quad-core Gateway refurb running Vista with an ATI video card that would not play well with any Linux distro I tried to put on it. So, for this new one, I made the decision to pick hardware that I knew that a good track record with Ubuntu.

First of all, I just want to commend the Canonical team for the excellent progress they have made in making Ubuntu a viable option, and competitor, against Microsoft and Apple. I consider myself relatively new to Linux still -- my first installation that "stuck" was Ubuntu 8.10 -- and my newest installation of 10.04 was a piece of cake.

If you are considering trying out Ubuntu (or any other Linux flavor), here are a few things that I have learned while ramping up:

  1. Don't dual-boot. The reason I say that 8.10 was my first install that "stuck" was because I resisted the temptation to boot into a more familiar OS by not having it available. There are tons of alternative applications to those found on other platforms. Then, if you find yourself pining for an application that only runs in Windows, you can check out Wine.

  2. Adding monitors is easy. Frustrated by how Windows only natively gives you a task bar on one of your monitors? Gnome gives you full control over "panels", which allow you to add icons, widgets, and taskbars anywhere that you want. (Speaking of taskbars, MintMenu is amazing.)

  3. Desktop organization is now a reality. Like many power users, my Windows desktop at work tends to overflow with shortcuts, files, folders, and anything else that I need to have immediate access to. So, I can organize these icons into their meaningful groups, be it by type or project. That is, until I RDP into my machine, which condenses it down to one monitor and changes my resolution -- and there goes my attempt at organization. KDE and Gnome have solved this using "Plasmoids" and "Folderview Screenlets", respectively.

Courtesy of http://liquidat.wordpress.com/2008/06/26/improvements-in-kdes-folderview/ Courtesy of http://www.omgubuntu.co.uk/2009/04/folder-view-gnome-screenlet.html

Well, that's all I have for you for now. Obviously I didn't even tackle the fact that the command line is infinitely more powerful than that on Windows, and the UI is so much more configurable than OSX -- but for the average user, those are not the important things. I think that Ubuntu has become an OS that even my grandmother could use. And that's the point, right?

And now, my desktop:

A screenshot of my desktop - as of 2010-08-28

2010-08-24 Fitting Labels in a Pie Chart

A while back, the following question was posed: how can I try to fit a label in a slice of a pie chart? So, I did the obligatory Googling, but alas, I came up empty handed. I proceeded to come up with a solution on my own. I will explain what I came up with, and I hope that this will be helpful to someone else down the line. I also hope that someone will improve upon this and let me know what changes they made. Note: I did my best to make this framework-agnostic, which is why you will see this "Labelizer" object taking in so many parameters. If this were to be adapted in some framework, I would hope that several parameters could be extrapolated from object instances that already exist.

Also, this implementation only tries to fit the labels inside of the pie slices. If it fails to find a suitable place in the slice, the label is discarded. This leaves the problem of how to position the labels outside of the pie, which would involve some collision detection. Perhaps another time.

Assumptions that were made:

  1. The pie is a perfect circle. If one wanted to modify this for a more flexible ellipse, such as in the case of a 3D pie chart, it could certainly be done.
  2. The slices of the pie add up to 100%.
  3. The labels will not rotate to fit.
  4. The ideal placement for the labels would be as close to the edge of the pie as possible.*

Let's start with the inputs. What do we need to know?

  1. We need some information about our pie. The base information is the x and y coordinates of the origin of the circle, as well as its radius.
  2. We need to have the width and height of the label we want to try to position. We don't really care about the label itself, be it an image or text -- just that it has dimensions.
  3. We need some definition around what slice of the pie we're working with. Therefore, we need to know the starting and ending angles of the pie slice.

The very first thing we need to do is verify our starting and ending angles. If we end up in a case where our starting angle is greater than our ending angle, we should abort the labeling attempt. This is a very basic early-escape check so that we don't do unnecessary calculations. Another check that we can do is to make sure that our label has even the possibility of fitting:

  1. Take the ending angle minus the starting angle. We'll call this the "opening angle".
  2. We now need to find out what the maximum length of our label could be, so:
    1. if the opening angle is less than 90 degrees, our label cannot be bigger than the pie's radius.
    2. if the opening angle is greater than 180 degrees, our label cannot be bigger than the pie's diameter
    3. if the opening angle is in between those two ranges, we need to find the coordinates where the starting and ending angles of our slice intersect with the edge of the pie. The line that connects those two points will be our maximum length.
  3. We now take our label dimensions (the width and the height) and find its hypotenuse. If this hypotenuse length is greater than our maximum value, we know that the label cannot possibly fit.

Now that we've exhausted all of the tests for saving ourselves the work of finding where to place this label, it's time to find the sweet spot. Note: I have spent many, many hours trying to come up with an approach that is not iterative, but apparently my geometry is too rusty.

The approach I took started by finding the middle angle (halfway between the starting and ending angle) and placing the appropriate corner against the edge of the pie. The "appropriate" corner of the label is dependent on the quadrant that this middle angle fell in. On a Cartesian coordinate system, Quadrant I would be the top-right corner, Quadrant II would be the top-left, Quadrant III would be the bottom-left, and Quadrant IV would be the bottom-right. At this point, we check a couple things:

  1. any line drawn from the origin of the pie to a corner of the label would be an angle between the starting and ending angles of the slice
  2. any line drawn from the origin of the pie to a corner of the label would have a length less than the radius of the pie

As soon as either of these conditions are not met, we should abandon trying to fit the label in that spot and move on. We repeat the process by moving the "label" along the edge of the pie, within the bounds of that slice. I provided an extra parameter (delta) to the Labelizer object that would allow the user to specify the iteration step. While the default is to check every 1 degree, for larger charts, this may not be granular enough.

If no suitable coordinate for the label is found, the Labelizer will return 'false'. At this stage, the label could perhaps be thrown into a mechanism for placing the labels around the pie.

  • if the labels could fit closer to the origin of the pie, a second set of iterations could be performed to try to find a more ideal spot.

Please see a demo here) (and since I'm too lazy to go and add in ExCanvas, you will need to use a decent browser that supports canvas natively). I hope that this was helpful, and I'm looking forward to hearing your thoughts on this. Especially if someone has another solution in lieu of my iterative approach (I just can't shake the code smell). I'm sure there's a formula that will do it much more elegantly, but I'm not familiar enough with net areas and intersections (and I imagine there are probably even integrals involved in there somewhere).

And here's the code:

Labelizer = (function() {

    /*
        Labelizer is designed to determine if a text label will fit
        into a slice of a pie chart. The pie chart must be a perfect
        circle (pie.width = pie.height) at this point

        It is helpful to pad your label text with a couple spaces on
        either side for display purposes. This will help push the label
        away from the edges of the circle.

        oArgs = {
            pie : {
                x : REQUIRED - origin x of the pie
                y : REQUIRED - origin y of the pie
                r : REQUIRED - radius of the pie
            }
            labelwidth: REQUIRED - width of label to be positioned
            labelheight: REQUIRED - height of label to be positioned
            start: REQUIRED - Slice starting angle (radians)
            end: REQUIRED - Slice ending angle (radians)
            dt: OPTIONAL - Delta Theta in Radians will determine the iteration
                distance for .testLabel(). Defaults to PI/180 (every 1 degree)
        }
    */
    var Labelizer = function(oArgs) { this.init(oArgs); }

    Labelizer.prototype = {

        dt : Math.PI/180,

        init : function(oArgs) {

            var requiredInputs = this._verifyInputs(oArgs);
            if(!requiredInputs) {
                this.error("Required Parameters Missing.");
                return;
            }

            this.label_width = oArgs.labelwidth;
            this.label_height = oArgs.labelheight;
            this.diameter = oArgs.pie.r*2;

            this.savedorigin = new LabelUtils.Point(oArgs.pie.x, oArgs.pie.y);
            this.p_origin = new LabelUtils.Point(0,0);

            var coord_startx = (oArgs.pie.r*Math.cos(oArgs.start)) + oArgs.pie.x; //Math.round(oArgs.pie.edgeX(oArgs.start));
            var coord_starty = (oArgs.pie.r*Math.sin(oArgs.start)) + oArgs.pie.y; //Math.round(oArgs.pie.edgeY(oArgs.start));
            var coord_endx = (oArgs.pie.r*Math.cos(oArgs.end)) + oArgs.pie.x; //Math.round(oArgs.pie.edgeX(oArgs.end));
            var coord_endy = (oArgs.pie.r*Math.sin(oArgs.end)) + oArgs.pie.y; //Math.round(oArgs.pie.edgeY(oArgs.end));

            var startx = coord_startx - oArgs.pie.x;
            var starty = oArgs.pie.y - coord_starty;
            var endx = coord_endx - oArgs.pie.x;
            var endy = oArgs.pie.y - coord_endy;

            this.p_start = new LabelUtils.Point(startx, starty);
            this.p_end = new LabelUtils.Point(endx, endy);

            this.l_start = new LabelUtils.Line(this.p_origin, this.p_start);
            this.l_end = new LabelUtils.Line(this.p_origin, this.p_end);

            if(this.l_start.getAngle() > this.l_end.getAngle()) {
                this.l_end.addAngleRevolution();
            }
            if(this.l_start.getAngle() > this.l_end.getAngle()) {
                this.error("Label could not be attached.");
                return;
            }

            this.showTrace = oArgs.showTrace;
            this.dt = oArgs.dt || this.dt;
        },

        _verifyInputs : function(oArgs) {
            if(!oArgs.labelheight ||
                !oArgs.labelwidth ||
                !oArgs.pie ||
                oArgs.start == undefined ||
                oArgs.end == undefined) {

                return false;
            }
            return true;
        },

        error : function(err) {

            if(err) {
                this.err = err;
                this.errorCounter = this.errorCounter || 0;
                this.errorCounter++;
            }
            return this.err;
        },

        checkOpening : function() {

            var label = new LabelUtils.Label(this.label_height, this.label_width);
            var openingAngle = this.l_end.getAngle() - this.l_start.getAngle();
            var maxLength;
            if(openingAngle < (Math.PI/2)) { maxLength = this.diameter/2; }
            else if(openingAngle < Math.PI) {
                var cap = new LabelUtils.Line(this.l_end.p2, this.l_start.p2);
                maxLength = cap.getLength();
            }
            else { maxLength = this.diameter; }

            if(label.getHypotenuse() > maxLength) { return false; }
            return true;
        },

        calculate : function() {

            if(this.error()) { console.log(this.err); return false; }
            if(!this.checkOpening()) { return false; }

            var label = this.placeLabel(this.l_start, this.l_end);
            if(!label) { return false; }
            var points = label.corners;

            var attacher = points.tl;
            return {
                x: this.savedorigin.x + attacher.x,
                y: this.savedorigin.y - attacher.y
            }
        },

        getPointFromAngle : function(theta) {

            //TODO:
            // Add ability to calculate coordinate if pie.width and
            // pie.height are not equal

            var x_theta = Math.cos(theta)*(this.diameter/2);
            var y_theta = Math.sin(theta)*(this.diameter/2);
            return new LabelUtils.Point(x_theta, y_theta);
        },

        testLabel : function(l_start, l_end, theta) {

            var p_theta = this.getPointFromAngle(theta);
            var label = new LabelUtils.Label(this.label_height, this.label_width);
            var success = label.attach(p_theta);
            if(!success) {
                this.error("Label could not be attached.");
                return false;
            }
            var verdict = label.verify(this.diameter/2, l_start, l_end);
            if(verdict) { return label; }
            return false;
        },

        placeLabel : function(l_start, l_end) {

            var result;
            var midTheta = (l_start.getAngle() + l_end.getAngle())/2;
            for(thetaLow = midTheta, thetaHigh = midTheta; thetaLow>l_start.getAngle() || thetaHigh < l_end.getAngle(); thetaLow-=this.dt, thetaHigh+=this.dt) {
                if(thetaLow > l_start.getAngle()) {
                    result = this.testLabel(l_start,l_end,thetaLow);
                    if(result) { return result; }
                }
                if(thetaHigh < l_end.getAngle()) {
                    result = this.testLabel(l_start,l_end,thetaHigh);
                    if(result) { return result; }
                }
            }
            return false;
        }


    }

    /*
        Utility Objects Collection Used by Labelizer
    */
    var LabelUtils = {

        /*
            Point is used to store an x-y coordinate and
            calculate information about that point
        */
        Point : function(x,y) {

            this.x = x;
            this.y = y;

            this.getQuadrant = function() {

                var q = false;
                if(this.x >= 0 && this.y >= 0) { q = 1; }
                else if(this.x < 0 && this.y > 0) { q = 2; }
                else if(this.x <= 0 && this.y <= 0) { q = 3; }
                else if(this.x > 0 && this.y < 0) { q = 4; }

                this.getQuadrant = function() { return q; }
                return this.getQuadrant();
            };
        },

        /*
            Line is comprised of two Points and can
            calculate information about its geometry
        */
        Line : function(p1,p2) {

            this.p1 = p1;
            this.p2 = p2;

            this.getAngle = function() {

                var opposite = this.p2.y - this.p1.y;
                var adjacent = this.p2.x - this.p1.x;
                var theta = Math.atan(opposite/adjacent);
                if(theta < 0) { theta += (2*Math.PI); }

                switch(this.p2.getQuadrant()) {
                    case 1: break;
                    case 2: theta -= Math.PI; break;
                    case 3: theta += Math.PI; break;
                    case 4: break;
                }

                this.getAngle = function() { return theta; }
                return this.getAngle();
            };

            this.addAngleRevolution = function() {

                var angle = this.getAngle();
                angle += (2*Math.PI);
                this.getAngle = function() { return angle; }
                return this.getAngle();
            };

            this.getLength = function() {

                var distance = Math.abs(
                    Math.sqrt(
                        Math.pow(this.p2.x - this.p1.x,2) +
                        Math.pow(this.p2.y - this.p1.y,2)
                    )
                );
                this.getLength = function() { return distance; }
                return this.getLength();
            };
        },

        /*
            Label is a collection of Points that represent
            the bounding box for the label that will be placed.
            The label will attach to a coordinate on the pie
            (placement dependent on quadrant) and then verify
            that it falls within the bounds of the slice.
        */
        Label : function(height, width) {

            this.height = height;
            this.width = width;

            this.getHypotenuse = function() {
                // a^2 + b^2 = c^2
                var length = Math.abs(
                    Math.sqrt(
                        Math.pow(this.width,2) +
                        Math.pow(this.height,2)
                    )
                );
                this.getHypotenuse = function() { return length; }
                return this.getHypotenuse();
            };

            this.attach = function(p) {

                var tr, tl, bl, br; //top-right, top-left, bottom-left, bottom-right
                var px = p.x, py = p.y;
                switch(p.getQuadrant()) {
                    case 1:
                        tr = p;
                        tl = new LabelUtils.Point(px - this.width, py);
                        bl = new LabelUtils.Point(px - this.width, py - this.height);
                        br = new LabelUtils.Point(px, py - this.height);
                        break;
                    case 2:
                        tl = p;
                        tr = new LabelUtils.Point(px + this.width, py)
                        br = new LabelUtils.Point(px + this.width, py - this.height);
                        bl = new LabelUtils.Point(px, py - this.height);
                        break;
                    case 3:
                        bl = p;
                        br = new LabelUtils.Point(px + this.width, py);
                        tr = new LabelUtils.Point(px + this.width, py + this.height);
                        tl = new LabelUtils.Point(px, py + this.height);
                        break;
                    case 4:
                        br = p;
                        bl = new LabelUtils.Point(px - this.width, py);
                        tl = new LabelUtils.Point(px - this.width, py + this.height);
                        tr = new LabelUtils.Point(px, py + this.height);
                        break;
                }
                if(!tr || !tl || !bl || !br) { return false; }
                this.corners = { tr: tr, tl: tl, bl: bl, br: br }
                return true;
            };

            this.verify = function(radius,l_start,l_end) {

                //TODO:
                // Add ability to calculate radius based on angle if
                // pie.width and pie.height are not equal

                var corner, line;
                var origin = new LabelUtils.Point(0,0);
                for(var i in this.corners) {
                    corner = this.corners[i];
                    if(!this._checkInBounds(
                        new LabelUtils.Line(origin,corner),
                        l_start,
                        l_end,
                        radius)
                    ) { return false; }
                }
                return true;
            };

            this._checkInBounds = function(line,start,end,radius) {

                var startAngle = start.getAngle(),
                    endAngle = end.getAngle();
                var allowRevolution = (endAngle >= (2*Math.PI))
                if(line.getAngle() < startAngle && line.getAngle() < endAngle && allowRevolution) {
                    line.addAngleRevolution();
                }

                if(line.getAngle() < startAngle && line.getAngle() < endAngle) { return false }
                if(line.getAngle() > startAngle && line.getAngle() > endAngle) { return false }
                if(line.getLength() > radius) { return false; }

                return true;
            };

        },

        /*
            rad2deg: Helper function useful for translating
            radians to degrees (for display purposes and
            debugging, since radians -- at least for me --
            are not intuitive)
        */
        rad2deg : function(rad) { return (rad * (180/Math.PI)); }
    };

    return Labelizer;

})();

2010-08-23 T+0

Well, I thought it was about time that I started a blog. All the cool kids are doing it, right? I guess the hardest part for me was picking a name. "Curiosity was framed. Ignorance killed the cat." has been a quote that has always made a lot of sense to me (as both a curious person and a cat owner). So, I don't plan for this site to be narrowly focused. I'm looking forward to posting about programming, new technology, motorcycles and road trips, as well as anything else that happens to be going on. If you are reading this on or around the date of its posting, you'll likely see a lot of changes going on as I continue to tweak the UI and navigation.

Coming soon, I hope to bring you my explorations/exploitations of NodeJS, CouchDB, and other nerdiness that has just been dying to be let free to roam the web upon the backs of Google spiders. I also hope to start plotting a map of road trips that I have done, and take your suggestions. Perhaps some picture will even follow.

Let's have some fun with this!