<p>Created by <ahref="http://rhysbrettbowen.com">Rhys Brett-Bowen</a> (<ahref="https://twitter.com/RhysBB">RhysBB</a>)</p>
<p>Using <ahref="https://github.com/rhysbrettbowen/PlastronJS">PlastronJS</a> and <ahref="https://developers.google.com/closure/">Closure Tools</a></p>
<p>Part of <ahref="http://todomvc.com">TodoMVC</a></p>
n.appendChild=function(a,b){a.appendChild(b)};n.contains=Ub;functionVb(a){C.call(this);this.$b=a;this.Ta=[]}B(Vb,C);varWb=[];functionXb(a,b,c,d,e){u(c)||(Wb[0]=c,c=Wb);for(varf=0;f<c.length;f++){varh=U(b,c[f],d||a,e||m,a.$b||a);a.Ta.push(h)}returna}functionYb(a){F(a.Ta,vb);a.Ta.length=0}Vb.prototype.m=function(){Vb.d.m.call(this);Yb(this)};Vb.prototype.handleEvent=function(){g(Error("EventHandler.handleEvent not implemented"))};functionZb(a,b){P.call(this,"navigate");this.Cc=a;this.xc=b}B(Zb,P);function$b(a,b,c,d){C.call(this);a&&!b&&g(Error("Can't use invisible history without providing a blank page."));vare;c?e=c:(e="history_state"+ac,document.write(ma(bc,e,e)),e=Nb(e));this.ra=e;this.h=c?Mb(c)?Mb(c).parentWindow||Mb(c).defaultView:window:window;this.Ob=this.h.location.href.split("#")[0];this.sa=b;M&&!b&&(this.sa="https"==window.location.protocol?"https:///":'javascript:""');this.k=newzb(cc);this.X=!a;this.L=newVb(this);if(a||dc)d?a=d:(a="history_iframe"+ac,b=this.sa?'src="'+pa(this.sa)+
qc.prototype.fc=function(){vara=this.ca.z();a!=this.Ra&&(this.dispatchEvent({type:"routeExpired",Ac:this.Ra,vc:a}),this.Ra=a,za(this.Cb||[],function(b){varc=b.ja.exec(a);c?(b.Sb.apply(b.Wb,c),b=j):b=m;returnb},this))};functionW(){}W.sb=function(){returnW.vb?W.vb:W.vb=newW};W.prototype.dc=0;W.sb();functionrc(a){C.call(this);this.aa=a||Jb();this.nc=sc}B(rc,V);rc.prototype.ac=W.sb();varsc=k;n=rc.prototype;n.R=k;n.g=m;n.f=k;n.nc=k;n.c=k;n.r=k;n.b=k;n.l=k;n.Kb=m;functiontc(a){returna.R||(a.R=":"+(a.ac.dc++).toString(36))}n.v=function(){returnthis.f};n.eb=function(a){this.f=a};functionuc(a,b){a==b&&g(Error("Unable to set parent component"));b&&(a.r&&a.R&&a.r.l&&a.R&&(a.Rina.r.l&&a.r.l[a.R])&&a.r!=b)&&g(Error("Unable to set parent component"));a.r=b;rc.d.gb.call(a,b)}n.getParent=function(){returnthis.r};
n.gb=function(a){this.r&&this.r!=a&&g(Error("Method not supported"));rc.d.gb.call(this,a)};n.N=function(){this.f=this.aa.createElement("div")};functionvc(a,b,c){a.g&&g(Error("Component already rendered"));a.f||a.N();b?b.insertBefore(a.f,c||k):a.aa.O.body.appendChild(a.f);(!a.r||a.r.g)&&a.C()}n.C=function(){this.g=j;xc(this,function(a){!a.g&&a.v()&&a.C()})};functionyc(a){xc(a,function(a){a.g&&yc(a)});a.Q&&Yb(a.Q);a.g=m}
n.Z=function(a,b,c){a.g&&(c||!this.g)&&g(Error("Component already rendered"));(0>b||b>(this.b?this.b.length:0))&&g(Error("Child component index out of bounds"));if(!this.l||!this.b)this.l={},this.b=[];if(a.getParent()==this){vard=tc(a);this.l[d]=a;Ca(this.b,a)}elsemb(this.l,tc(a),a);uc(a,this);Ea(this.b,b,0,a);a.g&&this.g&&a.getParent()==this?(c=this.D(),c.insertBefore(a.v(),c.childNodes[b]||k)):c?(this.f||this.N(),b=this.b?this.b[b+1]||k:k,vc(a,this.D(),b?b.f:k)):this.g&&(!a.g&&a.f&&a.f.parentNode)&&
a.C()};n.D=function(){returnthis.f};functionxc(a,b){a.b&&F(a.b,b,i)}n.removeChild=function(a,b){if(a){varc=v(a)?a:tc(a),a=this.l&&c?(cinthis.l?this.l[c]:i)||k:k;c&&a&&(lb(this.l,c),Ca(this.b,a),b&&(yc(a),a.f&&Tb(a.f)),uc(a,k))}a||g(Error("Child is not in parent component"));returna};functionzc(){zc.d.constructor.apply(this,L(arguments,0));this.q={Va:{},F:{}}}B(zc,rc);n=zc.prototype;n.remove=function(){Tb(this.v());this.o()};n.Yb=function(a,b){if(this.q.F[a]){varc=b.target;F(this.q.F[a],function(a){b.target=c;if(!b.H&&(!a.Db.length||ya(a.Db,function(a){if(w(a))returna(b);if(a=za(X(this,a),function(a){returnUb(a,b.target)}))b.target=a;returna},this)))a.M.call(a.ba,b),a.stop&&b.stopPropagation()},this)}};
n.Z=function(a,b,c){if(M&&!O(9))zc.d.Z.call(this,a,b,c);else{a.g&&(c||!this.g)&&g(Error("Component already rendered"));(0>b||b>(this.b?this.b.length:0))&&g(Error("Child component index out of bounds"));if(!this.l||!this.b)this.l={},this.b=[];if(a.getParent()==this){vard=tc(a);this.l[d]=a;Ca(this.b,a)}elsemb(this.l,tc(a),a);uc(a,this);Ea(this.b,b,0,a);if(c&&(!a.bc||!this.bc||a.getParent!=this))this.f||this.N(),d=this.b?this.b[b+1]||k:k,vc(a,this.D(),d?d.f:k);if(a.g&&this.g&&a.getParent()==this){vare=
n.Na=function(){Tc.d.Na.call(this);this.G[0]&&(F(K(this.Xa),function(a){a(this)},this),this.G[0]=m);this.K[0]&&(F(K(this.Ia),function(a){a(this)},this),this.i&&Q(this.i,function(a,b){a.va&&F(this.oa,function(a){H(a.A,b)&&a.M.apply(a.ub,J(G(a.A,function(a){returnthis.get(a)},this)))},this)},this),this.K[0]=m);F(this.bb,function(a){F(this.cb,function(b){a(b.n,b.id)})},this);Ba(this.cb);F(this.Ga,function(a){F(this.Ha,function(b){a(b)})},this);Ba(this.Ha)};functionUc(){};functionVc(a){this.ha=a;this.Eb=newJc}n=Vc.prototype;n.ha=k;n.Eb=k;n.set=function(a,b){s(b)?this.ha.set(a,Kc(this.Eb,b)):this.ha.remove(a)};n.get=function(a){a=this.ha.get(a);if(a!==k)try{returnIc(a)}catch(b){g("Storage: Invalid value was encountered")}};n.remove=function(a){this.ha.remove(a)};functionWc(){}B(Wc,Uc);functionXc(a){this.Ca=a}B(Xc,Wc);Xc.prototype.set=function(a,b){try{this.Ca.setItem(a,b)}catch(c){g("Storage mechanism: Quota exceeded")}};Xc.prototype.get=function(a){a=this.Ca.getItem(a);!v(a)&&a!==k&&g("Storage mechanism: Invalid value was encountered");returna};Xc.prototype.remove=function(a){this.Ca.removeItem(a)};functionYc(){vara=k;try{a=window.localStorage||k}catch(b){}this.Ca=a}B(Yc,Xc);functionZc(){this.Da=newVc(newYc)}Zc.prototype.create=function(a,b){varc;this.pb=this.pb||0;c=this.pb+++"|"+parseInt((newDate).getTime(),36);a.set("id",c);w(b)&&b.call(a,a)};Zc.prototype.Bb=function(a,b){a.set(this.Da.get(a.get("id")));w(b)&&b.call(a,a)};Zc.prototype.update=function(a,b){this.Da.set(a.get("id"),a.hb());w(b)&&b.call(a,a)};function$c(){Zc.call(this)}B($c,Zc);$c.prototype.Bb=function(a){varb=a.get("id"),b=this.Da.get(b)||[];F(b,function(b){b=newa.Ya(b);a.add(b,i,j)});a.$()};functionad(a){$.call(this,a);this.i.title=this.i.title||{};this.i.title.set=A(function(a){a=na(a);a.length||g(newQc);returna},this);this.tb=function(){this.o()}}B(ad,$);functionbd(){Tc.call(this,{id:"todos-plastronjs",sync:new$c,schema:{completed:{get:function(){returnthis.p("completed").length},va:j},allDone:{get:function(){returnthis.p().length===this.p("completed").length},set:function(a){F(this.p("none"),function(b){b.set("completed",a)})},va:j},active:{get:function(){returnthis.p().length-this.p("completed").length},va:j},total:{get:function(){returnthis.p().length},va:j}},modelType:ad});this.ka.Bb(this,i);this.ma(this.save)}B(bd,Tc);
varcd={none:function(){returnj},active:function(a){return!a.get("completed")},completed:function(a){returna.get("completed")}};bd.prototype.p=function(a){returnbd.d.p.call(this,cd[a||this.get("filter")])};bd.prototype.hb=function(){returnG(this.p("none"),function(a){returna.hb()})};vardd=newbd,ed=newHc(dd),fd=Nb("todoapp");ed.g&&g(Error("Component already rendered"));if(fd){ed.Kb=j;vargd;if(!(gd=!ed.aa))gd=ed.aa.O!=Mb(fd);gd&&(ed.aa=Jb(fd));ed.f=fd;ed.C()}elseg(Error("Invalid element to decorate"));varhd=newqc;hd.ja("{/}",function(){dd.set("filter","none")});hd.ja("/active",function(){dd.set("filter","active")});hd.ja("/completed",function(){dd.set("filter","completed")});})();
_If you have other helpful links to share, or find any of the links above no longer work, please [let us know](https://github.com/tastejs/todomvc/issues)._
## Running
The app is built with [Plovr](http://plovr.com). To run the unminified version you need to:
<ahref="examples/olives/"data-source="https://github.com/flams/olives"data-content="Olives is a JS MVC framework that helps you create realtime UIs. It includes a set of AMD/CommonJS modules that are easily extensive, a high level of abstraction to reduce boilerplate and is based on socket.io, to provide a powerful means to communicate with node.js.">Olives</a>
<ahref="examples/olives/"data-source="https://github.com/flams/olives"data-content="Olives is a JS MVC framework that helps you create realtime UIs. It includes a set of AMD/CommonJS modules that are easily extensive, a high level of abstraction to reduce boilerplate and is based on socket.io, to provide a powerful means to communicate with node.js.">Olives</a>
</li>
</li>
<liclass="routing">
<ahref="examples/plastronjs/"data-source="https://github.com/rhysbrettbowen/PlastronJS"data-content="PlastronJS is an mvc framework built on top of the Closure Library and built to compile with projects that use the Closure Compiler.">PlastronJS</a>
</li>
<li>
<li>
<ahref="examples/dijon/"data-source="https://github.com/creynders/dijon-framework"data-content="Dijon is an IOC and DI micro-framework for Javascript. Originally it was meant to be a port of Robotlegs, but deviated to something quite different. It remains however heavily inspired by Robotlegs, and more specifically Swiftsuspenders.">Dijon</a>
<ahref="examples/dijon/"data-source="https://github.com/creynders/dijon-framework"data-content="Dijon is an IOC and DI micro-framework for Javascript. Originally it was meant to be a port of Robotlegs, but deviated to something quite different. It remains however heavily inspired by Robotlegs, and more specifically Swiftsuspenders.">Dijon</a>
"description":"Polymer is a new type of library for the web, built on top of Web Components, and designed to leverage the evolving web platform on modern browsers. It is comprised of core platform features (e.g Shadow DOM, Custom Elements, MDV) enabled with polyfills and a next generation web application framework built on these technologies.",
"description":"Polymer is a new type of library for the web, built on top of Web Components, and designed to leverage the evolving web platform on modern browsers. It is comprised of core platform features (e.g Shadow DOM, Custom Elements, MDV) enabled with polyfills and a next generation web application framework built on these technologies.",