/*
Copyright (c) 2007-2008 James Coglan, http://jsclass.jcoglan.com
Licensed under the MIT license, http://www.opensource.org/licenses/mit-license.php
*/

JS={extend:function(a,b){b=b||{};for(var c in b){if(a[c]===b[c])continue;a[c]=b[c]}return a},makeFunction:function(){return function(){return this.initialize?(this.initialize.apply(this,arguments)||this):this}},makeBridge:function(a){var b=function(){};b.prototype=a.prototype;return new b},delegate:function(a,b){return function(){return this[a][b].apply(this[a],arguments)}},bind:function(){var a=JS.array(arguments),b=a.shift(),c=a.shift()||null;return function(){return b.apply(c,a.concat(JS.array(arguments)))}},callsSuper:function(a){return a.SUPER===undefined?a.SUPER=/\bcallSuper\b/.test(a.toString()):a.SUPER},mask:function(a){var b=a.toString().replace(/callSuper/g,'super');a.toString=function(){return b};return a},array:function(a){if(!a)return[];if(a.toArray)return a.toArray();var b=a.length,c=[];while(b--)c[b]=a[b];return c},indexOf:function(a,b){for(var c=0,d=a.length;c<d;c++){if(a[c]===b)return c}return-1},isFn:function(a){return a instanceof Function},ignore:function(a,b){return/^(include|extend)$/.test(a)&&typeof b==='object'}};JS.Module=JS.makeFunction();JS.extend(JS.Module.prototype,{initialize:function(a,b){b=b||{};this.__mod__=this;this.__inc__=[];this.__fns__={};this.__dep__=[];this.__res__=b._1||null;this.include(a||{})},define:function(a,b,c){c=c||{};this.__fns__[a]=b;if(JS.Module._0&&c._0&&JS.isFn(b))JS.Module._0(a,c._0);var d=this.__dep__.length;while(d--)this.__dep__[d].resolve()},instanceMethod:function(a){var b=this.lookup(a).pop();return JS.isFn(b)?b:null},include:function(a,b,c){if(!a)return c&&this.resolve();b=b||{};var d=a.include,e=a.extend,f,g,i,h,j=b._4||this;if(a.__inc__&&a.__fns__){this.__inc__.push(a);a.__dep__.push(this);if(b._2)a.extended&&a.extended(b._2);else a.included&&a.included(j)}else{if(b._5){for(h in a){if(JS.ignore(h,a[h]))continue;this.define(h,a[h],{_0:j||b._2||this})}}else{if(typeof d==='object'){f=[].concat(d);for(g=0,i=f.length;g<i;g++)j.include(f[g],b)}if(typeof e==='object'){f=[].concat(e);for(g=0,i=f.length;g<i;g++)j.extend(f[g],false);j.extend()}b._5=true;return j.include(a,b,c)}}c&&this.resolve()},includes:function(a){if(Object===a||this===a||this.__res__===a.prototype)return true;var b=this.__inc__.length;while(b--){if(this.__inc__[b].includes(a))return true}return false},ancestors:function(a){a=a||[];for(var b=0,c=this.__inc__.length;b<c;b++)this.__inc__[b].ancestors(a);var d=(this.__res__||{}).klass,e=(d&&this.__res__===d.prototype)?d:this;if(JS.indexOf(a,e)===-1)a.push(e);return a},lookup:function(a){var b=this.ancestors(),c=[],d,e,f;for(d=0,e=b.length;d<e;d++){f=b[d].__mod__.__fns__[a];if(f)c.push(f)}return c},make:function(a,b){if(!JS.isFn(b)||!JS.callsSuper(b))return b;var c=this;return function(){return c.chain(this,a,arguments)}},chain:JS.mask(function(c,d,e){var f=this.lookup(d),g=f.length-1,i=c.callSuper,h=JS.array(e),j;c.callSuper=function(){var a=arguments.length;while(a--)h[a]=arguments[a];g-=1;var b=f[g].apply(c,h);g+=1;return b};j=f.pop().apply(c,h);i?c.callSuper=i:delete c.callSuper;return j}),resolve:function(a){var a=a||this,b=a.__res__,c,d,e,f;if(a===this){c=this.__dep__.length;while(c--)this.__dep__[c].resolve()}if(!b)return;for(c=0,d=this.__inc__.length;c<d;c++)this.__inc__[c].resolve(a);for(e in this.__fns__){f=a.make(e,this.__fns__[e]);if(b[e]!==f)b[e]=f}}});JS.ObjectMethods=new JS.Module({__eigen__:function(){if(this.__meta__)return this.__meta__;var a=this.__meta__=new JS.Module({},{_1:this});a.include(this.klass.__mod__);return a},extend:function(a,b){return this.__eigen__().include(a,{_2:this},b!==false)},isA:function(a){return this.__eigen__().includes(a)},method:function(a){var b=this,c=b.__mcache__=b.__mcache__||{};if((c[a]||{}).fn===b[a])return c[a].bd;return(c[a]={fn:b[a],bd:JS.bind(b[a],b)}).bd}});JS.Class=JS.makeFunction();JS.extend(JS.Class.prototype=JS.makeBridge(JS.Module),{initialize:function(a,b){var c=JS.extend(JS.makeFunction(),this);c.klass=c.constructor=this.klass;if(!JS.isFn(a)){b=a;a=Object}c.inherit(a);c.include(b,null,false);c.resolve();do{a.inherited&&a.inherited(c)}while(a=a.superclass);return c},inherit:function(a){this.superclass=a;if(this.__eigen__){this.__eigen__().include(a.__eigen__?a.__eigen__():new JS.Module(a.prototype));this.__meta__.resolve()}this.subclasses=[];(a.subclasses||[]).push(this);var b=this.prototype=JS.makeBridge(a);b.klass=b.constructor=this;this.__mod__=new JS.Module({},{_1:this.prototype});this.include(JS.ObjectMethods,null,false);if(a!==Object)this.include(a.__mod__||new JS.Module(a.prototype,{_1:a.prototype}),null,false)},include:function(a,b,c){if(!a)return;var d=this.__mod__,b=b||{};b._4=this;return d.include(a,b,c!==false)},extend:function(a){if(!this.callSuper)return;this.callSuper();var b=this.subclasses.length;while(b--)this.subclasses[b].extend()},define:function(){var a=this.__mod__;a.define.apply(a,arguments);a.resolve()},includes:JS.delegate('__mod__','includes'),ancestors:JS.delegate('__mod__','ancestors'),resolve:JS.delegate('__mod__','resolve')});JS.Module=JS.extend(new JS.Class(JS.Module.prototype),JS.ObjectMethods.__fns__);JS.Module.include(JS.ObjectMethods);JS.Class=JS.extend(new JS.Class(JS.Module,JS.Class.prototype),JS.ObjectMethods.__fns__);JS.Module.klass=JS.Module.constructor=JS.Class.klass=JS.Class.constructor=JS.Class;JS.Module.extend({_3:[],methodAdded:function(a,b){this._3.push([a,b])},_0:function(a,b){var c=this._3,d=c.length;while(d--)c[d][0].call(c[d][1]||null,a,b)}});JS.extend(JS,{Interface:new JS.Class({initialize:function(d){this.test=function(a,b){var c=d.length;while(c--){if(!JS.isFn(a[d[c]]))return b?d[c]:false}return true}},extend:{ensure:function(){var a=JS.array(arguments),b=a.shift(),c,d;while(c=a.shift()){d=c.test(b,true);if(d!==true)throw new Error('object does not implement '+d+'()');}}}}),Singleton:new JS.Class({initialize:function(a,b){return new(new JS.Class(a,b))}})});JS.MethodChain=function(c){var d=[],e=c||{};this.____=function(a,b){d.push({func:a,args:b})};this.fire=function(a){return JS.MethodChain.fire(d,a||e)}};JS.MethodChain.fire=function(a,b){var c,d,e,f;loop:for(e=0,f=a.length;e<f;e++){c=a[e];if(b instanceof JS.MethodChain){b.____(c.func,c.args);continue}switch(typeof c.func){case'string':d=b[c.func];break;case'function':d=c.func;break;case'object':b=c.func;continue loop;break}b=(typeof d==='function')?d.apply(b,c.args):d}return b};JS.MethodChain.prototype={_:function(){var a=arguments[0],b,c,d;switch(typeof a){case'object':case'function':b=[];for(c=1,d=arguments.length;c<d;c++)b.push(arguments[c]);this.____(a,b)}return this},toFunction:function(){var b=this;return function(a){return b.fire(a)}}};JS.MethodChain.reserved=(function(){var a=[],b;for(b in new JS.MethodChain)a.push(b);return new RegExp('^(?:'+a.join('|')+')$')})();JS.MethodChain.addMethod=function(a){if(this.reserved.test(a))return;this.prototype[a]=function(){this.____(a,arguments);return this}};JS.MethodChain.addMethods=function(a){var b=[],c,d;for(c in a)Number(c)!==c&&b.push(c);if(a instanceof Array){d=a.length;while(d--)typeof a[d]==='string'&&b.push(a[d])}d=b.length;while(d--)this.addMethod(b[d]);a.prototype&&this.addMethods(a.prototype)};it=its=function(){return new JS.MethodChain};JS.Module.methodAdded(function(a){JS.MethodChain.addMethod(a)});JS.ObjectMethods.include({wait:function(a){var b=new JS.MethodChain;typeof a==='number'&&setTimeout(b.fire.bind(b,this),a*1000);this.forEach&&typeof a==='function'&&this.forEach(function(){setTimeout(b.fire.bind(b,arguments[0]),a.apply(this,arguments)*1000)});return b},_:function(){var a=arguments[0],b=[],c,d;for(c=1,d=arguments.length;c<d;c++)b.push(arguments[c]);return(typeof a==='object'&&a)||(typeof a==='function'&&a.apply(this,b))||this}});JS.Observable=new JS.Module({addObserver:function(a,b){(this.__observers__=this.__observers__||[]).push({bk:a,cx:b||null})},removeObserver:function(a,b){this.__observers__=this.__observers__||[];b=b||null;var c=this.countObservers();while(c--){if(this.__observers__[c].bk===a&&this.__observers__[c].cx===b){this.__observers__.splice(c,1);return}}},removeObservers:function(){this.__observers__=[]},countObservers:function(){return(this.__observers__=this.__observers__||[]).length},notifyObservers:function(){if(!this.isChanged())return;var a=this.countObservers(),b;while(a--){b=this.__observers__[a];b.bk.apply(b.cx,arguments)}},setChanged:function(a){this.__changed__=!(a===false)},isChanged:function(){if(this.__changed__===undefined)this.__changed__=true;return!!this.__changed__}});JS.Observable.include({subscribe:JS.Observable.instanceMethod('addObserver'),unsubscribe:JS.Observable.instanceMethod('removeObserver')});JS.State=new JS.Module({__getState__:function(a){return(typeof a==='object'&&a)||(typeof a==='string'&&((this.states||{})[a]||{}))||{}},setState:function(a){this.__state__=this.__getState__(a);JS.State.addMethods(this.__state__,this.klass)},inState:function(){var a=arguments.length;while(a--){if(this.__state__===this.__getState__(arguments[a]))return true}return false},extend:{stub:function(){return this},buildStubs:function(a,b,c){var d,e;for(d in c){b[d]={};for(e in c[d])a[e]=this.stub}},buildCollection:function(a,b){var c={},d={},e=a.lookup('states').pop()||{};this.buildStubs(c,d,b);this.buildStubs(c,d,e);var f,g,i,h;for(f in d){g=(e[f]||{}).klass;g=g?new JS.Class(g,b[f]):new JS.Class(b[f]);i={};for(h in c){if(!g.prototype[h])i[h]=c[h]}g.include(i);d[f]=new g}if(a.__res__)this.addMethods(c,a.__res__.klass);return d},addMethods:function(a,b){if(!b)return;var c={},d=b.prototype;for(var e in a){if(d[e])continue;d[e]=b.__mod__.__fns__[e]=this.wrapped(e)}},wrapped:function(b){return function(){var a=(this.__state__||{})[b];return a?a.apply(this,arguments):this}}}});JS.Module.include({define:(function(c){return function(a,b){if(a==='states'&&typeof b==='object')arguments[1]=JS.State.buildCollection(this,b);return c.apply(this,arguments)}})(JS.Module.prototype.define)});