Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Loading…

Escape HTML entered in epitome example #390

Merged
merged 1 commit into from

3 participants

@passy
Owner

The Epitome example doesn't escape HTML currently. I added some dirty escaping to the model layer, while I think this would fit much better in the view or template. I didn't find any good way to do this with Epitome and underscore templates, though.

Maybe @DimitarChristoff has a better idea?

@sindresorhus

Couldn't you just use Underscore's escaping ability?

<%- title %>

dash instead of equal

@passy
Owner

I don't know what version of underscore is included there, but it doesn't seem to support that yet.

@passy
Owner

Oh, they don't actually use underscore at all, they're just underscore-style templates.

@sindresorhus

@DimitarChristoff Epitome.Template should really inherit the Underscore escape syntax too.

@DimitarChristoff

To be honest, at the time we were writing this, we didn't even think to release a templating component but we put one anyway, based upon the code in _.js at the time.

It was not very fast and it was also throwing exceptions when you referenced object attributes in the template that were not being passed. In ended up being rewritten and simplified somewhat. Escapes was seen as an extra chained replace and it got dropped in favour of doing this upstream...

Anyway, reality is that most ppl (including ourselves) use handlebars/mustache/hogan, which is easy:

http://dimitarchristoff.github.com/Epitome/#epitome-view/template

The provided engine is quite limited but is being used by people in a hurry. I am happy to look at the current _.js implementation and porting it over in full, just create an issue on the repo and will land it shortly.

@DimitarChristoff
@passy
Owner

@DimitarChristoff Thanks for the update! Regarding stipTags I must have search for the wrong term in the docs. However, stripping is actually still the wrong behavior.

I updated the PR to use the new escaping mechanism.

@sindresorhus sindresorhus merged commit 5b9773d into tastejs:gh-pages
@DimitarChristoff
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Jan 16, 2013
  1. @passy
This page is out of date. Refresh to see the latest.
View
2  labs/architecture-examples/epitome/index.html
@@ -31,7 +31,7 @@
<script type="text/template" id="item-template">
<div class="view">
<input class="toggle" type="checkbox" <%=completedCheckbox%>>
- <label><%=title%></label>
+ <label><%-title%></label>
<button class="destroy"></button>
</div>
<input class="edit" value="<%=title%>">
View
2  labs/architecture-examples/epitome/js/lib/Epitome-min.js
@@ -1 +1 @@
-(function(e){var t=function(){return{}};typeof define=="function"&&define.amd?define("epitome",[],t):e.Epitome=t(e)})(this),function(e){var t=function(e){var t=e.isEqual=function(e,n,r){r=r||[];if(e===n)return e!==0||1/e==1/n;if(e==null||n==null)return e===n;var i=typeOf(e),s=typeOf(n);if(i!=s)return!1;switch(i){case"string":return e==String(n);case"number":return e!=+e?n!=+n:e==0?1/e==1/n:e==+n;case"date":case"boolean":return+e==+n;case"regexp":return e.source==n.source&&e.global==n.global&&e.multiline==n.multiline&&e.ignoreCase==n.ignoreCase}if(typeof e!="object"||typeof n!="object")return!1;var o=r.length;while(o--)if(r[o]==e)return!0;r.push(e);var u=0,a=!0;if(i=="array"){u=e.length,a=u==n.length;if(a)while(u--)if(!(a=u in e==u in n&&t(e[u],n[u],r)))break}else{if("constructor"in e!="constructor"in n||e.constructor!=n.constructor)return!1;for(var f in e)if(e.hasOwnProperty(f)){u++;if(!(a=n.hasOwnProperty(f)&&t(e[f],n[f],r)))break}if(a){for(f in n)if(n.hasOwnProperty(f)&&!(u--))break;a=!u}}return r.pop(),a};return e};typeof define=="function"&&define.amd?define("epitome-isequal",["./epitome"],t):e.Epitome=t(e)}(this),function(e){var t=function(e){return e.Model=new Class({Implements:[Options,Events],_attributes:{},properties:{id:{get:function(){var e=this._attributes.id||(this._attributes.id=String.uniqueID());return this.cid||(this.cid=e),e}}},options:{defaults:{}},collections:[],initialize:function(e,t){return t&&t.defaults&&(this.options.defaults=Object.merge(this.options.defaults,t.defaults)),e=e&&typeOf(e)==="object"?e:{},this.set(Object.merge(this.options.defaults,e)),this.setOptions(t),this.fireEvent("ready")},set:function(){this.propertiesChanged=[],this._set.apply(this,arguments),this.propertiesChanged.length&&this.fireEvent("change",this.get(this.propertiesChanged))},_set:function(t,n){return!t||typeof n=="undefined"?this:this.properties[t]&&this.properties[t].set?this.properties[t].set.call(this,n):this._attributes[t]&&e.isEqual(this._attributes[t],n)?this:(n===null?delete this._attributes[t]:this._attributes[t]=n,this.fireEvent("change:"+t,n),this.propertiesChanged.push(t),this)}.overloadSetter(),get:function(e){return e&&this.properties[e]&&this.properties[e].get?this.properties[e].get.call(this):e&&typeof this._attributes[e]!="undefined"?this._attributes[e]:null}.overloadGetter(),unset:function(){var e=Array.prototype.slice.apply(arguments),t={},n=e.length;return n?(Array.each(Array.flatten(e),function(e){t[e]=null}),this.set(t),this):this},toJSON:function(){return Object.clone(this._attributes)},empty:function(){var e=Object.keys(this.toJSON()),t=this;this.fireEvent("change",[e]),Array.each(e,function(e){t.fireEvent("change:"+e,null)},this),this._attributes={},this.fireEvent("empty")},destroy:function(){this._attributes={},this.fireEvent("destroy")}}),e};typeof define=="function"&&define.amd?define("epitome-model",["./epitome-isequal"],t):e.Epitome=t(e)}(this),function(e){var t=function(e){var t=e.Model,n="sync:",r={create:"POST",read:"GET",update:"PUT",delete_:"DELETE"};return t.Sync=new Class({Extends:t,properties:{id:{get:function(){var e=this._attributes.id||(this._attributes.id=String.uniqueID());return this.cid||(this.cid=e),e}},urlRoot:{set:function(e){this.urlRoot=e,delete this._attributes.urlRoot},get:function(){var e=this.urlRoot||this.options.urlRoot||"no-urlRoot-set";return e.charAt(e.length-1)!="/"&&(e+="/"),e}}},options:{emulateREST:!1},initialize:function(e,t){this.setupSync(),this.parent(e,t)},sync:function(e,t){var n={};e=e&&r[e]?r[e]:r.read,n.method=e;if(e==r.create||e==r.update)n.data=t||this.toJSON();return n.url=this.get("urlRoot")+this.get("id")+"/",this.request.setOptions(n),this.request[e](t),this},setupSync:function(){var e=this,t=0,i=function(){t++};return this.getRequestId=function(){return t+1},this.request=new Request.JSON({link:"chain",url:this.get("urlRoot"),emulation:this.options.emulateREST,onRequest:i,onCancel:function(){this.removeEvents(n+t)},onSuccess:function(r){r=e.parse&&e.parse(r),e.fireEvent(n+t,[r]),e.fireEvent("sync",[r,this.options.method,this.options.data])},onFailure:function(){e.fireEvent(n+"error",[this.options.method,this.options.url,this.options.data])}}),Object.each(r,function(t,n){e[n]=function(e){this.sync(n,e)}}),this},_throwAwaySyncEvent:function(e,t){e=e||n+this.getRequestId();var r=this,i={};return i[e]=function(e){e&&typeof e=="object"&&(r.set(e),t&&t.call(r,e)),r.removeEvents(i)},this.addEvents(i)}.protect(),parse:function(e){return e},fetch:function(){return this._throwAwaySyncEvent(n+this.getRequestId(),function(){this.fireEvent("fetch"),this.isNewModel=!1}),this.read(),this},save:function(e,t){var r=["update","create"][+this.isNew()];if(e){var i=typeOf(e),s=i=="object"||i=="string"&&typeof t!="undefined";s&&this._set.apply(this,arguments)}return this._throwAwaySyncEvent(n+this.getRequestId(),function(){this.fireEvent("save"),this.fireEvent(r)}),this[r](),this.isNewModel=!1,this},destroy:function(){this._throwAwaySyncEvent(n+this.getRequestId(),function(){this._attributes={},this.delete_(),this.fireEvent("destroy")})},isNew:function(){return typeof this.isNewModel=="undefined"&&(this.isNewModel=!0),this.isNewModel}}),e};typeof define=="function"&&define.amd?define("epitome-model-sync",["./epitome-model"],t):e.Epitome=t(e)}(this),function(e){var t=function(t){return t.Storage=function(){var t=typeof e.localStorage=="object"&&!!e.localStorage.getItem,n="localStorage",r="sessionStorage",i=function(n){var r,i="epitome-"+n,s={},o="model";if(t)try{s=JSON.decode(e[n].getItem(i))||s}catch(u){t=!1}if(!t)try{r=JSON.decode(e.name),r&&typeof r=="object"&&r[i]&&(s=r[i])}catch(u){h()}var a={store:function(e){e=e||this.toJSON(),l([o,this.get("id")].join(":"),e),this.fireEvent("store",e)},eliminate:function(){return c([o,this.get("id")].join(":")),this.fireEvent("eliminate")},retrieve:function(){var e=f([o,this.get("id")].join(":"))||null;return this.fireEvent("retrieve",e),e}},f=function(e){return s[e]||null},l=function(r,o){s=JSON.decode(e[n].getItem(i))||s,s[r]=o;if(t)try{e[n].setItem(i,JSON.encode(s))}catch(u){}else h();return this},c=function(r){delete s[r];if(t)try{e[n].setItem(i,JSON.encode(s))}catch(o){}else h()},h=function(){var t={},n=JSON.decode(e.name);t[i]=s,e.name=JSON.encode(Object.merge(t,n))};return function(e){return e&&(o=e),new Class(Object.clone(a))}};return{localStorage:i(n),sessionStorage:i(r)}}(),t};typeof define=="function"&&define.amd?define("epitome-storage",["./epitome"],t):e.Epitome=t(e)}(this),function(e){var t=function(e){var t=["forEach","each","invoke","filter","map","some","indexOf","contains","getRandom","getLast"];Function.extend({monitorModelEvents:function(e,t){var n=this;return t=t||this,!e||!e.fireEvent?this:function(r,i,s){n.apply(t,arguments),e.getModelByCID(t.cid)&&e.fireEvent(r,Array.flatten([t,i]),s)}}});var n=e.Collection=new Class({Implements:[Options,Events],model:e.Model,_models:[],initialize:function(e,t){return this.setOptions(t),e&&this.setUp(e),this.id=this.options.id||String.uniqueID(),this.fireEvent("ready")},setUp:function(e){return e=Array.from(e),Array.each(e,this.addModel.bind(this)),this.addEvent("destroy",this.removeModel.bind(this)),this},addModel:function(e,t){var n;return typeOf(e)=="object"&&!instanceOf(e,this.model)&&(e=new this.model(e)),e.cid=e.cid||e.get("id")||String.uniqueID(),n=this.getModelByCID(e.cid),n&&t!==!0?this.fireEvent("add:error",e):(n&&t===!0&&(this._models[this._models.indexOf(e)]=e),e.fireEvent=Function.monitorModelEvents.apply(e.fireEvent,[this,e]),this._models.push(e),e.collections.include(this),this.length=this._models.length,this.fireEvent("add",[e,e.cid]).fireEvent("reset",[e,e.cid]))},removeModel:function(e){var t=this;return e=Array.from(e),Array.each(e,function(e){e.collections.erase(t),e.collections.length||delete e.fireEvent,Array.erase(t._models,e),t.length=t._models.length,t.fireEvent("remove",[e,e.cid])}),this.fireEvent("reset",[e])},get:function(e){return this[e]},getModelByCID:function(e){var t=null;return this.some(function(n){return n.cid==e&&(t=n)}),t},getModelById:function(e){var t=null;return this.some(function(n){return n.get("id")==e&&(t=n)}),t},getModel:function(e){return this._models[e]},toJSON:function(){var e=function(e){return e.toJSON()};return Array.map(this._models,e)},empty:function(){return this.removeModel(this._models),this.fireEvent("empty")},sort:function(e){if(!e)return this._models.sort(),this.fireEvent("sort");if(typeof e=="function")return this.model.sort(e),this.fireEvent("sort");var t="asc",n=e.split(":"),r=n[0],i=function(e,t){return e<t?-1:e>t?1:0};return n[1]&&(t=n[1]),this._models.sort(function(e,n){var s=e.get(r),o=n.get(r),u=i(s,o),a={asc:u,desc:-u};return typeof a[t]=="undefined"&&(t="asc"),a[t]}),this.fireEvent("sort")},reverse:function(){return Array.reverse(this._models),this.fireEvent("sort")}});return Array.each(t,function(e){n.implement(e,function(){return Array.prototype[e].apply(this._models,arguments)})}),e};typeof define=="function"&&define.amd?define("epitome-collection",["./epitome-model"],t):e.Epitome=t(e)}(this),function(e){var t=function(e){var t="no-urlRoot-set",n="fetch:";return e.Collection.Sync=new Class({Extends:e.Collection,options:{urlRoot:t},initialize:function(e,t){this.setupSync(),this.parent(e,t)},setupSync:function(){var e=this,t=0,r=function(){t++};return this.getRequestId=function(){return t+1},this.request=new Request.JSON({link:"chain",url:this.options.urlRoot,emulation:this.options.emulateREST,onRequest:r,onCancel:function(){this.removeEvents(n+t)},onSuccess:function(r){r=e.parse&&e.parse(r),e.fireEvent(n+t,[[r]])},onFailure:function(){e.fireEvent(n+"error",[this.options.method,this.options.url,this.options.data])}}),this},parse:function(e){return e},fetch:function(e){return this._throwAwayEvent(function(t){e?(this.empty(),Array.each(t,this.addModel.bind(this))):this.processModels(t),this.fireEvent("fetch",[t])}),this.request.get(),this},processModels:function(e){var t=this;Array.each(e,function(e){var n=e.id&&t.getModelById(e.id);n?n.set(e):t.addModel(e)})},_throwAwayEvent:function(e){var t=n+this.getRequestId(),r=this,i={};if(!e||typeof e!="function")return;return i[t]=function(t){e.apply(r,t),r.removeEvents(i)},this.addEvents(i)}.protect()}),e};typeof define=="function"&&define.amd?define("epitome-collection-sync",["./epitome-model"],t):e.Epitome=t(e)}(this),function(e){var t=function(e){return e.Template=new Class({options:{evaluate:/<%([\s\S]+?)%>/g,normal:/<%=([\s\S]+?)%>/g,noMatch:/.^/,escaper:/\\|'|\r|\n|\t|\u2028|\u2029/g,unescaper:/\\(\\|'|r|n|t|u2028|u2029)/g},Implements:[Options],initialize:function(e){this.setOptions(e);var t=this.options.unescaper,n=this.escapes={"\\":"\\","'":"'",r:"\r",n:"\n",t:" ",u2028:"\u2028",u2029:"\u2029"};return Object.each(n,function(e,t){this[e]=t},n),this.unescape=function(e){return e.replace(t,function(e,t){return n[t]})},this},template:function(e,t){var n=this.options,r=this.escapes,i=this.unescape,s=n.noMatch,o=n.escaper,u,a=["var __p=[],print=function(){__p.push.apply(__p,arguments);};","with(obj||{}){__p.push('",e.replace(o,function(e){return"\\"+r[e]}).replace(n.normal||s,function(e,t){return"',\nobj['"+i(t)+"'],\n'"}).replace(n.evaluate||s,function(e,t){return"');\n"+i(t)+"\n;__p.push('"}),"');\n}\nreturn __p.join('');"].join(""),f=new Function("obj","_",a);return t?f(t):(u=function(e){return f.call(this,e)},u.source="function(obj){\n"+a+"\n}",u)}}),e};typeof define=="function"&&define.amd?define("epitome-template",["./epitome"],t):e.Epitome=t(e)}(this),function(e){var t=function(e){return e.View=new Class({Implements:[Options,Events],element:null,collection:null,model:null,options:{template:"",events:{}},initialize:function(e){return e&&e.collection&&(this.setCollection(e.collection),delete e.collection),e&&e.model&&(this.setModel(e.model),delete e.model),this.setOptions(e),this.options.element&&(this.setElement(this.options.element,this.options.events),delete this.options.element),this.fireEvent("ready")},setElement:function(e,t){return this.element&&this.detachEvents()&&this.destroy(),this.element=document.id(e),t&&this.attachEvents(t),this},setCollection:function(t){var n=this,r=function(e){return function(){n.fireEvent(e+":collection",arguments)}};return instanceOf(t,e.Collection)&&(this.collection=t,this.collection.addEvents({change:r("change"),fetch:r("fetch"),add:r("add"),remove:r("remove"),sort:r("sort"),reset:r("reset")})),this},setModel:function(t){var n=this,r=function(e){return function(){n.fireEvent(e+":model",arguments)}};return instanceOf(t,e.Model)&&(this.model=t,this.model.addEvents({change:r("change"),destroy:r("destroy"),empty:r("empty")})),this},attachEvents:function(e){var t=this;return Object.each(e,function(e,n){t.element.addEvent(n,function(n){t.fireEvent(e,arguments)})}),this.element.store("attachedEvents",e),this},detachEvents:function(){var e=this.element.retrieve("attachedEvents");return e&&this.element.removeEvents(e).eliminate("attachedEvents"),this},template:function(t,n){n=n||this.options.template;var r=this.Template||(this.Template=new e.Template);return r.template(n,t)},render:function(){return this.fireEvent("render")},empty:function(e){return e?this.element.empty():this.element.set("html",""),this.fireEvent("empty")},dispose:function(){return this.element.dispose(),this.fireEvent("dispose")},destroy:function(){return this.element.destroy(),this.fireEvent("destroy")}}),e};typeof define=="function"&&define.amd?define("epitome-view",["./epitome-template","./epitome-model","./epitome-collection"],t):e.Epitome=t(e)}(this),function(e){var t=function(e){var t="hashchange",n="on"+t in window,r=[window,document],i,s=function(e){var t={},n=/([^&=]+)=([^&]*)/g,r;while(r=n.exec(e))t[decodeURIComponent(r[1])]=decodeURIComponent(r[2]);return t};return Element.Events.hashchange={onAdd:function(){var e=location.hash,s=function(){if(e==location.hash)return;e=location.hash,r.invoke("fireEvent",t,e.indexOf("#")==0?e.substr(1):e)};n&&(window.onhashchange=s)||(i=s.periodical(100))},onRemove:function(){n&&(window.onhashchange=null)||clearInterval(i)}},e.Router=new Class({Implements:[Options,Events],options:{triggerOnLoad:!0},routes:{},boundEvents:{},initialize:function(e){var n=this;this.setOptions(e),this.options.routes&&(this.routes=this.options.routes),window.addEvent(t,function(e){var t=location.hash,r=t.split("?")[0],i=t.split("?")[1]||"",o=!0,u;for(u in n.routes){var a=[],f=n.normalize(u,a,!0,!1),l=f.exec(r),c=!1;if(l){o=!1,n.req=l[0];var h=l.slice(1),p={};Array.each(h,function(e,t){typeof a[t]!="undefined"&&(p[a[t].name]=e)}),n.route=u,n.param=p||{},n.query=i&&s(i),c=n.routes[u],n.fireEvent("before",c),c&&n.$events[c]?(n.fireEvent(c+":before"),n.fireEvent(c,Object.values(n.param))):n.fireEvent("error",["Route",c,"is undefined"].join(" ")),n.fireEvent("after",c),c&&n.fireEvent(c+":after");break}}o&&n.fireEvent("undefined")}),this.fireEvent("ready"),this.options.triggerOnLoad&&window.fireEvent(t)},navigate:function(e,n){location.hash==e&&n?window.fireEvent(t):location.hash=e},normalize:function(e,t,n,r){return e instanceof RegExp?e:(e=e.concat(r?"":"/?").replace(/\/\(/g,"(?:/").replace(/(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?/g,function(e,n,r,i,s,o){return t.push({name:i,optional:!!o}),n=n||"",[o?"":n,"(?:",o?n:"",(r||"")+(s||r&&"([^/.]+?)"||"([^/]+?)")+")",o||""].join("")}).replace(/([\/.])/g,"\\$1").replace(/\*/g,"(.*)"),new RegExp("^"+e+"$",n?"":"i"))},addRoute:function(e){return!e||!e.route||!e.id||!e.events?this.fireEvent("error","Please include route, id and events in the argument object when adding a route"):e.id.length?this.routes[e.route]?this.fireEvent("error",'Route "{route}" or id "{id}" already exists, aborting'.substitute(e)):(this.routes[e.route]=e.id,this.addEvents(this.boundEvents[e.route]=e.events),this.fireEvent("route:add",e)):this.fireEvent("error","Route id cannot be empty, aborting")},removeRoute:function(e){return!e||!this.routes[e]||!this.boundEvents[e]?this.fireEvent("error","Could not find route or route is not removable"):(this.removeEvents(this.boundEvents[e]),delete this.routes[e],delete this.boundEvents[e],this.fireEvent("route:remove",e))}}),e};typeof define=="function"&&define.amd?define("epitome-router",["./epitome"],t):e.Epitome=t(e)}(this)
+(function(t){var e=function(){return{}};"function"==typeof define&&define.amd?define("epitome",e):t.Epitome=e(t)})(this),function(t){var e=function(){var t=function(e,n,i){if(i=i||[],e===n)return 0!==e||1/e==1/n;if(null==e||null==n)return e===n;var o=typeOf(e),r=typeOf(n);if(o!=r)return!1;switch(o){case"string":return e==n+"";case"number":return e!=+e?n!=+n:0==e?1/e==1/n:e==+n;case"date":case"boolean":return+e==+n;case"regexp":return e.source==n.source&&e.global==n.global&&e.multiline==n.multiline&&e.ignoreCase==n.ignoreCase}if("object"!=typeof e||"object"!=typeof n)return!1;for(var s=i.length;s--;)if(i[s]==e)return!0;i.push(e);var u=0,a=!0;if("array"==o){if(u=e.length,a=u==n.length)for(;u--&&(a=u in e==u in n&&t(e[u],n[u],i)););}else{if("constructor"in e!="constructor"in n||e.constructor!=n.constructor)return!1;for(var c in e)if(e.hasOwnProperty(c)&&(u++,!(a=n.hasOwnProperty(c)&&t(e[c],n[c],i))))break;if(a){for(c in n)if(n.hasOwnProperty(c)&&!u--)break;a=!u}}return i.pop(),a};return t};"function"==typeof define&&define.amd?define("epitome-isequal",["./epitome"],e):(t.Epitome=t.Epitome||{},t.Epitome.isEqual=e(t.Epitome))}(this),function(t){var e=function(t){return new Class({Implements:[Options,Events],_attributes:{},properties:{id:{get:function(){var t=this._attributes.id||String.uniqueID();return this.cid||(this.cid=t),this._attributes.id}}},validators:{},options:{defaults:{}},collections:[],initialize:function(t,e){return e&&e.defaults&&(this.options.defaults=Object.merge(this.options.defaults,e.defaults)),t=t&&"object"===typeOf(t)?t:{},this.set(Object.merge(this.options.defaults,t)),this.setOptions(e),this.fireEvent("ready")},set:function(){this.propertiesChanged=this.validationFailed=[],this._set.apply(this,arguments),this.propertiesChanged.length&&this.fireEvent("change",this.get(this.propertiesChanged)),this.validationFailed.length&&this.fireEvent("error",[this.validationFailed])},_set:function(e,n){if(!e||n===void 0)return this;if(this.properties[e]&&this.properties[e].set)return this.properties[e].set.call(this,n);if(this._attributes[e]&&t(this._attributes[e],n))return this;var i=this.validate(e,n);if(this.validators[e]&&i!==!0){var o={};return o[e]={key:e,value:n,error:i},this.validationFailed.push(o),this.fireEvent("error:"+e,o[e]),this}return null===n?delete this._attributes[e]:this._attributes[e]=n,this.fireEvent("change:"+e,n),this.propertiesChanged.push(e),this}.overloadSetter(),get:function(t){return t&&this.properties[t]&&this.properties[t].get?this.properties[t].get.call(this):t&&this._attributes[t]!==void 0?this._attributes[t]:null}.overloadGetter(),unset:function(){var t=Array.prototype.slice.apply(arguments),e={},n=t.length;return n?(Array.each(Array.flatten(t),function(t){e[t]=null}),this.set(e),this):this},toJSON:function(){return Object.clone(this._attributes)},empty:function(){var t=Object.keys(this.toJSON()),e=this;this.fireEvent("change",[t]),Array.each(t,function(t){e.fireEvent("change:"+t,null)},this),this._attributes={},this.fireEvent("empty")},destroy:function(){this._attributes={},this.fireEvent("destroy")},validate:function(t,e){return t in this.validators?this.validators[t].call(this,e):!0}})};"function"==typeof define&&define.amd?define("epitome-model",["./epitome-isequal"],e):(t.Epitome=t.Epitome||{isEqual:{}},t.Epitome.Model=e(t.Epitome.isEqual))}(this),function(t){var e=new Class({Extends:Request,options:{secure:!0},initialize:function(t){this.parent(t),Object.append(this.headers,{Accept:"application/json","X-Request":"JSON"})},success:function(t){var e;try{e=this.response.json=JSON.decode(t,this.options.secure)}catch(n){return this.fireEvent("error",[t,n]),void 0}t&&null==e&&204!=this.status?this.onFailure():this.onSuccess(e,t)}}),n=function(t){var n="sync:",i={create:"POST",read:"GET",update:"PUT",delete_:"DELETE"};return new Class({Extends:t,properties:{urlRoot:{set:function(t){this.urlRoot=t,delete this._attributes.urlRoot},get:function(){var t=this.urlRoot||this.options.urlRoot||"no-urlRoot-set";return"/"!=t.charAt(t.length-1)&&(t+="/"),t}}},options:{emulateREST:!1,useJSON:!1},initialize:function(t,e){this.setupSync(),this.parent(t,e)},sync:function(t,e){var n={};return t=t&&i[t]?i[t]:i.read,n.method=t,(t==i.create||t==i.update)&&(n.data=e||this.toJSON(),this.preProcessor&&(n.data=this.preProcessor(n.data))),this.options.useJSON&&["POST","PUT","DELETE"].contains(t)?(n.data=JSON.encode(n.data),n.urlEncoded=!1,this.request.setHeader("Content-type","application/json")):n.urlEncoded=!0,n.url=[this.get("urlRoot"),this.get("id")].join(""),"/"!==n.url.slice(-1)&&(n.url+="/"),this.request.setOptions(n),this.request[t](e),this},setupSync:function(){var t=this,o=0,r=function(){o++};return this.getRequestId=function(){return o+1},this.request=new e({link:"chain",url:this.get("urlRoot"),emulation:this.options.emulateREST,onRequest:r,onCancel:function(){this.removeEvents(n+o)},onSuccess:function(e){e=t.postProcessor&&t.postProcessor(e),t.fireEvent(n+o,[e]),t.fireEvent("sync",[e,this.options.method,this.options.data]),t.isNewModel=!1},onFailure:function(){t.fireEvent(n+"error",[this.options.method,this.options.url,this.options.data]),t.fireEvent("requestFailure",[this.status,this.response.text])}}),Object.each(i,function(e,n){t[n]=function(t){this.sync(n,t)}}),this},_throwAwaySyncEvent:function(t,e){t=t||n+this.getRequestId();var i=this,o={};return o[t]=function(t){t&&"object"==typeof t&&i.set(t),e&&e.call(i,t),i.removeEvents(o)},this.addEvents(o)}.protect(),postProcessor:function(t){return t},preProcessor:function(t){return t},fetch:function(){return this._throwAwaySyncEvent(n+this.getRequestId(),function(){this.fireEvent("fetch"),this.isNewModel=!1}),this.read(),this},save:function(t,e){var i=["update","create"][+this.isNew()];if(t){var o=typeOf(t),r="object"==o||"string"==o&&e!==void 0;r&&this._set.apply(this,arguments)}return this._throwAwaySyncEvent(n+this.getRequestId(),function(){this.fireEvent("save"),this.fireEvent(i)}),this[i](),this},destroy:function(){this._throwAwaySyncEvent(n+this.getRequestId(),function(){this._attributes={},this.fireEvent("destroy")}),this.delete_()},isNew:function(){return this.isNewModel===void 0&&(this.isNewModel=!this.get("id")),this.isNewModel}})};"function"==typeof define&&define.amd?define("epitome-model-sync",["./epitome-model"],n):(t.Epitome=t.Epitome||{Model:{}},t.Epitome.Model.Sync=n(t.Epitome.Model))}(this),function(t){var e=function(){var e=function(){var e=!("object"!=typeof t.localStorage||!t.localStorage.getItem),n="localStorage",i="sessionStorage",o=function(n){var i,o="epitome-"+n,r={},s="model";if(e)try{r=JSON.decode(t[n].getItem(o))||r}catch(u){e=!1}if(!e)try{i=JSON.decode(t.name),i&&"object"==typeof i&&i[o]&&(r=i[o])}catch(u){f()}var a={store:function(t){t=t||this.toJSON(),h([s,this.get("id")].join(":"),t),this.fireEvent("store",t)},eliminate:function(){return l([s,this.get("id")].join(":")),this.fireEvent("eliminate")},retrieve:function(){var t=c([s,this.get("id")].join(":"))||null;return this.fireEvent("retrieve",t),t}},c=function(t){return r[t]||null},h=function(i,s){if(r=e?JSON.decode(t[n].getItem(o))||r:r,r[i]=s,e)try{t[n].setItem(o,JSON.encode(r))}catch(u){}else f();return this},l=function(i){if(delete r[i],e)try{t[n].setItem(o,JSON.encode(r))}catch(s){}else f()},f=function(){var e={},n=JSON.decode(t.name);e[o]=r,t.name=JSON.encode(Object.merge(e,n))};return function(t){return t&&(s=t),new Class(Object.clone(a))}};return{localStorage:o(n),sessionStorage:o(i)}}();return e};"function"==typeof define&&define.amd?define("epitome-storage",["./epitome"],e):(t.Epitome=t.Epitome||{},t.Epitome.Storage=e(t))}(this),function(t){var e=function(e){var n=["forEach","each","invoke","filter","map","some","indexOf","contains","getRandom","getLast"];Function.extend({monitorModelEvents:function(t,e){var n=this;return e=e||this,t&&t.fireEvent&&!t.hasOwnProperty("fireEvent")?function(i,o,r){n.apply(e,arguments),t.getModelByCID(e.cid)&&t.fireEvent(i,Array.flatten([e,o]),r)}:this}});var i=new Class({Implements:[Options,Events],model:e,_models:[],initialize:function(t,e){return this.setOptions(e),t&&this.setUp(t),this.id=this.options.id||String.uniqueID(),this.fireEvent("ready")},setUp:function(t){return t=Array.from(t),Array.each(t,this.addModel.bind(this)),this.addEvent("destroy",this.removeModel.bind(this)),this},addModel:function(t,e){var n;return"object"!=typeOf(t)||instanceOf(t,this.model)||(t=new this.model(t)),t.cid=t.cid||t.get("id")||String.uniqueID(),n=this.getModelByCID(t.cid),n&&e!==!0?this.fireEvent("add:error",t):(n&&e===!0&&(this._models[this._models.indexOf(t)]=t),t.fireEvent=Function.monitorModelEvents.apply(t.fireEvent,[this,t]),this._models.push(t),t.collections.include(this),this.length=this._models.length,this.fireEvent("add",[t,t.cid]).fireEvent("reset",[t,t.cid]))},removeModel:function(t,e){var n=this;return t=Array.from(t).slice(),Array.each(t,function(t){t.collections.erase(n),t.collections.length||delete t.fireEvent,Array.erase(n._models,t),n.length=n._models.length,e||n.fireEvent("remove",[t,t.cid])}),this.fireEvent("reset",[t])},get:function(t){return this[t]},getModelByCID:function(t){var e=null;return this.some(function(n){return n.cid==t&&(e=n)}),e},getModelById:function(t){var e=null;return this.some(function(n){return n.get("id")==t&&(e=n)}),e},getModel:function(t){return this._models[t]},toJSON:function(){var t=function(t){return t.toJSON()};return Array.map(this._models,t)},empty:function(t){return this.removeModel(this._models,t),this.fireEvent("empty")},sort:function(t){if(!t)return this._models.sort(),this.fireEvent("sort");if("function"==typeof t)return this.model.sort(t),this.fireEvent("sort");var e="asc",n=t.split(","),i=function(t,e){return e>t?-1:t>e?1:0};return this._models.sort(function(t,o){var r=0;return Array.some(n,function(n){n=n.trim();var s=n.split(":"),u=s[0],a=s[1]?s[1]:e,c=t.get(u),h=o.get(u),l=i(c,h),f={asc:l,desc:-l};return f[a]===void 0&&(a=e),r=f[a],0!=r}),r}),this.fireEvent("sort")},reverse:function(){return Array.reverse(this._models),this.fireEvent("sort")},find:function(e){var n=t.Slick.parse(e),i=[],o=this,r={"=":function(t,e){return t==e},"!=":function(t,e){return t!=e},"^=":function(t,e){return 0===t.indexOf(e)},"*=":function(t,e){return-1!==t.indexOf(e)},"$=":function(t,e){return t.indexOf(e)==t.length-e.length},"*":function(t){return t!==void 0}},s=function(t){return t&&r[t]?r[t]:null},u=function(t){var e=t.key,n=t.value||null,i=t.tag||null,r=s(t.operator);o=o.filter(function(t){var o,s;return i&&e?(o=t.get(i),s=o?o[e]:null):s=i?t.get(i):t.get(e),null!==s&&null!==n&&null!==r?r(s,n):null!=s})};if(n.expressions.length){var a,c,h,l,f,d,p,v,m=n.expressions;t:for(c=0;l=m[c];c++){for(a=0;f=l[a];a++){if(h=f.attributes,d=f.id,d&&(p={key:"id",value:d,operator:"="},h||(h=[]),h.push(p)),v=f.tag,v&&"*"!=v&&(h||(h=[{key:null,value:"",operator:"*"}]),h=Array.map(h,function(t){return t.tag=v,t})),!h)continue t;Array.each(h,u)}i[c]=o,o=this}}return[].combine(Array.flatten(i))},findOne:function(t){var e=this.find(t);return e.length?e[0]:null}});return Array.each(n,function(t){i.implement(t,function(){return Array.prototype[t].apply(this._models,arguments)})}),i};"function"==typeof define&&define.amd?define("epitome-collection",["./epitome-model"],e):(t.Epitome=t.Epitome||{Model:{}},t.Epitome.Collection=e(t.Epitome.Model))}(this),function(t){var e=function(t){var e="no-urlRoot-set",n="fetch:";return new Class({Extends:t,options:{urlRoot:e},initialize:function(t,e){this.setupSync(),this.parent(t,e)},setupSync:function(){var t=this,e=0,i=function(){e++};return this.getRequestId=function(){return e+1},this.request=new Request.JSON({link:"chain",url:this.options.urlRoot,emulation:this.options.emulateREST,onRequest:i,onCancel:function(){this.removeEvents(n+e)},onSuccess:function(i){i=t.postProcessor&&t.postProcessor(i),t.fireEvent(n+e,[[i]])},onFailure:function(){t.fireEvent(n+"error",[this.options.method,this.options.url,this.options.data])}}),this},parse:function(t){return t},fetch:function(t){return this._throwAwayEvent(function(e){t?(this.empty(),Array.each(e,this.addModel.bind(this))):this.processModels(e),this.fireEvent("fetch",[e])}),this.request.get(),this},processModels:function(t){var e=this;Array.each(t,function(t){var n=t.id&&e.getModelById(t.id);n?n.set(t):e.addModel(t)})},_throwAwayEvent:function(t){var e=n+this.getRequestId(),i=this,o={};if(t&&"function"==typeof t)return o[e]=function(e){t.apply(i,e),i.removeEvents(o)},this.addEvents(o)}.protect(),postProcessor:function(t){return t}})};"function"==typeof define&&define.amd?define("epitome-collection-sync",["./epitome-collection"],e):(t.Epitome=t.Epitome||{Collection:{}},t.Epitome.Collection.Sync=e(t.Epitome.Collection))}(this),function(t){(function(){var t={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#x27;","/":"&#x2F;"},e=RegExp("["+Object.keys(t).join("")+"]","g");String.implement({escape:function(){return(this+"").replace(e,function(e){return t[e]})}})})();var e=function(){return new Class({options:{evaluate:/<%([\s\S]+?)%>/g,normal:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g,noMatch:/.^/,escaper:/\\|'|\r|\n|\t|\u2028|\u2029/g},Implements:[Options],initialize:function(t){this.setOptions(t);var e=this.escapes={"\\":"\\","'":"'",r:"\r",n:"\n",t:" ",u2028:"\u2028",u2029:"\u2029"};return Object.each(e,function(t,e){this[t]=e},e),this.matcher=RegExp([(this.options.escape||this.options.noMatch).source,(this.options.normal||this.options.noMatch).source,(this.options.evaluate||this.options.noMatch).source].join("|")+"|$","g"),this},template:function(t,e,n){var i,o=n?Object.merge(this.options,n):this.options,r=this.escapes,s=o.escaper,u=0,a="__p+='";t.replace(this.matcher,function(e,n,i,o,c){return a+=t.slice(u,c).replace(s,function(t){return"\\"+r[t]}),n&&(a+="'+\n((__t=(obj['"+n+"']))==null?'':String.escape(__t))+\n'"),i&&(a+="'+\n((__t=(obj['"+i+"']))==null?'':__t)+\n'"),o&&(a+="';\n"+o+"\n__p+='"),u=c+e.length,e}),a+="';\n",o.variable||(a="obj=obj||{};with(obj){\n"+a+"}\n"),a="var __t,__p='',__j=Array.prototype.join,print=function(){__p+=__j.call(arguments,'');};\n"+a+"return __p;\n";try{i=Function(o.variable||"obj",a)}catch(c){throw c.source=a,c}if(e)return i(e);var h=function(t){return i.call(this,t)};return h.source="function("+(o.variable||"obj")+"){\n"+a+"}",h}})};"function"==typeof define&&define.amd?define("epitome-template",["./epitome"],e):(t.Epitome=t.Epitome||{},t.Epitome.Template=e(t.Epitome))}(this),function(t){var e=function(t,e,n){return new Class({Implements:[Options,Events],element:null,collection:null,model:null,options:{template:"",events:{}},initialize:function(t){return t&&t.collection&&(this.setCollection(t.collection),delete t.collection),t&&t.model&&(this.setModel(t.model),delete t.model),this.setOptions(t),this.options.element&&(this.setElement(this.options.element,this.options.events),delete this.options.element),this.fireEvent("ready")},setElement:function(t,e){return this.element&&this.detachEvents()&&this.destroy(),this.element=document.id(t),e&&this.attachEvents(e),this},setCollection:function(t){var e=this,i=function(t){return function(){e.fireEvent(t+":collection",arguments)}};return instanceOf(t,n)&&(this.collection=t,this.collection.addEvents({change:i("change"),fetch:i("fetch"),add:i("add"),remove:i("remove"),sort:i("sort"),reset:i("reset"),error:i("error")})),this},setModel:function(t){var n=this,i=function(t){return function(){n.fireEvent(t+":model",arguments)}};return instanceOf(t,e)&&(this.model=t,this.model.addEvents({change:i("change"),destroy:i("destroy"),empty:i("empty"),error:i("error")})),this},attachEvents:function(t){var e=this;return Object.each(t,function(t,n){e.element.addEvent(n,function(){e.fireEvent(t,arguments)})}),this.element.store("attachedEvents",t),this},detachEvents:function(){var t=this.element.retrieve("attachedEvents");return t&&this.element.removeEvents(t).eliminate("attachedEvents"),this},template:function(e,n){n=n||this.options.template;var i=this.Template||(this.Template=new t);return i.template(n,e)},render:function(){return this.fireEvent("render")},empty:function(t){return t?this.element.empty():this.element.set("html",""),this.fireEvent("empty")},dispose:function(){return this.element.dispose(),this.fireEvent("dispose")},destroy:function(){return this.element.destroy(),this.fireEvent("destroy")}})};"function"==typeof define&&define.amd?define("epitome-view",["./epitome-template","./epitome-model","./epitome-collection"],e):(t.Epitome=t.Epitome||{Template:{},Model:{},Collection:{}},t.Epitome.View=e(t.Epitome.Template,t.Epitome.Model,t.Epitome.Collection))}(this),function(t){var e=function(){var t,e="hashchange",n="on"+e in window,i=[window,document],o=function(t){for(var e,n={},i=/([^&=]+)=([^&]*)/g;e=i.exec(t);)n[decodeURIComponent(e[1])]=decodeURIComponent(e[2]);return n};return Element.Events.hashchange={onAdd:function(){var o=location.hash,r=function(){o!=location.hash&&(o=location.hash,i.invoke("fireEvent",e,0==o.indexOf("#")?o.substr(1):o))};n&&(window.onhashchange=r)||(t=r.periodical(100))},onRemove:function(){n&&(window.onhashchange=null)||clearInterval(t)}},new Class({Implements:[Options,Events],options:{triggerOnLoad:!0},routes:{},boundEvents:{},initialize:function(t){var n=this;this.setOptions(t),this.options.routes&&(this.routes=this.options.routes),window.addEvent(e,function(){var t,e=location.hash,i=e.split("?")[0],r=e.split("?")[1]||"",s=!0;for(t in n.routes){var u=[],a=n.normalize(t,u,!0,!1),c=a.exec(i),h=!1;if(c){s=!1,n.req=c[0];var l=c.slice(1),f={};Array.each(l,function(t,e){u[e]!==void 0&&(f[u[e].name]=t)}),n.route=t,n.param=f||{},n.query=r&&o(r),h=n.routes[t],n.fireEvent("before",h),h&&n.$events[h]?(n.fireEvent(h+":before"),n.fireEvent(h,Object.values(n.param))):n.fireEvent("error",["Route",h,"is undefined"].join(" ")),n.fireEvent("after",h),h&&n.fireEvent(h+":after");break}}s&&n.fireEvent("undefined")}),this.fireEvent("ready"),this.options.triggerOnLoad&&window.fireEvent(e)},navigate:function(t,n){location.hash==t&&n?window.fireEvent(e):location.hash=t},normalize:function(t,e,n,i){return t instanceof RegExp?t:(t=t.concat(i?"":"/?").replace(/\/\(/g,"(?:/").replace(/(\/)?(\.)?:(\w+)(?:(\(.*?\)))?(\?)?/g,function(t,n,i,o,r,s){return e.push({name:o,optional:!!s}),n=n||"",[s?"":n,"(?:",s?n:"",(i||"")+(r||i&&"([^/.]+?)"||"([^/]+?)")+")",s||""].join("")}).replace(/([\/.])/g,"\\$1").replace(/\*/g,"(.*)"),RegExp("^"+t+"$",n?"":"i"))},addRoute:function(t){return t&&t.route&&t.id&&t.events?t.id.length?this.routes[t.route]?this.fireEvent("error",'Route "{route}" or id "{id}" already exists, aborting'.substitute(t)):(this.routes[t.route]=t.id,this.addEvents(this.boundEvents[t.route]=t.events),this.fireEvent("route:add",t)):this.fireEvent("error","Route id cannot be empty, aborting"):this.fireEvent("error","Please include route, id and events in the argument object when adding a route")},removeRoute:function(t){return t&&this.routes[t]&&this.boundEvents[t]?(this.removeEvents(this.boundEvents[t]),delete this.routes[t],delete this.boundEvents[t],this.fireEvent("route:remove",t)):this.fireEvent("error","Could not find route or route is not removable")}})};"function"==typeof define&&define.amd?define("epitome-router",["./epitome"],e):(t.Epitome=t.Epitome||{},t.Epitome.Router=e(t.Epitome))}(this);
Something went wrong with that request. Please try again.