/** Operative v0.2.0 (c) 2013 James padolsey, MIT-licensed, http://github.com/padolsey/operative **/
(function(){function makeBlobURI(e){var t;try{t=new Blob([e],{type:"text/javascript"})}catch(r){t=new BlobBuilder,t.append(e),t=t.getBlob()}return URL.createObjectURL(t)}function Operative(e,t){var r=this;e.get=e.get||function(e){return this[e]},e.set=e.set||function(e,t){return this[e]=t},this._curToken=0,this._queue=[],this.isDestroyed=!1,this.isContextReady=!1,this.module=e,this.dependencies=t||[],this.dataProperties={},this.api={},this.callbacks={},this.deferreds={},this._fixDependencyURLs(),this._setup();for(var o in e)hasOwn.call(e,o)&&this._createExposedMethod(o);this.api.__operative__=this,this.api.destroy=function(){return r.destroy()}}function operative(e,t){var r=operative.hasWorkerSupport?Operative.Worker:Operative.Iframe;if("function"==typeof e){var o=new r({main:e},t);return function(){return o.api.main.apply(o,arguments)}}return new r(e,t).api}function iframeBoilerScript(){window.__run__=function(e,t,r,o){var i=!1,s=!1;window.async=function(){return i=!0,r},window.deferred=function(){return s=!0,o},r&&t.push(r);var n=window[e].apply(window,t);window.async=function(){throw Error("Operative: async() called at odd time")},window.deferred=function(){throw Error("Operative: deferred() called at odd time")},s||i||void 0===n||r(n)}}function workerBoilerScript(){var postMessage=self.postMessage,objectTransferSupport=null;self.console={},self.isWorker=!0,["log","debug","error","info","warn","time","timeEnd"].forEach(function(e){self.console[e]=function(){postMessage({cmd:"console",method:e,args:[].slice.call(arguments)})}}),self.addEventListener("message",function(e){function returnResult(e){postMessage({cmd:"result",token:data.token,result:e}),returnResult=function(){throw Error("Operative: You have already returned.")}}var data=e.data;if("string"==typeof data&&0===data.indexOf("EVAL|"))return eval(data.substring(5)),void 0;if(null==objectTransferSupport)return objectTransferSupport="PING"===e.data[0],self.postMessage(objectTransferSupport?"pingback:objectTransferSupport=YES":"pingback:objectTransferSupport=NO"),objectTransferSupport||(postMessage=function(e){return self.postMessage(JSON.stringify(e))}),void 0;objectTransferSupport||(data=JSON.parse(data));var defs=data.definitions,isDeferred=!1,isAsync=!1,args=data.args;if(defs)for(var i in defs)self[i]=defs[i];else{args.push(function(){returnResult({args:[].slice.call(arguments)})}),self.async=function(){return isAsync=!0,function(){returnResult({args:[].slice.call(arguments)})}},self.deferred=function(){function e(e){return returnResult({isDeferred:!0,action:"fulfill",args:[e]}),r}function t(e){returnResult({isDeferred:!0,action:"reject",args:[e]})}isDeferred=!0;var r={};return r.fulfil=r.fulfill=e,r.reject=t,r};var result=self[data.method].apply(self,args);isDeferred||isAsync||void 0===result||returnResult({args:[result]}),self.deferred=function(){throw Error("Operative: deferred() called at odd time")},self.async=function(){throw Error("Operative: async() called at odd time")}}})}if("undefined"==typeof window&&self.importScripts)return workerBoilerScript(),void 0;var slice=[].slice,hasOwn={}.hasOwnProperty,scripts=document.getElementsByTagName("script"),opScript=scripts[scripts.length-1],opScriptURL=/operative/.test(opScript.src)&&opScript.src,baseURL=(location.protocol+"//"+location.hostname+(location.port?":"+location.port:"")+location.pathname).replace(/[^\/]+$/,""),URL=window.URL||window.webkitURL,BlobBuilder=window.BlobBuilder||window.WebKitBlobBuilder||window.MozBlobBuilder,workerViaBlobSupport=function(){try{new Worker(makeBlobURI(";"))}catch(e){return!1}return!0}(),objCreate=Object.create||function(e){function t(){}return t.prototype=e,new t};operative.hasWorkerSupport=!!window.Worker,operative.Promise=window.Promise,"undefined"!=typeof module&&module.exports?module.exports=operative:window.operative=operative,operative.setSelfURL=function(e){opScriptURL=e},operative.setBaseURL=function(e){baseURL=e},operative.getBaseURL=function(){return baseURL},Operative.prototype={_marshal:function(e){return e},_demarshal:function(e){return e},_enqueue:function(e){this._queue.push(e)},_fixDependencyURLs:function(){for(var e=this.dependencies,t=0,r=e.length;r>t;++t){var o=e[t];/\/\//.test(o)||(e[t]=o.replace(/^\/?/,baseURL))}},_dequeueAll:function(){for(var e=0,t=this._queue.length;t>e;++e)this._queue[e].call(this);this._queue=[]},_buildContextScript:function(e){var t,r=[],o=this.module,i=this.dataProperties;for(var s in o)t=o[s],"function"==typeof t?r.push('   self["'+s.replace(/"/g,'\\"')+'"] = '+(""+t)+";"):i[s]=t;return r.join("\n")+(e?"\n("+(""+e)+"());":"")},_createExposedMethod:function(e){var t=this;this.api[e]=function(){function r(){t.isContextReady?t._runMethod(e,o,i):t._enqueue(r)}if(t.isDestroyed)throw Error("Operative: Cannot run method. Operative has already been destroyed");var o=++t._curToken,i=slice.call(arguments),s="function"==typeof i[i.length-1]&&i.pop();if(!s&&!operative.Promise)throw Error("Operative: No callback has been passed. Assumed that you want a promise. But `operative.Promise` is null. Please provide Promise polyfill/lib.");if(s)t.callbacks[o]=s,setTimeout(function(){r()},1);else if(operative.Promise)return new operative.Promise(function(e){e.fulfil=e.fulfill,t.deferreds[o]=e,r()})}},destroy:function(){this.isDestroyed=!0}},Operative.Worker=function Worker(){this._msgQueue=[],Operative.apply(this,arguments)};var WorkerProto=Operative.Worker.prototype=objCreate(Operative.prototype);WorkerProto._onWorkerMessage=function(e){var t=e.data;if("string"==typeof t&&0===t.indexOf("pingback"))return"pingback:objectTransferSupport=NO"===t&&(this._marshal=function(e){return JSON.stringify(e)},this._demarshal=function(e){return JSON.parse(e)}),this.isContextReady=!0,this._dequeueAll(),void 0;switch(t=this._demarshal(t),t.cmd){case"console":window.console&&window.console[t.method].apply(window.console,t.args);break;case"result":var r=this.callbacks[t.token],o=this.deferreds[t.token];delete this.callbacks[t.token],delete this.deferreds[t.token];var i=t.result&&t.result.isDeferred&&t.result.action;o&&i?o[i](t.result.args[0]):r&&r.apply(this,t.result.args)}},WorkerProto._setup=function(){var e,t=this,r=this._buildContextScript(workerBoilerScript);if(this.dependencies.length&&(r='importScripts("'+this.dependencies.join('", "')+'");\n'+r),workerViaBlobSupport)e=this.worker=new Worker(makeBlobURI(r));else{if(!opScriptURL)throw Error("Operaritve: No operative.js URL available. Please set via operative.setSelfURL(...)");e=this.worker=new Worker(opScriptURL),e.postMessage("EVAL|"+this._buildWorkerScript(null))}e.postMessage(["PING"]),e.addEventListener("message",function(e){t._onWorkerMessage(e)}),this._postMessage({definitions:this.dataProperties})},WorkerProto._postMessage=function(e){return this.worker.postMessage(this._marshal(e))},WorkerProto._runMethod=function(e,t,r){this._postMessage({method:e,args:r,token:t})},WorkerProto.destroy=function(){this.worker.terminate(),Operative.prototype.destroy.call(this)},Operative.Iframe=function Iframe(){Operative.apply(this,arguments)};var IframeProto=Operative.Iframe.prototype=objCreate(Operative.prototype);IframeProto._setup=function(){var e=this;this.module.isWorker=!1;var t=this.iframe=document.body.appendChild(document.createElement("iframe"));t.style.display="none";var r=this.iframeWindow=t.contentWindow,o=r.document;r.__loaded__=function(){var t=o.createElement("script"),i=e._buildContextScript(iframeBoilerScript);void 0!==t.text?t.text=i:t.innerHTML=i,o.documentElement.appendChild(t);for(var s in e.dataProperties)r[s]=e.dataProperties[s];e.isContextReady=!0,e._dequeueAll()},o.open(),this.dependencies.length&&o.write('<script src="'+this.dependencies.join('"></script><script src="')+'"></script>'),o.write("<script>__loaded__()</script>"),o.close()},IframeProto._runMethod=function(e,t,r){var o=this,i=this.callbacks[t],s=this.deferreds[t];delete this.callbacks[t],delete this.deferreds[t],this.iframeWindow.__run__(e,r,function(){var e=i;if(!e)throw Error("Operative: You have already returned.");i=null,e.apply(o,arguments)},s)},IframeProto.destroy=function(){this.iframe.parentNode.removeChild(this.iframe),Operative.prototype.destroy.call(this)},operative.Operative=Operative})();