rack-oauth2-server 1.2.2 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. data/CHANGELOG +14 -0
  2. data/Gemfile +3 -0
  3. data/README.rdoc +26 -7
  4. data/Rakefile +1 -1
  5. data/VERSION +1 -0
  6. data/lib/rack/oauth2/admin/css/screen.css +233 -0
  7. data/lib/rack/oauth2/admin/images/loading.gif +0 -0
  8. data/lib/rack/oauth2/admin/js/application.js +154 -0
  9. data/lib/rack/oauth2/admin/js/jquery.js +166 -0
  10. data/lib/rack/oauth2/admin/js/jquery.tmpl.js +414 -0
  11. data/lib/rack/oauth2/admin/js/sammy.js +5 -0
  12. data/lib/rack/oauth2/admin/js/sammy.json.js +5 -0
  13. data/lib/rack/oauth2/admin/js/sammy.storage.js +5 -0
  14. data/lib/rack/oauth2/admin/js/sammy.title.js +5 -0
  15. data/lib/rack/oauth2/admin/js/sammy.tmpl.js +5 -0
  16. data/lib/rack/oauth2/admin/js/underscore.js +722 -0
  17. data/lib/rack/oauth2/admin/views/client.tmpl +48 -0
  18. data/lib/rack/oauth2/admin/views/clients.tmpl +36 -0
  19. data/lib/rack/oauth2/admin/views/edit.tmpl +57 -0
  20. data/lib/rack/oauth2/admin/views/index.html +26 -0
  21. data/lib/rack/oauth2/models/access_grant.rb +6 -4
  22. data/lib/rack/oauth2/models/access_token.rb +36 -4
  23. data/lib/rack/oauth2/models/auth_request.rb +4 -3
  24. data/lib/rack/oauth2/models/client.rb +15 -2
  25. data/lib/rack/oauth2/server.rb +71 -58
  26. data/lib/rack/oauth2/server/admin.rb +216 -0
  27. data/lib/rack/oauth2/server/helper.rb +4 -4
  28. data/lib/rack/oauth2/sinatra.rb +2 -2
  29. data/rack-oauth2-server.gemspec +2 -3
  30. data/test/admin/api_test.rb +196 -0
  31. data/test/admin_test_.rb +49 -0
  32. data/test/{access_grant_test.rb → oauth/access_grant_test.rb} +1 -1
  33. data/test/{access_token_test.rb → oauth/access_token_test.rb} +83 -12
  34. data/test/{authorization_test.rb → oauth/authorization_test.rb} +1 -1
  35. data/test/rails/config/environment.rb +2 -0
  36. data/test/rails/log/test.log +72938 -0
  37. data/test/setup.rb +17 -1
  38. data/test/sinatra/my_app.rb +1 -1
  39. metadata +27 -9
  40. data/lib/rack/oauth2/server/version.rb +0 -9
@@ -0,0 +1,5 @@
1
+ // -- Sammy -- /sammy.js
2
+ // http://code.quirkey.com/sammy
3
+ // Version: 0.6.2
4
+ // Built: Mon Oct 11 12:41:51 -0700 2010
5
+ (function(g,i){var n,f="([^/]+)",j=/:([\w\d]+)/g,k=/\?([^#]*)$/,b=function(o){return Array.prototype.slice.call(o)},c=function(o){return Object.prototype.toString.call(o)==="[object Function]"},l=function(o){return Object.prototype.toString.call(o)==="[object Array]"},h=decodeURIComponent,e=function(o){return o.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;")},m=function(o){return function(p,q){return this.route.apply(this,[o,p,q])}},a={},d=[];n=function(){var p=b(arguments),q,o;n.apps=n.apps||{};if(p.length===0||p[0]&&c(p[0])){return n.apply(n,["body"].concat(p))}else{if(typeof(o=p.shift())=="string"){q=n.apps[o]||new n.Application();q.element_selector=o;if(p.length>0){g.each(p,function(r,s){q.use(s)})}if(q.element_selector!=o){delete n.apps[o]}n.apps[q.element_selector]=q;return q}}};n.VERSION="0.6.2";n.addLogger=function(o){d.push(o)};n.log=function(){var o=b(arguments);o.unshift("["+Date()+"]");g.each(d,function(q,p){p.apply(n,o)})};if(typeof i.console!="undefined"){if(c(console.log.apply)){n.addLogger(function(){i.console.log.apply(console,arguments)})}else{n.addLogger(function(){i.console.log(arguments)})}}else{if(typeof console!="undefined"){n.addLogger(function(){console.log.apply(console,arguments)})}}g.extend(n,{makeArray:b,isFunction:c,isArray:l});n.Object=function(o){return g.extend(this,o||{})};g.extend(n.Object.prototype,{escapeHTML:e,h:e,toHash:function(){var o={};g.each(this,function(q,p){if(!c(p)){o[q]=p}});return o},toHTML:function(){var o="";g.each(this,function(q,p){if(!c(p)){o+="<strong>"+q+"</strong> "+p+"<br />"}});return o},keys:function(o){var p=[];for(var q in this){if(!c(this[q])||!o){p.push(q)}}return p},has:function(o){return this[o]&&g.trim(this[o].toString())!=""},join:function(){var p=b(arguments);var o=p.shift();return p.join(o)},log:function(){n.log.apply(n,arguments)},toString:function(o){var p=[];g.each(this,function(r,q){if(!c(q)||o){p.push('"'+r+'": '+q.toString())}});return"Sammy.Object: {"+p.join(",")+"}"}});n.HashLocationProxy=function(p,o){this.app=p;this.is_native=false;this._startPolling(o)};n.HashLocationProxy.prototype={bind:function(){var o=this,p=this.app;g(i).bind("hashchange."+this.app.eventNamespace(),function(r,q){if(o.is_native===false&&!q){n.log("native hash change exists, using");o.is_native=true;i.clearInterval(n.HashLocationProxy._interval)}p.trigger("location-changed")});if(!n.HashLocationProxy._bindings){n.HashLocationProxy._bindings=0}n.HashLocationProxy._bindings++},unbind:function(){g(i).unbind("hashchange."+this.app.eventNamespace());n.HashLocationProxy._bindings--;if(n.HashLocationProxy._bindings<=0){i.clearInterval(n.HashLocationProxy._interval)}},getLocation:function(){var o=i.location.toString().match(/^[^#]*(#.+)$/);return o?o[1]:""},setLocation:function(o){return(i.location=o)},_startPolling:function(q){var p=this;if(!n.HashLocationProxy._interval){if(!q){q=10}var o=function(){var r=p.getLocation();if(!n.HashLocationProxy._last_location||r!=n.HashLocationProxy._last_location){i.setTimeout(function(){g(i).trigger("hashchange",[true])},13)}n.HashLocationProxy._last_location=r};o();n.HashLocationProxy._interval=i.setInterval(o,q)}}};n.Application=function(o){var p=this;this.routes={};this.listeners=new n.Object({});this.arounds=[];this.befores=[];this.namespace=(new Date()).getTime()+"-"+parseInt(Math.random()*1000,10);this.context_prototype=function(){n.EventContext.apply(this,arguments)};this.context_prototype.prototype=new n.EventContext();if(c(o)){o.apply(this,[this])}if(!this._location_proxy){this.setLocationProxy(new n.HashLocationProxy(this,this.run_interval_every))}if(this.debug){this.bindToAllEvents(function(r,q){p.log(p.toString(),r.cleaned_type,q||{})})}};n.Application.prototype=g.extend({},n.Object.prototype,{ROUTE_VERBS:["get","post","put","delete"],APP_EVENTS:["run","unload","lookup-route","run-route","route-found","event-context-before","event-context-after","changed","error","check-form-submission","redirect","location-changed"],_last_route:null,_location_proxy:null,_running:false,element_selector:"body",debug:false,raise_errors:false,run_interval_every:50,template_engine:null,toString:function(){return"Sammy.Application:"+this.element_selector},$element:function(){return g(this.element_selector)},use:function(){var o=b(arguments),q=o.shift(),p=q||"";try{o.unshift(this);if(typeof q=="string"){p="Sammy."+q;q=n[q]}q.apply(this,o)}catch(r){if(typeof q==="undefined"){this.error("Plugin Error: called use() but plugin ("+p.toString()+") is not defined",r)}else{if(!c(q)){this.error("Plugin Error: called use() but '"+p.toString()+"' is not a function",r)}else{this.error("Plugin Error",r)}}}return this},setLocationProxy:function(o){var p=this._location_proxy;this._location_proxy=o;if(this.isRunning()){if(p){p.unbind()}this._location_proxy.bind()}},route:function(s,p,u){var r=this,t=[],o,q;if(!u&&c(p)){p=s;u=p;s="any"}s=s.toLowerCase();if(p.constructor==String){j.lastIndex=0;while((q=j.exec(p))!==null){t.push(q[1])}p=new RegExp("^"+p.replace(j,f)+"$")}if(typeof u=="string"){u=r[u]}o=function(v){var w={verb:v,path:p,callback:u,param_names:t};r.routes[v]=r.routes[v]||[];r.routes[v].push(w)};if(s==="any"){g.each(this.ROUTE_VERBS,function(x,w){o(w)})}else{o(s)}return this},get:m("get"),post:m("post"),put:m("put"),del:m("delete"),any:m("any"),mapRoutes:function(p){var o=this;g.each(p,function(q,r){o.route.apply(o,r)});return this},eventNamespace:function(){return["sammy-app",this.namespace].join("-")},bind:function(o,q,s){var r=this;if(typeof s=="undefined"){s=q}var p=function(){var v,t,u;v=arguments[0];u=arguments[1];if(u&&u.context){t=u.context;delete u.context}else{t=new r.context_prototype(r,"bind",v.type,u,v.target)}v.cleaned_type=v.type.replace(r.eventNamespace(),"");s.apply(t,[v,u])};if(!this.listeners[o]){this.listeners[o]=[]}this.listeners[o].push(p);if(this.isRunning()){this._listen(o,p)}return this},trigger:function(o,p){this.$element().trigger([o,this.eventNamespace()].join("."),[p]);return this},refresh:function(){this.last_location=null;this.trigger("location-changed");return this},before:function(o,p){if(c(o)){p=o;o={}}this.befores.push([o,p]);return this},after:function(o){return this.bind("event-context-after",o)},around:function(o){this.arounds.push(o);return this},isRunning:function(){return this._running},helpers:function(o){g.extend(this.context_prototype.prototype,o);return this},helper:function(o,p){this.context_prototype.prototype[o]=p;return this},run:function(o){if(this.isRunning()){return false}var p=this;g.each(this.listeners.toHash(),function(q,r){g.each(r,function(t,s){p._listen(q,s)})});this.trigger("run",{start_url:o});this._running=true;this.last_location=null;if(this.getLocation()==""&&typeof o!="undefined"){this.setLocation(o)}this._checkLocation();this._location_proxy.bind();this.bind("location-changed",function(){p._checkLocation()});this.bind("submit",function(r){var q=p._checkFormSubmission(g(r.target).closest("form"));return(q===false)?r.preventDefault():false});g(i).bind("beforeunload",function(){p.unload()});return this.trigger("changed")},unload:function(){if(!this.isRunning()){return false}var o=this;this.trigger("unload");this._location_proxy.unbind();this.$element().unbind("submit").removeClass(o.eventNamespace());g.each(this.listeners.toHash(),function(p,q){g.each(q,function(s,r){o._unlisten(p,r)})});this._running=false;return this},bindToAllEvents:function(p){var o=this;g.each(this.APP_EVENTS,function(q,r){o.bind(r,p)});g.each(this.listeners.keys(true),function(r,q){if(o.APP_EVENTS.indexOf(q)==-1){o.bind(q,p)}});return this},routablePath:function(o){return o.replace(k,"")},lookupRoute:function(r,p){var q=this,o=false;this.trigger("lookup-route",{verb:r,path:p});if(typeof this.routes[r]!="undefined"){g.each(this.routes[r],function(t,s){if(q.routablePath(p).match(s.path)){o=s;return false}})}return o},runRoute:function(q,D,s,v){var r=this,B=this.lookupRoute(q,D),p,y,t,x,C,z,w,A,o;this.log("runRoute",[q,D].join(" "));this.trigger("run-route",{verb:q,path:D,params:s});if(typeof s=="undefined"){s={}}g.extend(s,this._parseQueryString(D));if(B){this.trigger("route-found",{route:B});if((A=B.path.exec(this.routablePath(D)))!==null){A.shift();g.each(A,function(E,F){if(B.param_names[E]){s[B.param_names[E]]=h(F)}else{if(!s.splat){s.splat=[]}s.splat.push(h(F))}})}p=new this.context_prototype(this,q,D,s,v);t=this.arounds.slice(0);C=this.befores.slice(0);w=[p].concat(s.splat);y=function(){var E;while(C.length>0){z=C.shift();if(r.contextMatchesOptions(p,z[0])){E=z[1].apply(p,[p]);if(E===false){return false}}}r.last_route=B;p.trigger("event-context-before",{context:p});E=B.callback.apply(p,w);p.trigger("event-context-after",{context:p});return E};g.each(t.reverse(),function(E,F){var G=y;y=function(){return F.apply(p,[G])}});try{o=y()}catch(u){this.error(["500 Error",q,D].join(" "),u)}return o}else{return this.notFound(q,D)}},contextMatchesOptions:function(r,t,p){var q=t;if(typeof q==="undefined"||q=={}){return true}if(typeof p==="undefined"){p=true}if(typeof q==="string"||c(q.test)){q={path:q}}if(q.only){return this.contextMatchesOptions(r,q.only,true)}else{if(q.except){return this.contextMatchesOptions(r,q.except,false)}}var o=true,s=true;if(q.path){if(c(q.path.test)){o=q.path.test(r.path)}else{o=(q.path.toString()===r.path)}}if(q.verb){s=q.verb===r.verb}return p?(s&&o):!(s&&o)},getLocation:function(){return this._location_proxy.getLocation()},setLocation:function(o){return this._location_proxy.setLocation(o)},swap:function(o){return this.$element().html(o)},templateCache:function(o,p){if(typeof p!="undefined"){return a[o]=p}else{return a[o]}},clearTemplateCache:function(){return a={}},notFound:function(q,p){var o=this.error(["404 Not Found",q,p].join(" "));return(q==="get")?o:true},error:function(p,o){if(!o){o=new Error()}o.message=[p,o.message].join(" ");this.trigger("error",{message:o.message,error:o});if(this.raise_errors){throw (o)}else{this.log(o.message,o)}},_checkLocation:function(){var o,p;o=this.getLocation();if(!this.last_location||this.last_location[0]!="get"||this.last_location[1]!=o){this.last_location=["get",o];p=this.runRoute("get",o)}return p},_getFormVerb:function(q){var p=g(q),r,o;o=p.find('input[name="_method"]');if(o.length>0){r=o.val()}if(!r){r=p[0].getAttribute("method")}return g.trim(r.toString().toLowerCase())},_checkFormSubmission:function(q){var o,r,t,s,p;this.trigger("check-form-submission",{form:q});o=g(q);r=o.attr("action");t=this._getFormVerb(o);if(!t||t==""){t="get"}this.log("_checkFormSubmission",o,r,t);if(t==="get"){this.setLocation(r+"?"+o.serialize());p=false}else{s=g.extend({},this._parseFormParams(o));p=this.runRoute(t,r,s,q.get(0))}return(typeof p=="undefined")?false:p},_parseFormParams:function(o){var r={},q=o.serializeArray(),p;for(p=0;p<q.length;p++){r=this._parseParamPair(r,q[p].name,q[p].value)}return r},_parseQueryString:function(r){var t={},q,p,s,o;q=r.match(k);if(q){p=q[1].split("&");for(o=0;o<p.length;o++){s=p[o].split("=");t=this._parseParamPair(t,h(s[0]),h(s[1]))}}return t},_parseParamPair:function(q,o,p){if(q[o]){if(l(q[o])){q[o].push(p)}else{q[o]=[q[o],p]}}else{q[o]=p}return q},_listen:function(o,p){return this.$element().bind([o,this.eventNamespace()].join("."),p)},_unlisten:function(o,p){return this.$element().unbind([o,this.eventNamespace()].join("."),p)}});n.RenderContext=function(o){this.event_context=o;this.callbacks=[];this.previous_content=null;this.content=null;this.next_engine=false;this.waiting=false};g.extend(n.RenderContext.prototype,{then:function(q){if(!c(q)){if(typeof q==="string"&&q in this.event_context){var p=this.event_context[q];q=function(r){return p.apply(this.event_context,[r])}}else{return this}}var o=this;if(this.waiting){this.callbacks.push(q)}else{this.wait();i.setTimeout(function(){var r=q.apply(o,[o.content,o.previous_content]);if(r!==false){o.next(r)}},13)}return this},wait:function(){this.waiting=true},next:function(o){this.waiting=false;if(typeof o!=="undefined"){this.previous_content=this.content;this.content=o}if(this.callbacks.length>0){this.then(this.callbacks.shift())}},load:function(o,p,r){var q=this;return this.then(function(){var s,t,v,u;if(c(p)){r=p;p={}}else{p=g.extend({},p)}if(r){this.then(r)}if(typeof o==="string"){v=(o.match(/\.json$/)||p.json);s=((v&&p.cache===true)||p.cache!==false);q.next_engine=q.event_context.engineFor(o);delete p.cache;delete p.json;if(p.engine){q.next_engine=p.engine;delete p.engine}if(s&&(t=this.event_context.app.templateCache(o))){return t}this.wait();g.ajax(g.extend({url:o,data:{},dataType:v?"json":null,type:"get",success:function(w){if(s){q.event_context.app.templateCache(o,w)}q.next(w)}},p));return false}else{if(o.nodeType){return o.innerHTML}if(o.selector){q.next_engine=o.attr("data-engine");if(p.clone===false){return o.remove()[0].innerHTML.toString()}else{return o[0].innerHTML.toString()}}}})},render:function(o,p,q){if(c(o)&&!p){return this.then(o)}else{if(!p&&this.content){p=this.content}return this.load(o).interpolate(p,o).then(q)}},partial:function(o,p){return this.render(o,p).swap()},send:function(){var q=this,p=b(arguments),o=p.shift();if(l(p[0])){p=p[0]}return this.then(function(r){p.push(function(s){q.next(s)});q.wait();o.apply(o,p);return false})},collect:function(s,r,o){var q=this;var p=function(){if(c(s)){r=s;s=this.content}var t=[],u=false;g.each(s,function(v,x){var w=r.apply(q,[v,x]);if(w.jquery&&w.length==1){w=w[0];u=true}t.push(w);return w});return u?t:t.join("")};return o?p():this.then(p)},renderEach:function(o,p,q,r){if(l(p)){r=q;q=p;p=null}return this.load(o).then(function(t){var s=this;if(!q){q=l(this.previous_content)?this.previous_content:[]}if(r){g.each(q,function(u,w){var x={},v=this.next_engine||o;p?(x[p]=w):(x=w);r(w,s.event_context.interpolate(t,x,v))})}else{return this.collect(q,function(u,w){var x={},v=this.next_engine||o;p?(x[p]=w):(x=w);return this.event_context.interpolate(t,x,v)},true)}})},interpolate:function(r,q,o){var p=this;return this.then(function(t,s){if(!r&&s){r=s}if(this.next_engine){q=this.next_engine;this.next_engine=false}var u=p.event_context.interpolate(t,r,q);return o?s+u:u})},swap:function(){return this.then(function(o){this.event_context.swap(o)}).trigger("changed",{})},appendTo:function(o){return this.then(function(p){g(o).append(p)}).trigger("changed",{})},prependTo:function(o){return this.then(function(p){g(o).prepend(p)}).trigger("changed",{})},replace:function(o){return this.then(function(p){g(o).html(p)}).trigger("changed",{})},trigger:function(o,p){return this.then(function(q){if(typeof p=="undefined"){p={content:q}}this.event_context.trigger(o,p)})}});n.EventContext=function(s,r,p,q,o){this.app=s;this.verb=r;this.path=p;this.params=new n.Object(q);this.target=o};n.EventContext.prototype=g.extend({},n.Object.prototype,{$element:function(){return this.app.$element()},engineFor:function(q){var p=this,o;if(c(q)){return q}q=q.toString();if((o=q.match(/\.([^\.]+)$/))){q=o[1]}if(q&&c(p[q])){return p[q]}if(p.app.template_engine){return this.engineFor(p.app.template_engine)}return function(r,s){return r}},interpolate:function(p,q,o){return this.engineFor(o).apply(this,[p,q])},render:function(o,p,q){return new n.RenderContext(this).render(o,p,q)},renderEach:function(o,p,q,r){return new n.RenderContext(this).renderEach(o,p,q,r)},load:function(o,p,q){return new n.RenderContext(this).load(o,p,q)},partial:function(o,p){return new n.RenderContext(this).partial(o,p)},send:function(){var o=new n.RenderContext(this);return o.send.apply(o,arguments)},redirect:function(){var q,p=b(arguments),o=this.app.getLocation();if(p.length>1){p.unshift("/");q=this.join.apply(this,p)}else{q=p[0]}this.trigger("redirect",{to:q});this.app.last_location=[this.verb,this.path];this.app.setLocation(q);if(o==q){this.app.trigger("location-changed")}},trigger:function(o,p){if(typeof p=="undefined"){p={}}if(!p.context){p.context=this}return this.app.trigger(o,p)},eventNamespace:function(){return this.app.eventNamespace()},swap:function(o){return this.app.swap(o)},notFound:function(){return this.app.notFound(this.verb,this.path)},json:function(o){return g.parseJSON(o)},toString:function(){return"Sammy.EventContext: "+[this.verb,this.path,this.params].join(" ")}});g.sammy=i.Sammy=n})(jQuery,window);
@@ -0,0 +1,5 @@
1
+ // -- Sammy -- /plugins/sammy.json.js
2
+ // http://code.quirkey.com/sammy
3
+ // Version: 0.6.2
4
+ // Built: Mon Oct 11 12:41:43 -0700 2010
5
+ (function($){if(!window.JSON){window.JSON={}}(function(){function f(n){return n<10?"0"+n:n}if(typeof Date.prototype.toJSON!=="function"){Date.prototype.toJSON=function(key){return this.getUTCFullYear()+"-"+f(this.getUTCMonth()+1)+"-"+f(this.getUTCDate())+"T"+f(this.getUTCHours())+":"+f(this.getUTCMinutes())+":"+f(this.getUTCSeconds())+"Z"};String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function(key){return this.valueOf()}}var cx=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,escapable=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,gap,indent,meta={"\b":"\\b","\t":"\\t","\n":"\\n","\f":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},rep;function quote(string){escapable.lastIndex=0;return escapable.test(string)?'"'+string.replace(escapable,function(a){var c=meta[a];return typeof c==="string"?c:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+string+'"'}function str(key,holder){var i,k,v,length,mind=gap,partial,value=holder[key];if(value&&typeof value==="object"&&typeof value.toJSON==="function"){value=value.toJSON(key)}if(typeof rep==="function"){value=rep.call(holder,key,value)}switch(typeof value){case"string":return quote(value);case"number":return isFinite(value)?String(value):"null";case"boolean":case"null":return String(value);case"object":if(!value){return"null"}gap+=indent;partial=[];if(Object.prototype.toString.apply(value)==="[object Array]"){length=value.length;for(i=0;i<length;i+=1){partial[i]=str(i,value)||"null"}v=partial.length===0?"[]":gap?"[\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"]":"["+partial.join(",")+"]";gap=mind;return v}if(rep&&typeof rep==="object"){length=rep.length;for(i=0;i<length;i+=1){k=rep[i];if(typeof k==="string"){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}else{for(k in value){if(Object.hasOwnProperty.call(value,k)){v=str(k,value);if(v){partial.push(quote(k)+(gap?": ":":")+v)}}}}v=partial.length===0?"{}":gap?"{\n"+gap+partial.join(",\n"+gap)+"\n"+mind+"}":"{"+partial.join(",")+"}";gap=mind;return v}}if(typeof JSON.stringify!=="function"){JSON.stringify=function(value,replacer,space){var i;gap="";indent="";if(typeof space==="number"){for(i=0;i<space;i+=1){indent+=" "}}else{if(typeof space==="string"){indent=space}}rep=replacer;if(replacer&&typeof replacer!=="function"&&(typeof replacer!=="object"||typeof replacer.length!=="number")){throw new Error("JSON.stringify")}return str("",{"":value})}}if(typeof JSON.parse!=="function"){JSON.parse=function(text,reviver){var j;function walk(holder,key){var k,v,value=holder[key];if(value&&typeof value==="object"){for(k in value){if(Object.hasOwnProperty.call(value,k)){v=walk(value,k);if(v!==undefined){value[k]=v}else{delete value[k]}}}}return reviver.call(holder,key,value)}cx.lastIndex=0;if(cx.test(text)){text=text.replace(cx,function(a){return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})}if(/^[\],:{}\s]*$/.test(text.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))){j=eval("("+text+")");return typeof reviver==="function"?walk({"":j},""):j}throw new SyntaxError("JSON.parse")}}}());Sammy=Sammy||{};Sammy.JSON=function(app){app.helpers({json:function(object){if(typeof object=="string"){return JSON.parse(object)}else{return JSON.stringify(object)}}})}})(jQuery);
@@ -0,0 +1,5 @@
1
+ // -- Sammy -- /plugins/sammy.storage.js
2
+ // http://code.quirkey.com/sammy
3
+ // Version: 0.6.2
4
+ // Built: Mon Oct 11 12:41:48 -0700 2010
5
+ (function(a){Sammy=Sammy||{};Sammy.Store=function(c){var b=this;this.options=c||{};this.name=this.options.name||"store";this.element=this.options.element||"body";this.$element=a(this.element);if(a.isArray(this.options.type)){a.each(this.options.type,function(d,e){if(Sammy.Store.isAvailable(e)){b.type=e;return false}})}else{this.type=this.options.type||"memory"}this.meta_key=this.options.meta_key||"__keys__";this.storage=new Sammy.Store[Sammy.Store.stores[this.type]](this.name,this.element,this.options)};Sammy.Store.stores={memory:"Memory",data:"Data",local:"LocalStorage",session:"SessionStorage",cookie:"Cookie"};a.extend(Sammy.Store.prototype,{isAvailable:function(){if(a.isFunction(this.storage.isAvailable)){return this.storage.isAvailable()}else{true}},exists:function(b){return this.storage.exists(b)},set:function(c,d){var b=(typeof d=="string")?d:JSON.stringify(d);c=c.toString();this.storage.set(c,b);if(c!=this.meta_key){this._addKey(c);this.$element.trigger("set-"+this.name,{key:c,value:d});this.$element.trigger("set-"+this.name+"-"+c,{key:c,value:d})}return d},get:function(b){var c=this.storage.get(b);if(typeof c=="undefined"||c==null||c==""){return c}try{return JSON.parse(c)}catch(d){return c}},clear:function(b){this._removeKey(b);return this.storage.clear(b)},clearAll:function(){var b=this;this.each(function(c,d){b.clear(c)})},keys:function(){return this.get(this.meta_key)||[]},each:function(e){var b=0,d=this.keys(),c;for(b;b<d.length;b++){c=e(d[b],this.get(d[b]));if(c===false){return false}}},filter:function(c){var b=[];this.each(function(d,e){if(c(d,e)){b.push([d,e])}return true});return b},first:function(c){var b=false;this.each(function(d,e){if(c(d,e)){b=[d,e];return false}});return b},fetch:function(b,c){if(!this.exists(b)){return this.set(b,c.apply(this))}else{return this.get(b)}},load:function(b,d,e){var c=this;a.get(d,function(f){c.set(b,f);if(e){e.apply(this,[f])}})},_addKey:function(b){var c=this.keys();if(a.inArray(b,c)==-1){c.push(b)}this.set(this.meta_key,c)},_removeKey:function(c){var d=this.keys();var b=a.inArray(c,d);if(b!=-1){d.splice(b,1)}this.set(this.meta_key,d)}});Sammy.Store.isAvailable=function(b){try{return Sammy.Store[Sammy.Store.stores[b]].prototype.isAvailable()}catch(c){return false}};Sammy.Store.Memory=function(b,c){this.name=b;this.element=c;this.namespace=[this.element,this.name].join(".");Sammy.Store.Memory.store=Sammy.Store.Memory.store||{};Sammy.Store.Memory.store[this.namespace]=Sammy.Store.Memory.store[this.namespace]||{};this.store=Sammy.Store.Memory.store[this.namespace]};a.extend(Sammy.Store.Memory.prototype,{isAvailable:function(){return true},exists:function(b){return(typeof this.store[b]!="undefined")},set:function(b,c){return this.store[b]=c},get:function(b){return this.store[b]},clear:function(b){delete this.store[b]}});Sammy.Store.Data=function(b,c){this.name=b;this.element=c;this.$element=a(c)};a.extend(Sammy.Store.Data.prototype,{isAvailable:function(){return true},exists:function(b){return !!this.$element.data(this._key(b))},set:function(b,c){return this.$element.data(this._key(b),c)},get:function(b){return this.$element.data(this._key(b))},clear:function(b){this.$element.removeData(this._key(b))},_key:function(b){return["store",this.name,b].join(".")}});Sammy.Store.LocalStorage=function(b,c){this.name=b;this.element=c};a.extend(Sammy.Store.LocalStorage.prototype,{isAvailable:function(){return("localStorage" in window)&&(window.location.protocol!="file:")},exists:function(b){return(this.get(b)!=null)},set:function(b,c){return window.localStorage.setItem(this._key(b),c)},get:function(b){return window.localStorage.getItem(this._key(b))},clear:function(b){window.localStorage.removeItem(this._key(b))},_key:function(b){return["store",this.element,this.name,b].join(".")}});Sammy.Store.SessionStorage=function(b,c){this.name=b;this.element=c};a.extend(Sammy.Store.SessionStorage.prototype,{isAvailable:function(){return("sessionStorage" in window)&&(window.location.protocol!="file:")&&(a.isFunction(window.sessionStorage.setItem))},exists:function(b){return(this.get(b)!=null)},set:function(b,c){return window.sessionStorage.setItem(this._key(b),c)},get:function(b){var c=window.sessionStorage.getItem(this._key(b));if(c&&typeof c.value!="undefined"){c=c.value}return c},clear:function(b){window.sessionStorage.removeItem(this._key(b))},_key:function(b){return["store",this.element,this.name,b].join(".")}});Sammy.Store.Cookie=function(c,d,b){this.name=c;this.element=d;this.options=b||{};this.path=this.options.path||"/";this.expires_in=this.options.expires_in||(14*24*60*60)};a.extend(Sammy.Store.Cookie.prototype,{isAvailable:function(){return("cookie" in document)&&(window.location.protocol!="file:")},exists:function(b){return(this.get(b)!=null)},set:function(b,c){return this._setCookie(b,c)},get:function(b){return this._getCookie(b)},clear:function(b){this._setCookie(b,"",-1)},_key:function(b){return["store",this.element,this.name,b].join(".")},_getCookie:function(c){var d=this._key(c).replace(/(\.|\*|\(|\)|\[|\])/g,"\\$1");var b=document.cookie.match("(^|;\\s)"+d+"=([^;]*)(;|$)");return(b?b[2]:null)},_setCookie:function(e,f,c){if(!c){c=(this.expires_in*1000)}var d=new Date();d.setTime(d.getTime()+c);var b=[this._key(e),"=",f,"; expires=",d.toGMTString(),"; path=",this.path].join("");document.cookie=b}});Sammy.Storage=function(b){this.use(Sammy.JSON);this.stores=this.stores||{};this.store=function(d,c){if(typeof this.stores[d]=="undefined"){var e="clear"+d.substr(0,1).toUpperCase()+d.substr(1);this.stores[d]=new Sammy.Store(a.extend({name:d,element:this.element_selector},c||{}));this[d]=function(f,g){if(typeof g=="undefined"){return this.stores[d].get(f)}else{if(a.isFunction(g)){return this.stores[d].fetch(f,g)}else{return this.stores[d].set(f,g)}}};this[e]=function(){return this.stores[d].clearAll()};this.helper(d,function(){return this.app[d].apply(this.app,arguments)});this.helper(e,function(){return this.app[e]()})}return this.stores[d]};this.helpers({store:function(){return this.app.store.apply(this.app,arguments)}})};Sammy.Session=function(c,b){this.use(Sammy.Storage);this.store("session",a.extend({type:["local","cookie","memory"]},b))};Sammy.Cache=function(c,b){this.use(Sammy.Storage);this.cache_partials=true;this.store("cache",a.extend({type:["local","session","memory"]},b))}})(jQuery);
@@ -0,0 +1,5 @@
1
+ // -- Sammy -- /plugins/sammy.title.js
2
+ // http://code.quirkey.com/sammy
3
+ // Version: 0.6.2
4
+ // Built: Mon Oct 11 12:41:49 -0700 2010
5
+ (function(a){Sammy=Sammy||{};Sammy.Title=function(){this.setTitle=function(b){if(!a.isFunction(b)){this.title_function=function(c){return[b,c].join(" ")}}else{this.title_function=b}};this.helper("title",function(){var b=a.makeArray(arguments).join(" ");if(this.app.title_function){b=this.app.title_function(b)}document.title=b})}})(jQuery);
@@ -0,0 +1,5 @@
1
+ // -- Sammy -- /plugins/sammy.tmpl.js
2
+ // http://code.quirkey.com/sammy
3
+ // Version: 0.6.2
4
+ // Built: Mon Oct 11 12:41:50 -0700 2010
5
+ (function(i,f){var t=i.fn.domManip,h="_tmplitem",u=/^[^<]*(<[\w\W]+>)[^>]*$|\{\{\! /,p={},e={},y,x={key:0,data:{}},w=0,q=0,g=[];function k(B,A,D,E){var C={data:E||(A?A.data:{}),_wrap:A?A._wrap:null,tmpl:null,parent:A||null,nodes:[],calls:c,nest:b,wrap:n,html:r,update:z};if(B){i.extend(C,B,{nodes:[],parent:A})}if(D){C.tmpl=D;C._ctnt=C._ctnt||C.tmpl(i,C);C.key=++w;(g.length?e:p)[w]=C}return C}i.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(A,B){i.fn[A]=function(C){var F=[],I=i(C),E,G,D,J,H=this.length===1&&this[0].parentNode;y=p||{};if(H&&H.nodeType===11&&H.childNodes.length===1&&I.length===1){I[B](this[0]);F=this}else{for(G=0,D=I.length;G<D;G++){q=G;E=(G>0?this.clone(true):this).get();i.fn[B].apply(i(I[G]),E);F=F.concat(E)}q=0;F=this.pushStack(F,A,I.selector)}J=y;y=null;i.tmpl.complete(J);return F}});i.fn.extend({tmpl:function(C,B,A){return i.tmpl(this[0],C,B,A)},tmplItem:function(){return i.tmplItem(this[0])},template:function(A){return i.template(A,this[0])},domManip:function(C,G,H,B){if(C[0]&&C[0].nodeType){var F=i.makeArray(arguments),E=C.length,D=0,A;while(D<E&&!(A=i.data(C[D++],"tmplItem"))){}if(E>1){F[0]=[i.makeArray(C)]}if(A&&q){F[2]=function(I){i.tmpl.afterManip(this,I,H)}}t.apply(this,F)}else{t.apply(this,arguments)}q=0;if(!y){i.tmpl.complete(p)}return this}});i.extend({tmpl:function(C,F,E,B){var D,A=!B;if(A){B=x;C=i.template[C]||i.template(null,C);e={}}else{if(!C){C=B.tmpl;p[B.key]=B;B.nodes=[];if(B.wrapped){s(B,B.wrapped)}return i(m(B,null,B.tmpl(i,B)))}}if(!C){return[]}if(typeof F==="function"){F=F.call(B||{})}if(E&&E.wrapped){s(E,E.wrapped)}D=i.isArray(F)?i.map(F,function(G){return G?k(E,B,C,G):null}):[k(E,B,C,F)];return A?i(m(B,null,D)):D},tmplItem:function(B){var A;if(B instanceof i){B=B[0]}while(B&&B.nodeType===1&&!(A=i.data(B,"tmplItem"))&&(B=B.parentNode)){}return A||x},template:function(B,A){if(A){if(typeof A==="string"){A=l(A)}else{if(A instanceof i){A=A[0]||{}}}if(A.nodeType){A=i.data(A,"tmpl")||i.data(A,"tmpl",l(A.innerHTML))}return typeof B==="string"?(i.template[B]=A):A}return B?(typeof B!=="string"?i.template(null,B):(i.template[B]||i.template(null,u.test(B)?B:i(B)))):null},encode:function(A){return(""+A).split("<").join("&lt;").split(">").join("&gt;").split('"').join("&#34;").split("'").join("&#39;")}});i.extend(i.tmpl,{tag:{tmpl:{_default:{$2:"null"},open:"if($notnull_1){_=_.concat($item.nest($1,$2));}"},wrap:{_default:{$2:"null"},open:"$item.calls(_,$1,$2);_=[];",close:"call=$item.calls();_=call._.concat($item.wrap(call,_));"},each:{_default:{$2:"$index, $value"},open:"if($notnull_1){$.each($1a,function($2){with(this){",close:"}});}"},"if":{open:"if(($notnull_1) && $1a){",close:"}"},"else":{_default:{$1:"true"},open:"}else if(($notnull_1) && $1a){"},html:{open:"if($notnull_1){_.push($1a);}"},"=":{_default:{$1:"$data"},open:"if($notnull_1){_.push($.encode($1a));}"},"!":{open:""}},complete:function(A){p={}},afterManip:function v(C,A,D){var B=A.nodeType===11?i.makeArray(A.childNodes):A.nodeType===1?[A]:[];D.call(C,A);o(B);q++}});function m(A,E,C){var D,B=C?i.map(C,function(F){return(typeof F==="string")?(A.key?F.replace(/(<\w+)(?=[\s>])(?![^>]*_tmplitem)([^>]*)/g,"$1 "+h+'="'+A.key+'" $2'):F):m(F,A,F._ctnt)}):A;if(E){return B}B=B.join("");B.replace(/^\s*([^<\s][^<]*)?(<[\w\W]+>)([^>]*[^>\s])?\s*$/,function(G,H,F,I){D=i(F).get();o(D);if(H){D=a(H).concat(D)}if(I){D=D.concat(a(I))}});return D?D:a(B)}function a(B){var A=document.createElement("div");A.innerHTML=B;return i.makeArray(A.childNodes)}function l(A){return new Function("jQuery","$item","var $=jQuery,call,_=[],$data=$item.data;with($data){_.push('"+i.trim(A).replace(/([\\'])/g,"\\$1").replace(/[\r\t\n]/g," ").replace(/\$\{([^\}]*)\}/g,"{{= $1}}").replace(/\{\{(\/?)(\w+|.)(?:\(((?:[^\}]|\}(?!\}))*?)?\))?(?:\s+(.*?)?)?(\(((?:[^\}]|\}(?!\}))*?)\))?\s*\}\}/g,function(I,C,G,D,E,J,F){var L=i.tmpl.tag[G],B,H,K;if(!L){throw"Template command not found: "+G}B=L._default||[];if(J&&!/\w$/.test(E)){E+=J;J=""}if(E){E=j(E);F=F?(","+j(F)+")"):(J?")":"");H=J?(E.indexOf(".")>-1?E+J:("("+E+").call($item"+F)):E;K=J?H:"(typeof("+E+")==='function'?("+E+").call($item):("+E+"))"}else{K=H=B.$1||"null"}D=j(D);return"');"+L[C?"close":"open"].split("$notnull_1").join(E?"typeof("+E+")!=='undefined' && ("+E+")!=null":"true").split("$1a").join(K).split("$1").join(H).split("$2").join(D?D.replace(/\s*([^\(]+)\s*(\((.*?)\))?/g,function(N,M,O,P){P=P?(","+P+")"):(O?")":"");return P?("("+M+").call($item"+P):N}):(B.$2||""))+"_.push('"})+"');}return _;")}function s(B,A){B._wrap=m(B,true,i.isArray(A)?A:[u.test(A)?A:i(A).html()]).join("")}function j(A){return A?A.replace(/\\'/g,"'").replace(/\\\\/g,"\\"):null}function d(A){var B=document.createElement("div");B.appendChild(A.cloneNode(true));return B.innerHTML}function o(G){var I="_"+q,B,A,E={},F,D,C;for(F=0,D=G.length;F<D;F++){if((B=G[F]).nodeType!==1){continue}A=B.getElementsByTagName("*");for(C=A.length-1;C>=0;C--){H(A[C])}H(B)}function H(O){var L,N=O,M,J,K;if((K=O.getAttribute(h))){while(N.parentNode&&(N=N.parentNode).nodeType===1&&!(L=N.getAttribute(h))){}if(L!==K){N=N.parentNode?(N.nodeType===11?0:(N.getAttribute(h)||0)):0;if(!(J=p[K])){J=e[K];J=k(J,p[N]||e[N],null,true);J.key=++w;p[w]=J}if(q){P(K)}}O.removeAttribute(h)}else{if(q&&(J=i.data(O,"tmplItem"))){P(J.key);p[J.key]=J;N=i.data(O.parentNode,"tmplItem");N=N?N.key:0}}if(J){M=J;while(M&&M.key!=N){M.nodes.push(O);M=M.parent}delete J._ctnt;delete J._wrap;i.data(O,"tmplItem",J)}function P(Q){Q=Q+I;J=E[Q]=(E[Q]||k(J,p[J.parent.key+I]||J.parent,null,true))}}}function c(C,A,D,B){if(!C){return g.pop()}g.push({_:C,tmpl:A,item:this,data:D,options:B})}function b(A,C,B){return i.tmpl(i.template(A),C,B,this)}function n(C,A){var B=C.options||{};B.wrapped=A;return i.tmpl(i.template(C.tmpl),C.data,B,C.item)}function r(B,C){var A=this._wrap;return i.map(i(i.isArray(A)?A.join(""):A).filter(B||"*"),function(D){return C?D.innerText||D.textContent:D.outerHTML||d(D)})}function z(){var A=this.nodes;i.tmpl(null,null,null,this).insertBefore(A[0]);i(A).remove()}Sammy=Sammy||{};Sammy.Tmpl=function(C,A){var B=function(E,F,D){if(typeof D=="undefined"){D=E}if(!i.template[D]){i.template(D,E)}return i.tmpl(D,i.extend({},this,F))};if(!A){A="tmpl"}C.helper(A,B)}})(jQuery);
@@ -0,0 +1,722 @@
1
+ // (c) 2010 Jeremy Ashkenas, DocumentCloud Inc.
2
+ // Underscore is freely distributable under the terms of the MIT license.
3
+ // Portions of Underscore are inspired by or borrowed from Prototype.js,
4
+ // Oliver Steele's Functional, and John Resig's Micro-Templating.
5
+ // For all details and documentation:
6
+ // http://documentcloud.github.com/underscore
7
+
8
+ (function() {
9
+
10
+ // Baseline setup
11
+ // --------------
12
+
13
+ // Establish the root object, `window` in the browser, or `global` on the server.
14
+ var root = this;
15
+
16
+ // Save the previous value of the `_` variable.
17
+ var previousUnderscore = root._;
18
+
19
+ // Establish the object that gets thrown to break out of a loop iteration.
20
+ var breaker = typeof StopIteration !== 'undefined' ? StopIteration : '__break__';
21
+
22
+ // Quick regexp-escaping function, because JS doesn't have a `RegExp.escape()`.
23
+ var escapeRegExp = function(s) { return s.replace(/([.*+?^${}()|[\]\/\\])/g, '\\$1'); };
24
+
25
+ // Save bytes in the minified (but not gzipped) version:
26
+ var ArrayProto = Array.prototype, ObjProto = Object.prototype;
27
+
28
+ // Create quick reference variables for speed access to core prototypes.
29
+ var slice = ArrayProto.slice,
30
+ unshift = ArrayProto.unshift,
31
+ toString = ObjProto.toString,
32
+ hasOwnProperty = ObjProto.hasOwnProperty,
33
+ propertyIsEnumerable = ObjProto.propertyIsEnumerable;
34
+
35
+ // All **ECMAScript 5** native function implementations that we hope to use
36
+ // are declared here.
37
+ var
38
+ nativeForEach = ArrayProto.forEach,
39
+ nativeMap = ArrayProto.map,
40
+ nativeReduce = ArrayProto.reduce,
41
+ nativeReduceRight = ArrayProto.reduceRight,
42
+ nativeFilter = ArrayProto.filter,
43
+ nativeEvery = ArrayProto.every,
44
+ nativeSome = ArrayProto.some,
45
+ nativeIndexOf = ArrayProto.indexOf,
46
+ nativeLastIndexOf = ArrayProto.lastIndexOf,
47
+ nativeIsArray = Array.isArray,
48
+ nativeKeys = Object.keys;
49
+
50
+ // Create a safe reference to the Underscore object for use below.
51
+ var _ = function(obj) { return new wrapper(obj); };
52
+
53
+ // Export the Underscore object for **CommonJS**.
54
+ if (typeof exports !== 'undefined') exports._ = _;
55
+
56
+ // Export Underscore to the global scope.
57
+ root._ = _;
58
+
59
+ // Current version.
60
+ _.VERSION = '1.1.1';
61
+
62
+ // Collection Functions
63
+ // --------------------
64
+
65
+ // The cornerstone, an `each` implementation.
66
+ // Handles objects implementing `forEach`, arrays, and raw objects.
67
+ // Delegates to **ECMAScript 5**'s native `forEach` if available.
68
+ var each = _.forEach = function(obj, iterator, context) {
69
+ try {
70
+ if (nativeForEach && obj.forEach === nativeForEach) {
71
+ obj.forEach(iterator, context);
72
+ } else if (_.isNumber(obj.length)) {
73
+ for (var i = 0, l = obj.length; i < l; i++) iterator.call(context, obj[i], i, obj);
74
+ } else {
75
+ for (var key in obj) {
76
+ if (hasOwnProperty.call(obj, key)) iterator.call(context, obj[key], key, obj);
77
+ }
78
+ }
79
+ } catch(e) {
80
+ if (e != breaker) throw e;
81
+ }
82
+ return obj;
83
+ };
84
+
85
+ // Return the results of applying the iterator to each element.
86
+ // Delegates to **ECMAScript 5**'s native `map` if available.
87
+ _.map = function(obj, iterator, context) {
88
+ if (nativeMap && obj.map === nativeMap) return obj.map(iterator, context);
89
+ var results = [];
90
+ each(obj, function(value, index, list) {
91
+ results[results.length] = iterator.call(context, value, index, list);
92
+ });
93
+ return results;
94
+ };
95
+
96
+ // **Reduce** builds up a single result from a list of values, aka `inject`,
97
+ // or `foldl`. Delegates to **ECMAScript 5**'s native `reduce` if available.
98
+ _.reduce = function(obj, iterator, memo, context) {
99
+ if (nativeReduce && obj.reduce === nativeReduce) {
100
+ if (context) iterator = _.bind(iterator, context);
101
+ return obj.reduce(iterator, memo);
102
+ }
103
+ each(obj, function(value, index, list) {
104
+ memo = iterator.call(context, memo, value, index, list);
105
+ });
106
+ return memo;
107
+ };
108
+
109
+ // The right-associative version of reduce, also known as `foldr`. Uses
110
+ // Delegates to **ECMAScript 5**'s native reduceRight if available.
111
+ _.reduceRight = function(obj, iterator, memo, context) {
112
+ if (nativeReduceRight && obj.reduceRight === nativeReduceRight) {
113
+ if (context) iterator = _.bind(iterator, context);
114
+ return obj.reduceRight(iterator, memo);
115
+ }
116
+ var reversed = _.clone(_.toArray(obj)).reverse();
117
+ return _.reduce(reversed, iterator, memo, context);
118
+ };
119
+
120
+ // Return the first value which passes a truth test.
121
+ _.detect = function(obj, iterator, context) {
122
+ var result;
123
+ each(obj, function(value, index, list) {
124
+ if (iterator.call(context, value, index, list)) {
125
+ result = value;
126
+ _.breakLoop();
127
+ }
128
+ });
129
+ return result;
130
+ };
131
+
132
+ // Return all the elements that pass a truth test.
133
+ // Delegates to **ECMAScript 5**'s native `filter` if available.
134
+ _.filter = function(obj, iterator, context) {
135
+ if (nativeFilter && obj.filter === nativeFilter) return obj.filter(iterator, context);
136
+ var results = [];
137
+ each(obj, function(value, index, list) {
138
+ if (iterator.call(context, value, index, list)) results[results.length] = value;
139
+ });
140
+ return results;
141
+ };
142
+
143
+ // Return all the elements for which a truth test fails.
144
+ _.reject = function(obj, iterator, context) {
145
+ var results = [];
146
+ each(obj, function(value, index, list) {
147
+ if (!iterator.call(context, value, index, list)) results[results.length] = value;
148
+ });
149
+ return results;
150
+ };
151
+
152
+ // Determine whether all of the elements match a truth test.
153
+ // Delegates to **ECMAScript 5**'s native `every` if available.
154
+ _.every = function(obj, iterator, context) {
155
+ iterator = iterator || _.identity;
156
+ if (nativeEvery && obj.every === nativeEvery) return obj.every(iterator, context);
157
+ var result = true;
158
+ each(obj, function(value, index, list) {
159
+ if (!(result = result && iterator.call(context, value, index, list))) _.breakLoop();
160
+ });
161
+ return result;
162
+ };
163
+
164
+ // Determine if at least one element in the object matches a truth test.
165
+ // Delegates to **ECMAScript 5**'s native `some` if available.
166
+ _.some = function(obj, iterator, context) {
167
+ iterator = iterator || _.identity;
168
+ if (nativeSome && obj.some === nativeSome) return obj.some(iterator, context);
169
+ var result = false;
170
+ each(obj, function(value, index, list) {
171
+ if (result = iterator.call(context, value, index, list)) _.breakLoop();
172
+ });
173
+ return result;
174
+ };
175
+
176
+ // Determine if a given value is included in the array or object using `===`.
177
+ _.include = function(obj, target) {
178
+ if (nativeIndexOf && obj.indexOf === nativeIndexOf) return obj.indexOf(target) != -1;
179
+ var found = false;
180
+ each(obj, function(value) {
181
+ if (found = value === target) _.breakLoop();
182
+ });
183
+ return found;
184
+ };
185
+
186
+ // Invoke a method (with arguments) on every item in a collection.
187
+ _.invoke = function(obj, method) {
188
+ var args = slice.call(arguments, 2);
189
+ return _.map(obj, function(value) {
190
+ return (method ? value[method] : value).apply(value, args);
191
+ });
192
+ };
193
+
194
+ // Convenience version of a common use case of `map`: fetching a property.
195
+ _.pluck = function(obj, key) {
196
+ return _.map(obj, function(value){ return value[key]; });
197
+ };
198
+
199
+ // Return the maximum element or (element-based computation).
200
+ _.max = function(obj, iterator, context) {
201
+ if (!iterator && _.isArray(obj)) return Math.max.apply(Math, obj);
202
+ var result = {computed : -Infinity};
203
+ each(obj, function(value, index, list) {
204
+ var computed = iterator ? iterator.call(context, value, index, list) : value;
205
+ computed >= result.computed && (result = {value : value, computed : computed});
206
+ });
207
+ return result.value;
208
+ };
209
+
210
+ // Return the minimum element (or element-based computation).
211
+ _.min = function(obj, iterator, context) {
212
+ if (!iterator && _.isArray(obj)) return Math.min.apply(Math, obj);
213
+ var result = {computed : Infinity};
214
+ each(obj, function(value, index, list) {
215
+ var computed = iterator ? iterator.call(context, value, index, list) : value;
216
+ computed < result.computed && (result = {value : value, computed : computed});
217
+ });
218
+ return result.value;
219
+ };
220
+
221
+ // Sort the object's values by a criterion produced by an iterator.
222
+ _.sortBy = function(obj, iterator, context) {
223
+ return _.pluck(_.map(obj, function(value, index, list) {
224
+ return {
225
+ value : value,
226
+ criteria : iterator.call(context, value, index, list)
227
+ };
228
+ }).sort(function(left, right) {
229
+ var a = left.criteria, b = right.criteria;
230
+ return a < b ? -1 : a > b ? 1 : 0;
231
+ }), 'value');
232
+ };
233
+
234
+ // Use a comparator function to figure out at what index an object should
235
+ // be inserted so as to maintain order. Uses binary search.
236
+ _.sortedIndex = function(array, obj, iterator) {
237
+ iterator = iterator || _.identity;
238
+ var low = 0, high = array.length;
239
+ while (low < high) {
240
+ var mid = (low + high) >> 1;
241
+ iterator(array[mid]) < iterator(obj) ? low = mid + 1 : high = mid;
242
+ }
243
+ return low;
244
+ };
245
+
246
+ // Safely convert anything iterable into a real, live array.
247
+ _.toArray = function(iterable) {
248
+ if (!iterable) return [];
249
+ if (iterable.toArray) return iterable.toArray();
250
+ if (_.isArray(iterable)) return iterable;
251
+ if (_.isArguments(iterable)) return slice.call(iterable);
252
+ return _.values(iterable);
253
+ };
254
+
255
+ // Return the number of elements in an object.
256
+ _.size = function(obj) {
257
+ return _.toArray(obj).length;
258
+ };
259
+
260
+ // Array Functions
261
+ // ---------------
262
+
263
+ // Get the first element of an array. Passing **n** will return the first N
264
+ // values in the array. Aliased as `head`. The **guard** check allows it to work
265
+ // with `_.map`.
266
+ _.first = function(array, n, guard) {
267
+ return n && !guard ? slice.call(array, 0, n) : array[0];
268
+ };
269
+
270
+ // Returns everything but the first entry of the array. Aliased as `tail`.
271
+ // Especially useful on the arguments object. Passing an **index** will return
272
+ // the rest of the values in the array from that index onward. The **guard**
273
+ // check allows it to work with `_.map`.
274
+ _.rest = function(array, index, guard) {
275
+ return slice.call(array, _.isUndefined(index) || guard ? 1 : index);
276
+ };
277
+
278
+ // Get the last element of an array.
279
+ _.last = function(array) {
280
+ return array[array.length - 1];
281
+ };
282
+
283
+ // Trim out all falsy values from an array.
284
+ _.compact = function(array) {
285
+ return _.filter(array, function(value){ return !!value; });
286
+ };
287
+
288
+ // Return a completely flattened version of an array.
289
+ _.flatten = function(array) {
290
+ return _.reduce(array, function(memo, value) {
291
+ if (_.isArray(value)) return memo.concat(_.flatten(value));
292
+ memo[memo.length] = value;
293
+ return memo;
294
+ }, []);
295
+ };
296
+
297
+ // Return a version of the array that does not contain the specified value(s).
298
+ _.without = function(array) {
299
+ var values = slice.call(arguments, 1);
300
+ return _.filter(array, function(value){ return !_.include(values, value); });
301
+ };
302
+
303
+ // Produce a duplicate-free version of the array. If the array has already
304
+ // been sorted, you have the option of using a faster algorithm.
305
+ _.uniq = function(array, isSorted) {
306
+ return _.reduce(array, function(memo, el, i) {
307
+ if (0 == i || (isSorted === true ? _.last(memo) != el : !_.include(memo, el))) memo[memo.length] = el;
308
+ return memo;
309
+ }, []);
310
+ };
311
+
312
+ // Produce an array that contains every item shared between all the
313
+ // passed-in arrays.
314
+ _.intersect = function(array) {
315
+ var rest = slice.call(arguments, 1);
316
+ return _.filter(_.uniq(array), function(item) {
317
+ return _.every(rest, function(other) {
318
+ return _.indexOf(other, item) >= 0;
319
+ });
320
+ });
321
+ };
322
+
323
+ // Zip together multiple lists into a single array -- elements that share
324
+ // an index go together.
325
+ _.zip = function() {
326
+ var args = slice.call(arguments);
327
+ var length = _.max(_.pluck(args, 'length'));
328
+ var results = new Array(length);
329
+ for (var i = 0; i < length; i++) results[i] = _.pluck(args, "" + i);
330
+ return results;
331
+ };
332
+
333
+ // If the browser doesn't supply us with indexOf (I'm looking at you, MSIE),
334
+ // we need this function. Return the position of the first occurence of an
335
+ // item in an array, or -1 if the item is not included in the array.
336
+ // Delegates to **ECMAScript 5**'s native `indexOf` if available.
337
+ _.indexOf = function(array, item) {
338
+ if (nativeIndexOf && array.indexOf === nativeIndexOf) return array.indexOf(item);
339
+ for (var i = 0, l = array.length; i < l; i++) if (array[i] === item) return i;
340
+ return -1;
341
+ };
342
+
343
+
344
+ // Delegates to **ECMAScript 5**'s native `lastIndexOf` if available.
345
+ _.lastIndexOf = function(array, item) {
346
+ if (nativeLastIndexOf && array.lastIndexOf === nativeLastIndexOf) return array.lastIndexOf(item);
347
+ var i = array.length;
348
+ while (i--) if (array[i] === item) return i;
349
+ return -1;
350
+ };
351
+
352
+ // Generate an integer Array containing an arithmetic progression. A port of
353
+ // the native Python `range()` function. See
354
+ // [the Python documentation](http://docs.python.org/library/functions.html#range).
355
+ _.range = function(start, stop, step) {
356
+ var a = slice.call(arguments);
357
+ var solo = a.length <= 1;
358
+ var start = solo ? 0 : a[0], stop = solo ? a[0] : a[1], step = a[2] || 1;
359
+ var len = Math.ceil((stop - start) / step);
360
+ if (len <= 0) return [];
361
+ var range = new Array(len);
362
+ for (var i = start, idx = 0; true; i += step) {
363
+ if ((step > 0 ? i - stop : stop - i) >= 0) return range;
364
+ range[idx++] = i;
365
+ }
366
+ };
367
+
368
+ // Function Functions
369
+ // ------------------
370
+
371
+ // Create a function bound to a given object (assigning `this`, and arguments,
372
+ // optionally). Binding with arguments is also known as `curry`.
373
+ _.bind = function(func, obj) {
374
+ var args = slice.call(arguments, 2);
375
+ return function() {
376
+ return func.apply(obj || {}, args.concat(slice.call(arguments)));
377
+ };
378
+ };
379
+
380
+ // Bind all of an object's methods to that object. Useful for ensuring that
381
+ // all callbacks defined on an object belong to it.
382
+ _.bindAll = function(obj) {
383
+ var funcs = slice.call(arguments, 1);
384
+ if (funcs.length == 0) funcs = _.functions(obj);
385
+ each(funcs, function(f) { obj[f] = _.bind(obj[f], obj); });
386
+ return obj;
387
+ };
388
+
389
+ // Memoize an expensive function by storing its results.
390
+ _.memoize = function(func, hasher) {
391
+ var memo = {};
392
+ hasher = hasher || _.identity;
393
+ return function() {
394
+ var key = hasher.apply(this, arguments);
395
+ return key in memo ? memo[key] : (memo[key] = func.apply(this, arguments));
396
+ };
397
+ };
398
+
399
+ // Delays a function for the given number of milliseconds, and then calls
400
+ // it with the arguments supplied.
401
+ _.delay = function(func, wait) {
402
+ var args = slice.call(arguments, 2);
403
+ return setTimeout(function(){ return func.apply(func, args); }, wait);
404
+ };
405
+
406
+ // Defers a function, scheduling it to run after the current call stack has
407
+ // cleared.
408
+ _.defer = function(func) {
409
+ return _.delay.apply(_, [func, 1].concat(slice.call(arguments, 1)));
410
+ };
411
+
412
+ // Returns the first function passed as an argument to the second,
413
+ // allowing you to adjust arguments, run code before and after, and
414
+ // conditionally execute the original function.
415
+ _.wrap = function(func, wrapper) {
416
+ return function() {
417
+ var args = [func].concat(slice.call(arguments));
418
+ return wrapper.apply(wrapper, args);
419
+ };
420
+ };
421
+
422
+ // Returns a function that is the composition of a list of functions, each
423
+ // consuming the return value of the function that follows.
424
+ _.compose = function() {
425
+ var funcs = slice.call(arguments);
426
+ return function() {
427
+ var args = slice.call(arguments);
428
+ for (var i=funcs.length-1; i >= 0; i--) {
429
+ args = [funcs[i].apply(this, args)];
430
+ }
431
+ return args[0];
432
+ };
433
+ };
434
+
435
+ // Object Functions
436
+ // ----------------
437
+
438
+ // Retrieve the names of an object's properties.
439
+ // Delegates to **ECMAScript 5**'s native `Object.keys`
440
+ _.keys = nativeKeys || function(obj) {
441
+ if (_.isArray(obj)) return _.range(0, obj.length);
442
+ var keys = [];
443
+ for (var key in obj) if (hasOwnProperty.call(obj, key)) keys[keys.length] = key;
444
+ return keys;
445
+ };
446
+
447
+ // Retrieve the values of an object's properties.
448
+ _.values = function(obj) {
449
+ return _.map(obj, _.identity);
450
+ };
451
+
452
+ // Return a sorted list of the function names available on the object.
453
+ _.functions = function(obj) {
454
+ return _.filter(_.keys(obj), function(key){ return _.isFunction(obj[key]); }).sort();
455
+ };
456
+
457
+ // Extend a given object with all the properties in passed-in object(s).
458
+ _.extend = function(obj) {
459
+ each(slice.call(arguments, 1), function(source) {
460
+ for (var prop in source) obj[prop] = source[prop];
461
+ });
462
+ return obj;
463
+ };
464
+
465
+ // Create a (shallow-cloned) duplicate of an object.
466
+ _.clone = function(obj) {
467
+ if (_.isArray(obj)) return obj.slice(0);
468
+ return _.extend({}, obj);
469
+ };
470
+
471
+ // Invokes interceptor with the obj, and then returns obj.
472
+ // The primary purpose of this method is to "tap into" a method chain, in
473
+ // order to perform operations on intermediate results within the chain.
474
+ _.tap = function(obj, interceptor) {
475
+ interceptor(obj);
476
+ return obj;
477
+ };
478
+
479
+ // Perform a deep comparison to check if two objects are equal.
480
+ _.isEqual = function(a, b) {
481
+ // Check object identity.
482
+ if (a === b) return true;
483
+ // Different types?
484
+ var atype = typeof(a), btype = typeof(b);
485
+ if (atype != btype) return false;
486
+ // Basic equality test (watch out for coercions).
487
+ if (a == b) return true;
488
+ // One is falsy and the other truthy.
489
+ if ((!a && b) || (a && !b)) return false;
490
+ // One of them implements an isEqual()?
491
+ if (a.isEqual) return a.isEqual(b);
492
+ // Check dates' integer values.
493
+ if (_.isDate(a) && _.isDate(b)) return a.getTime() === b.getTime();
494
+ // Both are NaN?
495
+ if (_.isNaN(a) && _.isNaN(b)) return false;
496
+ // Compare regular expressions.
497
+ if (_.isRegExp(a) && _.isRegExp(b))
498
+ return a.source === b.source &&
499
+ a.global === b.global &&
500
+ a.ignoreCase === b.ignoreCase &&
501
+ a.multiline === b.multiline;
502
+ // If a is not an object by this point, we can't handle it.
503
+ if (atype !== 'object') return false;
504
+ // Check for different array lengths before comparing contents.
505
+ if (a.length && (a.length !== b.length)) return false;
506
+ // Nothing else worked, deep compare the contents.
507
+ var aKeys = _.keys(a), bKeys = _.keys(b);
508
+ // Different object sizes?
509
+ if (aKeys.length != bKeys.length) return false;
510
+ // Recursive comparison of contents.
511
+ for (var key in a) if (!(key in b) || !_.isEqual(a[key], b[key])) return false;
512
+ return true;
513
+ };
514
+
515
+ // Is a given array or object empty?
516
+ _.isEmpty = function(obj) {
517
+ if (_.isArray(obj) || _.isString(obj)) return obj.length === 0;
518
+ for (var key in obj) if (hasOwnProperty.call(obj, key)) return false;
519
+ return true;
520
+ };
521
+
522
+ // Is a given value a DOM element?
523
+ _.isElement = function(obj) {
524
+ return !!(obj && obj.nodeType == 1);
525
+ };
526
+
527
+ // Is a given value an array?
528
+ // Delegates to ECMA5's native Array.isArray
529
+ _.isArray = nativeIsArray || function(obj) {
530
+ return !!(obj && obj.concat && obj.unshift && !obj.callee);
531
+ };
532
+
533
+ // Is a given variable an arguments object?
534
+ _.isArguments = function(obj) {
535
+ return !!(obj && obj.callee);
536
+ };
537
+
538
+ // Is a given value a function?
539
+ _.isFunction = function(obj) {
540
+ return !!(obj && obj.constructor && obj.call && obj.apply);
541
+ };
542
+
543
+ // Is a given value a string?
544
+ _.isString = function(obj) {
545
+ return !!(obj === '' || (obj && obj.charCodeAt && obj.substr));
546
+ };
547
+
548
+ // Is a given value a number?
549
+ _.isNumber = function(obj) {
550
+ return (obj === +obj) || (toString.call(obj) === '[object Number]');
551
+ };
552
+
553
+ // Is a given value a boolean?
554
+ _.isBoolean = function(obj) {
555
+ return obj === true || obj === false;
556
+ };
557
+
558
+ // Is a given value a date?
559
+ _.isDate = function(obj) {
560
+ return !!(obj && obj.getTimezoneOffset && obj.setUTCFullYear);
561
+ };
562
+
563
+ // Is the given value a regular expression?
564
+ _.isRegExp = function(obj) {
565
+ return !!(obj && obj.test && obj.exec && (obj.ignoreCase || obj.ignoreCase === false));
566
+ };
567
+
568
+ // Is the given value NaN -- this one is interesting. NaN != NaN, and
569
+ // isNaN(undefined) == true, so we make sure it's a number first.
570
+ _.isNaN = function(obj) {
571
+ return _.isNumber(obj) && isNaN(obj);
572
+ };
573
+
574
+ // Is a given value equal to null?
575
+ _.isNull = function(obj) {
576
+ return obj === null;
577
+ };
578
+
579
+ // Is a given variable undefined?
580
+ _.isUndefined = function(obj) {
581
+ return typeof obj == 'undefined';
582
+ };
583
+
584
+ // Utility Functions
585
+ // -----------------
586
+
587
+ // Run Underscore.js in *noConflict* mode, returning the `_` variable to its
588
+ // previous owner. Returns a reference to the Underscore object.
589
+ _.noConflict = function() {
590
+ root._ = previousUnderscore;
591
+ return this;
592
+ };
593
+
594
+ // Keep the identity function around for default iterators.
595
+ _.identity = function(value) {
596
+ return value;
597
+ };
598
+
599
+ // Run a function **n** times.
600
+ _.times = function (n, iterator, context) {
601
+ for (var i = 0; i < n; i++) iterator.call(context, i);
602
+ };
603
+
604
+ // Break out of the middle of an iteration.
605
+ _.breakLoop = function() {
606
+ throw breaker;
607
+ };
608
+
609
+ // Add your own custom functions to the Underscore object, ensuring that
610
+ // they're correctly added to the OOP wrapper as well.
611
+ _.mixin = function(obj) {
612
+ each(_.functions(obj), function(name){
613
+ addToWrapper(name, _[name] = obj[name]);
614
+ });
615
+ };
616
+
617
+ // Generate a unique integer id (unique within the entire client session).
618
+ // Useful for temporary DOM ids.
619
+ var idCounter = 0;
620
+ _.uniqueId = function(prefix) {
621
+ var id = idCounter++;
622
+ return prefix ? prefix + id : id;
623
+ };
624
+
625
+ // By default, Underscore uses ERB-style template delimiters, change the
626
+ // following template settings to use alternative delimiters.
627
+ _.templateSettings = {
628
+ evaluate : /<\%([\s\S]+?)%>/g,
629
+ interpolate : /<\%\=([\s\S]+?)%>/g
630
+ };
631
+
632
+ // JavaScript micro-templating, similar to John Resig's implementation.
633
+ // Underscore templating handles arbitrary delimiters, preserves whitespace,
634
+ // and correctly escapes quotes within interpolated code.
635
+ _.template = function(str, data) {
636
+ var c = _.templateSettings;
637
+ var tmpl = 'var __p=[],print=function(){__p.push.apply(__p,arguments);};' +
638
+ 'with(obj||{}){__p.push(\'' +
639
+ str.replace(/'/g, "\\'")
640
+ .replace(c.interpolate, function(match, code) {
641
+ return "'," + code.replace(/\\'/g, "'") + ",'";
642
+ })
643
+ .replace(c.evaluate || null, function(match, code) {
644
+ return "');" + code.replace(/\\'/g, "'")
645
+ .replace(/[\r\n\t]/g, ' ') + "__p.push('";
646
+ })
647
+ .replace(/\r/g, '\\r')
648
+ .replace(/\n/g, '\\n')
649
+ .replace(/\t/g, '\\t')
650
+ + "');}return __p.join('');";
651
+ var func = new Function('obj', tmpl);
652
+ return data ? func(data) : func;
653
+ };
654
+
655
+ // Aliases:
656
+ // --------
657
+
658
+ _.each = _.forEach;
659
+ _.foldl = _.inject = _.reduce;
660
+ _.foldr = _.reduceRight;
661
+ _.select = _.filter;
662
+ _.all = _.every;
663
+ _.any = _.some;
664
+ _.contains = _.include;
665
+ _.head = _.first;
666
+ _.tail = _.rest;
667
+ _.methods = _.functions;
668
+
669
+ // The OOP Wrapper
670
+ // ---------------
671
+
672
+ // If Underscore is called as a function, it returns a wrapped object that
673
+ // can be used OO-style. This wrapper holds altered versions of all the
674
+ // underscore functions. Wrapped objects may be chained.
675
+ var wrapper = function(obj) { this._wrapped = obj; };
676
+
677
+ // Helper function to continue chaining intermediate results.
678
+ var result = function(obj, chain) {
679
+ return chain ? _(obj).chain() : obj;
680
+ };
681
+
682
+ // A method to easily add functions to the OOP wrapper.
683
+ var addToWrapper = function(name, func) {
684
+ wrapper.prototype[name] = function() {
685
+ var args = slice.call(arguments);
686
+ unshift.call(args, this._wrapped);
687
+ return result(func.apply(_, args), this._chain);
688
+ };
689
+ };
690
+
691
+ // Add all of the Underscore functions to the wrapper object.
692
+ _.mixin(_);
693
+
694
+ // Add all mutator Array functions to the wrapper.
695
+ each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift'], function(name) {
696
+ var method = ArrayProto[name];
697
+ wrapper.prototype[name] = function() {
698
+ method.apply(this._wrapped, arguments);
699
+ return result(this._wrapped, this._chain);
700
+ };
701
+ });
702
+
703
+ // Add all accessor Array functions to the wrapper.
704
+ each(['concat', 'join', 'slice'], function(name) {
705
+ var method = ArrayProto[name];
706
+ wrapper.prototype[name] = function() {
707
+ return result(method.apply(this._wrapped, arguments), this._chain);
708
+ };
709
+ });
710
+
711
+ // Start chaining a wrapped Underscore object.
712
+ wrapper.prototype.chain = function() {
713
+ this._chain = true;
714
+ return this;
715
+ };
716
+
717
+ // Extracts the result from a wrapped and chained object.
718
+ wrapper.prototype.value = function() {
719
+ return this._wrapped;
720
+ };
721
+
722
+ })();