var World = (function() {
    var objects = [];
    var physics

    var add = function(obj) {
        objects.push(obj);
    };

    var del = function(obj) {
        obj("delete");
        objects = _.filter(objects, function(x) { return x !== obj; });
    };

    var all = function(callback) {
        _.each(objects, callback);
    };

    return {"add": add, "delete": del, "all": all};
}());

setInterval(function() {
    World.all(function(x) { x("update") });
}, 1000 * (1 / 30));

var FINISH = {"id": undefined};

var Entity = function(name) {
    name = (name === undefined) ? "Object" : name;

    var MAX_RECURSION_DEPTH = 100;
    var components = [];
    var recursionTrap = 0;

    var wrapMessage = function(message) {
        if (typeof message === "string") {
            message = {"id": message};
        }
        return message;
    }

    var target = function(message) {
        if (recursionTrap > MAX_RECURSION_DEPTH) {
            throw "Recursive message.";
        }
        //console.log("Message for " + name + ":");
        //console.log(message);
        message = wrapMessage(message);
        if (message.id === "addComponent") {
            recursionTrap++;
            message.component.call(target, {id: "attach"});
            recursionTrap--;
            components.unshift(message.component);
            return FINISH;
        } else {
            var cLen = components.length;
            for (var i = 0; i < cLen; ++i) {
                recursionTrap++;
                var rv = components[i].call(target, message);
                recursionTrap--;
                if (rv !== undefined) {
                    message = wrapMessage(rv);
                }
            }
        }
    };

    target.addComponent = function(component) {
        target({"id": "addComponent", "component": component});
    };

    return target;
};

var PhysicsComponent = function(body) {
    return function(message) {
        if (message.id === "update") {
            var position = body.GetTransform().position;
            this({id:"position",
                  x: position.x * PIXELS_PER_METER,
                  y: position.y * PIXELS_PER_METER})
        }
    }
}

var SpriteComponent = function(stage, sprite) {
    stage.addChild(sprite);
    return function(message) {
        if (message.id === "position") {
            sprite.position = new PIXI.Point(message.x, message.y);
        }
        if (message.id === "rotate") {
            sprite.rotation += message.amount;
        }
        if (message.id === "delete") {
            stage.removeChild(sprite);
        }
    };
};

var RollComponent = function() {
    var rate = 0.0;
    return function(message) {
        if (message.id === "update") {
            this({id: "rotate", amount: rate});
        }
        if (message.id === "rotationRate") {
            rate = message.rotationRate;
        }
    };
};

// ENTITY DEFINITIONS

var Bee = function(stage) {
    var entity = Entity("bee");

    var beeTexture = PIXI.Texture.fromImage('bee.png');
    var beeSprite = new PIXI.Sprite(beeTexture);

    beeSprite.anchor.x = 0.5;
    beeSprite.anchor.y = 0.5;

    entity.addComponent(SpriteComponent(stage, beeSprite));
    entity.addComponent(RollComponent());

    Constants.get("debug_beeRotationRate", function(x) {
        entity({"id": "rotationRate", "rotationRate": x});
    });

    entity({id: "position", x: 200, y: 200});

    return entity;
};


@@ -513,24 +513,376 @@
 ndefined%7D;%0A%0A
+var RecursionTrap = function(limit) %7B%0A    limit = (limit %7C%7C 1);%0A    var level = 0;%0A%0A    this.safely = function(f) %7B%0A        level++;%0A        try %7B%0A            return f();%0A        %7D finally %7B%0A            level--;%0A        %7D%0A    %7D%0A%0A    this.check = function() %7B%0A        if (level %3E= limit) %7B%0A            throw %22Recursion overflowed.%22;%0A        %7D%0A    %7D%0A%7D;%0A%0A
 var Entity =
@@ -998,50 +998,87 @@
 var 
-components = %5B%5D;%0A    var recursionTrap = 0
+recursionTrap = new RecursionTrap(MAX_RECURSION_DEPTH);%0A    var components = %5B%5D
 ;%0A%0A 
@@ -1286,20 +1286,16 @@
         
-if (
 recursio
@@ -1303,83 +1303,17 @@
 Trap
- %3E MAX_RECURSION_DEPTH) %7B%0A            throw %22Recursive message.%22;%0A        %7D
+.check();
 %0A   
@@ -1495,36 +1495,57 @@
    recursionTrap
-++;%0A
+.safely(function() %7B%0A    
             mess
@@ -1596,39 +1596,26 @@
             
-recursionTrap--
+%7D)
 ;%0A          
@@ -1793,32 +1793,41 @@
 %0A               
+ var rv =
  recursionTrap++
@@ -1824,19 +1824,36 @@
 sionTrap
-++;
+.safely(function() %7B
 %0A       
@@ -1861,24 +1861,26 @@
         
-var rv =
+    return
  compone
@@ -1929,23 +1929,10 @@
     
-recursionTrap--
+%7D)
 ;%0A  
@@ -2040,32 +2040,55 @@
 %7D%0A            %7D%0A
+            return rv;%0A
         %7D%0A    %7D;

Factor out the recursion trap