/*
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){for(var c in b)a[c]=b[c]},method:function(a){var b=this,c=b._methods=b._methods||{};if((c[a]||{}).fn==b[a])return c[a].bd;return(c[a]={fn:b[a],bd:b[a].bind(b)}).bd},util:{}};Array.from=function(a){if(!a)return[];if(a.toArray)return a.toArray();var b=a.length,c=[];while(b--)c[b]=a[b];return c};JS.extend(Function.prototype,{bind:function(){var a=this,b=Array.from(arguments),c=b.shift()||null;return function(){return a.apply(c,b.concat(Array.from(arguments)))}},callsSuper:function(){return/\bcallSuper\b/.test(this.toString())},is:function(a){return typeof a=='function'}});JS.Class=function(){var a=Array.from(arguments),b,c=Function.is(a[0])?a.shift():null,d=JS.Class.create(c);while(b=a.shift())d.include(b);c&&Function.is(c.inherited)&&c.inherited(d);return d};JS.extend(JS.Class,{create:function(a){var b=function(){this.initialize.apply(this,arguments)};this.ify(b);a&&this.subclass(a,b);var c=b.prototype;c.klass=c.constructor=b;b.include(this.INSTANCE_METHODS,false);b.instanceMethod('extend',this.INSTANCE_METHODS.extend,false);return b},ify:function(a,b){a.superclass=a.superclass||Object;a.subclasses=a.subclasses||[];if(b===false)return a;for(var c in this.CLASS_METHODS)this.CLASS_METHODS.hasOwnProperty(c)&&(a[c]=this.CLASS_METHODS[c]);return a},subclass:function(a,b){this.ify(a,false);b.superclass=a;a.subclasses.push(b);var c=function(){};c.prototype=a.prototype;b.prototype=new c();b.extend(a);return b},properties:function(a){var b={},c,d=this.ify(function(){});loop:for(var e in a){for(c in d){if(e==c)continue loop}b[e]=a[e]}return b},addMethod:function(f,i,g,h){if(!Function.is(h))return(f[g]=h);if(!h.callsSuper())return(f[g]=h);var j=function(){var b=i[g],c=Array.from(arguments),d=this.callSuper,e;Function.is(b)&&(this.callSuper=function(){var a=arguments.length;while(a--)c[a]=arguments[a];return b.apply(this,c)});e=h.apply(this,arguments);d?this.callSuper=d:delete this.callSuper;return e};j.valueOf=function(){return h};j.toString=function(){return h.toString()};f[g]=j},INSTANCE_METHODS:{initialize:function(){},method:JS.method,extend:function(a){for(var b in a)a.hasOwnProperty(b)&&JS.Class.addMethod(this,this.klass.prototype,b,a[b]);return this},isA:function(a){var b=this.klass;while(b){if(b===a)return true;b=b.superclass}return false}},CLASS_METHODS:{include:function(a,b){var c,d,e,f=a.include,i=a.extend;if(f){c=[].concat(f);for(d=0,e=c.length;d<e;d++)this.include(c[d],b)}if(i){c=[].concat(i);for(d=0,e=c.length;d<e;d++)this.extend(c[d],b)}for(var g in a){!/^(included?|extend(ed)?)$/.test(g)&&this.instanceMethod(g,a[g],b)}Function.is(a.included)&&a.included(this);return this},instanceMethod:function(a,b,c){if(!this.prototype[a]||c!==false)JS.Class.addMethod(this.prototype,this.superclass.prototype,a,b);return this},extend:function(a,b){Function.is(a)&&(a=JS.Class.properties(a));for(var c in a){a.hasOwnProperty(c)&&!/^(included?|extend(ed)?)$/.test(c)&&this.classMethod(c,a[c],b)}Function.is(a.extended)&&a.extended(this);return this},classMethod:function(a,b,c){for(var d=0,e=this.subclasses.length;d<e;d++)this.subclasses[d].classMethod(a,b,false);(!this[a]||c!==false)&&JS.Class.addMethod(this,this.superclass,a,b);return this},method:JS.method}});JS.extend(JS,{Interface:JS.Class({initialize:function(d){this.test=function(a,b){var c=d.length;while(c--){if(!Function.is(a[d[c]]))return b?d[c]:false}return true}},extend:{ensure:function(){var a=Array.from(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:function(){return new(JS.Class.apply(JS,arguments))},Module:function(b){return{included:function(a){a.include(b)},extended:function(a){a.extend(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,e;for(c in a)Number(c)!=c&&b.push(c);if(a instanceof Array){for(d=0,e=a.length;d<e;d++)typeof a[d]=='string'&&b.push(a[d])}for(d=0,e=b.length;d<e;d++)this.addMethod(b[d]);a.prototype&&this.addMethods(a.prototype)};it=its=function(){return new JS.MethodChain};JS.Class.addMethod=(function(a){return function(){JS.MethodChain.addMethods([arguments[2]]);return a.apply(JS.Class,arguments)}})(JS.Class.addMethod);(function(a){JS.extend(JS.Class.INSTANCE_METHODS,a);JS.extend(JS.Class.CLASS_METHODS,a)})({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={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;for(var c=0,d=this.countObservers();c<d;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;for(var a=0,b=this.countObservers(),c;a<b;a++){c=this._observers[a];c.bk.apply(c.cx,arguments)}},setChanged:function(a){this._changed=!(a===false)},isChanged:function(){if(this._changed===undefined)this._changed=true;return!!this._changed}};JS.Observable.subscribe=JS.Observable.addObserver;JS.Observable.unsubscribe=JS.Observable.removeObserver;JS.Observable=JS.Module(JS.Observable);JS.State=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.util.State.addMethods(this._state,this.klass)},inState:function(){for(var a=0,b=arguments.length;a<b;a++){if(this._state==this._getState(arguments[a]))return true}return false}});JS.util.State={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,c,d){var e={},f={},i=c.states||{};this.buildStubs(e,f,d);this.buildStubs(e,f,i);var g,h;for(g in f){h=(i[g]||{}).klass;h=h?JS.Class(h,d[g]):JS.Class(d[g]);h.include(e,false);f[g]=new h;JS.util.State.addMethods(f[g],b.klass)}return a.call(JS.Class,b,c,'states',f)},addMethods:function(a,b){for(var c in a)this.addMethod(b,c)},addMethod:function(b,c){b.instanceMethod(c,function(){var a=(this._state||{})[c];return a?a.apply(this,arguments):this},false)}};JS.Class.addMethod=(function(e){return function(a,b,c,d){if(c!='states'||typeof d!='object')return e.apply(JS.Class,arguments);return JS.util.State.buildCollection(e,a,b,d)}})(JS.Class.addMethod);