(function(root){var module={exports:{}};(function(require,exports,module){"use strict";function PubSub(){this._subscribers=[]}PubSub.prototype={subscribe:function(fn,ctx){var self=this;function callback(){return fn.apply(ctx||self,arguments)}callback.fn=fn;callback.ctx=ctx;this._subscribers.push(callback)},unsubscribe:function(fn,ctx){for(var i=0;i1){if(typeof args[1]==="function"){config.write=args[1];if(args.length>2){config.watch=args[2]}}else{config.watch=args[1]}}}return config}function obs(config){function observable(value){if(arguments.length){if(typeof observable.write==="function"){observable.write.call(observable.context,value)}else{throw new Error("This observable cannot be written to!")}}else{if(typeof observable.read==="function"){return observable.read.call(observable.context)}else{throw new Error("This observable cannot be read from!")}}}ext(observable,PubSub.prototype,{context:config.context||observable,read:config.read,write:config.write,onNotify:function(onNotify){return function(){onNotify.call(observable)}}(config.onNotify||function(){}),_initialValue:config.value,_currentValue:config.value,_previousValue:undefined,_subscriptions:[]},obs.fn);PubSub.apply(observable);if(config.watch){observable.watch.apply(observable,isArray(config.watch)?config.watch:[config.watch])}return observable}obs.fn={__is_obs__:true,notify:function(){this.dirty=this._currentValue===this._initialValue;this.publish(this._currentValue,this._previousValue)},peek:function(){return this._currentValue},commit:function(){this._initialValue=this._currentValue;this.dirty=false},reset:function(){this._previousValue=this._currentValue;this._currentValue=this._initialValue;this.notify()},watch:function(){var args=slice.call(arguments,0),sub,i;for(i=0;i