hell 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. data/.document +5 -0
  2. data/Gemfile +14 -0
  3. data/LICENSE.txt +20 -0
  4. data/README.markdown +108 -0
  5. data/Rakefile +38 -0
  6. data/VERSION +1 -0
  7. data/bin/hell +12 -0
  8. data/lib/hell.rb +0 -0
  9. data/lib/hell/app.rb +128 -0
  10. data/lib/hell/config.ru +4 -0
  11. data/lib/hell/hell.rb +0 -0
  12. data/lib/hell/lib/helpers.rb +119 -0
  13. data/lib/hell/lib/monkey_patch.rb +79 -0
  14. data/lib/hell/public/assets/css/bootstrap-responsive.css +1088 -0
  15. data/lib/hell/public/assets/css/bootstrap-responsive.min.css +9 -0
  16. data/lib/hell/public/assets/css/bootstrap.css +5893 -0
  17. data/lib/hell/public/assets/css/bootstrap.min.css +9 -0
  18. data/lib/hell/public/assets/css/hell.css +158 -0
  19. data/lib/hell/public/assets/ico/favicon.ico +0 -0
  20. data/lib/hell/public/assets/ico/favicon.png +0 -0
  21. data/lib/hell/public/assets/img/glyphicons-halflings-white.png +0 -0
  22. data/lib/hell/public/assets/img/glyphicons-halflings.png +0 -0
  23. data/lib/hell/public/assets/js/backbone-localstorage.js +84 -0
  24. data/lib/hell/public/assets/js/backbone.js +1431 -0
  25. data/lib/hell/public/assets/js/backbone.min.js +38 -0
  26. data/lib/hell/public/assets/js/bankersbox.js +768 -0
  27. data/lib/hell/public/assets/js/bootstrap.growl.js +2 -0
  28. data/lib/hell/public/assets/js/bootstrap.js +2025 -0
  29. data/lib/hell/public/assets/js/bootstrap.min.js +6 -0
  30. data/lib/hell/public/assets/js/hashchange.min.js +9 -0
  31. data/lib/hell/public/assets/js/hell.js +444 -0
  32. data/lib/hell/public/assets/js/jquery.min.js +4 -0
  33. data/lib/hell/public/assets/js/timeago.js +152 -0
  34. data/lib/hell/public/assets/js/underscore.min.js +1 -0
  35. data/lib/hell/views/index.erb +146 -0
  36. data/test/helper.rb +18 -0
  37. data/test/test_hell.rb +7 -0
  38. metadata +201 -0
@@ -0,0 +1,38 @@
1
+ // Backbone.js 0.9.2
2
+
3
+ // (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc.
4
+ // Backbone may be freely distributed under the MIT license.
5
+ // For all details and documentation:
6
+ // http://backbonejs.org
7
+ (function(){var l=this,y=l.Backbone,z=Array.prototype.slice,A=Array.prototype.splice,g;g="undefined"!==typeof exports?exports:l.Backbone={};g.VERSION="0.9.2";var f=l._;!f&&"undefined"!==typeof require&&(f=require("underscore"));var i=l.jQuery||l.Zepto||l.ender;g.setDomLibrary=function(a){i=a};g.noConflict=function(){l.Backbone=y;return this};g.emulateHTTP=!1;g.emulateJSON=!1;var p=/\s+/,k=g.Events={on:function(a,b,c){var d,e,f,g,j;if(!b)return this;a=a.split(p);for(d=this._callbacks||(this._callbacks=
8
+ {});e=a.shift();)f=(j=d[e])?j.tail:{},f.next=g={},f.context=c,f.callback=b,d[e]={tail:g,next:j?j.next:f};return this},off:function(a,b,c){var d,e,h,g,j,q;if(e=this._callbacks){if(!a&&!b&&!c)return delete this._callbacks,this;for(a=a?a.split(p):f.keys(e);d=a.shift();)if(h=e[d],delete e[d],h&&(b||c))for(g=h.tail;(h=h.next)!==g;)if(j=h.callback,q=h.context,b&&j!==b||c&&q!==c)this.on(d,j,q);return this}},trigger:function(a){var b,c,d,e,f,g;if(!(d=this._callbacks))return this;f=d.all;a=a.split(p);for(g=
9
+ z.call(arguments,1);b=a.shift();){if(c=d[b])for(e=c.tail;(c=c.next)!==e;)c.callback.apply(c.context||this,g);if(c=f){e=c.tail;for(b=[b].concat(g);(c=c.next)!==e;)c.callback.apply(c.context||this,b)}}return this}};k.bind=k.on;k.unbind=k.off;var o=g.Model=function(a,b){var c;a||(a={});b&&b.parse&&(a=this.parse(a));if(c=n(this,"defaults"))a=f.extend({},c,a);b&&b.collection&&(this.collection=b.collection);this.attributes={};this._escapedAttributes={};this.cid=f.uniqueId("c");this.changed={};this._silent=
10
+ {};this._pending={};this.set(a,{silent:!0});this.changed={};this._silent={};this._pending={};this._previousAttributes=f.clone(this.attributes);this.initialize.apply(this,arguments)};f.extend(o.prototype,k,{changed:null,_silent:null,_pending:null,idAttribute:"id",initialize:function(){},toJSON:function(){return f.clone(this.attributes)},get:function(a){return this.attributes[a]},escape:function(a){var b;if(b=this._escapedAttributes[a])return b;b=this.get(a);return this._escapedAttributes[a]=f.escape(null==
11
+ b?"":""+b)},has:function(a){return null!=this.get(a)},set:function(a,b,c){var d,e;f.isObject(a)||null==a?(d=a,c=b):(d={},d[a]=b);c||(c={});if(!d)return this;d instanceof o&&(d=d.attributes);if(c.unset)for(e in d)d[e]=void 0;if(!this._validate(d,c))return!1;this.idAttribute in d&&(this.id=d[this.idAttribute]);var b=c.changes={},h=this.attributes,g=this._escapedAttributes,j=this._previousAttributes||{};for(e in d){a=d[e];if(!f.isEqual(h[e],a)||c.unset&&f.has(h,e))delete g[e],(c.silent?this._silent:
12
+ b)[e]=!0;c.unset?delete h[e]:h[e]=a;!f.isEqual(j[e],a)||f.has(h,e)!=f.has(j,e)?(this.changed[e]=a,c.silent||(this._pending[e]=!0)):(delete this.changed[e],delete this._pending[e])}c.silent||this.change(c);return this},unset:function(a,b){(b||(b={})).unset=!0;return this.set(a,null,b)},clear:function(a){(a||(a={})).unset=!0;return this.set(f.clone(this.attributes),a)},fetch:function(a){var a=a?f.clone(a):{},b=this,c=a.success;a.success=function(d,e,f){if(!b.set(b.parse(d,f),a))return!1;c&&c(b,d)};
13
+ a.error=g.wrapError(a.error,b,a);return(this.sync||g.sync).call(this,"read",this,a)},save:function(a,b,c){var d,e;f.isObject(a)||null==a?(d=a,c=b):(d={},d[a]=b);c=c?f.clone(c):{};if(c.wait){if(!this._validate(d,c))return!1;e=f.clone(this.attributes)}a=f.extend({},c,{silent:!0});if(d&&!this.set(d,c.wait?a:c))return!1;var h=this,i=c.success;c.success=function(a,b,e){b=h.parse(a,e);if(c.wait){delete c.wait;b=f.extend(d||{},b)}if(!h.set(b,c))return false;i?i(h,a):h.trigger("sync",h,a,c)};c.error=g.wrapError(c.error,
14
+ h,c);b=this.isNew()?"create":"update";b=(this.sync||g.sync).call(this,b,this,c);c.wait&&this.set(e,a);return b},destroy:function(a){var a=a?f.clone(a):{},b=this,c=a.success,d=function(){b.trigger("destroy",b,b.collection,a)};if(this.isNew())return d(),!1;a.success=function(e){a.wait&&d();c?c(b,e):b.trigger("sync",b,e,a)};a.error=g.wrapError(a.error,b,a);var e=(this.sync||g.sync).call(this,"delete",this,a);a.wait||d();return e},url:function(){var a=n(this,"urlRoot")||n(this.collection,"url")||t();
15
+ return this.isNew()?a:a+("/"==a.charAt(a.length-1)?"":"/")+encodeURIComponent(this.id)},parse:function(a){return a},clone:function(){return new this.constructor(this.attributes)},isNew:function(){return null==this.id},change:function(a){a||(a={});var b=this._changing;this._changing=!0;for(var c in this._silent)this._pending[c]=!0;var d=f.extend({},a.changes,this._silent);this._silent={};for(c in d)this.trigger("change:"+c,this,this.get(c),a);if(b)return this;for(;!f.isEmpty(this._pending);){this._pending=
16
+ {};this.trigger("change",this,a);for(c in this.changed)!this._pending[c]&&!this._silent[c]&&delete this.changed[c];this._previousAttributes=f.clone(this.attributes)}this._changing=!1;return this},hasChanged:function(a){return!arguments.length?!f.isEmpty(this.changed):f.has(this.changed,a)},changedAttributes:function(a){if(!a)return this.hasChanged()?f.clone(this.changed):!1;var b,c=!1,d=this._previousAttributes,e;for(e in a)if(!f.isEqual(d[e],b=a[e]))(c||(c={}))[e]=b;return c},previous:function(a){return!arguments.length||
17
+ !this._previousAttributes?null:this._previousAttributes[a]},previousAttributes:function(){return f.clone(this._previousAttributes)},isValid:function(){return!this.validate(this.attributes)},_validate:function(a,b){if(b.silent||!this.validate)return!0;var a=f.extend({},this.attributes,a),c=this.validate(a,b);if(!c)return!0;b&&b.error?b.error(this,c,b):this.trigger("error",this,c,b);return!1}});var r=g.Collection=function(a,b){b||(b={});b.model&&(this.model=b.model);b.comparator&&(this.comparator=b.comparator);
18
+ this._reset();this.initialize.apply(this,arguments);a&&this.reset(a,{silent:!0,parse:b.parse})};f.extend(r.prototype,k,{model:o,initialize:function(){},toJSON:function(a){return this.map(function(b){return b.toJSON(a)})},add:function(a,b){var c,d,e,g,i,j={},k={},l=[];b||(b={});a=f.isArray(a)?a.slice():[a];c=0;for(d=a.length;c<d;c++){if(!(e=a[c]=this._prepareModel(a[c],b)))throw Error("Can't add an invalid model to a collection");g=e.cid;i=e.id;j[g]||this._byCid[g]||null!=i&&(k[i]||this._byId[i])?
19
+ l.push(c):j[g]=k[i]=e}for(c=l.length;c--;)a.splice(l[c],1);c=0;for(d=a.length;c<d;c++)(e=a[c]).on("all",this._onModelEvent,this),this._byCid[e.cid]=e,null!=e.id&&(this._byId[e.id]=e);this.length+=d;A.apply(this.models,[null!=b.at?b.at:this.models.length,0].concat(a));this.comparator&&this.sort({silent:!0});if(b.silent)return this;c=0;for(d=this.models.length;c<d;c++)if(j[(e=this.models[c]).cid])b.index=c,e.trigger("add",e,this,b);return this},remove:function(a,b){var c,d,e,g;b||(b={});a=f.isArray(a)?
20
+ a.slice():[a];c=0;for(d=a.length;c<d;c++)if(g=this.getByCid(a[c])||this.get(a[c]))delete this._byId[g.id],delete this._byCid[g.cid],e=this.indexOf(g),this.models.splice(e,1),this.length--,b.silent||(b.index=e,g.trigger("remove",g,this,b)),this._removeReference(g);return this},push:function(a,b){a=this._prepareModel(a,b);this.add(a,b);return a},pop:function(a){var b=this.at(this.length-1);this.remove(b,a);return b},unshift:function(a,b){a=this._prepareModel(a,b);this.add(a,f.extend({at:0},b));return a},
21
+ shift:function(a){var b=this.at(0);this.remove(b,a);return b},get:function(a){return null==a?void 0:this._byId[null!=a.id?a.id:a]},getByCid:function(a){return a&&this._byCid[a.cid||a]},at:function(a){return this.models[a]},where:function(a){return f.isEmpty(a)?[]:this.filter(function(b){for(var c in a)if(a[c]!==b.get(c))return!1;return!0})},sort:function(a){a||(a={});if(!this.comparator)throw Error("Cannot sort a set without a comparator");var b=f.bind(this.comparator,this);1==this.comparator.length?
22
+ this.models=this.sortBy(b):this.models.sort(b);a.silent||this.trigger("reset",this,a);return this},pluck:function(a){return f.map(this.models,function(b){return b.get(a)})},reset:function(a,b){a||(a=[]);b||(b={});for(var c=0,d=this.models.length;c<d;c++)this._removeReference(this.models[c]);this._reset();this.add(a,f.extend({silent:!0},b));b.silent||this.trigger("reset",this,b);return this},fetch:function(a){a=a?f.clone(a):{};void 0===a.parse&&(a.parse=!0);var b=this,c=a.success;a.success=function(d,
23
+ e,f){b[a.add?"add":"reset"](b.parse(d,f),a);c&&c(b,d)};a.error=g.wrapError(a.error,b,a);return(this.sync||g.sync).call(this,"read",this,a)},create:function(a,b){var c=this,b=b?f.clone(b):{},a=this._prepareModel(a,b);if(!a)return!1;b.wait||c.add(a,b);var d=b.success;b.success=function(e,f){b.wait&&c.add(e,b);d?d(e,f):e.trigger("sync",a,f,b)};a.save(null,b);return a},parse:function(a){return a},chain:function(){return f(this.models).chain()},_reset:function(){this.length=0;this.models=[];this._byId=
24
+ {};this._byCid={}},_prepareModel:function(a,b){b||(b={});a instanceof o?a.collection||(a.collection=this):(b.collection=this,a=new this.model(a,b),a._validate(a.attributes,b)||(a=!1));return a},_removeReference:function(a){this==a.collection&&delete a.collection;a.off("all",this._onModelEvent,this)},_onModelEvent:function(a,b,c,d){("add"==a||"remove"==a)&&c!=this||("destroy"==a&&this.remove(b,d),b&&a==="change:"+b.idAttribute&&(delete this._byId[b.previous(b.idAttribute)],this._byId[b.id]=b),this.trigger.apply(this,
25
+ arguments))}});f.each("forEach,each,map,reduce,reduceRight,find,detect,filter,select,reject,every,all,some,any,include,contains,invoke,max,min,sortBy,sortedIndex,toArray,size,first,initial,rest,last,without,indexOf,shuffle,lastIndexOf,isEmpty,groupBy".split(","),function(a){r.prototype[a]=function(){return f[a].apply(f,[this.models].concat(f.toArray(arguments)))}});var u=g.Router=function(a){a||(a={});a.routes&&(this.routes=a.routes);this._bindRoutes();this.initialize.apply(this,arguments)},B=/:\w+/g,
26
+ C=/\*\w+/g,D=/[-[\]{}()+?.,\\^$|#\s]/g;f.extend(u.prototype,k,{initialize:function(){},route:function(a,b,c){g.history||(g.history=new m);f.isRegExp(a)||(a=this._routeToRegExp(a));c||(c=this[b]);g.history.route(a,f.bind(function(d){d=this._extractParameters(a,d);c&&c.apply(this,d);this.trigger.apply(this,["route:"+b].concat(d));g.history.trigger("route",this,b,d)},this));return this},navigate:function(a,b){g.history.navigate(a,b)},_bindRoutes:function(){if(this.routes){var a=[],b;for(b in this.routes)a.unshift([b,
27
+ this.routes[b]]);b=0;for(var c=a.length;b<c;b++)this.route(a[b][0],a[b][1],this[a[b][1]])}},_routeToRegExp:function(a){a=a.replace(D,"\\$&").replace(B,"([^/]+)").replace(C,"(.*?)");return RegExp("^"+a+"$")},_extractParameters:function(a,b){return a.exec(b).slice(1)}});var m=g.History=function(){this.handlers=[];f.bindAll(this,"checkUrl")},s=/^[#\/]/,E=/msie [\w.]+/;m.started=!1;f.extend(m.prototype,k,{interval:50,getHash:function(a){return(a=(a?a.location:window.location).href.match(/#(.*)$/))?a[1]:
28
+ ""},getFragment:function(a,b){if(null==a)if(this._hasPushState||b){var a=window.location.pathname,c=window.location.search;c&&(a+=c)}else a=this.getHash();a.indexOf(this.options.root)||(a=a.substr(this.options.root.length));return a.replace(s,"")},start:function(a){if(m.started)throw Error("Backbone.history has already been started");m.started=!0;this.options=f.extend({},{root:"/"},this.options,a);this._wantsHashChange=!1!==this.options.hashChange;this._wantsPushState=!!this.options.pushState;this._hasPushState=
29
+ !(!this.options.pushState||!window.history||!window.history.pushState);var a=this.getFragment(),b=document.documentMode;if(b=E.exec(navigator.userAgent.toLowerCase())&&(!b||7>=b))this.iframe=i('<iframe src="javascript:0" tabindex="-1" />').hide().appendTo("body")[0].contentWindow,this.navigate(a);this._hasPushState?i(window).bind("popstate",this.checkUrl):this._wantsHashChange&&"onhashchange"in window&&!b?i(window).bind("hashchange",this.checkUrl):this._wantsHashChange&&(this._checkUrlInterval=setInterval(this.checkUrl,
30
+ this.interval));this.fragment=a;a=window.location;b=a.pathname==this.options.root;if(this._wantsHashChange&&this._wantsPushState&&!this._hasPushState&&!b)return this.fragment=this.getFragment(null,!0),window.location.replace(this.options.root+"#"+this.fragment),!0;this._wantsPushState&&this._hasPushState&&b&&a.hash&&(this.fragment=this.getHash().replace(s,""),window.history.replaceState({},document.title,a.protocol+"//"+a.host+this.options.root+this.fragment));if(!this.options.silent)return this.loadUrl()},
31
+ stop:function(){i(window).unbind("popstate",this.checkUrl).unbind("hashchange",this.checkUrl);clearInterval(this._checkUrlInterval);m.started=!1},route:function(a,b){this.handlers.unshift({route:a,callback:b})},checkUrl:function(){var a=this.getFragment();a==this.fragment&&this.iframe&&(a=this.getFragment(this.getHash(this.iframe)));if(a==this.fragment)return!1;this.iframe&&this.navigate(a);this.loadUrl()||this.loadUrl(this.getHash())},loadUrl:function(a){var b=this.fragment=this.getFragment(a);return f.any(this.handlers,
32
+ function(a){if(a.route.test(b))return a.callback(b),!0})},navigate:function(a,b){if(!m.started)return!1;if(!b||!0===b)b={trigger:b};var c=(a||"").replace(s,"");this.fragment!=c&&(this._hasPushState?(0!=c.indexOf(this.options.root)&&(c=this.options.root+c),this.fragment=c,window.history[b.replace?"replaceState":"pushState"]({},document.title,c)):this._wantsHashChange?(this.fragment=c,this._updateHash(window.location,c,b.replace),this.iframe&&c!=this.getFragment(this.getHash(this.iframe))&&(b.replace||
33
+ this.iframe.document.open().close(),this._updateHash(this.iframe.location,c,b.replace))):window.location.assign(this.options.root+a),b.trigger&&this.loadUrl(a))},_updateHash:function(a,b,c){c?a.replace(a.toString().replace(/(javascript:|#).*$/,"")+"#"+b):a.hash=b}});var v=g.View=function(a){this.cid=f.uniqueId("view");this._configure(a||{});this._ensureElement();this.initialize.apply(this,arguments);this.delegateEvents()},F=/^(\S+)\s*(.*)$/,w="model,collection,el,id,attributes,className,tagName".split(",");
34
+ f.extend(v.prototype,k,{tagName:"div",$:function(a){return this.$el.find(a)},initialize:function(){},render:function(){return this},remove:function(){this.$el.remove();return this},make:function(a,b,c){a=document.createElement(a);b&&i(a).attr(b);c&&i(a).html(c);return a},setElement:function(a,b){this.$el&&this.undelegateEvents();this.$el=a instanceof i?a:i(a);this.el=this.$el[0];!1!==b&&this.delegateEvents();return this},delegateEvents:function(a){if(a||(a=n(this,"events"))){this.undelegateEvents();
35
+ for(var b in a){var c=a[b];f.isFunction(c)||(c=this[a[b]]);if(!c)throw Error('Method "'+a[b]+'" does not exist');var d=b.match(F),e=d[1],d=d[2],c=f.bind(c,this),e=e+(".delegateEvents"+this.cid);""===d?this.$el.bind(e,c):this.$el.delegate(d,e,c)}}},undelegateEvents:function(){this.$el.unbind(".delegateEvents"+this.cid)},_configure:function(a){this.options&&(a=f.extend({},this.options,a));for(var b=0,c=w.length;b<c;b++){var d=w[b];a[d]&&(this[d]=a[d])}this.options=a},_ensureElement:function(){if(this.el)this.setElement(this.el,
36
+ !1);else{var a=n(this,"attributes")||{};this.id&&(a.id=this.id);this.className&&(a["class"]=this.className);this.setElement(this.make(this.tagName,a),!1)}}});o.extend=r.extend=u.extend=v.extend=function(a,b){var c=G(this,a,b);c.extend=this.extend;return c};var H={create:"POST",update:"PUT","delete":"DELETE",read:"GET"};g.sync=function(a,b,c){var d=H[a];c||(c={});var e={type:d,dataType:"json"};c.url||(e.url=n(b,"url")||t());if(!c.data&&b&&("create"==a||"update"==a))e.contentType="application/json",
37
+ e.data=JSON.stringify(b.toJSON());g.emulateJSON&&(e.contentType="application/x-www-form-urlencoded",e.data=e.data?{model:e.data}:{});if(g.emulateHTTP&&("PUT"===d||"DELETE"===d))g.emulateJSON&&(e.data._method=d),e.type="POST",e.beforeSend=function(a){a.setRequestHeader("X-HTTP-Method-Override",d)};"GET"!==e.type&&!g.emulateJSON&&(e.processData=!1);return i.ajax(f.extend(e,c))};g.wrapError=function(a,b,c){return function(d,e){e=d===b?e:d;a?a(b,e,c):b.trigger("error",b,e,c)}};var x=function(){},G=function(a,
38
+ b,c){var d;d=b&&b.hasOwnProperty("constructor")?b.constructor:function(){a.apply(this,arguments)};f.extend(d,a);x.prototype=a.prototype;d.prototype=new x;b&&f.extend(d.prototype,b);c&&f.extend(d,c);d.prototype.constructor=d;d.__super__=a.prototype;return d},n=function(a,b){return!a||!a[b]?null:f.isFunction(a[b])?a[b]():a[b]},t=function(){throw Error('A "url" property or function must be specified');}}).call(this);
@@ -0,0 +1,768 @@
1
+ /**
2
+ * @license MIT License
3
+ *
4
+ * Copyright (c) 2012 Twilio Inc.
5
+ *
6
+ * Authors: Chad Etzel <chetzel@twilio.com>
7
+ *
8
+ * Permission is hereby granted, free of charge, to any person obtaining
9
+ * a copy of this software and associated documentation files (the
10
+ * "Software"), to deal in the Software without restriction, including
11
+ * without limitation the rights to use, copy, modify, merge, publish,
12
+ * distribute, sublicense, and/or sell copies of the Software, and to
13
+ * permit persons to whom the Software is furnished to do so, subject to
14
+ * the following conditions:
15
+ *
16
+ * The above copyright notice and this permission notice shall be
17
+ * included in all copies or substantial portions of the Software.
18
+ *
19
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23
+ * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24
+ * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25
+ * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
+ */
27
+
28
+ (function(ctx) {
29
+
30
+ if (typeof(window) === 'undefined') {
31
+ window = {};
32
+ }
33
+
34
+ if (typeof(window.localStorage) === 'undefined' && ctx !== window) {
35
+ // fake out localStorage functionality, mostly for testing purposes
36
+ window.localStorage = {};
37
+ window.localStorage.store = {};
38
+ window.localStorage.setItem = function(k, v) {
39
+ window.localStorage.store[k] = v;
40
+ };
41
+ window.localStorage.getItem = function(k) {
42
+ var ret;
43
+ ret = window.localStorage.store[k];
44
+ if (ret === undefined) {
45
+ return null;
46
+ }
47
+ return ret;
48
+ };
49
+ window.localStorage.removeItem = function(k) {
50
+ delete window.localStorage.store[k];
51
+ };
52
+ window.localStorage.clear = function() {
53
+ window.localStorage.store = {};
54
+ };
55
+ }
56
+
57
+ // Array Remove - By John Resig (MIT Licensed)
58
+ var arr_remove = function(array, from, to) {
59
+ var rest = array.slice((to || from) + 1 || array.length);
60
+ array.length = from < 0 ? array.length + from : from;
61
+ return array.push.apply(array, rest);
62
+ };
63
+
64
+ var BB = function(dbi, opts) {
65
+
66
+ if (isNaN(parseInt(dbi, 10))) {
67
+ throw(new BankersBoxException("db index must be an integer"));
68
+ }
69
+ dbi = parseInt(dbi, 10);
70
+
71
+ opts = opts || {};
72
+
73
+ var self = this;
74
+
75
+ var db = dbi;
76
+ var adapter = opts.adapter;
77
+
78
+ if (adapter === undefined) {
79
+ adapter = new BankersBoxLocalStorageAdapter();
80
+ } else if (adapter === null) {
81
+ adapter = new BankersBoxNullAdapter();
82
+ }
83
+
84
+ var prefix = "bb:" + db.toString() + ":";
85
+ var keyskey = "bb:" + db.toString() + "k:___keys___";
86
+ var store = {};
87
+
88
+ this.toString = function() {
89
+ return "bb:" + db.toString();
90
+ };
91
+
92
+ if (typeof(JSON) == 'undefined' && !(window.JSON && window.JSON.parse && window.JSON.stringify)) {
93
+ throw("No JSON support detected. Please include a JSON module with 'parse' and 'stringify' functions.");
94
+ }
95
+
96
+ var exists_raw = function(k) {
97
+ var ret = store[k] || adapter.getItem(k);
98
+ return ret ? true : false;
99
+ };
100
+
101
+ var get_raw = function(k, t) {
102
+ var ret = store[k];
103
+ if (ret !== undefined) {
104
+ return ret;
105
+ }
106
+ ret = adapter.getItem(k);
107
+ var obj = ret;
108
+ try {
109
+ obj = JSON.parse(ret);
110
+ } catch (e) {
111
+ } finally {
112
+ store[k] = obj;
113
+ }
114
+ return obj;
115
+ };
116
+
117
+ var set_raw = function(k, v, t) {
118
+ store[k] = v;
119
+ adapter.storeItem(k, JSON.stringify(v));
120
+ };
121
+
122
+ var del_raw = function(k) {
123
+ delete store[k];
124
+ adapter.removeItem(k);
125
+ };
126
+
127
+ var get_raw_value = function(k, t) {
128
+ var val = get_raw(k, t);
129
+ if (val === null) {
130
+ return null;
131
+ }
132
+ return val.v;
133
+ };
134
+
135
+ var get_raw_meta = function(k, meta, t) {
136
+ var val = get_raw(k, t);
137
+ if (val === null) {
138
+ return null;
139
+ }
140
+ return val.m[meta];
141
+ };
142
+
143
+ var set_raw_value = function(k, v, t) {
144
+ var val = get_raw(k, t);
145
+ if (val === undefined || val === null) {
146
+ val = {};
147
+ val.m = {};
148
+ }
149
+ val.v = v;
150
+ if (t !== undefined) {
151
+ val.m.t = t;
152
+ }
153
+ set_raw(k, val, t);
154
+ };
155
+
156
+ var set_raw_meta = function(k, meta, v) {
157
+ var val = store[k];
158
+ if (val === undefined || val === null) {
159
+ return;
160
+ }
161
+ val.m[meta] = v;
162
+ set_raw(k, val);
163
+ };
164
+
165
+ var exists_bbkey = function(k) {
166
+ return exists_raw(prefix + k);
167
+ };
168
+
169
+ var set_bbkey = function(k, v, t) {
170
+ set_raw_value(prefix + k, v, t);
171
+ if (t !== undefined) {
172
+ set_bbkeytype(k, t);
173
+ }
174
+ keystore[k] = 1;
175
+ set_raw_value(keyskey, keystore, "set");
176
+ };
177
+
178
+ var get_bbkey = function(k, t) {
179
+ return get_raw_value(prefix + k, t);
180
+ };
181
+
182
+ var del_bbkey = function(k) {
183
+ del_raw(prefix + k);
184
+ delete keystore[k];
185
+ set_raw_value(keyskey, keystore, "set");
186
+ };
187
+
188
+ var set_bbkeymeta = function(k, meta, v) {
189
+ set_raw_meta(prefix + k, meta, v);
190
+ };
191
+
192
+ var get_bbkeymeta = function(k, meta) {
193
+ return get_raw_meta(prefix + k, meta);
194
+ };
195
+
196
+ var set_bbkeytype = function(k, v) {
197
+ set_bbkeymeta(k, "t", v);
198
+ };
199
+
200
+ var get_bbkeytype = function(k) {
201
+ return get_bbkeymeta(k, "t");
202
+ };
203
+
204
+ var validate_key = function(k, checktype) {
205
+ var keytype = self.type(k);
206
+ var tmap = {};
207
+ tmap["get"] = "string";
208
+ tmap["set"] = "string";
209
+ tmap["strlen"] = "string";
210
+ tmap["setnx"] = "string";
211
+ tmap["append"] = "string";
212
+ tmap["incr"] = "string";
213
+ tmap["incrby"] = "string";
214
+ tmap["getset"] = "string";
215
+ tmap["lpush"] = "list";
216
+ tmap["lpushx"] = "list";
217
+ tmap["lpop"] = "list";
218
+ tmap["rpush"] = "list";
219
+ tmap["rpushx"] = "list";
220
+ tmap["rpop"] = "list";
221
+ tmap["rpoplpush"] = "list";
222
+ tmap["llen"] = "list";
223
+ tmap["lindex"] = "list";
224
+ tmap["lrange"] = "list";
225
+ tmap["lrem"] = "list";
226
+ tmap["lset"] = "list";
227
+ tmap["ltrim"] = "list";
228
+ tmap["sadd"] = "set";
229
+ tmap["scard"] = "set";
230
+ tmap["sismember"] = "set";
231
+ tmap["smembers"] = "set";
232
+ tmap["srem"] = "set";
233
+ tmap["smove"] = "set";
234
+ tmap["spop"] = "set";
235
+ tmap["srandmember"] = "set";
236
+
237
+ if (tmap[checktype] === undefined) {
238
+ throw new BankersBoxException("unknown key operation in validate_key");
239
+ }
240
+
241
+ if (keytype === undefined || keytype === null || tmap[checktype] === undefined || tmap[checktype] == keytype) {
242
+ return true;
243
+ }
244
+ throw(new BankersBoxKeyException("invalid operation on key type: " + keytype));
245
+ };
246
+
247
+ /* ---- PRIVILEGED METHODS ---- */
248
+
249
+ /* ---- KEY ---- */
250
+
251
+ this.del = function(k) {
252
+ var ret = 0;
253
+ if (get_bbkey(k)) {
254
+ ret = 1;
255
+ }
256
+ del_bbkey(k);
257
+ return ret;
258
+ };
259
+
260
+ this.exists = function(k) {
261
+ return exists_bbkey(k);
262
+ };
263
+
264
+ this.type = function(k) {
265
+ return get_bbkeytype(k);
266
+ };
267
+
268
+
269
+ /* ---- STRING ---- */
270
+
271
+ this.get = function(k) {
272
+ validate_key(k, "get");
273
+ return get_bbkey(k);
274
+ };
275
+
276
+ this.getset = function(k, v) {
277
+ validate_key(k, "getset");
278
+ var val = self.get(k);
279
+ self.set(k, v);
280
+ return val;
281
+ };
282
+
283
+ this.append = function(k, v) {
284
+ validate_key(k, "append");
285
+ var val = self.get(k);
286
+ if (val !== null) {
287
+ self.set(k, val + v);
288
+ return (val + v).length;
289
+ }
290
+ self.set(k, v);
291
+ return v.toString().length;
292
+ };
293
+
294
+ this.decr = function(k) {
295
+ return self.incrby(k, -1);
296
+ };
297
+
298
+ this.decrby = function(k, i) {
299
+ return self.incrby(k, 0 - i);
300
+ };
301
+
302
+ this.incr = function(k) {
303
+ return self.incrby(k, 1);
304
+ };
305
+
306
+ this.incrby = function(k, i) {
307
+ validate_key(k, "incrby");
308
+ var val = self.get(k);
309
+ if (val !== null) {
310
+ if (isNaN(parseInt(val, 10))) {
311
+ throw(new BankersBoxKeyException("key is not parsable as an integer"));
312
+ }
313
+ self.set(k, val + i);
314
+ return val + i;
315
+ }
316
+ self.set(k, i);
317
+ return i;
318
+ };
319
+
320
+ this.set = function(k, v) {
321
+ validate_key(k, "set");
322
+ set_bbkey(k, v);
323
+ set_bbkeytype(k, "string");
324
+ return "OK";
325
+ };
326
+
327
+ this.setnx = function(k, v) {
328
+ validate_key(k, "setnx");
329
+ var val = self.get(k);
330
+ if (val !== null) {
331
+ return 0;
332
+ }
333
+ self.set(k, v);
334
+ return 1;
335
+ };
336
+
337
+ this.strlen = function(k) {
338
+ validate_key(k, "strlen");
339
+ var v = self.get(k);
340
+ if (v !== null) {
341
+ return v.toString().length;
342
+ }
343
+ return 0;
344
+ };
345
+
346
+ /* ---- LIST ---- */
347
+
348
+ this.llen = function(k) {
349
+ validate_key(k, "llen");
350
+ var val = get_bbkey(k, "list");
351
+ if (val === null) {
352
+ return 0;
353
+ }
354
+ return val.length;
355
+ };
356
+
357
+ this.lindex = function(k, i) {
358
+ validate_key(k, "lindex");
359
+ var val = get_bbkey(k, "list");
360
+ if (val !== null) {
361
+ if (i < 0) {
362
+ i = val.length + i;
363
+ }
364
+ var ret = val[i];
365
+ if (ret === undefined) {
366
+ ret = null;
367
+ }
368
+ return ret;
369
+ }
370
+ return null;
371
+ };
372
+
373
+ this.lpop = function(k) {
374
+ validate_key(k, "lpop");
375
+ var val = get_bbkey(k, "list");
376
+ if (val === null) {
377
+ return null;
378
+ }
379
+ var ret = val.shift();
380
+ if (val.length === 0) {
381
+ self.del(k);
382
+ } else {
383
+ set_bbkey(k, val, "list");
384
+ }
385
+ return ret;
386
+ };
387
+
388
+ this.lpush = function(k, v) {
389
+ validate_key(k, "lpush");
390
+ var val = get_bbkey(k, "list");
391
+ if (val === null) {
392
+ val = [];
393
+ }
394
+ val.unshift(v);
395
+ set_bbkey(k, val, "list");
396
+ return val.length;
397
+ };
398
+
399
+ this.lpushx = function(k, v) {
400
+ validate_key(k, "lpushx");
401
+ var val = get_bbkey(k, "list");
402
+ if (val !== null) {
403
+ return self.lpush(k, v);
404
+ }
405
+ return 0;
406
+ };
407
+
408
+ this.lrange = function(k, start, end) {
409
+ validate_key(k, "lrange");
410
+ var val = get_bbkey(k, "list");
411
+ if (val === null) {
412
+ return [];
413
+ }
414
+ if (end === -1) {
415
+ return val.slice(start);
416
+ }
417
+ return val.slice(start, end + 1);
418
+ };
419
+
420
+ this.lrem = function(k, count, v) {
421
+ validate_key(k, "lrem");
422
+ var val = get_bbkey(k, "list");
423
+ if (val === null) {
424
+ return 0;
425
+ }
426
+ var ret = 0;
427
+ var to_remove = [];
428
+ for (var i = 0; i < val.length; i++) {
429
+ if (val[i] == v) {
430
+ to_remove.push(i);
431
+ ret++;
432
+ }
433
+ }
434
+
435
+ if (count > 0) {
436
+ to_remove = to_remove.slice(0, count);
437
+ } else if (count < 0) {
438
+ to_remove = to_remove.slice(count);
439
+ }
440
+
441
+ while(to_remove.length) {
442
+ var el = to_remove.pop();
443
+ arr_remove(val, el);
444
+ }
445
+
446
+ if (val.length === 0) {
447
+ self.del(k);
448
+ } else {
449
+ set_bbkey(k, val, "list");
450
+ }
451
+ if (count === 0) {
452
+ return ret;
453
+ } else {
454
+ return Math.min(ret, Math.abs(count));
455
+ }
456
+ };
457
+
458
+ this.lset = function(k, i, v) {
459
+ validate_key(k, "lset");
460
+ var val = get_bbkey(k, "list");
461
+ if (val === null) {
462
+ throw(new BankersBoxKeyException("no such key"));
463
+ }
464
+ if (i < 0) {
465
+ i = val.length + i;
466
+ }
467
+ if (i < 0 || i >= val.length) {
468
+ throw(new BankersBoxException("index out of range"));
469
+ }
470
+ val[i] = v;
471
+ set_bbkey(k, val, "list");
472
+ return "OK";
473
+ };
474
+
475
+ this.ltrim = function(k, start, end) {
476
+ validate_key(k, "ltrim");
477
+ var val = get_bbkey(k, "list");
478
+ if (val === null) {
479
+ return "OK";
480
+ }
481
+ if (end === -1) {
482
+ val = val.slice(start);
483
+ } else {
484
+ val = val.slice(start, end + 1);
485
+ }
486
+ if (val.length === 0) {
487
+ self.del(k);
488
+ } else {
489
+ set_bbkey(k, val, "list");
490
+ }
491
+ return "OK";
492
+ };
493
+
494
+ this.rpop = function(k) {
495
+ validate_key(k, "rpop");
496
+ var val = get_bbkey(k, "list");
497
+ if (val === null) {
498
+ return null;
499
+ }
500
+ var ret = val.pop();
501
+ if (val.length === 0) {
502
+ self.del(k);
503
+ } else {
504
+ set_bbkey(k, val, "list");
505
+ }
506
+ return ret;
507
+ };
508
+
509
+ this.rpush = function(k, v) {
510
+ validate_key(k, "rpush");
511
+ var val = get_bbkey(k);
512
+ if (val === null) {
513
+ val = [];
514
+ }
515
+ val.push(v);
516
+ set_bbkey(k, val, "list");
517
+ return val.length;
518
+ };
519
+
520
+ this.rpushx = function(k, v) {
521
+ validate_key(k, "rpushx");
522
+ var val = get_bbkey(k, "list");
523
+ if (val !== null) {
524
+ return self.rpush(k, v);
525
+ }
526
+ return 0;
527
+ };
528
+
529
+ this.rpoplpush = function(src, dest) {
530
+ validate_key(src, "rpoplpush");
531
+ validate_key(dest, "rpoplpush");
532
+
533
+ var srcval = get_bbkey(src, "list");
534
+ var destval = get_bbkey(dest, "list");
535
+
536
+ if (srcval === null) {
537
+ return null;
538
+ }
539
+
540
+ var val = self.rpop(src);
541
+ self.lpush(dest, val);
542
+ return val;
543
+ };
544
+
545
+
546
+ /* ---- SET ---- */
547
+
548
+ this.sadd = function(k, v) {
549
+ validate_key(k, "sadd");
550
+ var val = get_bbkey(k, "set");
551
+ var scard;
552
+ var ret = 0;
553
+ if (val === null) {
554
+ val = {};
555
+ scard = 0;
556
+ } else {
557
+ scard = parseInt(get_bbkeymeta(k, "card"), 10);
558
+ }
559
+ if (val[v] !== 1) {
560
+ ret = 1;
561
+ scard = scard + 1;
562
+ }
563
+ val[v] = 1;
564
+ set_bbkey(k, val, "set");
565
+ set_bbkeymeta(k, "card", scard);
566
+ return ret;
567
+ };
568
+
569
+ this.scard = function(k) {
570
+ validate_key(k, "scard");
571
+ if (self.exists(k)) {
572
+ return parseInt(get_bbkeymeta(k, "card"), 10);
573
+ }
574
+ return 0;
575
+ };
576
+
577
+ this.sismember = function(k, v) {
578
+ validate_key(k, "sismember");
579
+ var val = get_bbkey(k, "set");
580
+ if (val === null) {
581
+ return false;
582
+ }
583
+ if (val[v] === 1) {
584
+ return true;
585
+ }
586
+ return false;
587
+ };
588
+
589
+ this.smembers = function(k) {
590
+ validate_key(k, "smembers");
591
+ var val = get_bbkey(k, "set");
592
+ if (val === null) {
593
+ return [];
594
+ }
595
+ var ret = [];
596
+ for (var v in val) {
597
+ if (val.hasOwnProperty(v)) {
598
+ ret.push(v);
599
+ }
600
+ }
601
+ return ret;
602
+ };
603
+
604
+ this.smove = function(src, dest, v) {
605
+ validate_key(src, "smove");
606
+ validate_key(dest, "smove");
607
+ var srcval = get_bbkey(src, "set");
608
+ if (srcval === null) {
609
+ return 0;
610
+ }
611
+ var ret = self.srem(src, v);
612
+ if (ret) {
613
+ self.sadd(dest, v);
614
+ }
615
+ return ret;
616
+ };
617
+
618
+ this.spop = function(k) {
619
+ validate_key(k, "spop");
620
+ var member = self.srandmember(k);
621
+ if (member !== null) {
622
+ self.srem(k, member);
623
+ }
624
+ return member;
625
+ };
626
+
627
+ this.srandmember = function(k) {
628
+ validate_key(k, "srandmember");
629
+ var val = get_bbkey(k, "set");
630
+ if (val === null) {
631
+ return null;
632
+ }
633
+ var members = self.smembers(k);
634
+ var i = Math.floor(Math.random() * members.length);
635
+ var ret = members[i];
636
+ return ret;
637
+ };
638
+
639
+ this.srem = function(k, v) {
640
+ validate_key(k, "srem");
641
+ var val = get_bbkey(k, "set");
642
+ if (val === null) {
643
+ return 0;
644
+ }
645
+ var ret = 0;
646
+ if (val[v] === 1) {
647
+ ret = 1;
648
+ delete val[v];
649
+ var scard = parseInt(get_bbkeymeta(k, "card"), 10) - 1;
650
+ if (scard === 0) {
651
+ self.del(k);
652
+ } else {
653
+ set_bbkey(k, val, "set");
654
+ set_bbkeymeta(k, "card", scard);
655
+ }
656
+ }
657
+ return ret;
658
+ };
659
+
660
+ /* ---- SERVER ---- */
661
+
662
+ this.keys = function(filter) {
663
+ // TODO: implement filter.. for now just return *
664
+ var ret = [];
665
+ for (var k in keystore) {
666
+ if (keystore.hasOwnProperty(k)) {
667
+ ret.push(k);
668
+ }
669
+ }
670
+ return ret;
671
+ };
672
+
673
+ this.flushdb = function() {
674
+ var keys = self.keys("*");
675
+ for (var i in keys) {
676
+ self.del(keys[i]);
677
+ }
678
+ del_raw(keyskey);
679
+ return "OK";
680
+ };
681
+
682
+ this.select = function(i) {
683
+ if (isNaN(parseInt(i, 10))) {
684
+ throw(new BankersBoxException("db index must be an integer"));
685
+ }
686
+ db = i;
687
+ prefix = "bb:" + i.toString() + ":";
688
+ keyskey = "bb:" + i.toString() + "k:___keys___";
689
+ keystore = get_raw_value(keyskey, "set") || {};
690
+ };
691
+
692
+ var keystore = get_raw_value(keyskey, "set") || {};
693
+
694
+ }; /* end constructor */
695
+
696
+
697
+ BB.toString = function() {
698
+ return "[object BankersBox]";
699
+ };
700
+
701
+
702
+ var BankersBoxException = function(msg) {
703
+ this.type = "BankersBoxException";
704
+ this.toString = function() {
705
+ return this.type + ": " + msg.toString();
706
+ };
707
+ };
708
+
709
+ var BankersBoxKeyException = function(msg) {
710
+ BankersBoxException.call(this, msg);
711
+ this.type = "BankersBoxKeyException";
712
+ };
713
+
714
+ var BankersBoxLocalStorageAdapter = function() {
715
+
716
+ if (typeof(window) === 'undefined' || typeof(window.localStorage) === 'undefined') {
717
+ throw("window.localStorage is undefined, consider a different storage adapter");
718
+ }
719
+
720
+ this.getItem = function(k) {
721
+ return window.localStorage.getItem(k);
722
+ };
723
+
724
+ this.storeItem = function(k, v) {
725
+ try {
726
+ window.localStorage.setItem(k, v);
727
+ } catch (e) {
728
+ if (e == QUOTA_EXCEEDED_ERR) {
729
+ // TODO: properly handle quota exceeded behavior
730
+ }
731
+ throw(e);
732
+ }
733
+ };
734
+
735
+ this.removeItem = function(k) {
736
+ window.localStorage.removeItem(k);
737
+ };
738
+
739
+ this.clear = function() {
740
+ window.localStorage.clear();
741
+ };
742
+ };
743
+
744
+ var BankersBoxNullAdapter = function() {
745
+
746
+ this.getItem = function(k) {
747
+ };
748
+
749
+ this.storeItem = function(k, v) {
750
+ };
751
+
752
+ this.removeItem = function(k) {
753
+ };
754
+
755
+ this.clear = function() {
756
+ };
757
+ };
758
+
759
+ ctx.BankersBox = BB;
760
+ ctx.BankersBoxException = BankersBoxException;
761
+ ctx.BankersBoxKeyException = BankersBoxKeyException;
762
+ ctx.BankersBoxLocalStorageAdapter = BankersBoxLocalStorageAdapter;
763
+ ctx.BankersBoxNullAdapter = BankersBoxNullAdapter;
764
+ if (ctx !== window) {
765
+ ctx.mock_window = window;
766
+ }
767
+
768
+ })(typeof(module) !== 'undefined' && module && module.exports ? module.exports : window);