Backbone Vs John Resig's Simple JavaScript Inheritance Vs Kickbox

JavaScript performance comparison

Revision 14 of this test case created by Xav Laumonier

Info

This is a performance test of object creation between Backbone models, John Resig's Simple JavaScript Inheritance script and Kickbox (MV* framework to become public early 2014).

Preparation code

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js">
</script>
<script src="http://ajax.aspnetcdn.com/ajax/knockout/knockout-2.2.1.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.4.4/underscore-min.js">
</script>
<script src="//cdnjs.cloudflare.com/ajax/libs/backbone.js/1.0.0/backbone-min.js">
</script>
<script type="text/javascript">
  /* Simple JavaScript Inheritance
 * By John Resig http://ejohn.org/
 * MIT Licensed.
 */

  // Inspired by base2 and Prototype
  (function() {
    var a = false,
        b = /xyz/.test(function() {
        xyz
      }) ? /\b_super\b/ : /.*/;
    this.Class = function() {};
    Class.extend = function(g) {
      var f = this.prototype;
      a = true;
      var e = new this();
      a = false;
      for (var d in g) {
        e[d] = typeof g[d] == "function" && typeof f[d] == "function" && b.test(g[d]) ? (function(h, i) {
          return function() {
            var k = this._super;
            this._super = f[h];
            var j = i.apply(this, arguments);
            this._super = k;
            return j
          }
        })(d, g[d]) : g[d]
      }

      function c() {
        if (!a && this.init) {
          this.init.apply(this, arguments)
        }
      }
      c.prototype = e;
      c.prototype.constructor = c;
      c.extend = arguments.callee;
      return c
    }
  })();
</script>

<script type="text/javascript">
!function(){"use strict";var globals="undefined"!=typeof window?window:global;if("function"!=typeof globals.require){var modules={},cache={},has=function(object,name){return{}.hasOwnProperty.call(object,name)},expand=function(root,name){var parts,part,results=[];parts=/^\.\.?(\/|$)/.test(name)?[root,name].join("/").split("/"):name.split("/");for(var i=0,length=parts.length;length>i;i++)part=parts[i],".."===part?results.pop():"."!==part&&""!==part&&results.push(part);return results.join("/")},dirname=function(path){return path.split("/").slice(0,-1).join("/")},localRequire=function(path){return function(name){var dir=dirname(path),absolute=expand(dir,name);return globals.require(absolute,path)}},initModule=function(name,definition){var module={id:name,exports:{}};definition(module.exports,localRequire(name),module);var exports=cache[name]=module.exports;return exports},require=function(name,loaderPath){var path=expand(name,".");if(null==loaderPath&&(loaderPath="/"),has(cache,path))return cache[path];if(has(modules,path))return initModule(path,modules[path]);var dirIndex=expand(path,"./index");if(has(cache,dirIndex))return cache[dirIndex];if(has(modules,dirIndex))return initModule(dirIndex,modules[dirIndex]);throw new Error('Cannot find module "'+name+'" from '+'"'+loaderPath+'"')},define=function(bundle,fn){if("object"==typeof bundle)for(var key in bundle)has(bundle,key)&&(modules[key]=bundle[key]);else modules[bundle]=fn},list=function(){var result=[];for(var item in modules)has(modules,item)&&result.push(item);return result};globals.require=require,globals.require.define=define,globals.require.register=define,globals.require.list=list,globals.require.brunch=!0}}(),require.register("kickbox/about",function(){}),require.register("kickbox/adapters",function(){!function(){"use strict";KB.adapters={_list:{},register:function(id,clazz){F.str("id",id,"KB.adapters.register"),KB.adapters._list[id]=clazz},get:function(id){return F.str("id",id,"KB.adapters.register"),F.assert(!!KB.adapters._list[id],'No adapter named "'+id+'"'),KB.adapters._list[id]},instance:function(id,options){return F.str("id",id,"KB.adapters.register"),F.assert(!!KB.adapters._list[id],'No adapter named "'+id+'"'),new KB.adapters._list[id](options)}}}()}),require.register("kickbox/adapters/base-adapter",function(){!function(){"use strict";KB.adapters.register("Base",KB.Class.extend({root:"",loader:null,mapper:null,uri_key:null,getURL:function(){F.assert(!1,"Not implemented")},find:function(){F.assert(!1,"Not implemented")},findMany:function(){F.assert(!1,"Not implemented")},findWhere:function(){F.assert(!1,"Not implemented")},findManyAtURL:function(){F.assert(!1,"Not implemented")},create:function(){F.assert(!1,"Not implemented")},update:function(){F.assert(!1,"Not implemented")},partialUpdate:function(model_name,id,data,callback){this.update(model_name,id,data,callback,!0)},remove:function(){F.assert(!1,"Not implemented")},call:function(){F.assert(!1,"Not implemented")},sideload:function(){},extractMeta:function(){F.assert(!1,"Not implemented")}}))}()}),require.register("kickbox/adapters/dy-tastypie-adapter",function(){!function(){"use strict";KB.adapters.register("DynamoTastypie",KB.adapters.get("Tastypie").extend({getURL:function(model_name,id){var url,rangeId;return F.str("model_name",model_name,"KB.DynamoTastypieAdapter.getURL"),url=this.root+this.mapper.getKey(model_name)+"/",F.isStr(id)&&(id=id.split(":"),0===id.length?url+=id+"/":1===id.length?url+=id.join("/")+"/":(rangeId=id.pop(),url+=id.join(":")+"/"+rangeId+"/")),url+"?format=json"}}))}()}),require.register("kickbox/adapters/tastypie-adapter",function(){!function(){"use strict";KB.adapters.register("Tastypie",KB.adapters.get("Base").extend({uri_key:"resource_uri",getURL:function(model_name,id,key){var url;return F.str("model_name",model_name,"KB.TastypieAdapter.hydrate"),url=this.root+this.mapper.getKey(model_name)+"/",F.isStr(id)&&(url+=id+"/"),F.isStr(key)&&(url+=key+"/"),url+"?format=json"},extractModel:function(resource_uri){F.str("resource_uri",resource_uri,"KB.TastypieAdapter.extractModel");var str=resource_uri.substr(this.root.length);return str=str.substr(0,str.length-1),str.split("/")[0]},extractId:function(resource_uri){F.str("resource_uri",resource_uri,"KB.TastypieAdapter.extractId");var str=resource_uri.substr(this.root.length);return str=str.substr(0,str.length-1).split("/"),str.length>2?str[1]+":"+str[2]:str[1]},hydrate:function(model_name,raw_data,key){var i,l,rels,k;if(F.str("model_name",model_name,"KB.TastypieAdapter.hydrate"),F.def("raw_data",raw_data,"KB.TastypieAdapter.hydrate"),key&&this.loader.$store.isRelationship(model_name,key)){if(F.isStr(raw_data))raw_data={model:this.mapper.getModel(this.extractModel(raw_data)),id:this.extractId(raw_data)};else if(F.isArr(raw_data))for(i=0,l=raw_data.length;l>i;i+=1)raw_data[i]=this.hydrate(model_name,raw_data[i],key);else if(F.isObj(raw_data))for(rels=this.loader.$store.getRelationship(model_name,key),l=rels?rels.length:0,i=0;l>i;i+=1)this.hydrate(rels[i].model,raw_data)}else if(F.isArr(raw_data))for(i=0,l=raw_data.length;l>i;i+=1)raw_data[i]=this.hydrate(model_name,raw_data[i],key);else if(F.isObj(raw_data))for(k in raw_data)raw_data[k]=k===this.mapper.getPrimaryKey(model_name)?F.toStr(raw_data[k]):this.hydrate(model_name,raw_data[k],k);return raw_data},dehydrate:function(model_name,data){var k;F.str("model_name",model_name,"KB.TastypieAdapter.dehydrate"),F.def("data",data,"KB.TastypieAdapter.dehydrate");for(k in data)data[k]=this.dehydrateField(model_name,data[k],k);return data},dehydrateField:function(model_name,value,key){var rels;return F.str("model_name",model_name,"KB.TastypieAdapter.dehydrateField"),F.def("key",key,"KB.TastypieAdapter.dehydrateField"),rels=this.loader.$store.getRelationship(model_name,key),F.isUdef(value)?null:value&&rels&&0!==rels.length?this.dehydrateRel(model_name,value,key):value},dehydrateRel:function(model_name,value,key){var i,l,a,k=this.mapper.getKey(value.model);if(F.str("model_name",model_name,"KB.TastypieAdapter.dehydrateRel"),F.def("value",value,"KB.TastypieAdapter.dehydrateRel"),F.def("key",key,"KB.TastypieAdapter.dehydrateRel"),value&&F.isStr(value.id))value.id.indexOf(":")>-1&&(value.id=value.id.split(":").join("/")),value=this.root+k+"/"+value.id+"/";else if(value&&F.isArr(value.ids)){for(a=[],l=value.ids.length,i=0;l>i;i+=1)value.ids[i].indexOf(":")>-1&&(value.ids[i]=value.ids[i].split(":").join("/")),a.push(this.root+k+"/"+value.ids[i]+"/");value=a}return value},find:function(model_name,id,callback){var jqxhr;F.str("model_name",model_name,"KB.TastypieAdapter.find"),F.str("id",id,"KB.TastypieAdapter.find"),F.fn("callback",callback,"KB.TastypieAdapter.find"),jqxhr=$.ajax({cache:!1,url:this.getURL(model_name,id),beforeSend:function(xhr){xhr.setRequestHeader("X-CSRFToken",$.cookie("csrftoken"))}}),jqxhr.fail(function(){callback(!1)}),jqxhr.done(KB.del(this,function(data){var meta=this.extractMeta(data);this.sideload(data),data.hasOwnProperty("object")&&data.object.hasOwnProperty("resource_uri")?data=this.hydrate(model_name,data.object):(data=this.hydrate(model_name,data.hasOwnProperty("objects")&&!data.hasOwnProperty("resource_uri")?data.objects:data),F.isArr(data)&&data.length>0&&(data=data[0])),callback(!0,data,meta)}))},findMany:function(model_name,callback){this.findWhere(model_name,null,null,callback)},findWhere:function(model_name,field,value,callback){var k,url;if(F.str("model_name",model_name,"KB.TastypieAdapter.findWhere"),F.fn("callback",callback,"KB.TastypieAdapter.findWhere"),null===field)this.findManyAtURL(model_name,this.getURL(model_name),callback);else if(F.isNotNone(value))F.str("field",field,"KB.TastypieAdapter.findWhere"),F.str("value",value,"KB.TastypieAdapter.findWhere"),this.findManyAtURL(model_name,this.getURL(model_name)+(field?"&"+field+"="+value:""),callback);else if(F.isObj(field)){url=this.getURL(model_name);for(k in field)url+="&"+k+"="+field[k];this.findManyAtURL(model_name,url,callback)}},findManyAtURL:function(model_name,url,callback){var jqxhr;F.str("model_name",model_name,"KB.TastypieAdapter.findManyAtURL"),F.str("url",url,"KB.TastypieAdapter.findManyAtURL"),F.fn("callback",callback,"KB.TastypieAdapter.findManyAtURL"),jqxhr=$.ajax({cache:!1,url:url,beforeSend:function(xhr){xhr.setRequestHeader("X-CSRFToken",$.cookie("csrftoken"))}}),jqxhr.fail(function(){callback(!1)}),jqxhr.done(KB.del(this,function(data){var meta=this.extractMeta(data);this.sideload(data),data=this.hydrate(model_name,data.hasOwnProperty("objects")&&!data.hasOwnProperty("resource_uri")?data.objects:data),callback(!0,data,meta)}))},create:function(model_name,data,callback){var jqxhr,loc,callback_called=!1;F.str("model_name",model_name,"KB.TastypieAdapter.create"),F.obj("data",data,"KB.TastypieAdapter.create"),F.fn("callback",callback,"KB.TastypieAdapter.create"),data=this.dehydrate(model_name,data),jqxhr=$.ajax({type:"POST",contentType:"application/json",data:JSON.stringify(data),processData:!1,beforeSend:function(xhr){xhr.setRequestHeader("X-CSRFToken",$.cookie("csrftoken"))},url:this.getURL(model_name)}),jqxhr.done(KB.del(this,function(data){var meta=null;data&&(callback_called=!0,data?(meta=this.extractMeta(data),this.sideload(data)):(loc=jqxhr.getResponseHeader("Location"),""!==this.root&&(loc=this.root+loc.split(this.root).pop()),data[this.mapper.getPrimaryKey(model_name)]=this.extractId(loc)),data=this.hydrate(model_name,data.hasOwnProperty("object")&&!data.hasOwnProperty("resource_uri")?data.object:data),callback(!0,data,meta))})),jqxhr.always(KB.del(this,function(){if(callback_called===!1){callback_called=!0;var loc=jqxhr.getResponseHeader("Location"),data={};if(!loc)return callback(!1),void 0;""!==this.root&&(loc=this.root+loc.split(this.root).pop()),data[this.mapper.getPrimaryKey(model_name)]=this.extractId(loc),callback(!0,data,{})}}))},update:function(model_name,id,data,callback,patch){var jqxhr,callback_called=!1;F.str("model_name",model_name,"KB.TastypieAdapter.update"),F.str("id",id,"KB.TastypieAdapter.update"),F.obj("data",data,"KB.TastypieAdapter.update"),F.fn("callback",callback,"KB.TastypieAdapter.update"),F.bool("patch",patch,"KB.TastypieAdapter.update"),data=this.dehydrate(model_name,data),jqxhr=$.ajax({type:patch?"PATCH":"PUT",contentType:"application/json",data:JSON.stringify(data),processData:!1,beforeSend:function(xhr){xhr.setRequestHeader("X-CSRFToken",$.cookie("csrftoken"))},url:this.getURL(model_name,id)}),jqxhr.done(KB.del(this,function(data){var meta;data&&(meta=this.extractMeta(data),this.sideload(data),data=this.hydrate(model_name,data.hasOwnProperty("object")&&!data.hasOwnProperty("resource_uri")?data.object:data)),callback_called=!0,callback(!0,data,meta)})),jqxhr.always(KB.del(this,function(){callback_called===!1&&(callback_called=!0,jqxhr.status>=200&&jqxhr.status<300?callback(!0,{},{}):callback(!1))}))},remove:function(model_name,id,callback){var jqxhr;F.str("model_name",model_name,"KB.TastypieAdapter.remove"),F.str("id",id,"KB.TastypieAdapter.remove"),F.fn("callback",callback,"KB.TastypieAdapter.remove"),jqxhr=$.ajax({type:"DELETE",contentType:"application/json",processData:!1,beforeSend:function(xhr){xhr.setRequestHeader("X-CSRFToken",$.cookie("csrftoken"))},url:this.getURL(model_name,id)}),jqxhr.done(function(){204===jqxhr.status?callback(!0,null):callback(!1)}),jqxhr.fail(function(){callback(!1)})},call:function(request,callback){var jqxhr,url;F.inst("request",request,KB.APIRequest,"KB.TastypieAdapter.call"),url=this.getURL(request.model(),request.getId(),request.getKey()),jqxhr=$.ajax({type:request.HTTPMethod(),cache:!1,url:url,data:request.data,beforeSend:function(xhr){xhr.setRequestHeader("X-CSRFToken",$.cookie("csrftoken"))}}),jqxhr.fail(function(){callback(!1)}),jqxhr.done(KB.del(this,function(data){var meta=this.extractMeta(data);this.sideload(data),data=this.hydrate(request.model(),data.hasOwnProperty("objects")&&!data.hasOwnProperty("resource_uri")?data.objects:data),callback(!0,data,meta)}))},sideload:function(data){var k,model_name;if(F.obj("data",data,"KB.TastypieAdapter.sideload"),!data.hasOwnProperty("resource_uri"))for(k in data)"object"!==k&&"objects"!==k&&"meta"!==k&&(model_name=this.mapper.getModel(k),model_name?this.loader.sideload(model_name,this.hydrate(model_name,data[k])):F.log("No way to sideload "+k))},extractMeta:function(data){var m;return data&&data.meta?(m=data.meta,{count:m.total_count||-1,next:m.next||null,deleted:m.deleted||[]}):{}}}))}()}),require.register("kickbox/api-method",function(){!function(){"use strict";KB.APIMethod=KB.Class.extend({key:"",fields:null,vmo:null,meth:"GET",last_errs:null,construct:function(){F.inst("vmo",this.vmo,KB.ViewModelOperator,"KB.APIMethod.constuct"),F.isNone(this.fields)?this.fields=[]:this.fields.length>0&&(this.meth="POST"),this.validateHTTPMethod(this.meth)},validateData:function(data){var i,f,l=F.len(this.fields),errors=[],res=!0;if(this.last_errs=null,F.isNone(data)&&0===l)return res;for(i=0;l>i;i+=1)if(f=this.fields[i],data[f.name()])f.validate(data[f.name()])||(res=!1,errors.push(f.name()));else{if(f.isOptional())continue;res=!1,errors.push(f.name())}return res||(this.last_errs=errors),res},lastErrors:function(){return this.last_errs},validateHTTPMethod:function(method){return F.truthy("method",KB.APIMethod.METHODS.indexOf(method)>-1,"KB.APIMethod.validateHTTPMethod"),this},method:function(){return this.meth},getKey:function(){return this.key},isValid:function(){return F.isStr(this.key)&&KB.APIMethod.METHODS.indexOf(this.meth)>-1}}),KB.APIMethod.METHODS=["OPTIONS","GET","POST","HEAD","PUT","DELETE","PATCH"],KB.APIRequest=KB.EventDispatcher.extend({method:null,_data:null,recordId:null,record:null,callback:null,construct:function(){F.inst("method",this.method,KB.APIMethod,"KB.APIRequest.construct")},destroy:function(){this._super(),this.method=null,this.data=null,this.record=null},model:function(){return this.method.vmo.name},HTTPMethod:function(){return this.method.method()},data:function(){return this._data},getId:function(){return F.isInst(this.record,KB.ViewModel)?this.record.id():void 0},getKey:function(){return this.method.key},triggerCallback:function(success,result){F.isFn(this.callback)&&this.callback(success,result),this.record&&this.record.trigger("call",{success:success,result:result})}})}()}),require.register("kickbox/app",function(){!function(){"use strict";KB.App=KB.EventDispatcher.extend({$dependencies:["mapper","loader","store"],name:"App",$injector:null,mapper:null,loader:null,router:null,views:null,ui:null,models:null,i18n:null,l10n:null,__binder:null,__started:!1,__ready:null,__cache:null,construct:function(){this.__ready=[],this.$injector.register("app",this),this.mapper=this.$injector.register("mapper",KB.Mapper).object(),this.loader=this.$injector.register("loader",KB.Loader).object(),this.models=this.$injector.register("store",KB.Store).object(),this.router=this.$injector.register("router",KB.Router).object(),this.l10n=this.$injector.register("l10n",KB.L10n).object(),this.i18n=this.$injector.register("i18n",KB.I18n).object(),this.views=this.$injector.register("views",KB.Views).object(),this.ui=this.$injector.register("ui",KB.UI).object(),this.__binder=new KB._Binder,this.__cache=new KB.Cache},ready:function(callback){return F.fn("callback",callback,"KB.App.ready"),this.__started?(callback(),void 0):(this.__ready.push(callback),this)},start:function(){if(!this.__started){var self=this;return self.__started=!0,$(function(){for(;self.__ready.length>0;)self.__ready.shift()();self.__ready=null,self.trigger("start"),setTimeout(function(){self.router._update()},50)}),this}},validate:function(){return this.models.validateModels(),this},started:function(){return this.__started},redirect:function(hash,data){return F.str("hash",hash,"KB.App.redirect"),this.router.redirect(hash,data),this},route:function(){return this.router.current()},request:function(){return this.router.last()},refresh:function(){return this.views.refresh(),this},bind:function(obj,selector,template){return this.__binder.bind(obj,selector,template)},cache:function(){return this.__cache},get:function(key){return F.str("key",key,"KB.App.get"),this.__cache.get(key)},set:function(key,value){return F.str("key",key,"KB.App.set"),F.def("value",value,"KB.App.set"),this.__cache.set(key,value)},has:function(key){return F.str("key",key,"KB.App.has"),this.__cache.has(key)},getEnv:function(key){return F.str("key",key,"KB.App.getEnv"),F.isDef(KB.env[key])?KB.en[key]:(F.warn("Env variable ["+key+"] does not exist"),null)}}),KB.AppSkeleton=KB.App.extend({construct:function(){this._super(),F.deprecated("KB.AppSkeleton","KB.App")}})}()}),require.register("kickbox/array",function(){!function(){"use strict";Array.prototype.compare||(Array.prototype.compare=function(array){var i,l;if(!F.isArr(array))return!1;if(this.length!==array.length)return!1;for(i=0,l=this.length;l>i;i+=1)if(F.isArr(this[i])&&F.isArr(array[i])){if(!this[i].compare(array[i]))return!1}else if(this[i]!==array[i])return!1;return!0}),Array.prototype.map||(Array.prototype.map=function(callback,thisArg){var i,l=this.length,a=[];for(F.fn("callback",callback,"Array.map"),i=0;l>i;i+=1)a[i]=callback.apply(thisArg,[this[i],i,this])})}()}),require.register("kickbox/cache",function(){!function(){"use strict";KB.Cache=KB.Class.extend({__c:null,construct:function(){this.__c={}},get:function(key){return F.str("key",key,"KB.Cache.get"),F.isUdef(this.__c[key])?null:this.__c[key]},getAll:function(){return $.extend({},this.__c)},set:function(key,val){return F.str("key",key,"KB.Cache.set"),F.def("val",val,'KB.Cache.set("'+key+'")"'),this.__c[key]=val,this},setAll:function(obj){var k;F.obj("obj",obj,"KB.Cache.setAll");for(k in obj)obj.hasOwnProperty(k)&&this.set(k,obj[k]);return this},has:function(key){return F.str("key",key,"KB.Cache.has"),F.isDef(this.__c[key])},contains:function(val){F.def("val",val,"KB.Cache.contains");var k;for(k in this.__c)if(this.__c[k]===val)return!0;return!1},remove:function(key){return F.str("key",key,"KB.Cache.remove"),delete this.__c[key],this}}),KB._Cache=KB.Cache.extend({construct:function(){this._super(),F.deprecated("KB._Cache","KB.Cache")}})}()}),require.register("kickbox/class",function(){!function(){"use strict";var initializing=!1,fnTest=/xyz/.test(function(){})?/\b_super\b/:/.*/,override=function(prop,prototype,_super,func_name){prototype[func_name]=function(func_name,fn){return function(){var ret,tmp=this._super;return this._super=_super[func_name],ret=fn.apply(this,arguments),this._super=tmp,ret}}(func_name,prop[func_name])},map=function(prop,prototype,_super){var name;for(name in prop)F.isFn(prop[name])&&F.isFn(_super[name])&&fnTest.test(prop[name])?override(prop,prototype,_super,name):prototype[name]=prop[name]};KB.Class=function(){},KB.Class.extend=function(prop,prototype){function Class(opts){var k,v,t=this;if(!initializing){if(F.isInst(t,KB.EventDispatcher)&&(t.__events={}),F.isObj(opts))for(k in opts)v=opts[k],null!==v&&void 0!==v&&(t[k]=opts[k]);F.isArr(t.$dependencies)&&F.isInst(t.$injector,KB.Injector)&&t.$injector.solve(t),F.isFn(t.construct)&&t.construct.apply(t,F.argToArr(arguments))}}var _super=this.prototype;return F.obj("prop",prop,"KB.Class.extend"),initializing=!0,prototype=prototype?new prototype:new this,initializing=!1,map(prop,prototype,_super),Class.prototype=prototype,Class.constructor=Class,Class.extend=KB.Class.extend,Class},KB.EventDispatcher=KB.Class.extend({__events:null,trigger:function(event,options){if(F.str("event",event,"KB.EventDispatcher.trigger"),this.__events[event]){var i,res=!0,evts=this.__events[event],l=this.__events[event].length;for(options=[options||{}],i=0;l>i;i+=1)evts[i].apply(this,options)===!1&&(res=!1);return res}},bind:function(event,callback){return F.str("event",event,"KB.EventDispatcher.bind"),F.fn("callback",callback,"KB.EventDispatcher.bind"),this.__events[event]||(this.__events[event]=[]),this.__events[event].push(callback),this},on:function(event,callback){return this.bind(event,callback)},unbind:function(event,callback){if(F.str("event",event,"KB.EventDispatcher.unbind"),!this.__events[event])return this;for(var evts=this.__events[event],l=this.__events[event].length;(l-=1)>-1;)callback===evts[l]&&evts.splice(l,1);return this},unbindAll:function(event){return F.str("event",event,"KB.EventDispatcher.unbindAll"),this.__events[event]?(this.__events[event]=[],this):this},destroy:function(){this.__events=null}}),KB.Evented=KB.EventDispatcher.extend({__init:function(){F.deprecated("KB.Evented","KB.EventDispatcher"),this._super()}})}()}),require.register("kickbox/core",function(){"undefined"==typeof KickBox&&(KB=KickBox={},"undefined"!=typeof window&&(window.KB=window.KickBox=KickBox)),function(){"use strict";-1===$.event.props.indexOf("dataTransfer")&&$.event.props.push("dataTransfer"),KB.app=function(appName,prettyName){var app,k;F.str("appName",appName,"KB.getApp"),prettyName=prettyName||appName,app=new KB.App({$injector:new KB.Injector,name:prettyName}),appName&&void 0!==window&&(window[appName]=app),app.models.register("GenericArray",function(self){self.__readable="GenericArray",self.objects=ko.observableArray()});for(k in KB._CoreWidgets)app.ui.register(k,KB._CoreWidgets[k]);for(k in KB._CoreExtenders)ko.extenders[k]=KB._CoreExtenders[k];return app},KB.getApp=function(appName,prettyName){return KB.app(appName,prettyName)},KB.error=function(){return F.error.apply(F,F.argToArr(arguments))},KB.log=function(){return F.log.apply(F,F.argToArr(arguments))},KB.notice=function(){F.log.apply(F,F.argToArr(arguments))},KB.warn=function(){return F.warn.apply(F,F.argToArr(arguments))},KB.deprecated=function(){return F.deprecated.apply(F,F.argToArr(arguments))},KB.assert=function(){return F.assert.apply(F,F.argToArr(arguments))},KB.del=function(context,method){F.def("context",context,"KB.del");var f;return f=F.isStr(method)?context[method]:method,F.isFn(f)||F.error('KB.delegate: object "'+method+'"" is not a function'),function(){return context.__caller=this,f.apply(context,arguments)}},KB.delegate=function(context,method){return F.def("context",context,"KB.delegate"),KB.del(context,method)},KB.env=function(){var n=window.navigator,ua=n.userAgent,i=ua.match(/iPhone/i)||ua.match(/iPod/i),c=window.console,ip=ua.match(/iPad/i),ie=n.appName.indexOf("Internet Explorer")>-1;return{Opera:F.isObj(window.opera),Safari:/Safari/.test(ua),MobileSafari:new RegExp("/Apple.*Mobile.*Safari/").test(ua),FF:/Firefox/.test(ua),Chrome:F.isObj(window.chrome),iPhone:!!i,iPad:!!ip,tablet:!!ip,Firebug:!(!c||!c.firebug),WebKit:ua.indexOf("AppleWebKit/")>-1,Gecko:ua.indexOf("Gecko")>-1&&-1===ua.indexOf("KHTML"),IE:ie,IEVersion:function(){return ie?F.pFloat(n.appVersion.split("MSIE")[1]):null}(),IE9:ie&&n.appVersion.indexOf("MSIE 9")>-1,IE10:ie&&n.msPointerEnabled}}(),KB.utils={extension:function(fname){return F.str("fname",fname,"KB.utils.extension"),fname.toLowerCase().substr((Math.max(0,fname.lastIndexOf("."))||1/0)+1)}},KB.wait=function(callback,delay){setTimeout(callback,delay)},KB._CoreExtenders={setDirty:function(target,options){var old,model=options.model,field_name=options.field;return model.__subsc.push(target.subscribe(function(oldValue){old=oldValue},null,"beforeChange")),model.__subsc.push(target.subscribe(function(newValue){F.isArr(newValue)&&F.isArr(old)&&old.compare(newValue)||old!==newValue&&model.isLoaded()&&(model.__dirty(!0),-1===model.__updated.indexOf(field_name)&&model.__updated.push(field_name))})),target},"boolean":function(target,defaultValue){target(defaultValue);var result=ko.computed({read:target,write:function(value){void 0!==value&&""!==value&&(!value||value.match&&value.match(/^(false)|(null)|0$/)?target(!1):target(!0))}});return result.KB=!0,result(defaultValue),result},numeric:function(target,precision){var result=ko.computed({read:target,write:function(newValue){var current=target(),roundingMultiplier=Math.pow(10,precision),newValueAsNum=F.pFloat(newValue,0),valueToWrite=Math.round(newValueAsNum*roundingMultiplier)/roundingMultiplier;valueToWrite!==current?target(valueToWrite):newValue!==current&&target.notifySubscribers(valueToWrite)}});return result(target()),result}}}()}),require.register("kickbox/date",function(){!function(){"use strict";KB.date={getLeadZero:function(num){return F.def("num",num,"KB.date.getLeadZero"),(F.pInt(num)<10?"0":"")+num},timeToString:function(time){return F.num("time",time,"KB.date.timeToString"),this.msTimeToString(1e3*time)},msTimeToString:function(time){var d;return F.num("time",time,"KB.date.msTimeToString"),d=new Date,d.setTime(time),_("%0:%1, %2/%3/%4",KB.date.getLeadZero(d.getHours()),KB.date.getLeadZero(d.getMinutes()),d.getFullYear(),KB.date.getLeadZero(d.getMonth()+1),KB.date.getLeadZero(d.getDate()))},timeago:function(datetime,useOffset,def){return F.isNotNone(def)&&F.str("def",def,"KB.date.timeago"),F.isStr(datetime)?this.msTimeago(new Date(datetime).getTime(),useOffset,def||_("N/A")):def||_("N/A")},msTimeago:function(time,useOffset,def){var delta,i;return time=F.pInt(time,0),F.isNotNone(def)&&F.str("def",def,"KB.date.msTimeago"),0===time?def||_("N/A"):(delta=KB.date.deltaTime(time,F.toBool(useOffset))/1e3,60>delta?_("a few seconds"):120>delta?_("1 minute ago"):3600>delta?_("%0 minutes ago",F.pInt(delta/60)):7200>delta?_("about 1 hour ago"):129600>delta?_("about %0 hours ago",F.pInt(delta/3600)):172800>delta?(i=-Math.round((86400-delta)/3600),0!==i?_("1 day and %0 ago",_n("%0 hour","%0 hours",i,i)):_("1 day ago")):259200>delta?(i=-Math.round((172800-delta)/3600),0!==i?_("2 days and %0 ago",_n("%0 hour","%0 hours",i,i)):_("2 days ago")):_("%0 days ago",F.pInt(delta/86400)))},deltaTime:function(time,useOffset){F.num("time",time,"KB.date.timeago");var rel_to=new Date,delta=F.pInt(rel_to.getTime()-parseFloat(time));return F.toBool(useOffset)?delta+60*rel_to.getTimezoneOffset():delta}}}()}),require.register("kickbox/dependencies/dependency",function(){!function(){"use strict";KB.Dependency=KB.Class.extend({_name:"",_strategy:"service",_dep:null,strategy:function(strategy){return F.isStr(strategy)?(this._strategy=strategy,this):this._strategy},name:function(name){return F.isStr(name)?(this._name=name,this):this._name},object:function(object){return F.isDef(object)?(this._dep=object,this):this._dep},apply:function(target){var k;if(this._strategy===KB.Injector.Strategy.PROTO)for(k in this._dep)target.prototype[k]=this._dep[k];else target["$"+this._name]=this._dep;return this._strategy}})}()}),require.register("kickbox/dependencies/injector",function(){!function(){"use strict";KB.Injector=KB.Class.extend({_deps:null,_pending:null,construct:function(){this._deps={},this._pending={}},register:function(name,dep){F.str("name",name,"KB.Injector.add"),F.def("dep",dep,"KB.Injector.add"),F.isFn(dep)&&(dep=new dep({$injector:this}));var d=new KB.Dependency({_name:name,_strategy:KB.Injector.Strategy.SERVICE,_dep:dep});return this._deps[name]=d,!F.isInst(dep.$injector,KB.Injector)&&F.isArr(dep.$dependencies)&&(dep.$injector=this,this.solve(dep)),this._solvePending(name),d},get:function(name){return F.str("name",name,"KB.Injector.get"),F.assert(F.isInst(this._deps[name],KB.Dependency),'Dependency "'+name+'" has not been registered'),this._deps[name]},has:function(name){return F.str("name",name,"KB.Injector.has"),F.isStr(name)&&F.isInst(this._deps[name],KB.Dependency)},solve:function(target){var i,deps=target.$dependencies,l=F.len(deps);for(i=0;l>i;i+=1)this._solve(target,deps[i]);return this},_solve:function(target,name){var i,pend=this._pending[name];F.str("name",name,"KB.Injector._solve"),this.has(name)?(this.get(name).apply(target),F.isArr(pend)&&(i=pend.indexOf(target))>-1&&pend.splice(i,1)):(F.isArr(pend)||(this._pending[name]=[]),this._pending[name].push(target))},_solvePending:function(name){if(F.str("name",name,"KB.Injector._solvePending"),!F.isNone(this._pending[name]))for(var l=this._pending[name].length;(l-=1)>-1;)this._solve(this._pending[name][l],name)}}),KB.Injector.Strategy={PROTO:"proto",SERVICE:"service",validate:function(strategy){F.str("strategy",strategy,"KB.Strategy.validate")}}}()}),require.register("kickbox/field",function(){!function(){"use strict";KB.Field=KB.Class.extend({name:"",mapkey:"",defval:"",opt:!1,construct:function(){F.str("KB.Field.name",this.name,"KB.Field.construct"),this.map=this.name.underscore("_")},val:function(value){return this.validate(value)?(this.defval=value,this):(F.e("value","KB.Field.val",this.getType(),typeof value,value),this)},map:function(key){return this.mapkey=key,this},optional:function(bool){return this.opt=F.isNone(bool)?!0:!!bool,this},validate:function(){return!0},getName:function(){return this.name},getType:function(){return"any"},getObservable:function(){return ko.observable(this.getDefault())},getMap:function(){return this.mapkey},getDefault:function(){return this.defval},isOptional:function(){return this.opt}}),KB.Field.String=function(fieldname){return F.str("fieldname",fieldname,"KB.Field.String"),new KB.String({name:fieldname})},KB.Field.Number=function(fieldname){return F.str("fieldname",fieldname,"KB.Field.Number"),new KB.Number({name:fieldname})},KB.Field.Boolean=function(fieldname){return F.str("fieldname",fieldname,"KB.Field.Boolean"),new KB.Boolean({name:fieldname})},KB.Field.Array=function(fieldname){return F.str("fieldname",fieldname,"KB.Field.Array"),new KB.Array({name:fieldname})},KB.Field.Record=function(fieldname){return F.str("fieldname",fieldname,"KB.Field.Record"),new KB.Record({name:fieldname})},KB.String=KB.Field.extend({construct:function(){this._super()},validate:function(value){return F.isStr(value)},getType:function(){return"string"}}),KB.Number=KB.Field.extend({precision:0,defval:0,construct:function(){this._super()},validate:function(value){return F.isNum(value)},getType:function(){return"number"},getObservable:function(){return ko.observable(this.getDefault()).extend({numeric:this.precision})}}),KB.Boolean=KB.Field.extend({defval:!0,construct:function(){this._super()},validate:function(value){return F.isBool(value)},getType:function(){return"boolean"},getObservable:function(){return ko.observable(this.getDefault()).extend({"boolean":this.getDefault()})}}),KB.Array=KB.Field.extend({defval:[],construct:function(){this._super()},validate:function(value){return F.isArr(value)},getType:function(){return"array"},getObservable:function(){return ko.observableArray(this.getDefault())}}),KB.Record=KB.Field.extend({defval:null,construct:function(){this._super()},getType:function(){return"record"},getObservable:function(){return ko.observable(this.getDefault())}})}()}),require.register("kickbox/fighterr",function(){"undefined"==typeof F&&(F=FightErr=function(){"use strict";F.log.apply(F,F.argToArr(arguments))},"undefined"!=typeof window&&(window.F=window.FightErr=FightErr)),function(F){"use strict";{var fnType="function",obj={};!!window.chrome}F.fn=function(n,v,func){if(!F.isFn(v))throw F.e(n,func,"function",typeof v,v)},F.arr=function(n,v,func){if(!F.isArr(v))throw F.e(n,func,"Array",typeof v,v)},F.str=function(n,v,func){if(!F.isStr(v))throw F.e(n,func,"string",typeof v,v)},F.num=function(n,v,func){if("number"!=typeof v)throw F.e(n,func,"number",typeof v,v)},F.bool=function(n,v,func){if("boolean"!=typeof v)throw F.e(n,func,"boolean",typeof v,v)},F.obj=function(n,v,func){if(!F.isObj(v))throw F.e(n,func,"object",typeof v,v)},F.udef=function(n,v,func){if(!F.isUdef(v))throw F.e(n,func,"undefined",typeof v,v)},F.def=function(n,v,func){if(!F.isDef(v))throw F.e(n,func,"any defined value",typeof v,v)},F.inst=function(n,v,c,func){if(!F.isInst(v,c))throw F.e(n,func,"instance of "+F.toStr(v),v&&v.constructor?v.constructor.name:F.toStr(v),v)},F.truthy=function(n,v,func){if(!v)throw F.e(n,func,"truthy",!F.toBool(v),v)},F.falsy=function(n,v,func){if(v)throw F.e(n,func,"falsy",!!F.toBool(v),v)},F.assert=function(v,e,c){if(!v){if(!c)throw new Error(e);console.log("[FAILURE] "+e)}},F.isFn=function(v){return"[object Function]"===obj.toString.call(v)},F.isArr=function(v){return"[object Array]"===obj.toString.call(v)
},F.isBool=function(v){return"boolean"==typeof v},F.isStr=function(v){return"string"==typeof v&&!!v},F.isObj=function(v){return"object"==typeof v&&!!v&&v.constructor===obj.constructor},F.isUdef=function(v){return"undefined"==typeof v},F.isDef=function(v){return"undefined"!=typeof v},F.isNum=function(v){return("number"==typeof v||"[object Number]"===obj.toString.call(v))&&!isNaN(v)},F.isInt=function(v){return F.isNum(v)&&0===v%1},F.isFloat=function(v){return F.isNum(v)&&0!==v%1},F.isInst=function(v,c){try{return v instanceof c}catch(e){}return!1},F.isNone=function(v){return null===v||F.isUdef(v)},F.isNotNone=function(v){return null!==v&&F.isDef(v)},F.implement=function(obj,interfazz){var i,l;if(F.arr("interfazz",interfazz,"F.implement"),l=interfazz.length,F.isNone(obj))return!1;for(i=0;l>i;i+=1)if(!F.isFn(obj[interfazz[i]]))return!1;return!0},F.pInt=function(v,def){return isNaN(v)?def||0:parseInt(v,10)},F.pFloat=function(v,def){return isNaN(v)?def||0:(v=parseFloat(v),isNaN(v)?def||0:v)},F.toStr=function(v,def){return null===v||F.isUdef(v)?def||"":typeof v.toString===fnType?v.toString()||def||"":(v=String+v,!v&&def?def:v)},F.toString=function(v,def){return F.toStr(v,def)},F.toArr=function(v,def){return F.isArr(v)?v:F.isArr(def)?def:[]},F.toBool=function(v){return v===!0?v:!1},F.range=function(v,min,max,def){if(!F.isNum(v))return F.isNum(def)?def:0;if(F.num("min",min,"F.range"),F.num("max",max,"F.range"),min>max)throw new Error("F.range: Min value must be less than max value");if(min>v){if(F.isNum(def))return def;v=min}else if(v>max){if(F.isNum(def))return def;v=max}return v},F.len=function(a){return F.isArr(a)?a.length:0},F.argToArr=function(args_obj){return args_obj?Array.prototype.slice.call(args_obj):[]},F.error=function(msg){},F.log=function(){},F.notice=function(){F.log.apply(F,F.argToArr(arguments))},F.warn=function(){},F.deprecated=function(name,replacement,note){},F.assert=function(condition,msg,doContinue){if(!condition)throw new Error("[FAILURE] "+(msg||""))},F.e=function(name,func,required,given,value){return console.warn("Illegal argument type error: Argument "+name+" of function ["+func+"] should be ["+required+"] but is ["+given+"]. Argument value: ",value),new Error("Illegal argument error")}}(FightErr)}),require.register("kickbox/i18n",function(exports,require){!function(){"use strict";KB.I18n=KB.EventDispatcher.extend({$dependencies:["l10n"],method:"_",nmethod:"_n",current:null,available:["en_US"],_dic:{},construct:function(){this.bindMethods()},load:function(locale){return F.str("locale",locale,"KB.I18n.load"),require("locale/"+locale),this},getCurrent:function(){return this.current},setLocale:function(locale){return F.str("locale",locale,"KB.I18n.setLocale"),F.assert(this.exists(locale),'Locale "'+locale+'" does not exist'),this.current=locale,this._dic=this.$l10n.locales[locale],this},exists:function(locale){return F.str("locale",locale,"KB.I18n.exists"),F.isObj(this.$l10n.locales[locale])},methods:function(singular,plural){return F.str("singular",singular,"KB.I18n.methods"),F.str("plural",plural,"KB.I18n.methods"),this._unbind(),this.method=singular,this.nmethod=plural,this._bind(),this},gettext:function(){var a=F.argToArr(arguments),s=a[0],l=a.length,i=0;if(this._dic[s]&&(s=this._dic[s]),l>1)for(i;l>i;i+=1)s=s.split("%"+i).join(a[i+1]);return s},ngettext:function(singular,plural,n){var args=F.argToArr(arguments).slice(3);return F.str("singular",singular,"KB.I18n.ngettext"),F.str("plural",plural,"KB.I18n.ngettext"),F.num("n",n,"KB.I18n.ngettext"),!n||1>=n&&n>-1?args.unshift(singular):args.unshift(plural),this.gettext.apply(this,args)},bindMethods:function(){var method=this.method,nmethod=this.nmethod,self=this,_=this.gettext,_n=this.ngettext;return F.isUdef(window[method])&&(window[method]=function(){return _.apply(self,F.argToArr(arguments))},window[nmethod]=function(){return _n.apply(self,F.argToArr(arguments))}),this},unbindMethods:function(){var method=this.method,nmethod=this.nmethod;return window[method]=null,window[nmethod]=null,this},_bind:function(){return F.deprecated("KB.I18n._bind","KB.I18n.bindMethods"),this.bindMethods()},_unbind:function(){return F.deprecated("KB.I18n._unbind","KB.I18n.unbindMethods"),this.unbindMethods()}}),KB.L10n=KB.EventDispatcher.extend({locales:null,construct:function(){this.locales={}},load:function(locale){var r;F.str("locale",locale,"KB.L10n.load"),r=new KB.DataResource({url:"/static/locale/"+locale+".json"}),r.on("load",KB.del(this,function(){this.trigger("load",{locale:locale,data:r.raw()}),this.register(locale,r.raw()[locale])})).load()},register:function(locale,strings){var k;if(strings||(strings={}),F.str("locale",locale,"KB.L10n.register"),F.obj("strings",strings,"KB.L10n.register"),this.locales[locale])for(k in strings)this.locales[locale][k]=strings[k];else this.locales[locale]=strings;this.trigger("register_locale",{locale:locale})}}),KB._I18n=KB.I18n.extend({construct:function(){F.deprecated("KB._I18n","KB.I18n"),this._super()}}),KB._L10n=KB.L10n.extend({construct:function(){F.deprecated("KB._L10n","KB.L10n"),this._super()}})}()}),require.register("kickbox/init",function(exports,require){!function(){"use strict";require("kickbox/string"),require("kickbox/array"),require("kickbox/number"),require("kickbox/fighterr"),require("kickbox/core"),require("kickbox/ko"),require("kickbox/date"),require("kickbox/class"),require("kickbox/dependencies/injector"),require("kickbox/dependencies/dependency"),require("kickbox/cache"),require("kickbox/view-model-op"),require("kickbox/view-model-base"),require("kickbox/view-model"),require("kickbox/field"),require("kickbox/selection"),require("kickbox/mapper"),require("kickbox/loader"),require("kickbox/store"),require("kickbox/api-method"),require("kickbox/router"),require("kickbox/resource"),require("kickbox/resource-stack"),require("kickbox/ui"),require("kickbox/i18n"),require("kickbox/view"),require("kickbox/views"),require("kickbox/app"),require("kickbox/adapters"),require("kickbox/adapters/base-adapter"),require("kickbox/adapters/tastypie-adapter"),require("kickbox/adapters/dy-tastypie-adapter")}()}),require.register("kickbox/ko",function(){!function(){"use strict";ko.isComputed=function(instance){return null===instance||void 0===instance||void 0===instance.__ko_proto__?!1:instance.__ko_proto__===ko.dependentObservable?!0:ko.isComputed(instance.__ko_proto__)},ko.isObservableArray=function(instance){return!!instance&&F.isFn(instance.__isOA)&&instance.__isOA()},ko.observableArray.fn.__isOA=function(){return!0},ko.observableArray.fn.pushAll=function(items){return F.isArr(items)?(this.valueWillMutate(),ko.utils.arrayPushAll(this.peek(),items),this.valueHasMutated(),this.peek()):[]};var ErrorHandlingBindingProvider=function(){var original=new ko.bindingProvider;this.nodeHasBindings=original.nodeHasBindings,this.getBindings=function(node,bindingContext){var result,err;try{result=original.getBindings(node,bindingContext)}catch(e){throw err=new Error,err.message=e.message,err.node=node,err.bindingContext=bindingContext,err}return result}};ko.bindingProvider.instance=new ErrorHandlingBindingProvider}()}),require.register("kickbox/loader",function(){!function(){"use strict";KB.Loader=KB.EventDispatcher.extend({$dependencies:["store","mapper","app"],def_adapter:null,adapters:{},adapter_map:{},loading:{},ajax_counter:0,construct:function(){},_addRecordCallback:function(model_name,id,callback){F.str("model_name",model_name,"KB.Loader._addRecordCallback"),F.str("id",id,"KB.Loader._addRecordCallback"),F.fn("callback",callback,"KB.Loader._addRecordCallback"),this.loading[model_name+"_"+id]||(this.loading[model_name+"_"+id]=[]),this.loading[model_name+"_"+id].push(callback)},_performRecordCallbacks:function(success,record){F.bool("success",success,"KB.Loader._performRecordCallbacks"),F.inst("record",record,KB.ViewModel,"KB.Loader._performRecordCallbacks");var i,l,id=record.__name+"_"+record.id(),cbs=this.loading[id];if(cbs){for(l=cbs.length,i=0;l>i;i+=1)cbs[i](success,record);delete this.loading[id]}},register:function(id,adapter){return F.str("id",id,"KB.Loader.register"),F.isFn("adapter",adapter,"KB.Loader.register"),adapter.loader=this,adapter.mapper=this.$mapper,adapter.store=this.$store,adapter.app=this.$app,null===this.def_adapter&&(this.def_adapter=id),this.adapters[id]=adapter,this},mapAdapter:function(model_name,adapter_name){return F.str("model_name",model_name,"KB.Loader.mapAdapter"),this.adapter_map[model_name]=F.isStr(adapter_name)?adapter_name:this.def_adapter,this},getAdapter:function(model_name){return F.str("model_name",model_name,"KB.Loader.getAdapter"),this.adapter_map[model_name]?this.adapters[this.adapter_map[model_name]]:null},find:function(model_name,id,callback,force){F.str("model_name",model_name,"KB.Loader.find"),F.str("id",id,"KB.Loader.find"),id=id.split("/").join(":");var adapter=this.getAdapter(model_name),record=this.$store._materialize(model_name,id);return F.isNotNone(callback)&&F.fn("callback",callback,"KB.Loader.find"),"loading"===record.__state()?(callback&&this._addRecordCallback(model_name,id,callback),record):force!==!0&&"idle"!==record.__state()||!adapter?(this.trigger("find",{record:record}),callback&&callback(!0,record),record):(record.__state("loading"),this._onStart(),adapter.find(model_name,id,KB.del(this,function(success,data){return this._onEnd(),F.isArr(data)&&(0===data.length?(data=null,success=!1):data=data.unshift()),success&&data?(this.$store.materialize(model_name,data),"loading"===record.__state()&&(record.__state("loaded"),record.trigger("load",{sucess:!0})),this.trigger("find",{record:record}),this._performRecordCallbacks(success,record),callback&&callback(success,record),void 0):(this.$store.unmaterialize(model_name,id),callback&&callback(!1),void 0)})),record)},findMany:function(model_name,callback){return this.findWhere(model_name,null,null,callback)},findWhere:function(model_name,field,value,callback){var adapter=this.getAdapter(model_name);return adapter?(F.str("model_name",model_name,"KB.Loader.findWhere"),F.isNotNone(callback)&&F.fn("callback",callback,"KB.Loader.findWhere"),this._onStart(),adapter.findWhere(model_name,field,value,KB.del(this,function(success,data){var records,i,l;if(this._onEnd(),success&&data){for(records=this.$store.materializeMany(model_name,data),l=records.length,i=0;l>i;i+=1)("idle"===records[i].__state()||"loading"===records[i].__state())&&(records[i].__state("loaded"),this._performRecordCallbacks(success,records[i]),records[i].trigger("load",{sucess:!0}));return this.trigger("find_many",{records:records}),callback&&callback(!0,records),void 0}callback&&callback(!1,records)})),!0):(callback(!1,[]),!1)},selectMany:function(model_name,callback){return this.selectWhere(model_name,null,null,callback)},selectWhere:function(model_name,field,value,callback){var adapter=this.getAdapter(model_name),selection=new KB.Selection({__name:model_name,__op:this.$app[model_name],app:this.$app}),cb=KB.del(this,function(success,data,meta){if(this._onEnd(),success&&data){var i,records=this.$store.materializeMany(model_name,data),l=records.length;for(i=0;l>i;i+=1)("idle"===records[i].__state()||"loading"===records[i].__state())&&(records[i].__state("loaded"),this._performRecordCallbacks(success,records[i]),records[i].trigger("load",{sucess:!0}));return selection.pushAll(records),meta&&selection.meta(meta),this.trigger("select_many",{selection:selection}),callback&&callback(!0,selection),void 0}callback&&callback(!1,selection)});return F.str("model_name",model_name,"KB.Loader.selectWhere"),F.isNotNone(callback)&&F.fn("callback",callback,"KB.Loader.selectWhere"),adapter?(this._onStart(),F.isStr(field)?adapter.findWhere(model_name,field,value,cb):adapter.findWhere(model_name,field,null,cb),selection):(callback(!0,selection),void 0)},selectNext:function(selection,callback){var model_name=selection.__name,adapter=this.getAdapter(model_name);return F.inst("selection",selection,KB.Selection,"KB.Loader.selectNext"),F.isNotNone(callback)&&F.fn("callback",callback,"KB.Loader.selectNext"),this._onStart(),adapter.findManyAtURL(model_name,selection.nextURL,KB.del(this,function(success,data,meta){if(this._onEnd(),success&&data){var i,records=this.$store.materializeMany(model_name,data),l=records.length;for(i=0;l>i;i+=1)("idle"===records[i].__state()||"loading"===records[i].__state())&&(records[i].__state("loaded"),this._performRecordCallbacks(success,records[i]),records[i].trigger("load",{sucess:!0}));return selection.pushAll(records),meta&&selection.meta(meta),this.trigger("select_next",{selection:selection,appended:l,records:records}),callback&&callback(!0,selection,l,records),void 0}callback&&callback(!1,selection,0,[])})),!0},create:function(record,callback){var adapter=this.getAdapter(record.__name),model_name=record.__name,data=this.$store.recordToRaw(record);return F.inst("record",record,KB.ViewModel,"KB.Loader.create"),F.isNotNone(callback)&&F.fn("callback",callback,"KB.Loader.create"),adapter?(record.trigger("before_save",{}),record.__state("updating"),this._onStart(),adapter.create(record.__name,data,KB.del(this,function(success,data){this._onEnd(),data&&this.$store._validate(record,data,!0),this.trigger("create",{success:success,record:record,name:model_name}),this.trigger("save",{success:success,record:record,name:model_name}),success?(record.__state("updated"),record.__updated=[],record.__dirty(!1),record.trigger("save"),record.trigger("create")):record.__state("idle"),callback&&callback(success,record)})),!0):(record.__state("updated"),record.__dirty(!1),callback(!0,record),!0)},update:function(record,callback){var k,adapter=this.getAdapter(record.__name),model_name=record.__name,data=this.$store.recordToRaw(record),patch=!1,f_updated=record.__updated,has_data=!1;if(F.inst("record",record,KB.ViewModel,"KB.Loader.update"),F.isNotNone(callback)&&F.fn("callback",callback,"KB.Loader.update"),!adapter)return record.__state("updated"),record.__dirty(!1),callback(!0,record),!0;if(record.__op.patch&&f_updated){patch=!0;for(k in data)-1===f_updated.indexOf(k)&&delete data[k];for(k in data)has_data=!0;if(!has_data)return record.__state("updated"),record.__dirty(!1),callback(!0,record),record.trigger("save"),record.trigger("update"),this.trigger("update",{success:!0,record:record,name:model_name}),this.trigger("save",{success:!0,record:record,name:model_name}),!0}return record.trigger("beforeSave",{}),record.__state("updating"),this._onStart(),adapter.update(record.__name,record.id(),data,KB.del(this,function(success,data){this._onEnd(),data&&this.$store._validate(record,data,!1),success?(record.__state("updated"),record.__updated=[],record.__dirty(!1),record.trigger("save"),record.trigger("update")):record.__state("loaded"),this.trigger("update",{success:success,record:record,name:model_name}),this.trigger("save",{success:success,record:record,name:model_name}),callback&&callback(success,record)}),patch),!0},remove:function(record,callback,force){var adapter=this.getAdapter(record.__name),model_name=record.__name;return F.inst("record",record,KB.ViewModel,"KB.Loader.remove"),F.isNotNone(callback)&&F.fn("callback",callback,"KB.Loader.remove"),force!==!0&&this.trigger("removing",{record:record,name:model_name})===!1?!1:(record.__state("removing"),adapter&&record.isReal()?(this._onStart(),adapter.remove(record.__name,record.id(),KB.del(this,function(success){this._onEnd(),success?(record.__state("removed"),record.trigger("remove"),this.$store.unmaterialize(record.__name,record.id()),this.trigger("remove",{success:success,name:model_name,record:record})):record.rollback(),callback&&callback(success)})),!0):(record.__state("removed"),record.trigger("remove"),this.$store.unmaterialize(record.__name,record.id()),callback&&callback(!0),!0))},call:function(request){F.inst("request",request,KB.APIRequest,"KB.Loader.call");var result,adapter=this.getAdapter(request.model());return adapter?(this._onStart(),adapter.call(request,KB.del(this,function(success,data,meta){this._onEnd(),data&&(result=this.sideload(request.model(),data)),this._handleMeta(meta),this.trigger("call",{success:success,result:result}),request.triggerCallback(success,result)})),!0):!0},sideload:function(model_name,data){var i,l,result=null;if(F.str("model_name",model_name,"KB.Loader.sideload"),data){if(F.isArr(data))for(result=this.$store.materializeMany(model_name,data),l=result.length,i=0;l>i;i+=1)result[i].__state("loaded"),result[i].trigger("load",{success:!0});else F.isObj(data)&&(result=this.$store.materialize(model_name,data),result.__state("loaded"),result.trigger("load",{success:!0}));return result}},_handleMeta:function(meta){var k,model;if(F.isObj(meta)&&F.isObj(meta.deleted))for(k in meta.deleted)model=this.$mapper.getModel(k),F.isStr(model)&&F.isArr(meta.deleted[k])?this.$store.removeMany(model,meta.deleted[k]):F.warn('Unable to remove records for key "'+k+'"')},_onStart:function(){this.trigger("start"),this.ajax_counter+=1},_onEnd:function(){this.ajax_counter-=1,this.trigger("end")}}),KB._Loader=KB.Loader.extend({})}()}),require.register("kickbox/mapper",function(){!function(){"use strict";KB.Mapper=KB.Class.extend({_mapToModel:{},_mapToKey:{},_primaries:{},map:function(model_name,key){F.str("model_name",model_name,"KB.Mapper.map"),F.str("key",key),this._mapToKey[model_name]=key,this._mapToModel[key]=model_name},getKey:function(model_name){return F.str("model_name",model_name,"KB.Mapper.getKey"),this._mapToKey[model_name]?this._mapToKey[model_name]:(F.warn('API Mapping: key for model "'+model_name+'" not declared'),null)},getModel:function(key){return F.str("key",key,"KB.Mapper.getModel"),this._mapToModel[key]?this._mapToModel[key]:(F.warn('API Mapping: model for key "'+key+'" not exist'),null)},mapPrimaryKey:function(model_name,primary_key){F.str("model_name",model_name,"KB.Mapper.mapPrimaryKey"),F.str("primary_key",primary_key,"KB.Mapper.mapPrimaryKey"),this._primaries[model_name]=primary_key},getPrimaryKey:function(model_name){return F.str("model_name",model_name,"KB.Mapper.getPrimaryKey"),this._primaries[model_name]?this._primaries[model_name]:(F.warn('API Mapping: primary key for model "'+model_name+'" not exist.'),null)}}),KB._Mapper=KB.Mapper.extend({})}()}),require.register("kickbox/number",function(){!function(){"use strict";Number.prototype.prettify||(Number.prototype.prettify=function(sep){sep=F.isStr(sep)?sep:" ";for(var s=this.toString(),i=0,l=s.length,r="";(l-=1)>-1;)r=s[l]+r,i+=1,3===i&&(r=sep+r,i=0);return r.trim()})}()}),require.register("kickbox/query",function(){!function(){"use strict";KB.Queries=KB.EventDispatcher.extend({construct:function(){},fromStr:function(){},fromObj:function(){}}),KB.Query=KB.Class.extend({_orderFieldName:"order",_orderField:null,str:null,obj:null,cachable:!0,construct:function(){this.str="",this.obj={}},toString:function(){},toObj:function(){},equal:function(query){return this.toString()===query.toString()}})}()}),require.register("kickbox/resource-stack",function(){!function(){"use strict";KB.ResourceStack=KB.EventDispatcher.extend({app:null,request:null,cache:null,avoidRecords:null,parallelRecords:null,sequentialRecords:null,parallelResources:null,sequentialResources:null,stack:null,records:null,_q:null,_initializing:!1,construct:function(){this.stack=[],this.request={},this.records={},this.parallelRecords={},this.sequentialRecords={},this.parallelResources=[],this.sequentialResources=[]},reset:function(){return this.stack=[],this.request={},this.records={},this.parallelRecords={},this.sequentialRecords={},this.parallelResources=[],this.sequentialResources=[],this._q=null,this},load:function(){return this._initializing=!0,this._loadParallelRecords(),this.sequentialResources.length>0&&(this._q=this.sequentialResources.slice(0),this.stack.push("__queue"),this._loadSequentialResources()),this._loadParallelResources(),this._initializing=!1,this._checkStack(),this},setLoaded:function(identifier){F.str("identifier",identifier,"KB.ResourceStack.setLoaded"),this._onLoad(identifier)},addResource:function(resource){var i,l;if(F.isArr(resource)){for(i=0,l=resource.length;l>i;i+=1)this.addResource(resource[i]);return this}return F.str("resource",resource,"KB.ResourceStack.addResource"),this.parallelResources.push(resource),this},_loadParallelRecords:function(){var k;if(this.request&&!this.avoidRecords)for(k in this.parallelRecords)this.parallelRecords.hasOwnProperty(k)&&this._loadRecord(k,this.parallelRecords[k],this.request)},_loadSequentialRecords:function(){},_loadParallelResources:function(){var asset,i,res_length;for(i=0,res_length=this.parallelResources.length;res_length>i;i+=1)asset=this.parallelResources[i],this.stack.push(asset),this._loadResource(asset)},_loadSequentialResources:function(){this._q.length>0?this._loadResource(this._q.shift(),!0):0===this._q.length&&this._onLoad("__queue")},_loadResource:function(url,queued){var self=this;F.str("url",url,"KB.ResourceStack._loadResource"),KB.Resource.get(url,function(resource){F.toBool(queued)?self._loadSequentialResources():self._onLoad(resource.url)},this.cache)},_loadRecord:function(model_name,query,request){F.str("model_name",model_name,"KB.ResourceStack._loadRecord"),F.obj("request",request,"KB.ResourceStack._loadRecord");var returned,self=this;this._loadExistingRecord(model_name,query,request)||(this.stack.push(model_name+"/"+query),0===query.indexOf("source=")?this._loadPureJSONObject(model_name,query,request):"all."!==query.substr(0,4)&&query.indexOf(".")>-1&&-1===query.indexOf("/")?this._loadFromOtherSelection(model_name,query,request):"all"===query||"all."===query.substr(0,4)||"existing"===query?this._loadAllRecords(model_name,query,request):query.indexOf("/")>-1?this._loadRecordById(model_name,query,request):query.indexOf("=")>-1?returned=this._loadSelectWhere(model_name,query,request):"$"===query.substr(0,1)?returned=this._loadRecordByRequestParam(model_name,query,request):isNaN(query)?F.error('No way to load record of "'+model_name+'" with query '+query):this._loadRecordById(model_name,query,request),returned&&returned instanceof KB.Selection&&returned.on("change",function(){self._onRefresh()}))},_loadExistingRecord:function(model_name,query,request){return F.str("model_name",model_name,"KB.ResourceStack._loadRecord"),F.obj("request",request,"KB.ResourceStack._loadRecord"),F.isInst(query,KB.ViewModel)?(this.records[model_name]=query,"idle"===query.__state()&&(this.stack.push(model_name+"/"+query.id()),query.load(function(){this._onLoad(model_name+"/"+query.id())})),!0):F.isInst(query,KB.Selection)?(this.records[model_name]=query,!0):"new"===query?(this.records[model_name]=this.app[model_name].create(),!0):F.isFn(query)?(this.records[model_name]=query(request),!0):null===query?!0:void 0},_loadPureJSONObject:function(model_name,query,request){var obj,self=this;F.str("model_name",model_name,"KB.ResourceStack._loadPureJSONObject"),F.str("query",query,"KB.ResourceStack._loadPureJSONObject"),F.obj("request",request,"KB.ResourceStack._loadPureJSONObject"),F.assert("GenericArray"===model_name,"Pure JSON data requires a GenericArray model to be populated."),$.get(query.substr(7),function(remote_data){obj=self.app.GenericArray.create(),obj.objects(remote_data.objects),self.records.GenericArray=obj,self._onLoad(model_name+"/"+query)})},_loadFromOtherSelection:function(model_name,query,request){var id,test_f,self=this;F.str("model_name",model_name,"KB.ResourceStack._loadFromOtherSelection"),F.str("query",query,"KB.ResourceStack._loadFromOtherSelection"),F.obj("request",request,"KB.ResourceStack._loadFromOtherSelection"),id=query.split("."),test_f=function(){setTimeout(function(){var rec,res,identifier,i;if(self._isRecordLoaded(id[0])){if(rec=self.records[id[0]],rec[id[1]]){if(F.isFn(rec[id[1]])){if(res=rec[id[1]](),F.isArr(res)){for(i=0;i<res.length;i+=1)self._loadRecord(model_name,res[i],request);return self._onLoad(model_name+"/"+query),void 0}identifier=res.id()}else identifier=rec[id[1]];self.app[model_name].find(identifier,function(success,record){success?(self.records[model_name]=record,self._onLoad(model_name+"/"+query)):(self._onLoadError(model_name+"/"+query),self._onRecordNotFound(model_name,query,request))})}}else test_f()},50)},test_f()},_loadAllRecords:function(model_name,query,request){var subquery,method,model,returned,self=this;return F.str("model_name",model_name,"KB.ResourceStack._loadAllRecords"),F.str("query",query,"KB.ResourceStack._loadAllRecords"),F.obj("request",request,"KB.ResourceStack._loadAllRecords"),method="findMany",model=model_name,this.app[model_name]||(model=model_name.singularize(),method="selectMany"),"existing"===query?(self.records[model_name]=this.app[model].getAll(),self._onLoad(model_name+"/"+query),void 0):returned=this.app[model][method](function(success,records){success?("all."===query.substr(0,4)?(subquery=query.substr(4),"first"===subquery?self.records[model_name]=records.shift():"last"===subquery?self.records[model_name]=records.pop():isNaN(subquery)||(self.records[model_name]=records[parseInt(subquery,10)])):self.records[model_name]=records,self._onLoad(model_name+"/"+query)):(self._onLoadError(model_name+"/"+query),self._onRecordNotFound(model_name,query,request))})},_loadSelectWhere:function(model_name,query,request){var subquery,method,model,cb,i,l,obj,id,id2,returned,self=this;if(F.str("model_name",model_name,"KB.ResourceStack._loadAllRecords"),F.str("query",query,"KB.ResourceStack._loadAllRecords"),F.obj("request",request,"KB.ResourceStack._loadAllRecords"),method="findWhere",model=model_name,this.app[model_name]||(model=model_name.singularize(),method="selectWhere"),cb=function(success,records){success?("all."===query.substr(0,4)?(subquery=query.substr(4),"first"===subquery?self.records[model_name]=records.shift():"last"===subquery?self.records[model_name]=records.pop():isNaN(subquery)||(self.records[model_name]=records[parseInt(subquery,10)])):self.records[model_name]=records,self._onLoad(model_name+"/"+query)):(self._onLoadError(model_name+"/"+query),self._onRecordNotFound(model_name,query,request))},query.indexOf("&")>-1){for(id=query.split("&"),obj={},l=id.length,i=0;l>i;i+=1)id2=id[i].split("="),obj[request.map(id2[0])]=request.map(id2[1]);returned=this.app[model][method](obj,null,cb)}else id=query.split("="),returned=this.app[model][method](request.map(id[0]),request.map(id[1]),cb);return returned},_loadRecordByRequestParam:function(model_name,query,request){var id,self=this;F.str("model_name",model_name,"KB.ResourceStack._loadRecordByRequestParam"),F.str("query",query,"KB.ResourceStack._loadRecordByRequestParam"),F.obj("request",request,"KB.ResourceStack._loadRecordByRequestParam"),id=query.substr(1),isNaN(request[id])?F.error('No variable in request "'+request._route+'" named "'+id+'"'):this.app[model_name].find(request[id],function(success,record){success?(self.records[model_name]=record,self._onLoad(model_name+"/"+query)):(self._onLoadError(model_name+"/"+query),self._onRecordNotFound(model_name,query,request))})},_loadRecordById:function(model_name,query,request){var self=this;F.str("model_name",model_name,"KB.ResourceStack._loadRecordById"),F.str("query",query,"KB.ResourceStack._loadRecordById"),F.obj("request",request,"KB.ResourceStack._loadRecordById"),this.app[model_name].find(query,function(success,record){success?(self.records[model_name]=record,self._onLoad(model_name+"/"+query)):(self._onLoadError(model_name+"/"+query),self._onRecordNotFound(model_name,query,request))})},_isRecordLoaded:function(model_name){return F.str("model_name",model_name,"KB.ResourceStack._loadRecordById"),!!this.records&&!!this.records[model_name]},_onRecordNotFound:function(model_name,query,request){F.str("model_name",model_name,"KB.ResourceStack._loadRecordById"),F.str("query",query,"KB.ResourceStack._loadRecordById"),F.obj("request",request,"KB.ResourceStack._loadRecordById"),this.trigger("record_not_found",{model_name:model_name,query:query,request:request})},_onLoad:function(identifier){var i,item;F.str("identifier",identifier,"KB.ResourceStack._onLoad"),i=this.stack.indexOf(identifier),i>-1&&(item=this.stack.splice(i,1)),this._checkStack()},_checkStack:function(){0===this.stack.length&&this._initializing===!1&&this.trigger("load",{request:this.request,data:this.records,avoidRecords:this.avoidRecords})},_onLoadError:function(identifier){F.str("identifier",identifier,"KB.ResourceStack._onLoadError"),this.trigger("load_error",{identifier:identifier})},_onRefresh:function(){this.trigger("refresh")}})}()}),require.register("kickbox/resource",function(){!function(){"use strict";KB.Resource=KB.EventDispatcher.extend({root:"",cachable:!0,load_at_init:!0,cache:null,url:null,_raw:null,construct:function(){null!==this.url&&this.load_at_init&&this.load()},callback:function(callback){callback&&F.isFn(callback)&&callback(this)},setRoot:function(root){return this.root=root,this},getRoot:function(){return this.root},setURL:function(url){return this.url=url,this},getURL:function(){return this.root+this.url},getLoadedURL:function(){return this.root+this.url},load:function(callback){return F.isDef(callback)&&F.fn("callback",callback,"KB.Resource.load requires a function as callback"),this.isCached()?(null===this._raw&&(this._raw=this.cache.get(this.url)),this.trigger("load"),this.callback(callback),void 0):(this._load(callback),this)},reload:function(callback){return F.isDef(callback)&&F.fn("callback",callback,"KB.Resource.load requires a function as callback"),this._load(callback),this},_load:function(callback){var self=this;$.get(self.getLoadedURL(),function(data){self._raw=data,self.attach(),self.setCache(),self.trigger("load"),self.callback(callback)})},setCache:function(){return this.cache&&this.cachable?(this.cache.set(this.url,this._raw),this):void 0},isCached:function(){return!!this.cachable&&!!this.cache&&this.cache.has(this.url)},attach:function(){F.assert(!1,'KB.Resource.attach method must be extended. Cannot attach resource "'+this.url+'"')},raw:function(){return this._raw}}),KB.Resource.get=function(URL,callback,cache,type,root){var ext=F.isStr(type)?type:KB.utils.extension(URL),res=null;return F.str("URL",URL,"KB.Resource.get"),root=F.isStr(root)?root:"","css"===ext?res=new KB.CSSResource({root:root}):"js"===ext?res=new KB.JSResource({root:root}):"json"===ext?res=new KB.JSONResource({root:root}):"tpl"===ext||"html"===ext?res=new KB.TemplateResource({root:root}):"txt"===ext?res=new KB.PlainTextResource({root:root}):F.warn('No resource suitable to extension "'+ext+'"'),res&&(res.setURL(URL),cache&&(res.cache=cache),F.isFn(callback)&&res.load(callback)),res},KB.CSSResource=KB.Resource.extend({attach:function(){$('<style type="text/css"></style>').html(this.raw()).appendTo("head")}}),KB.JSResource=KB.Resource.extend({_load:function(callback){var self=this;$.ajax({url:self.url,dataType:"script",method:"GET",cache:self.cachable,success:function(data){self._raw=data,self.setCache(),self.trigger("load"),self.callback(callback)},error:function(jqxhr,settings,exception){F.error("Resource "+self.url+" not loaded: "+exception),self.trigger("error")}})}}),KB.JSONResource=KB.Resource.extend({_load:function(callback){var self=this;$.ajax({url:self.url,dataType:"text",method:"GET",cache:self.cachable,success:function(data){self._raw=JSON.parse(data),self.setCache(),self.trigger("load"),self.callback(callback)},error:function(jqxhr,settings,exception){F.error("Resource "+self.url+" not loaded: "+exception),self.trigger("error")}})}}),KB.TemplateResource=KB.Resource.extend({construct:function(){0===$("#"+KB.TemplateResource.containerId).length&&$("body").append($("<div />").attr("id",KB.TemplateResource.containerId).css("display","none")),this._super()},getLoadedURL:function(){return this.root+this.url+"?"+KB.TemplateResource.TS},attach:function(){$("#"+KB.TemplateResource.containerId).append(this.raw())}}),KB.TemplateResource.TS=(new Date).getTime(),KB.DataResource=KB.Resource.extend({_load:function(callback){var self=this,url=self.url;$.get(url,function(data){self._raw=data,self.trigger("load"),self.callback(callback)
})},attach:function(){}}),KB.TemplateResource.containerId="kb___tpls",KB.PlainTextResource=KB.Resource.extend({_load:function(callback){var self=this,url="/proxy/?url="+self.url;$.get(url,function(data){self._raw=data,self.attach(),self.setCache(),self.trigger("load"),self.callback(callback)})},attach:function(){}}),KB._Resource=KB.Resource.extend({construct:function(){this._super(),F.deprecated("KB._Resource","KB.Resource")}}),KB._Resource.get=function(url,callback,cache){return F.deprecated("KB._Resource.get","KB.Resource.get"),KB.Resource.get(url,callback,cache)}}()}),require.register("kickbox/router",function(){!function(){"use strict";KB.Router=KB.EventDispatcher.extend({$dependencies:["app"],_routes:null,_history:null,_curr:null,_match:null,_host:null,_path:null,_href:null,_lastRequest:null,_blocked:!1,_redirect_data:null,construct:function(){this._host=window.location.host,this._href=window.location.href.toString().split("#")[0].split("?")[0],this._path=this._href.split(this._host)[1],this._curr=this.clean(window.location.hash),this._match=[],this._routes=[],this._history=[];var splittedHash,self=this,hash=this.clean(window.location.hash);$(window).on("hashchange",function(){self._update()}),"/"===hash[hash.length-1]&&(hash=hash.substr(0,hash.length-1)),splittedHash=hash.split("/"),this._lastRequest=KB.Request.get({_hash:hash,_mappable:"",_app:this.$app,_splitted:splittedHash}),$(document).on("keydown",KB.del(this,function(e){8!==e.which||this._blocked!==!0||$(e.target).is("input, textarea")||e.preventDefault()}))},block:function(){return this._blocked=!0,this},unblock:function(){return this._blocked=!1,this},host:function(){return this._host},path:function(){return this._path},href:function(){return this._href},current:function(){return this._curr},actual:function(){return F.deprecated("KB.Router.actual","KB.Router.current"),this.current()},match:function(){return this._match},last:function(){return this._lastRequest},route:function(route,callback){if(F.fn("callback",callback,"KB.Router.route"),F.isArr(route)){var i,l=route.length;for(i=0;l>i;i+=1)this._routes.push(new KB.Route({raw:route[i],callback:callback,app:this.$app}))}else F.str("route",route,"KB.Router.route"),this._routes.push(new KB.Route({raw:route,callback:callback,app:this.$app}));return this},unroute:function(route){return this._routes.length,F.str("route",route,"KB.Router.unroute"),this},redirect:function(hash,data){return F.isStr(hash)&&0===hash.indexOf("http")?(window.location=hash,void 0):this._blocked?this:(F.isObj(data)&&(this._redirect_data=data),F.str("hash",hash,"redirect"),this.trigger("redirect",{URL:hash}),window.location.hash="#!/"+this.clean(hash),this)},previous:function(){return this._blocked?this:(history.go(-1),this)},next:function(){return this._blocked?this:(history.go(1),this)},getRawRoutesArray:function(){var i=0,a=[],l=this._routes.length;for(i=0;l>i;i+=1)a.push(this._routes[i].raw);return a},clean:function(hash){for(hash=F.toStr(hash);hash.length>0&&("#"===hash[0]||"!"===hash[0]||"/"===hash[0]);)hash=hash.substring(1);return hash},_update:function(){if(!this._blocked){this._curr=this.clean(window.location.hash),this._match=[];var splittedHash,i=0,hash=this._curr,l=this._routes.length,found=0;for("/"===hash[hash.length-1]&&(hash=hash.substr(0,hash.length-1)),splittedHash=hash.split("/"),this.trigger("beforeUpdate",{hash:hash}),this.trigger("before_update",{hash:hash}),this._history.push(hash),splittedHash=hash.split("/"),this._lastRequest=KB.Request.get({_hash:this._curr,_mappable:"",_app:this.$app,_splitted:splittedHash}),i=0;l>i;i+=1)this._routes[i]&&this._routes[i].apply(splittedHash,hash,this._redirect_data)&&(this._match.push(this._routes[i]),found+=1);this.trigger("update",{hash:hash}),this._redirect_data=null,0===found&&F.warn('No route set for hash "'+hash+'". Tested routes:\n    '+this.getRawRoutesArray().join("\n    "))}}}),KB.Route=KB.Class.extend({construct:function(){this.splitted=this.raw.split("/")},callback:null,app:null,raw:"",splitted:null,getRequest:function(splittedHash,hash,params){var k,o=KB.Request.get({_route:this.raw,_hash:hash,_mappable:"",_app:this.app,_splitted:splittedHash});if(F.isDef(params))for(k in params)o[k]=params[k];return o},apply:function(splittedHash,hash,data){var request,param_name,param_type,optional,param,subroute,exceptions,params={_data:data},maptrim=function(val){return val.trim()},mappable=[],i=0,l=this.splitted.length;for(i=0;l>i;i+=1){if(subroute=this.splitted[i],void 0===subroute)return!1;if("*"!==subroute){if("..."===subroute)return mappable.push(splittedHash[i]),params._mappable=mappable.join("/"),request=this.getRequest(splittedHash,hash,params),this.callback(request,data),!0;if("("===subroute[0]&&")"===subroute[subroute.length-1]||"["===subroute[0]&&"]"===subroute[subroute.length-1]){if(optional="["===subroute[0],void 0===splittedHash[i]&&!optional)return!1;if(param=splittedHash[i],param_name=subroute.substring(1,subroute.length-1),param_name.indexOf("!")>-1?(param_name=param_name.split("!"),exceptions=param_name[1].split(",").map(maptrim),param_name=param_name[0].trim()):exceptions=null,-1===param_name.indexOf(":")){if(exceptions&&exceptions.indexOf(param)>-1)return!1;params[param_name]=param,mappable.push("$"+param_name)}else{if(param_name=param_name.split(":"),param_type=param_name[1].trim(),param_name=param_name[0].trim(),"number"===param_type.trim()&&isNaN(param))return!1;if("boolean"===param_type){if("true"!==param||"false"!==param)return!1;param="true"!==param?!1:!0}else if("string"===param_type&&!isNaN(param))return!1;params[param_name]=param,mappable.push("$"+param_name)}}else{if(splittedHash[i]!==subroute)return!1;mappable.push(splittedHash[i])}}else mappable.push(splittedHash[i])}return params._mappable=mappable.join("/"),l===splittedHash.length?(request=this.getRequest(splittedHash,hash,params),this.callback(request,data),!0):!1}}),KB.Request={o:{map:function(URL){F.str("URL",URL,"KB.Request.map");var a=URL.split("/"),i=0,l=a.length;for(i=0;l>i;i+=1)"$"===a[i][0]&&(a[i]=this[a[i].substr(1)]);return a.join("/")},isEqual:function(request){return!!request&&!!request._route&&!!this._route&&request._route===this._route&&this._hash===request._hash},query:function(){return this._hash?this._hash:""},route:function(){return this._route?this._route:""},mappable:function(){return this._mappable?this._mappable:""},reapply:function(opts){return opts&&(F.obj("opts",opts,"KB.Request.reapply"),this.setAll(opts)),this._app.redirect(this.map(this.mappable())),this},setAll:function(opts){var k;F.obj("opts",opts,"KB.Request.reapply");for(k in opts)this[k]=opts[k];return this},set:function(k,v){return F.str("k",k,"KB.Request.set"),this[k]=v,this},get:function(k){return F.str("k",k,"KB.Request.get"),this[k]?this[k]:""},getAt:function(i){return F.num("i",i,"KB.Request.getAt"),this._splitted&&i>-1&&this._splitted.length>i?this._splitted[i]:null}},get:function(opts){var r={};return $.extend(r,this.o),$.extend(r,opts||{}),r},isRequest:function(obj){return F.implement(obj,["map","mappable","query","route","reapply"])}},KB._Route=KB.Route.extend({construct:function(){this._super(),F.deprecated("KB._Route","KB.Route")}}),KB._Router=KB.Router.extend({construct:function(){this._super(),F.deprecated("KB._Router","KB.Router")}})}()}),require.register("kickbox/selection",function(){!function(){"use strict";KB.Selection=KB.ViewModelBase.extend({_lists:null,_loading:!1,sorting:null,more:null,nextURL:null,iter:null,construct:function(){this._lists={},this.selection=ko.observableArray(),this.count=ko.observable(0),this.empty=ko.observable(!0),this.hasNext=ko.observable()},selection:null,count:null,hasNext:null,isLoading:function(){return this._loading},meta:function(meta){return this.nextURL=null,F.isObj(meta)&&(F.isNum(meta.count)&&this.count(meta.count),F.isStr(meta.next)&&(this.nextURL=meta.next)),this.empty(!(this.length()>0||this.count()>0)),this.hasNext(null!==this.nextURL),this},pushAll:function(records){F.arr("records",records,"KB.Selection.pushAll");var i,l=records.length;for(i=0;l>i;i+=1)this.add(records[i],"push",!1);return this.empty(!(this.length()>0||this.count()>0)),this.trigger("change"),this.hasNext()||this.trigger("done"),this.count()},unshift:function(record){return F.inst("record",record,KB.ViewModel,"KB.Selection.unshift"),this.add(record,"unshift")},push:function(record){return F.inst("record",record,KB.ViewModel,"KB.Selection.push"),this.add(record,"push")},add:function(record,method,triggerEvts){F.inst("record",record,KB.ViewModel,"KB.Selection.add"),F.str("method",method,"KB.Selection.add"),F.isFn(this.selection[method])||F.e("method","KB.Selection.add","Valid method name","Invalid method name"),this.selection[method](record);var l=this.selection().length,self=this;return this.count<l&&this.count(l),record.on("remove",function(){self.selection.remove(this),self.count(self.count()+1),self.trigger("change")}),this._lists={},triggerEvts!==!1&&(this.empty(!(this.length()>0||this.count()>0)),this.trigger("change"),this.hasNext()||this.trigger("done")),l},length:function(){return this.selection().length},first:function(){return this.selection().length>0?this.selection()[0]:null},last:function(){var l=this.selection().length;return l>0?this.selection()[l-1]:null},getById:function(id){var a=this.selection(),i=0,l=a.length;for(i=0;l>i;i+=1)if(a[i].id()===F.toStr(id))return a[i];return null},removeById:function(id){var a=this.selection(),i=0,found=!1,l=a.length;for(i=0;l>i;i+=1)if(a[i].id()===F.toStr(id)){this.selection.remove(a[i]),found=!0;break}return found&&(this._lists={},this.count(this.selection().length),this.trigger("change")),this.count()},removeBy:function(field,value){F.str("field",field,"KB.Selection.removeBy");var a=this.selection(),i=0,found=!1,l=a.length;for(i=0;l>i;i+=1)F.isFn(a[i][field])?a[i][field]()===value&&(this.selection.remove(a[i]),found=!0):a[i][field]===value&&(this.selection.remove(a[i]),found=!0);return found&&(this._lists={},this.count(this.selection().length),this.trigger("change")),this.count()},next:function(){return this._loading?void 0:(F.assert(!!this.nextURL,"[KB.Selection] Cant load next stack because theres no URL"),this.__op.selectNext(this,KB.del(this,function(success,selection,appended,records){this._loading=!1,success&&this.trigger("next",{appended:appended,records:records})})),this._loading=!0,this)},iterate:function(){return null===this.iter&&(this.iter=-1),this.iter<this.length()-1?(this.iter+=1,this.selection()[this.iter]):(this.iter=null,null)},rewind:function(){return this.iter=null,this},sort:function(field){return F.str("field",field,"KB.Selection.sort"),KB.del(this,function(){var inverse=this.sorting===field;this.sorting=inverse?null:field,this.selection.sort(function(l,r){return inverse?l[field]()<r[field]()?1:-1:l[field]()>r[field]()?1:-1})})},toList:function(record_text_field,list_text_field,filter){var list=F.toStr(record_text_field,"toString")+"-"+F.toStr(list_text_field,"text");return this._lists[list]?this._lists[list]:(this._lists[list]=KB.ViewModelOperator.toList(this.selection(),record_text_field,list_text_field,filter),this._lists[list])}}),KB._Selection=KB.Selection.extend({construct:function(){F.deprecated("KB._Selection","KB.Selection"),this._super()}})}()}),require.register("kickbox/store",function(){!function(){"use strict";KB.Store=KB.Class.extend({$dependencies:["app","loader","mapper"],mapper:null,_app_model:null,_idIdx:0,_models:null,_relationships:null,_records:null,_references:null,_props:null,_indexes:null,construct:function(){this._models={},this._indexes={},this._relationships={},this._records={},this._references={},this._props={}},register:function(model_name,constructor,adapter){F.str("model_name",model_name,"KB.Store.register"),F.fn("constructor",constructor,"KB.Store.register");var type,isKO,k,i,l,model=new KB.ViewModelBase,fields=[],parents=[];if(model_name.indexOf(":")>0)for(model_name=model_name.split(":"),F.assert(2===model_name.length,'Child models must be declared like this: "ModelName:ParentModel,AnotherParent", declaration was: "'+model_name.join(":")+'"'),parents=model_name[1].split(","),model_name=model_name[0].trim(),i=0,l=parents.length;l>i;i+=1)parents[i]=parents[i].trim(),F.assert(!!this.$app[parents[i]]&&this.$app[parents[i]]instanceof KB.ViewModelOperator,'Parent model "'+parents[i]+'" for "'+model_name+'" does not exist. You should create model or remove it in declaration.');for(this._records[model_name]||(this._records[model_name]={}),this._models[model_name]=constructor,this.$app[model_name]=new KB.ViewModelOperator({app:this.$app,name:model_name,loader:this.$loader,mapper:this.$mapper,store:this,parents:parents}),this.$app[model_name].primary("id"),i=0,l=parents.length;l>i;i+=1)fields=fields.concat(this._props[parents[i]]);constructor(model);for(k in model)type=typeof model[k],isKO=ko.isObservable(model[k])&&(!ko.isComputed(model[k])||!!model[k].KB),(isKO||"boolean"===type||"number"===type||"string"===type)&&fields.push(k);return this.$loader.mapAdapter(model_name,adapter),this._props[model_name]=fields,this.$app[model_name].mapTo(model_name.underscore()),this.$app[model_name]},isModel:function(model_name){return F.isFn(this._models[model_name])&&F.isArr(this._props[model_name])&&F.isInst(this.$app[model_name],KB.ViewModelOperator)},getByClientId:function(model_name,id){return F.str("model_name",model_name,"KB.Store.getByClientId"),id=F.toStr(id),id&&this._references[id]&&this._records[model_name][this._references[id]]?this._records[model_name][this._references[id]]:null},getBy:function(){var model_name,field,value,count,refs,k,args=F.argToArr(arguments),result=[],i=count;if(model_name=args.shift(),count=args.pop(),field=args.shift(),F.isObj(field)||(value=args.shift(),F.str("field",field,"KB.Store.getBy"),F.def("value",value,"KB.Store.getBy")),F.str("model_name",model_name,"KB.Store.getBy"),count=F.range(count,1,2048,2048),"id"===field&&1===count)return this.getById(model_name,value);refs=this._records[model_name];for(k in refs)if(this.compare(refs[k],field,value)&&(i-=1,result.push(refs[k])),0===i)break;return 1===count?result.length>0?result[0]:null:result},compare:function(record,field_or_obj,value){var k;if(F.inst("record",record,KB.ViewModel,"KB.Store.compare"),F.isObj(field_or_obj)){for(k in field_or_obj)if(!this.compare(record,k,field_or_obj[k]))return!1;return!0}return F.str("field_or_obj",field_or_obj,"KB.Store.compare"),F.def("value",value,"KB.Store.compare"),(F.isFn(record[field_or_obj])?record[field_or_obj]():record[field_or_obj])===value},getById:function(model_name,id,materialize){return F.str("model_name",model_name,"KB.Store.getById"),id=F.toStr(id),F.str("id",id,"KB.Store.getById"),this._records[model_name]&&this._records[model_name][id]?this._records[model_name][id]:materialize?this._materialize(model_name,id):null},getAll:function(model_name){F.str("model_name",model_name,"KB.Store.getAll");var k,a=[];if(this._records[model_name])for(k in this._records[model_name])a.push(this._records[model_name][k]);return a},materialize:function(model_name,data){F.str("model_name",model_name,"KB.Store.materialize"),F.obj("data",data,"KB.Store.materialize"),data=this.$app[model_name].applyInputs(data),data=this.$app[model_name].applyConversions(data);var rel,rels,i,k,record=this._materialize(model_name,data[this.$mapper.getPrimaryKey(model_name)]),l=0;for(k in data)if(rels=this.getRelationship(model_name,k))for(i=0,l=rels.length;l>i;i+=1)rel=rels[i],this._materializeRels(record[k],rel.type,model_name,rel.model,data[k]);else F.isFn(record[k])?record[k]()!==data[k]&&record[k](data[k]):record[k]!==data[k]&&(record[k]=data[k]);return record.onMaterialized(),record.onLoad(),record},materializeMany:function(model_name,list){F.str("model_name",model_name,"KB.Store.materializeMany"),F.arr("list",list,"KB.Store.materializeMany");var i,l,a=[];for(i=0,l=list.length;l>i;i+=1)a[i]=this.materialize(model_name,list[i]);return a},unmaterialize:function(model_name,id){F.str("model_name",model_name,"KB.Store.unmaterialize"),F.str("id",id,"KB.Store.unmaterialize");var subsc,k,i,i2,rel,l,j,m,related_record,related_rel_type,record=this._records[model_name][id],rels=this.getRelationships(model_name);for(F.assert(!!record,"You try to unmaterialize a record ("+id+') of "'+model_name+"\" that doesn't exist."),subsc=record.__subsc,l=subsc.length,k=0;l>k;k+=1)subsc[k].dispose(),delete subsc[k];for(l=rels?rels.length:0,i=0;l>i;i+=1)if(related_record=record[rels[i].key]())for(rel=this.getRelationship(rels[i].model,rels[i].foreign_key),m=rel.length,j=0;m>j;j+=1)if(related_rel_type=rel[j].type,F.isArr(related_record))for(i2=0;i2<related_record.length;i2+=1)"belongsTo"===related_rel_type?related_record[i2][rel[j].key](null):related_record[i2][rel[j].key].remove(record);else"belongsTo"===related_rel_type?related_record[rel[j].key](null):related_record[rel[j].key].remove(record);record.__nullify(),delete this._references[record.clientId],delete this._records[model_name][id];for(k in record)record[k]=null},isRelationship:function(model_name,key){if(F.str("model_name",model_name,"KB.Store.isRelationship"),F.str("key",key,"KB.Store.isRelationship"),!this._relationships[model_name])return!1;var i,l=this._relationships[model_name].length;for(i=0;l>i;i+=1)if(this._relationships[model_name][i].key===key)return!0;return!1},getRelationship:function(model_name,key){if(F.str("model_name",model_name,"KB.Store.isRelationship"),F.str("key",key,"KB.Store.isRelationship"),!this._relationships[model_name])return null;var i,l=this._relationships[model_name].length,res=[];for(i=0;l>i;i+=1)this._relationships[model_name][i].key===key&&res.push(this._relationships[model_name][i]);return res.length>0?res:null},getRelationships:function(model_name){return F.str("model_name",model_name,"KB.Store.getRelationships"),this._relationships[model_name]?this._relationships[model_name]:void 0},exclude:function(model_name,field){F.str("model_name",model_name,"KB.Store.exclude"),F.str("field",field,"KB.Store.exclude");var i=this._props[model_name].indexOf(field);F.assert(i>-1,"You're trying to exclude field \""+field+'"" from model "'+model_name+'"" but field does not exist in model. Fix "'+model_name+'" by creating the field or removing it from excluded fields.'),delete this._props[model_name][i]},include:function(model_name,prop){F.str("model_name",model_name,"KB.Store.include"),this._props[model_name].push(prop)},_validate:function(record,data,creation){F.inst("record",record,KB.ViewModel,"KB.Store._validate"),F.obj("data",data,"KB.Store._validate");var k,i,l,rel,rec,model_name=record.__name,primaryKey=this.$mapper.getPrimaryKey(model_name);if(data=this.$app[model_name].applyInputs(data),data=this.$app[model_name].applyConversions(data),creation){if(!data[primaryKey])return F.log('Data integrity validation failed. No id for creation of "'+model_name+'" record',record,data),!1;this._records[model_name][record.id()]&&delete this._records[model_name][record.id()],this._records[model_name][data[primaryKey]]=record,record.id(data[primaryKey])}for(k in data)if("id"!==k&&null!==data[k]&&-1!==this._props[model_name].indexOf(k))if(this.isRelationship(model_name,k))if(F.isArr(data[k])){for(l=data[k].length,rel=[],i=0;l>i;i+=1)data[k][i].model||!data[k][i].resource_uri?(rec=this.getById(data[k][i].model,data[k][i].id,!0),-1===rel.indexOf(rec)&&rel.push(rec)):rec=this.materialize(data[k][i].resource_uri.split("/").reverse()[2].camelize(),data[k][i]);record[k](rel)}else!data[k]||record[k]()&&record[k]().id()===data[k].id||(!data[k].model&&data[k].resource_uri?record[k](this.materialize(data[k].resource_uri.split("/").reverse()[2].camelize(),data[k])):record[k](this.getById(data[k].model,data[k].id,!0)));else F.isFn(record[k])?record[k](data[k]):record[k]=data[k];return!0},_materialize:function(model_name,id){if(F.assert(!!this._records[model_name],'No model declared as "'+model_name+'"'),id&&this._records[model_name][id])return this._records[model_name][id];var prop,i,l,sub,kb_model=new KB.ViewModel,ko_model=this._models[model_name],primaryKey=this.$mapper.getPrimaryKey(model_name),rels=this._relationships[model_name],parents=this.$app[model_name].parents,all_props=this._props[model_name],done=[];for(l=parents.length,i=0;l>i;i+=1)this._models[parents[i]](kb_model);ko_model(kb_model);for(prop in kb_model)all_props.indexOf(prop)>-1&&F.isFn(kb_model[prop])&&kb_model[prop].extend&&kb_model[prop].extend({setDirty:{model:kb_model,field:prop}});kb_model.__name=model_name,kb_model.app=this.$app,kb_model.__loader=this.$loader,kb_model.__op=this.$app[model_name],kb_model.clientId=F.toStr(this._idIdx);for(i in this.$app[model_name].subscriptions)sub=kb_model[i].subscribe(KB.del(kb_model,this.$app[model_name].subscriptions[i])),sub&&kb_model.__subsc.push(sub);if(kb_model.id="id"===primaryKey?ko.observable():ko.computed({read:function(){return kb_model[primaryKey]()},write:function(newValue){kb_model[primaryKey](newValue)}}),id?kb_model.id(id):(kb_model.id("__tmp_"+this._idIdx),kb_model.__dirty(!0),kb_model.__state("local")),this._idIdx+=1,this._references[kb_model.clientId]=kb_model.id(),this._records[model_name][kb_model.id()]=kb_model,rels)for(l=rels.length,i=0;l>i;i+=1)-1===done.indexOf(rels[i].key)&&(this._subscribe(kb_model,rels[i].key,rels[i]),done.push(rels[i].key));return kb_model.onMaterialize(),F.isFn(kb_model.init)&&kb_model.init(),kb_model},_materializeRels:function(observer,type,model_name,related_model_name,related_id){F.fn("observer",observer,"KB.Store._materializeRels"),F.str("type",type,"KB.Store._materializeRels"),F.str("model_name",model_name,"KB.Store._materializeRels"),F.str("related_model_name",related_model_name,"KB.Store._materializeRels"),F.def("related_id",related_id,"KB.Store._materializeRels");var new_relation,a,i,curRels=observer();if("belongsTo"===type){if(F.isObj(related_id)&&related_id.model&&(new_relation=this._materialize(related_id.model,related_id.id)),curRels===new_relation)return;observer(new_relation)}else{if(curRels||(curRels=[]),a=0,F.isObj(related_id))if(related_id.model)for(i=0;i<related_id.ids.length;i+=1)new_relation=F.isStr(related_id.ids[i])?this._materialize(related_id.model,related_id.ids[i]):this.materialize(related_id.model,related_id.ids[i]),-1===curRels.indexOf(new_relation)&&(curRels.push(new_relation),a+=1);else if(F.isArr(related_id))for(i=0;i<related_id.length;i+=1)new_relation=null,new_relation=related_id[i].model?this._materialize(related_id[i].model,related_id[i].id):this.materialize(related_model_name,related_id[i]),new_relation&&-1===curRels.indexOf(new_relation)&&(curRels.push(new_relation),a+=1);a>0&&observer(curRels)}},_materializeMany:function(model_name,id_list){var i,a=[];for(i=0;i<id_list.length;i+=1)a[i]=this._materialize(model_name,id_list[i]);return a},_subscribe:function(record,field,relation){var f,old,self=this;F.inst("record",record,KB.ViewModel,"KB.Store._subscribe"),F.str("field",field,"KB.Store._subscribe"),F.obj("relation",relation,"KB.Store._subscribe"),record[field]||F.error('Field "'+field+'" of model "'+record.__name+'" doesn\'t exist but is declared as a relationship of "'+relation.model+'". Fix "'+record.__name+'" model by creating field or removing relationship.'),f=record[field],old=f(),record.__subsc.push(f.subscribe(function(old_value){old=old_value},null,"beforeChange")),record.__subsc.push(f.subscribe(function(data){if(!f.__loop){f.__loop=!0;var inverse,i,i2,l2,rels=self.getRelationship(relation.model,relation.foreign_key),l=rels?rels.length:0;for(i=0;l>i;i+=1)if(inverse=rels[i],F.isArr(data))for(l2=data.length,i2=0;l2>i2;i2+=1)self._checkRelation(record,inverse.type,data[i2],relation);else self._checkRelation(record,inverse.type,data,relation,old);return record.setDirty(!0),f.__loop=!1,data}}))},_checkRelation:function(record,type,remote_record,relation,previous){var f,arr,i;F.isInst(remote_record,KB.ViewModel)&&(f=remote_record[relation.foreign_key],"belongsTo"===type?f&&f()!==record&&(f(record),remote_record.setDirty(!0)):f&&-1===f.indexOf(record)&&(f.push(record),remote_record.setDirty(!0))),F.isInst(previous,KB.ViewModel)&&previous.__nullified!==!0&&(f=previous[relation.foreign_key],"belongsTo"===type?null!==f()&&(f(null),previous.setDirty(!0)):F.isArr(f)&&(i=f.indexOf(record),-1>i&&(arr=f.splice(i,1),arr.length>0&&F.isInst(arr[0],KB.ViewModel)&&arr[0].setDirty(!0),previous.setDirty(!0))))},bulkSave:function(){var i,k,arg,cb,args=F.argToArr(arguments),l=args.length,toSave=[];if(0===l)return this;if(arg=args.shift(),F.isFn(arg))return arg(),this.bulkSave.apply(this,args),this;F.str("arg",arg,"KB.Store.bulkSave");for(k in this._records[arg])this._records[arg][k].isDirty()&&toSave.push(k);if(0===toSave.length)this.bulkSave.apply(this,args);else for(cb=KB.del(this,function(){toSave.shift(),0===toSave.length&&KB.wait(KB.del(this,function(){this.bulkSave.apply(this,args)}),10)}),i=0,l=toSave.length;l>i;i+=1)this._records[arg][toSave[i]]?this._records[arg][toSave[i]].save(cb):F.warn("Bulksaving "+arg+" returned undefined record",this._records[arg]);return this},removeMany:function(model_name,ids){F.str("model_name",model_name,"KB.Store.removeMany"),F.arr("ids",ids,"KB.Store.removeMany");var i,l,r;for(i=0,l=ids.length;l>i;i+=1)r=this.getById(model_name,ids[i],!1),F.isInst(r,KB.ViewModel)&&r.remove();return this},_registerRelationship:function(from,key,type,foreign_key,to){this._relationships[from]||(this._relationships[from]=[]),this._relationships[from].push({type:type,foreign_key:foreign_key||"id",model:to,from:from,key:key})},validateModels:function(){this.validateRelationships()},validateRelationships:function(){var k,i,l,rel,record_test,hasErr=!1,rels=this._relationships;for(k in rels)for(l=rels[k].length,i=0;l>i;i+=1)rel=rels[k][i],rels[rel.model]||this._models[rel.model]?this.getRelationship(rel.model,rel.foreign_key)||(F.warn("Inverse relationships of "+k+"."+rel.key+" (in "+rel.model+"."+rel.foreign_key+") not declared. "+rel.model+" model should have such thing as:\n    "+"[belongsTo|hasMany] ('"+rel.foreign_key+"', '"+k+"', '"+rels[k][i].key+"')"),hasErr=!0):(F.warn(k+"."+rel.key+" uses a "+rel.model+" model in a relationship but no such model exists. Please create model:\n    "+"[App].models.register( '"+rel.model+"' , function () { ... } ) ;"),hasErr=!0),record_test=new KB.ViewModelBase,this._models[rel.from](record_test),ko.isObservable(record_test[rel.key])?"belongsTo"===rel.type?ko.isObservableArray(record_test[rel.key])&&(F.warn("Field "+k+"."+rel.key+" should not be an observable array as it's a belongsTo relationship"),hasErr=!0):ko.isObservableArray(record_test[rel.key])||(F.warn("Field "+k+"."+rel.key+" must be an observable array as it's an hasMany relationship"),hasErr=!0):("belongsTo"===rel.type?F.warn("Field "+k+"."+rel.key+" should be an observable as it's a belongsTo relationship - it's no observable at all for the moment"):F.warn("Field "+k+"."+rel.key+" should be an observable array as it's an hasMany relationship - it's no observable at all for the moment"),hasErr=!0);F.assert(!hasErr,"Models declaration has one or more error. Please fix them.")},recordToRaw:function(record){return F.inst("record",record,KB.ViewModel,"KB.Store.recordToRaw"),record.raw([],!0)},index:function(model_name,field,unique){return F.str("model_name",model_name),F.str("field",field),unique=F.toBool(unique,!1),this}}),KB._Store=KB.Store.extend({construct:function(){F.deprecated("KB._Store","KB.Store"),this._super()}})}()}),require.register("kickbox/string",function(){!function(){"use strict";var urlizeAcc="Þßàáâãäåæçèéêëìíîïðñòóôõöøùúûýýþÿŕ",urlizeNoAcc="bsaaaaaaaceeeeiiiidnoooooouuuyybyr",InflectionJS={uncountable_words:["equipment","information","rice","money","species","series","fish","sheep","moose","deer","news"],plural_rules:[[new RegExp("(m)an$","gi"),"$1en"],[new RegExp("(pe)rson$","gi"),"$1ople"],[new RegExp("(child)$","gi"),"$1ren"],[new RegExp("^(ox)$","gi"),"$1en"],[new RegExp("(ax|test)is$","gi"),"$1es"],[new RegExp("(octop|vir)us$","gi"),"$1i"],[new RegExp("(alias|status)$","gi"),"$1es"],[new RegExp("(bu)s$","gi"),"$1ses"],[new RegExp("(buffal|tomat|potat)o$","gi"),"$1oes"],[new RegExp("([ti])um$","gi"),"$1a"],[new RegExp("sis$","gi"),"ses"],[new RegExp("(?:([^f])fe|([lr])f)$","gi"),"$1$2ves"],[new RegExp("(hive)$","gi"),"$1s"],[new RegExp("([^aeiouy]|qu)y$","gi"),"$1ies"],[new RegExp("(x|ch|ss|sh)$","gi"),"$1es"],[new RegExp("(matr|vert|ind)ix|ex$","gi"),"$1ices"],[new RegExp("([m|l])ouse$","gi"),"$1ice"],[new RegExp("(quiz)$","gi"),"$1zes"],[new RegExp("s$","gi"),"s"],[new RegExp("$","gi"),"s"]],singular_rules:[[new RegExp("(m)en$","gi"),"$1an"],[new RegExp("(pe)ople$","gi"),"$1rson"],[new RegExp("(child)ren$","gi"),"$1"],[new RegExp("([ti])a$","gi"),"$1um"],[new RegExp("((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$","gi"),"$1$2sis"],[new RegExp("(hive)s$","gi"),"$1"],[new RegExp("(tive)s$","gi"),"$1"],[new RegExp("(curve)s$","gi"),"$1"],[new RegExp("([lr])ves$","gi"),"$1f"],[new RegExp("([^fo])ves$","gi"),"$1fe"],[new RegExp("([^aeiouy]|qu)ies$","gi"),"$1y"],[new RegExp("(s)eries$","gi"),"$1eries"],[new RegExp("(m)ovies$","gi"),"$1ovie"],[new RegExp("(x|ch|ss|sh)es$","gi"),"$1"],[new RegExp("([m|l])ice$","gi"),"$1ouse"],[new RegExp("(bus)es$","gi"),"$1"],[new RegExp("(o)es$","gi"),"$1"],[new RegExp("(shoe)s$","gi"),"$1"],[new RegExp("(cris|ax|test)es$","gi"),"$1is"],[new RegExp("(octop|vir)i$","gi"),"$1us"],[new RegExp("(alias|status)es$","gi"),"$1"],[new RegExp("^(ox)en","gi"),"$1"],[new RegExp("(vert|ind)ices$","gi"),"$1ex"],[new RegExp("(matr)ices$","gi"),"$1ix"],[new RegExp("(quiz)zes$","gi"),"$1"],[new RegExp("s$","gi"),""]],non_titlecased_words:["and","or","nor","a","an","the","so","but","to","of","at","by","from","into","on","onto","off","out","in","over","with","for"],id_suffix:new RegExp("(_ids|_id)$","g"),underbar:new RegExp("_","g"),space_or_underbar:new RegExp("[ _]","g"),uppercase:new RegExp("([A-Z])","g"),underbar_prefix:new RegExp("^_"),apply_rules:function(str,rules,skip,override){if(override)str=override;else{var x,ignore=skip.indexOf(str.toLowerCase())>-1,l=rules.length;if(!ignore)for(x=0;l>x;x+=1)if(str.match(rules[x][0])){str=str.replace(rules[x][0],rules[x][1]);break}}return str}};Array.prototype.indexOf||(Array.prototype.indexOf=function(item,fromIndex,compareFunc){var i,index=-1,l=this.length;for(fromIndex||(fromIndex=-1),i=fromIndex;l>i;i+=1)if(this[i]===item||compareFunc&&compareFunc(this[i],item)){index=i;break}return index}),String.prototype._uncountable_words||(String.prototype._uncountable_words=InflectionJS.uncountable_words),String.prototype._plural_rules||(String.prototype._plural_rules=InflectionJS.plural_rules),String.prototype._singular_rules||(String.prototype._singular_rules=InflectionJS.singular_rules),String.prototype._non_titlecased_words||(String.prototype._non_titlecased_words=InflectionJS.non_titlecased_words),String.prototype.pluralize||(String.prototype.pluralize=function(plural){return InflectionJS.apply_rules(this,this._plural_rules,this._uncountable_words,plural)}),String.prototype.singularize||(String.prototype.singularize=function(singular){return InflectionJS.apply_rules(this,this._singular_rules,this._uncountable_words,singular)}),String.prototype.camelize||(String.prototype.camelize=function(lowFirstLetter){var i,str_arr,initX,l,x,str=this.toLowerCase(),str_path=str.split("/"),l2=str_path.length;for(i=0;l2>i;i+=1){for(str_arr=str_path[i].split("_"),initX=lowFirstLetter&&i+1===str_path.length?1:0,l=str_arr.length,x=initX;l>x;x+=1)str_arr[x]=str_arr[x].charAt(0).toUpperCase()+str_arr[x].substring(1);str_path[i]=str_arr.join("")}return str=str_path.join("::")}),String.prototype.underscore||(String.prototype.underscore=function(){var i,str=this,str_path=str.split("::"),l=str_path.length;for(i=0;l>i;i+=1)str_path[i]=str_path[i].replace(InflectionJS.uppercase,"_$1"),str_path[i]=str_path[i].replace(InflectionJS.underbar_prefix,"");return str=str_path.join("/").toLowerCase()
}),String.prototype.humanize||(String.prototype.humanize=function(lowFirstLetter){var str=this.toLowerCase();return str=str.replace(InflectionJS.id_suffix,""),str=str.replace(InflectionJS.underbar," "),lowFirstLetter||(str=str.capitalize()),str}),String.prototype.capitalize||(String.prototype.capitalize=function(){var str=this.toLowerCase();return str=str.substring(0,1).toUpperCase()+str.substring(1)}),String.prototype.dasherize||(String.prototype.dasherize=function(){var str=this;return str=str.replace(InflectionJS.space_or_underbar,"-")}),String.prototype.titleize||(String.prototype.titleize=function(){var str_arr,l,l2,x,d,i,str=this.toLowerCase();for(str=str.replace(InflectionJS.underbar," "),str_arr=str.split(" "),l=str_arr.length,x=0;l>x;x+=1){for(d=str_arr[x].split("-"),l2=d.length,i=0;l2>i;i+=1)this._non_titlecased_words.indexOf(d[i].toLowerCase())<0&&(d[i]=d[i].capitalize());str_arr[x]=d.join("-")}return str=str_arr.join(" "),str=str.substring(0,1).toUpperCase()+str.substring(1)}),String.prototype.demodulize||(String.prototype.demodulize=function(){var str=this,str_arr=str.split("::");return str=str_arr[str_arr.length-1]}),String.prototype.tableize||(String.prototype.tableize=function(){var str=this;return str=str.underscore().pluralize()}),String.prototype.classify||(String.prototype.classify=function(){var str=this;return str=str.camelize().singularize()}),String.prototype.ordinalize||(String.prototype.ordinalize=function(){var x,i,ltd,ld,suf,str=this,str_arr=str.split(" "),l=str_arr.length;for(x=0;l>x;x+=1)i=parseInt(str_arr[x],10),isNaN(i)&&(ltd=str_arr[x].substring(str_arr[x].length-2),ld=str_arr[x].substring(str_arr[x].length-1),suf="th","11"!==ltd&&"12"!==ltd&&"13"!==ltd&&("1"===ld?suf="st":"2"===ld?suf="nd":"3"===ld&&(suf="rd")),str_arr[x]+=suf);return str=str_arr.join(" ")}),String.prototype.urlize||(String.prototype.urlize=function(char){var str=this.toLowerCase().split(""),s=[],l=str.length,y=0,i=-1;for(y;l>y;y+=1)s[y]=(i=urlizeAcc.indexOf(str[y]))>-1?urlizeNoAcc[i]:str[y];return s.join("").trim().replace(/[^a-z0-9\-]/g," ").split(" ").join("-").replace(/[\-]{1,}/g,char||"-")}),String.prototype.first||(String.prototype.first=function(len,add,sep){var a=this.split(sep=F.toStr(sep," ")),l=a.length;return len=F.pInt(len,1),add=F.toStr(add),l>len?a.splice(0,len).join(sep)+add:this}),String.prototype.trim||(String.prototype.trim=function(){return this.replace(/^\s+|\s+$/g,"")}),!String.prototype.toText&&window.$&&(String.prototype.toText=function(links){var text,arr,len,$node=$("<div />").html(this);for($node.find("*").each(function(){var $t=$(this);("none"===$t.css("display")||"hidden"===$t.css("visibility")||0===$t.css("opacity"))&&$t.remove()}),$node.find("p, br, tr, div").each(function(){$(this).after("%%NEW_LINE%%")}),links===!0&&$node.find("a[href]").each(function(){$(this).replaceWith($(this).text()+" ["+$(this).attr("href")+"] ")}),text=$node.text().replace(/%%NEW_LINE%%/g,"\n"),arr=text.split("\n"),len=arr.length;(len-=1)>-1;)arr[len]=$.trim(arr[len]);return text=arr.join("\n").replace(/ {2,}/g," ").replace(/\n{3,}/g,"\n\n")}),String.prototype.cleanup||(String.prototype.cleanup=function(){return this.replace(/<!--[\s\S]*?-->/g,"").replace(/data-bind="[\s\S]*?"/g,"").replace("/\n+/g","\n")})}()}),require.register("kickbox/ui",function(){!function(){"use strict";KB.UI=KB.EventDispatcher.extend({$dependencies:["app","loader"],fuzzy_interval:null,construct:function(){window.addEventListener("dragenter",KB.del(this,function(e){this.trigger("dragenter",e)})),window.addEventListener("dragleave",KB.del(this,function(e){this.trigger("dragleave",e)})),this.$loader.on("start",KB.del(this,"_onStartLoading")),this.$loader.on("end",KB.del(this,"_onEndLoading")),this.fuzzyfy()},register:function(name,handler){return ko.bindingHandlers[name]=handler,this},success:function(message,container){return F.str("message",message,"KB.UI.success"),$.successMsg(message,this._getContainer(container)),this},error:function(message,binding,container){return $.errorMsg(message,this._getContainer(container)),F.isStr(binding)&&$("[data-bind*="+binding+"]").addClass("invalid"),this},warning:function(message,container){return $.warningMsg(message,this._getContainer(container)),this},notice:function(message,container){return $.noticeMsg(message,this._getContainer(container)),this},answer:function(result,successMsg,failureMsg,showError,container){return result?this.success(successMsg,this._getContainer(container)):showError===!0?this.error(failureMsg,null,this._getContainer(container)):this.warning(failureMsg,this._getContainer(container)),this},confirm:function(message,ok_cb,cancel_cb,ok_message,cancel_message,container){return $.confirm(message,ok_cb,cancel_cb,ok_message||_("Delete"),cancel_message||_("Cancel"),this._getContainer(container)),this},clearMessages:function(){return $("#global_response .response").fadeOut(),$(".invalid").removeClass("invalid"),this},block:function(container,message){var $c=$(container);return 0===$c.length&&F.log("Target element to block does not exist"),0===$(".ui-blocker",$c).length&&($c.append($("<div></div>").addClass("ui-blocker")),"absolute"!==$c.css("position")&&"body"!==container&&$c.css("position","relative")),message?0===$(".ui-blocker span",$c).length&&$(".ui-blocker",$c).append($("<span></span>").text(message)):$(".ui-blocker span",$c).remove(),this},unblock:function(container){var $el=$(container).find(".ui-blocker");return $el.length&&$el.remove(),this},isBlocked:function(container){return!!$(container).find(".ui-blocker").length},updateTimes:function(){return $("[data-timestamp]").each(function(index,el){$(el).html(KB.date.timeago(F.pInt($(el).attr("data-timestamp"))))}),this},fuzzyfy:function(){return null===this.fuzzy_interval&&(this.fuzzy_interval=setInterval(KB.del(this,function(){this.updateTimes()}),6e4)),this},unfuzzyfy:function(){return null===this.fuzzy_interval&&clearInterval(this.fuzzy_interval),this.fuzzy_interval=null,this},_getContainer:function(container){return container?container:$(".modal").length>0&&"block"===$(".modal").css("display")?$(".modal"):null},_onStartLoading:function(){var element='<div class="indicator"><span>Loading...</span></div>';$("header .indicator").length?$("header .indicator").not(":visible")&&$("header .indicator").show():$("header").append(element)},_onEndLoading:function(){0===this.$loader.ajax_counter&&$("header .indicator").is(":visible")&&$("header .indicator").hide()}}),KB.CoreWidgets={hidden:{update:function(element,valueAccessor){var value=ko.utils.unwrapObservable(valueAccessor());value?element.style.display="none":value||(element.style.display="")}},upload:{init:function(element,valueAccessor){element._utility=new KB.UploadUtility(element,valueAccessor)}},_:{init:function(element,valueAccessor){$(element).text(_(ko.utils.unwrapObservable(valueAccessor())))}},timeago:{init:function(element,valueAccessor){var timestamp=ko.utils.unwrapObservable(valueAccessor());$(element).text(KB.date.timeago(timestamp)),$(element).attr("data-timestamp",timestamp)}},booleanValue:{init:function(element,valueAccessor){var observable=valueAccessor(),interceptor=ko.computed({read:function(){return observable().toString()},write:function(newValue){observable(newValue)}});ko.applyBindingsToNode(element,{value:interceptor})}}},KB.UploadUtility=KB.Class.extend({$el:null,vAccessor:null,outText:null,inText:null,construct:function(element,valueAccessor){var el,input;this.outText=_("Drag file(s) here or click"),this.inText=_("Drop file(s) here"),this.vAccessor=valueAccessor,$(element).html('<div class="kb-upload" ondragover="return false"></div>'),this.$el=$(".kb-upload",$(element)).css({"min-width":"90px","min-height":"30px","text-align":"center",cursor:"pointer"}),el=this.$el[0],input=$('<input type="file" multiple="multiple" />'),$(element).append(input.on("change",KB.del(this,function(){1===input.length&&this.processFiles(input[0].files)})).css({display:"none"})),this.$el.text(this.outText),this.$el.on("click",function(){input.click()}),this._onDragOverCB=KB.del(this,function(e){e.stopPropagation(),e.preventDefault()}),this._onDragEnterCB=KB.del(this,function(e){e.stopPropagation(),e.preventDefault(),this.$el.addClass("in"),this.$el.text(this.inText)}),this._onDragExitCB=KB.del(this,function(e){e.stopPropagation(),e.preventDefault(),this.$el.removeClass("in"),this.$el.text(this.outText)}),this._onWDragEnterCB=KB.del(this,function(e){e.preventDefault(),this.$el.addClass("window_in")}),this._onWDragExitCB=KB.del(this,function(e){e.preventDefault(),this.$el.removeClass("window_in")}),this._onDropCB=KB.del(this,this.onDrop),window.addEventListener("dragenter",this._onWDragEnterCB),window.addEventListener("dragleave",this._onWDragExitCB),el.addEventListener("dragover",this._onDragOverCB,!0),el.addEventListener("dragenter",this._onDragEnterCB),el.addEventListener("dragleave",this._onDragExitCB),el.addEventListener("drop",this._onDropCB,!1)},onDrop:function(e){e.preventDefault(),e&&e.dataTransfer&&e.dataTransfer.files&&this.processFiles(e.dataTransfer.files)},processFiles:function(files){var i,l=files.length;for(this.$el.text(this.outText),this.$el.removeClass("in"),i=0;l>i;i+=1)this.vAccessor()(files[i])}});var currentOrientation,debounce,dispatchResizeEndEvent,events,getCurrentOrientation,initialOrientation,resizeDebounceTimeout;window.addEventListener&&document.createEvent&&(events=["resize:end","resizeend"].map(function(event){return event=document.createEvent("Event"),event.initEvent("resizeend",!1,!1),event}),dispatchResizeEndEvent=function(){return events.forEach(window.dispatchEvent)},getCurrentOrientation=function(){return Math.abs(+window.orientation||0)%180},initialOrientation=getCurrentOrientation(),currentOrientation=null,resizeDebounceTimeout=null,debounce=function(){return currentOrientation=getCurrentOrientation(),currentOrientation!==initialOrientation?(dispatchResizeEndEvent(),initialOrientation=currentOrientation):(clearTimeout(resizeDebounceTimeout),resizeDebounceTimeout=setTimeout(dispatchResizeEndEvent,100))},window.addEventListener("resize",debounce,!1),KB._UI=KB.UI.extend({construct:function(){F.deprecated("KB._UI","KB.UI"),this._super()}}),KB._CoreWidgets=KB.CoreWidgets,KB._UploadUtility=KB.UploadUtility.extend({construct:function(){F.deprecated("KB._UploadUtility","KB.UploadUtility"),this._super()}}))}()}),require.register("kickbox/view-model-base",function(){!function(){"use strict";KB.ViewModelBase=KB.EventDispatcher.extend({__name:"_Model",__op:null,__view:null,__files:null,app:null,more:null,construct:function(){},upload:function(model_name){var uploadContext;return F.str("model_name",model_name,"KB.ViewModelBase.upload"),F.assert(!!this.app[model_name]&&F.isFn(this.app[model_name].upload),'No "upload" method in "'+model_name+'" static model_name. Extend your static model_name with an "upload" method: '+'\n    App.models.register("MyModel", function(){}).extend({ upload: '+"function ( fileObject ) {\n        // Your upload code\n    } });"),uploadContext=this.app[model_name],function(value){return value?(uploadContext.upload(value),void 0):null}},leave:function(){this.app&&(this.app.views.leaveModal(),this.app&&this.app.views.leavePopup())},redirect:function(hash,data){return F.str("hash",hash,"KB.ViewModelBase.redirect"),KB.del(this,function(){this.app.redirect(hash,data)})},delegate:function(context,method){var f,args=[],i=2,l=arguments.length;if(f=F.isStr(method)?context[method]:method,F.isFn(f)||F.error('KB.delegate: object "'+method+'"" is not a function'),l>2)for(i=2;l>i;i+=1)args.push(arguments[i]);return function(){return context.__caller=this,f.apply(context,args.concat(arguments))}},view:function(){return this.__view}}),KB._DefaultViewModel=KB.ViewModelBase.extend({construct:function(){F.deprecated("KB._DefaultViewModel","KB.ViewModelBase"),this._super()}})}()}),require.register("kickbox/view-model-op",function(){!function(){"use strict";KB.ViewModelOperator=KB.EventDispatcher.extend({app:null,apis:null,name:null,mapper:null,loader:null,store:null,rules:null,sorting:null,conversion:null,inputs:null,outputs:null,parents:null,patch:!0,subscriptions:null,_primary:null,_idx:0,construct:function(){this.rules=[],this.sorting={},this.conversion={},this.inputs={},this.outputs={},this.subscriptions={},this.apis={}},validate:function(){var args=F.argToArr(arguments),field=args.shift(),rule=args.shift(),message=args.pop(),rule_args=args;return F.str("rule",rule,"KB.ViewModelOperator.validate"),-1===this.store._props[this.name].indexOf(field)&&F.error("Field "+field+" not found in model "+this.name),this.rules.push({field_name:field,validation_rule:rule,rule_args:rule_args,message:message}),this},exclude:function(){var i,l=arguments.length;for(i=0;l>i;i+=1)F.str("field_name[]",arguments[i],"KB.ViewModelOperator.exclude"),this.store.exclude(this.name,arguments[i]);return this},include:function(){var i,l=arguments.length;for(i=0;l>i;i+=1)F.str("field_name[]",arguments[i],"KB.ViewModelOperator.exclude"),this.store.include(this.name,arguments[i]);return this},enablePatch:function(){return this.patch=!0,this},disablePatch:function(){return this.patch=!1,this},mapTo:function(key){return F.str("key",key,"KB.ViewModelOperator.mapTo"),this.mapper.map(this.name,key),this},primary:function(primaryKey){return F.str("primaryKey",primaryKey,"Primary key of a model most be a non-empty string"),this.mapper.mapPrimaryKey(this.name,primaryKey),this._primary=primaryKey,this},getPrimary:function(){return this._primary},oneToOne:function(model){return F.str("model",model,"KB.ViewModelOperator.oneToOne"),this.belongsTo(model,this.name.underscore())},oneToMany:function(model){return F.str("model",model,"KB.ViewModelOperator.oneToMany"),this.belongsTo(model,this.name.underscore().pluralize())},manyToMany:function(model){return F.str("model",model,"KB.ViewModelOperator.manyToMany"),this.hasMany(model,this.name.underscore().pluralize())},manyToOne:function(model){return F.str("model",model,"KB.ViewModelOperator.manyToOne"),this.hasMany(model,this.name.underscore())},belongsTo:function(key,model,foreign_key){return F.str("key",key,"KB.ViewModelOperator.belongsTo"),F.str("model",model,"KB.ViewModelOperator.belongsTo"),F.isStr(foreign_key)||(foreign_key=model,model=key,key=key.underscore()),this.store._registerRelationship(this.name,key,"belongsTo",foreign_key,model),this},hasMany:function(key,model,foreign_key){return F.str("key",key,"KB.ViewModelOperator.hasMany"),F.str("model",model,"KB.ViewModelOperator.hasMany"),F.isStr(foreign_key)||(foreign_key=model,model=key,key=key.pluralize().underscore()),this.store._registerRelationship(this.name,key,"hasMany",foreign_key,model),this},convert:function(key,func){return F.str("key",key,"KB.ViewModelOperator.convert"),F.fn("func",func,"KB.ViewModelOperator.convert"),this.conversion[key]=func,this},input:function(func){return F.fn("func",func,"KB.ViewModelOperator.input"),this.inputs["f"+(this._idx+=1)]=func,this},output:function(func){return F.fn("func",func,"KB.ViewModelOperator.output"),this.outputs["f"+(this._idx+=1)]=func,this},api:function(){var method,i,l,args=F.argToArr(arguments),key=args.shift();for(F.str("key",key,"KB.ViewModelOperator.api"),i=0,l=args.length;l>i;i+=1)F.inst("field"+i,args[i],KB.Field,"KB.ViewModelOperator.api");return method=new KB.APIMethod({key:key,fields:args,vmo:this}),this.apis[key]=method,this},isApi:function(key){return F.isInst(this.apis[key],KB.APIMethod)},call:function(){return this.callOn.apply(this,F.argToArr(arguments))},callOn:function(){var record,callback,args=F.argToArr(arguments),key=args.shift(),data=null,request=null;F.str("key",key,"KB.ViewModelOperator.call"),F.assert(this.isApi(key),"API "+key+" does not exist"),F.isFn(args[0])?callback=args.shift():F.isObj(args[0])&&(data=args.shift(),F.isFn(args[0])&&(callback=args.shift())),request=new KB.APIRequest({data:data,method:this.apis[key],callback:callback,record:record}),this.loader.call(request)},extend:function(obj){var k;F.obj("obj",obj,"KB.ViewModelOperator.extend");for(k in obj)this[k]=obj[k];return this},subscribe:function(field,func){return F.str("field",field,"KB.ViewModelOperator.subscribe"),F.fn("func",func,"KB.ViewModelOperator.subscribe"),this.subscriptions[field]=func,this},create:function(param){var record;return F.isObj(param)?param[this._primary]?record=this.store.materialize(this.name,param):(record=this.store._materialize(this.name),record.__inject(param)):record=F.isNum(param)||F.isStr(param)?this.store._materialize(this.name,param):this.store._materialize(this.name),record.onMaterialized(),record},bulkSave:function(callback){var args=[this.name];return F.isFn(callback)&&args.push(callback),this.store.bulkSave.apply(this.store,args),this},generator:function(opts){return KB.del(this,function(request){var k,o=$.extend({},opts);if(request)for(k in o)o[k]=request.map(o[k]);return this.create(o)})},alive:function(id){if(!id)return!1;var r=this.store.getById(this.name,id,!1);return F.isInst(r,KB.ViewModel)&&r.isLoaded()},find:function(id,callback){return F.def("id",id,"KB.ViewModelOperator.find"),this.loader.find(this.name,F.toStr(id),callback)},findById:function(id,callback){return this.find(id,callback)},findMany:function(callback){return this.loader.findMany(this.name,callback)},findWhere:function(){var args=F.argToArr(arguments);return args.unshift(this.name),this.loader.findWhere.apply(this.loader,args)},selectMany:function(callback){return this.loader.selectMany(this.name,callback)},selectWhere:function(){var args=F.argToArr(arguments);return args.unshift(this.name),this.loader.selectWhere.apply(this.loader,args)},selectNext:function(selection,callback){return this.loader.selectNext(selection,callback)},getAll:function(){var selection=new KB.Selection;return selection.pushAll(this.store.getAll(this.name)),selection},getBy:function(){var field,value,count,selection,args=F.argToArr(arguments),nargs=[this.name];return count=args.pop(),field=args.shift(),nargs.push(field),F.isObj(field)||(value=args.shift(),F.str("field",field,"KB.ViewModelOperator.getBy"),F.def("value",value,"KB.ViewModelOperator.getBy"),nargs.push(value)),F.num("count",count,"KB.ViewModelOperator.getBy"),0===count?null:(nargs.push(count),1===count?this.store.getBy.apply(this.store,nargs):(selection=new KB.Selection,selection.pushAll(this.store.getBy.apply(this.store,nargs)),selection))},getFirstBy:function(field,value){return F.str("field",field,"KB.ViewModelOperator.getFirstBy"),F.def("value",value,"KB.ViewModelOperator.getFirstBy"),this.store.getBy(this.name,field,value,1)},getSortDirection:function(field,subfield){return F.str("field",field,"KB.ViewModelOperator.getSortDirection"),F.str("subfield",subfield,"KB.ViewModelOperator.getSortDirection"),this.sorting||(this.sorting={}),this.sorting[field]||(this.sorting[field]={}),F.isUdef(this.sorting[field][subfield])&&(this.sorting[field][subfield]=!0),this.sorting[field][subfield]=!this.sorting[field][subfield],this.sorting[field][subfield]},sort:function(model_name,field,subfield){return F.deprecated("KB.ViewModelOperator.sort","KB.ViewModelOperator.getSortDirection","Be aware of signature change!"),F.str("model_name",model_name,"KB.ViewModelOperator.sort"),F.str("field",field,"KB.ViewModelOperator.sort"),F.str("subfield",subfield,"KB.ViewModelOperator.sort"),this.sorting||(this.sorting={}),this.sorting[field]||(this.sorting[field]={}),F.isUdef(this.sorting[field][subfield])&&(this.sorting[field][subfield]=!0),this.sorting[field][subfield]=!this.sorting[field][subfield],this.sorting[field][subfield]},applyConversions:function(rawData){var k,i,l;if(!rawData)return rawData;for(k in this.conversion)F.isDef(rawData[k])&&(rawData[k]=this.conversion[k](rawData[k]));if(F.isArr(this.parents))for(i=0,l=this.parents.length;l>i;i+=1)rawData=this.app[this.parents[i]].applyConversions(rawData);return rawData},applyInputs:function(rawData){var k,i,l;if(!rawData)return rawData;for(k in this.inputs)rawData=this.inputs[k](rawData);if(F.isArr(this.parents))for(i=0,l=this.parents.length;l>i;i+=1)rawData=this.app[this.parents[i]].applyInputs(rawData);return rawData},applyOutputs:function(rawData){var k,i,l;if(!rawData)return rawData;for(k in this.outputs)rawData=this.outputs[k](rawData);if(F.isArr(this.parents))for(i=0,l=this.parents.length;l>i;i+=1)rawData=this.app[this.parents[i]].applyOutputs(rawData);return rawData}}),KB.ViewModelOperator.toList=function(arr,record_text_field,list_text_field,filter){var a,i,item,l;for(F.arr("arr",arr,"KB.ViewModelOperator.toList"),list_text_field=F.toStr(list_text_field,"text"),a=[],l=arr.length,i=0;l>i;i+=1){for(;l>i&&F.isFn(filter)&&!filter(arr[i]);)i+=1;if(i===l)return a;item={id:arr[i].id()},item[list_text_field]=F.isStr(record_text_field)?F.isFn(arr[i][record_text_field])?arr[i][record_text_field]():arr[i][record_text_field]:arr[i].toString(),a.push(item)}return a},KB._StaticModel=KB.ViewModelOperator.extend({construct:function(){F.deprecated("KB._StaticModel","KB.ViewModelOperator"),this._super()}}),KB._DAO=KB.ViewModelOperator.extend({construct:function(){this._super(),F.deprecated("KB._DAO","KB.ViewModelOperator")}})}()}),require.register("kickbox/view-model",function(){!function(){"use strict";KB.__states=["idle","local","loading","loaded","updating","updated","removing","removed"],KB.ViewModel=KB.ViewModelBase.extend({__adapter:null,__props:null,__subsc:null,__prev:null,__loader:null,__nullified:!1,__updated:null,__view:null,__state:null,__dirty:!1,__stable:null,__savable:null,id:null,clientId:null,resource_uri:"",construct:function(){this._super(),this.more={},this.__props=[],this.__subsc=[],this.__updated=[],this.__state=ko.observable("idle"),this.__dirty=ko.observable(!1),this.__stable=ko.observable(!1),this.__savable=ko.observable(!1),this.__subsc.push(this.__state.subscribe(KB.del(this,function(prev){this.__prev=prev}),this,"beforeChange")),this.__subsc.push(this.__state.subscribe(KB.del(this,function(value){this.__setSavable(value,this.__dirty()),this.__setStable(value)}))),this.__subsc.push(this.__dirty.subscribe(KB.del(this,function(value){this.__setSavable(this.__state(),value)})))},__setStable:function(state){this.__stable(!("updating"===state||"loading"===state||"removing"===state))},__setSavable:function(state,dirty){this.__savable(!("updating"===state||"loading"===state||"removing"===state)&&dirty)},__inject:function(data){var k;F.obj("data",data,"KB.ViewModel.__inject");for(k in data)data.hasOwnProperty(k)&&("id"!==k||"clientId"!==k)&&(F.isFn(this[k])?this[k](data[k]):this[k]=data[k]);this.setDirty(!0)},__nullify:function(){if(!this.__nullified){this.__nullified=!0;var n,val,i,fields=this.__loader.$store._props[this.__name],l=fields.length;for(i=0;l>i;i++)n=fields[i],(n||n&&0!==n.indexOf("__"))&&(F.isFn(this[n])?(val=this[n](),val&&F.isArr(val)&&F.isFn(this[n].removeAll)?this[n].removeAll():val&&F.isFn(this[n].id)&&this[n](null),this[n]=null):this[n]=null);for(l=this.__subsc.length,i=0;l>i;i++)this.__subsc[i]&&this.__subsc[i].dispose();this.__subsc=[]}},toString:function(){var n=(this.__readable?this.__readable:this.__name.humanize())+" ";return this.title&&this.title()?n+'"'+this.title()+'"':this.subject&&this.subject()?n+'"'+this.subject()+'"':this.name&&this.name()?n+'"'+this.name()+'"':n+"#"+this.id()},isSavable:function(){return this.__savable()},isStable:function(){return this.__stable()},isReal:function(){return"__tmp_"!==F.toStr(this.id()).substr(0,6)},isRemoved:function(){return F.isNone(this.__state)||"removing"===this.__state()||"removed"===this.__state()},isEmpty:function(checkfields){var i,l,n,val,fields=this.__loader.$store._props[this.__name];for(checkfields=F.isArr(checkfields)?checkfields:fields,l=checkfields.length,i=0;l>i;i++)if(n=checkfields[i],n&&0!==n.indexOf("__")&&(val=F.isFn(this[n])?this[n]():this[n]))return!1;return!0},isIdle:function(){return"idle"===this.__state()},isLoading:function(){return"loading"===this.__state()},isLoaded:function(){return"loaded"===this.__state()||"updated"===this.__state()},isUpdating:function(){return"updating"===this.__state()},isUpdated:function(){return"updated"===this.__state()},isUpdatable:function(){var s=this.__state();return this.__dirty()&&!("updating"===s||"loading"===s||"removing"===s)},isDirty:function(){return this.__dirty()},isValid:function(){return this.validate(!0)},setDirty:function(){return"idle"!==this.__state()&&this.__dirty(!0),this},load:function(callback){return callback=F.isFn(callback)?callback:null,this.__loader.find(this.__name,this.id(),callback),this},reload:function(callback){return callback=F.isFn(callback)?callback:null,this.__loader.find(this.__name,this.id(),callback,!0),this},save:function(callback){return callback=F.isFn(callback)?callback:null,this._execSave(callback),this},saveIfStable:function(callback){return callback=F.isFn(callback)?callback:null,this.isStable()&&this.save(callback),this},_execSave:function(callback){callback=F.isFn(callback)?callback:null;var s=this.__state(),r=!1;return"updating"===s||"loading"===s||"removing"===s||"removed"===s?(F.warn('[ILLEGAL OPERATION] state "'+s+'" of object "'+this.toString()+'" does not allow remote operation. Please use one of this model methods to block/allow edition of record(s):\n    '+"__stable() in templates, isStable() in code"),!1):this.__dirty()?this.validate()&&this.beforeSave()?(this.isReal()?this.beforeUpdate()&&(r=this.__loader.update(this,KB.del(this,function(success){this.onUpdate(),callback&&callback(success)})),r||this.onFailUpdate()):this.beforeCreate()&&this.beforeSave()&&(r=this.__loader.create(this,KB.del(this,function(success){this.onCreate(),callback&&callback(success)})),r||this.onFailCreate()),r):(callback&&callback(!1),r):(callback&&callback(!0),r)},clone:function(exclude){var i,n,rec=this.create(),fields=this.__loader.$store._props[this.__name],l=fields.length;for(exclude=F.isArr(exclude)?exclude:[],i=0;l>i;i++)n=fields[i],!n||exclude.indexOf(n)>-1||0===n.indexOf("__")||"id"===n||(F.isFn(this[n])?rec[n](this[n]()):rec[n]=this[n]);return rec},toRaw:function(prefix,suffix,separator){return F.deprecated("KB.ViewModel.toRaw","KB.ViewModel.raw","Be aware of signature change"),this.raw([],!1,prefix,suffix,separator)},raw:function(exclude,kb_rels,prefix,suffix,separator){var n,val,cbsl,i,i2,l2,rels,ok,fields=this.__loader.$store._props[this.__name],raw={},cbs=[],l=fields.length,a=[];for(exclude=F.toArr(exclude),kb_rels=F.toBool(kb_rels),separator=F.toStr(separator,"_"),prefix=prefix?prefix+separator:"",suffix=suffix?separator+suffix:"",i=0,l2=exclude.length;l2>i;i+=1)F.isFn(exclude[i])&&cbs.push(exclude[i]);for(cbsl=cbs.length,i=0;l>i;i++)if(n=fields[i],n&&0!==n.indexOf("__")&&-1===exclude.indexOf(n)){if(val=F.isFn(this[n])?this[n]():this[n],rels=this.__loader.$store.getRelationship(this.__name,n),rels&&rels.length>0)if(val&&F.isArr(val)){for(a=[],l2=val.length,i2=0;l2>i2;i2+=1)val[i2]&&F.isFn(val[i2].id)&&a.push(val[i2].id());val=kb_rels?{model:rels[0].model,ids:a}:a}else val&&F.isFn(val.id)&&(val=kb_rels?{model:val.__name,id:val.id()}:val.id());if(ok=!0,cbsl>0)for(i2=0;cbsl>i2;i2+=1)if(cbs[i2](val)===!1){ok=!1;break}ok&&(raw[prefix+n+suffix]=val)}return raw=this.__op.applyOutputs(raw)},create:function(model_name,data){model_name||(model_name=this.__name),F.str("model_name",model_name,"KB.ViewModel.create");var record=this.__loader.$store._materialize(model_name);return data&&record.__inject(data),record},saveRelations:function(){F.assert(!1,"Not implemented")},remove:function(callback,force){var r=!1,s=this.__state();return"updating"===s||"loading"===s||"removing"===s||"removed"===s?(F.warn('[ILLEGAL OPERATION] state "'+s+'" of object "'+this.__name+"/"+this.toString()+'" does not allow remote operation. Please use one of this model methods to block/allow edition of record(s):\n    '+"__stable() in templates, isStable() in code"),!1):(callback=F.isFn(callback)?callback:!1,force=force||!1,this.beforeRemove()&&(r=this.__loader.remove(this,function(success){callback&&callback(success)},force)),r)},rollback:function(){return this.__state(this.__prev),this},call:function(){var args=F.argToArr(arguments);args.push(this),this.__op.callOn.apply(this.__op,args)},validate:function(silent){for(var rule,i=this.__op.rules.length,valid=!0,validation=new KB.ValidationRules;i--;)rule=this.__op.rules[i],validation[rule.validation_rule].apply(null,$.merge($.merge([this[rule.field_name]()],rule.rule_args),[this]))||(silent!==!0&&this.__loader.$app.ui.error(rule.message,rule.field_name),valid=!1);return valid},sort:function(field,subfield){return F.str("field",field,"KB.ViewModel.sort"),F.str("subfield",subfield,"KB.ViewModel.sort"),KB.del(this,function(){var inverse=this.__op.sort(this.__name,field,subfield);this[field]&&this[field].sort&&this[field].sort(function(l,r){return inverse?l[subfield]()<r[subfield]()?1:-1:l[subfield]()>r[subfield]()?1:-1})})},commitAndLeave:function(){this.isStable()&&this.save(),this.leave()},removeAndLeave:function(){this.leave(),this.isReal()||this.remove()},removeAndRedirect:function(URL){F.str("URL",URL,"KB.ViewModel.removeAndRedirect");var app=this.app;return KB.del(this,function(){this.remove(KB.del(this,function(){app.redirect(URL)}))})},beforeLoad:function(){return!0},beforeCreate:function(){return!0},beforeUpdate:function(){return!0},beforeSave:function(){return!0},beforeRemove:function(){return!0},onFailLoad:function(){},onFailCreate:function(){},onFailUpdate:function(){},onFailRemove:function(){},onMaterialize:function(){},onMaterialized:function(){},onLoad:function(){},onCreate:function(){},onUpdate:function(){},onRemove:function(){}}),KB.ValidationRules=KB.Class.extend({construct:function(){},url:function(value){var pattern=/^(https?:\/\/)?([0-9a-z\.\-]+)\.([a-z]{2,6})(\/[\w\-]*)*\/?$/gi;return pattern.test(value)},email:function(value){var pattern=/^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i;return pattern.test(value)},required:function(value){return F.isStr(value)},equal:function(value,model,field){return value?value===model[field]():!0},regexp:function(value,pattern){return F.isStr(pattern)&&(pattern=new RegExp(pattern)),pattern.test(value)},equalTo:function(value,field,model){return F.deprecated("KB.ValidationRules.equalTo","KB.ValidationRules.equal","Be aware: signature of methods are not the same!"),value?value===model[field]():!0}}),KB._Model=KB.ViewModel.extend({construct:function(){F.deprecated("KB._Model","KB.ViewModel"),this._super()}}),KB._ModelValidation=KB.ValidationRules.extend({construct:function(){F.deprecated("KB._ModelValidation","KB.ValidationRules"),this._super()}})}()}),require.register("kickbox/view",function(){!function(){"use strict";KB.View=KB.EventDispatcher.extend({_id:null,app:null,_manager:null,_data:null,_cache:null,_attached:!1,_loaded:!1,_loading:!1,_request:null,_tpl:null,_main_model:null,_records:null,_template:null,_in:!1,_visible:!1,routes:null,containerId:null,container:null,block:!0,_waiting:!1,_rs:null,template:null,closable:!1,classname:"",methods:[],assets:[],queue:[],records:null,main:null,title:"",construct:function(){this.routes=[],this._records={},this._data={},this._rs=new KB.ResourceStack,this._rs.app=this.app,this._rs.cache=this._cache,this._rs.on("load",KB.del(this,function(args){F.obj("args",args,"KB.View.ResourceStack.on(load)");
var k,l=0;for(k in this.records)this.records.hasOwnProperty(k)&&(l+=1);if(this._request)for(k in args.data)args.data.hasOwnProperty(k)&&(this._data[k]=args.data[k]);this._loading=!1,this._loaded=!0,this.onLoad(args.request,this._data),null!==this._request&&this._show(this._request)})),this._rs.on("load_error",KB.del(this,function(args){this.container&&(this.container.attr("data-kbview-next",""),this.container.attr("data-kbview","")),this._manager.has("error/404")&&this._manager.display("error/404",{title:_("Record not found")}),this._loading=!1,this._loaded=!1})),this._rs.on("record_not_found",KB.del(this,function(args){F.obj("args",args,"KB.View.ResourceStack.on(record_not_found)"),this.onRecordNotFound(args.model_name,args.query,args.request)})),this._rs.on("refresh",KB.del(this,function(){this.refresh()})),KB.View.DEFAULT||(KB.View.DEFAULT=new KB.ViewModelBase({app:this.app}))},getTitle:function(){return this.title?this.title:""},setTitle:function(title){return F.str("title",title,"KB.View.setTitle"),this.title=title,this},getMain:function(){return this._main_model||this.main},setMain:function(model){return F.str("model",model,"KB.View.setMain"),this._main_model=this.main=model,this},isIn:function(){return this._in===!0},isVisible:function(){return this._visible===!0},element:function(){return this._in?this.container:null},set:function(key,val){F.str("key",key,"KB.View.set"),this._data&&(this._data[key]=val,this._main_model||(this._main_model=this.main||key))},has:function(key){return F.isDef(this._data[key])},get:function(key){return!F.isStr(key)&&this._main_model?this._data[this._main_model]:this._data[key]},request:function(){return this._request},wait:function(){return this._waiting=!0,this.app.ui.block("#"+this.containerId),this},resume:function(){return this._waiting=!1,this.app.ui.isBlocked(this.container)&&this.render(),this},enter:function(request){var $c,k;if(this._preattach(request)){if(this._in=!0,this._request=request,$c=this.container,request&&request._data)for(k in request._data)this._data[k]=request._data[k];return this.block&&!this.app.ui.isBlocked($c)&&this.app.ui.block($c),$c.attr("data-kbview-next",this._id),this.__preload(),this}},_preattach:function(request){var obj;return null===this.container&&(F.assert(null!==this.containerId,"View has no container declared"),this.container=$("#"+this.containerId),0===this.container.length&&F.error('No HTML object has "'+this.containerId+'" as id - view not attached')),this.container.attr("data-kbview")===this._id?request.isEqual(this._request)?(!this._waiting&&this.app.ui.isBlocked(this.container)?this.render():this._data[this._main_model]&&(this._data[this._main_model].__view=this,this._data[this._main_model].more=this._data),this.onRefresh(this.container,this._data,this._request),!1):(this.leave(),!0):(this.container.attr("data-kbview")&&(obj=this._manager.getById(this.container.attr("data-kbview")),obj&&obj.leave()),this.container.attr("data-kbview",this._id),!0)},_show:function(){if(this._in===!0){if(!this.beforeEnter(this._request,this._data))return;this.render(),this.trigger("enter")}},_elrg:/<!--\s{0,}kb\s{1,}([a-z0-9]{1,})\s{0,}:\s{0,}([a-z0-9\-\/\\\_\.]{1,})\s{0,}-->/gi,_setElements:function(tpl){return F.str("tpl",tpl,"KB.View._setElements"),F.isNone(tpl.match(this._elrg))?tpl:tpl.replace(this._elrg,KB.del(this,function(match,type,value){return"template"===type||"element"===type?$("#"+value.replace("/","-")+"-template").html():(F.warn("No KB template method matching with: "+type),"")}))},render:function(){if(!this._waiting){var tpl,$node=this.container,node=$node[0],main=this._data[this._main_model];return this.classname&&!$node.hasClass(this.classname)&&$node.addClass(this.classname),this.unapply(),F.assert(1===$("#"+this._tpl).length,'No template found for identifier "'+this._tpl+'"'),tpl=this._setElements($("#"+this._tpl).html()),$node.html(tpl),main&&F.isInst(main,KB.ViewModelBase)||(main=KB.View.DEFAULT),main.__view=this,main.more=this._data,KB._Binder._bindings[this.containerId]=main,ko.applyBindings(main,node),this._visible=!0,this.onEnter(this.container,this._data,this._request),this}},refresh:function(){return this.container&&this.container.attr("data-kbview")===this._id&&this.onRefresh(this.container,this._data,this._request),this},leave:function(){return null!==this.container?(this._in=!1,this._visible=!1,this._data[this._main_model]&&(this._data[this._main_model].__view=this,this._data[this._main_model].more=this._data),this.onLeave(this.container,this._data,this._request),this.trigger("leave"),this._request=null,this.empty(),this.container.attr("data-kbview",""),this.classname&&this.container.removeClass(this.classname),this):void 0},unapply:function(){var $node=this.container,node=$node[0];return KB._Binder._bindings[this.containerId]&&($node.find("*").each(function(){$(this).unbind()}),ko.cleanNode(node)),this},empty:function(){var $node=this.container;return $node[0],this.unapply(),$node.empty(),this},_empty:function(){return F.deprecated("KB.View._empty","KB.View.empty"),this.empty()},_unbind:function(){return F.deprecated("KB.View._unbind","KB.View.unapply"),this.unapply()},still:function(element,clean){var res="";return this.isIn()&&this.isVisible()&&(res=element?this.container.find(element).html()||"":this.container.html()),clean===!0?res.cleanup().trim():res.trim()},preload:function(){return this.__preload(!0),this},__preload:function(){if(!this._loading){var url,k;if(this._loaded=!1,this._loading=!0,this.beforeLoad(this._request,this._data),F.assert(!!this.template,"No template defined for view ["+this.routes.join(", ")+"] in container "+this.containerId),null===this._main_model)for(k in this.records){if(null!==this._main_model)break;this._main_model=k}this._rs.reset(),this._rs.request=this._request,this._rs.avoidRecords=!1,url=this.template.split("#"),1===url.length?this._tpl=this.template+"-template":(this._tpl=url[1]+"-template",this._rs.addResource(url[0])),this._rs.addResource(F.isArr(this.assets)?this.assets:[]),this._rs.sequentialResources=this.queue,this._rs.parallelRecords=this.records,this._rs.load()}},_isRecordLoaded:function(model_name){return!!this._data&&!!this._data[model_name]},redirect:function(hash){return this.app.redirect(hash),this},beforeLoad:function(){},onLoad:function(){},onRecordNotFound:function(){},beforeEnter:function(){return!0},beforeLeave:function(){},onEnter:function(){},onLeave:function(){},onRefresh:function(){},mainModel:function(){return this.getMain()},setData:function(key,val){return this.set(key,val)},hasData:function(key){return this.has(key)},getData:function(key){return this.get(key)},data:function(key){return this.get(key)}}),KB.View.DEFAULT=null}()}),require.register("kickbox/views",function(){!function(){"use strict";KB._Binder=KB.Class.extend({bind:function(obj,selector,tpl){if(!(obj||KB._Binder._bindings[selector]&&KB._Binder._bindings[selector]===obj)){var $tpl,$node=$(selector),node=$node[0];KB._Binder._bindings[selector]&&($node.find("*").each(function(){$(this).unbind()}),ko.cleanNode(node),tpl&&$node.empty()),tpl&&($tpl=$("#"+tpl),$node.html($tpl.html())),KB._Binder._bindings[selector]=obj,ko.applyBindings(obj,node)}}}),KB._Binder._bindings={},KB.Views=KB.EventDispatcher.extend({$dependencies:["app"],_views_by_id:null,_views:null,_modals:null,_modal:null,_methods:null,_currModal:null,_currPopup:null,_cache:null,RESERVED_KEYWORDS:["app","route","routes","containerId","container"],construct:function(){this._cache=new KB.Cache,this._views={},this._modals={},this._popups={},this._views_by_id={},this._methods={}},register:function(route,views){var k,i,l,j,m,view,self=this,_views=[],onRoute=function(request){self._onRoute(request)};for(route=F.isArr(route)?route:[route],m=route.length,j=0;m>j;j+=1){if(views instanceof KB.View)return views.app=this.$app,views.containerId="modal",this._modals[route[j]]=views,views.methods.length>0&&this.bindMethods(views),void 0;for(k in views)views.hasOwnProperty(k)&&(view=views[k],F.assert(view instanceof KB.View,'View for container "'+k+'" declared for route "'+route+'" is not an instance of KB.View'),view.routes.push(route[j]),view.containerId=k,view.methods.length>0&&this.bindMethods(view),_views.push(view));for(l=_views.length,F.assert(l>0,'No route declared for route "'+route[j]+'"'),this._views[route[j]]||(this._views[route[j]]=[],this.$app.router.route(route[j],onRoute)),i=0;l>i;i+=1)this._views[route[j]].push(_views[i])}return this},refresh:function(){var route,views,i,iLen,j,jLen,matched_routes=this.$app.router.match();for(i=0,iLen=matched_routes.length;iLen>i;i+=1)for(route=matched_routes[i].raw,views=this._views[route],j=0,jLen=views.length;jLen>j;j+=1)views[j].render();return this},getById:function(id){return F.str("id",id,"KB.Views.getById"),id&&this._views_by_id[id]?this._views_by_id[id]:null},_createModal:function(id){if(F.str("id",id,"KB.Views._createModal"),this._modal)return this._modal.removeClass().addClass("modal").addClass(id),void 0;var self=this,$outer=$("<div></div>").addClass("modal").addClass(id),$responses=$("<div></div>").addClass("responses"),$content=$("<div></div>").addClass("content"),$header=$("<div></div>").addClass("header"),$inner=$("<div></div>").addClass("inner");$outer.append($responses,$content.append($header.append($("<span></span>").addClass("title"),$("<button><i></i></button>").addClass("special_btn close").attr({title:_("Close")})),$inner)),this._modal=$outer,$("button",$outer).on("click",function(){self.leaveModal()}),this._modal.bind("DOMNodeInserted",function(){self._autoModalPos()}),this._modal.bind("DOMNodeRemoved",function(){self._autoModalPos()}),$("body").append(this._modal),this._modal.hide()},_autoModalPos:function(){var $m=$(".modal>div.content");$m.css({"margin-top":-$m.height()/2+"px"})},modal:function(id,opts,callback){var k,f;if(F.str("id",id,"KB.Views.modal"),null!==this._currModal)return null;if(F.assert(this._modals[id]instanceof KB.View,"Modal "+id+" doesn't exist"),this._createModal(id),this._currModal=this._modals[id],this._currModal.container=$(".inner",this._modal),F.isObj(opts))for(k in opts)opts.hasOwnProperty(k)&&this._currModal.setData(k,opts[k]);return F.isFn(callback)&&(f=KB.del(this._currModal,function(){this.unbind("leave",f),callback(this._data)}),this._currModal.on("leave",f)),this._modal.show(),this._currModal.enter(KB.Request.get()),this.$app.router.block(),this._currModal.closable===!0?$(".close",this._modal).show():$(".close",this._modal).hide(),this._currModal.title?$(".title",this._modal).text(this._currModal.title):$(".title",this._modal).text(""),this._autoModalPos(),this._currModal},leaveModal:function(){return this.$app.router.unblock(),null!==this._currModal&&(this._currModal.leave(),this._currModal.container=null,this._currModal=null,this._modal.hide()),this},_createPopup:function(id,parent){if(this.popupParent=parent,this._popup)return this._popup.removeClass().addClass("popup").addClass(id),void 0;var self=this,$outer=$("<div></div>").addClass("popup").addClass(id),$arrow=$("<i></i>"),$responses=$("<div></div>").addClass("responses"),$content=$("<div></div>").addClass("content"),$header=$("<div></div>").addClass("header"),$inner=$("<div></div>").addClass("inner");$outer.append($arrow,$responses,$content.append($header.append($("<span></span>").addClass("title"),$("<button><i></i></button>").addClass("special_btn close").attr({title:_("Close")})),$inner)),this._popup=$outer,$("button",$outer).on("click",function(){self.leavePopup()}),this._popup.bind("DOMNodeInserted",function(){self._autoPopupPos(self.popupParent)}),this._popup.bind("DOMNodeRemoved",function(){self._autoPopupPos(self.popupParent)}),$("body").append(this._popup),this._popup.hide()},_autoPopupPos:function(parent){var offset=$(parent).offset()||{top:0,left:0};offset.left+=$(parent).outerWidth()+20,offset.top-=30,offset.top=Math.max(offset.top,20),$(".popup").removeAttr("style").offset(offset)},popup:function(id,parent,opts,callback){var k,f;if(F.str("id",id,"KB.Views.popup"),F.def("parent",parent,"KB.Views.popup"),null!==this._currPopup&&this.leavePopup(),F.assert(this._modals[id]instanceof KB.View,"Popup "+id+" doesn't exist"),this._createPopup(id,parent),this._currPopup=this._modals[id],this._currPopup.container=$(".inner",this._popup),this._currPopup.containerId="popup",F.isObj(opts))for(k in opts)opts.hasOwnProperty(k)&&this._currPopup.setData(k,opts[k]);return this._popup.show(),this._currPopup.enter(KB.Request.get()),F.isFn(callback)&&(f=KB.del(this._currPopup,function(){this.unbind("leave",f),callback()}),this._currPopup.on("leave",f)),this._currPopup.closable===!0?$(".close",this._popup).show():$(".close",this._popup).hide(),$(".title",this._popup).text(this._currPopup.title?this._currPopup.title:""),this._autoPopupPos(parent),this._currPopup},leavePopup:function(){return null!==this._currPopup&&(this._currPopup.leave(),this._currPopup.container=null,this._currPopup=null,this._popup.hide()),this},create:function(opts){var v=new KB.View($.extend(F.isObj(opts)?opts:{},{app:this.$app,_manager:this,_id:this._getId(),_cache:this._cache}));return this._views_by_id[v._id]=v,v},display:function(route,data){var k,j,view,found=!1;for(k in this._views_by_id)if(this._views_by_id.hasOwnProperty(k)&&(view=this._views_by_id[k],view.routes.indexOf(route)>-1)){if(data)for(j in data)data.hasOwnProperty(j)&&view.set(j,data[j]);view.enter(),found=!0}return found===!1&&F.error("No view to dispay found for "+route),this},has:function(route){var k;for(k in this._views_by_id)if(this._views_by_id.hasOwnProperty(k)&&this._views_by_id[k].routes.indexOf(route)>-1)return!0;return!1},registerMethods:function(id,methods){return this._methods[id]=methods,this},bindMethods:function(view){var n,o,p,val;for(n=0,o=view.methods.length;o>n;n+=1){F.assert(!!this._methods[view.methods[n]],"Trying to attach some methods to view ["+view.routes.join(", ")+'] but no methods stack exist with id "'+view.methods[n]+'"');for(p in this._methods[view.methods[n]])this._methods[view.methods[n]].hasOwnProperty(p)&&(this.RESERVED_KEYWORDS.indexOf(p)>-1?F.warn('Shared method/prop name "'+p+'" of shared methods "'+n+'" is a reserved keyword. Please use another name.'):"_"===p.substr(0,1)?F.warn('Shared method/prop name "'+p+'" of shared methods "'+n+'" can not start with an underscore name. Please use another name, with no leading underscore.'):(val=this._methods[view.methods[n]][p],"assets"===p&&F.isArr(val)?view.assets=view.assets.concat(val):"records"===p&&F.isObj(val)?view.records=$.extend(view.records,val):view[p]=val))}return this},_getId:function(){return KB.Views.index+=1,"kb-v-"+KB.Views.index},_onRoute:function(request){var i,views=this._views[request._route],l=views.length;if(views&&0!==l)for(i=0;l>i;i+=1)views[i].enter(request)}}),KB.Views.index=0,KB._Views=KB.Views.extend({construct:function(){F.deprecated("KB._Views","KB.Views"),this._super()}})}()});

require('kickbox/init');
</script>
<script>
Benchmark.prototype.setup = function() {
    window.array = [];
   
    myModel = Backbone.Model.extend({
      afun: function() {}
    });
   
    ResigsClass = Class.extend({
      afun: function() {}
    });
   
    BResigsClass = ResigsClass.extend({
      afun: function() {}
    });
   
    KBClass = KB.Class.extend({
      afun: function() {}
    });
   
    KBEvented = KB.EventDispatcher.extend({
      afun: function() {}
    });
};
</script>

Preparation code output

Test runner

Warning! For accurate results, please disable Firebug before running the tests. (Why?)

Java applet disabled.

Testing in unknown unknown
Test Ops/sec
Backbone.Model registration
array.push(Backbone.Model.extend({
  afun: function() {}
}));
pending…
Backbone.Model instance
array.push(new myModel());
pending…
Resig class
array.push(new ResigsClass());
pending…
Kickbox class
array.push(new KBClass());
pending…
Kickbox Evented class
array.push(new KBEvented());
pending…
Kickbox ViewModel
array.push(new KB.ViewModel());
pending…
Extended Resig class
array.push(new BResigsClass ());
pending…

Compare results of other browsers

Revisions

You can edit these tests or add even more tests to this page by appending /edit to the URL. Here’s a list of current revisions for this page:

0 comments

Add a comment