Commit b7d1832a authored by TasteBot's avatar TasteBot

update the build files for gh-pages [ci skip]

parent ca4e845e
# editorconfig.org
root = true
[*]
indent_style = tab
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
[*.md]
trim_trailing_whitespace = false
node_modules
/bower_components
/dist
{
"requireCurlyBraces": ["if", "else", "for", "while", "do", "try", "catch"],
"requireSpaceAfterKeywords": ["if", "else", "for", "while", "do", "switch", "return", "try", "catch"],
"requireLeftStickedOperators": [","],
"requireParenthesesAroundIIFE": true,
"requireSpacesInFunctionExpression": {
"beforeOpeningCurlyBrace": true
},
"disallowSpaceAfterPrefixUnaryOperators": ["++", "--", "+", "-", "~", "!"],
"disallowSpaceBeforePostfixUnaryOperators": ["++", "--"],
"disallowEmptyBlocks": true,
"disallowSpacesInsideArrayBrackets": true,
"disallowSpacesInsideParentheses": true,
"disallowQuotedKeysInObjects": true,
"disallowSpaceAfterObjectKeys": true,
"requireCommaBeforeLineBreak": true,
"requireSpaceBeforeBinaryOperators": [
"+",
"-",
"/",
"*",
"=",
"==",
"===",
"!=",
"!=="
],
"requireSpaceAfterBinaryOperators": [
"+",
"-",
"/",
"*",
"=",
"==",
"===",
"!=",
"!=="
],
"requireCamelCaseOrUpperCaseIdentifiers": true,
"requireOperatorBeforeLineBreak": [
"?",
"+",
"-",
"/",
"*",
"=",
"==",
"===",
"!=",
"!==",
">",
">=",
"<",
"<="
],
"disallowLeftStickedOperators": [
"?",
"+",
"-",
"/",
"*",
"=",
"==",
"===",
"!=",
"!==",
">",
">=",
"<",
"<="
],
"disallowRightStickedOperators": [
"?",
"+",
"/",
"*",
":",
"=",
"==",
"===",
"!=",
"!==",
">",
">=",
"<",
"<="
],
"requireRightStickedOperators": ["!"],
"disallowImplicitTypeConversion": ["string"],
"disallowKeywords": ["with"],
"disallowMultipleLineStrings": true,
"disallowMultipleLineBreaks": true,
"validateLineBreaks": "LF",
"validateQuoteMarks": true,
"disallowMixedSpacesAndTabs": true,
"requireMultipleVarDecl": true,
"disallowTrailingWhitespace": true,
"disallowKeywordsOnNewLine": ["else"],
"maximumLineLength": 100,
"requireCapitalizedConstructors": true,
"safeContextKeyword": "self",
"requireDotNotation": true,
"requireLineFeedAtFileEnd": true,
"excludeFiles": [],
"validateJSDoc": {
"checkParamNames": true,
"requireParamTypes": true
}
}
{
"node": true,
"browser": true,
"esnext": true,
"bitwise": true,
"camelcase": true,
"curly": true,
"eqeqeq": true,
"immed": true,
"indent": 4,
"latedef": true,
"newcap": true,
"noarg": true,
"quotmark": "single",
"regexp": true,
"undef": true,
"unused": true,
"strict": true,
"trailing": true,
"smarttabs": true,
"white": true
}
# You must sign into travis-ci.org and set the commit hook on your project for travis to
# run on your project. The secure: variable must be generated by running `travis encrypt`
# on a github oauth key that you can generate using curl.
language:
node_js
node_js:
- 0.10
notifications:
irc: "irc.freenode.org#tastejs"
branches:
only:
- master
env:
global:
# GH_OAUTH_TOKEN is the oauth token generated as described at
# https://help.github.com/articles/creating-an-oauth-token-for-command-line-use
#
# curl -u 'username' -d '{"scopes":["repo"],"note":"push to gh-pages from travis"}' https://api.github.com/authorizations
#
# It must be encrypted using the travis gem
# http://about.travis-ci.org/docs/user/build-configuration/#Secure-environment-variables
#
# travis encrypt GH_OAUTH_TOKEN=XXXXXXXXXXXXXXX
#
# User specific env variables
- secure: "fHgfjMpYuliwMr2QLnjYZExIViNrxprf9dhXRBLZ6P9Hz7P6m1BMYrI/xEG8X+fFbCi0+n3AXh8SEMHi9ou/Pty/cx12z4w/z3B2BHMxh4XBwpZHs+AB4IXkLiwwWoP4QFy4vTipgYnMDMq9CRhlRbhZEpenQBmaTEc472By1uM="
- GH_OWNER: tastejs
- GH_PROJECT_NAME: todomvc
before_script:
# install dependencies
- npm install -g gulp
script:
# We want to gate on passing tests and a successful build
- gulp
after_success:
# Any command that using GH_OAUTH_TOKEN must pipe the output to /dev/null to not expose your oauth token
- git submodule add -b gh-pages https://${GH_OAUTH_TOKEN}@github.com/${GH_OWNER}/${GH_PROJECT_NAME} site > /dev/null 2>&1
- cd site
- if git checkout gh-pages; then git checkout -b gh-pages; fi
- git rm -r .
- cp -R ../dist/* .
- cp ../dist/.* .
- git add -f .
- git config user.email "travis@rdrei.net"
- git config user.name "TasteBot"
- git commit -am "update the build files for gh-pages [ci skip]"
# Any command that using GH_OAUTH_TOKEN must pipe the output to /dev/null to not expose your oauth token
- git push https://${GH_OAUTH_TOKEN}@github.com/${GH_OWNER}/${GH_PROJECT_NAME} HEAD:gh-pages > /dev/null 2>&1
# Application Specification
We have created this short spec to help you create awesome and consistent todo apps. Make sure to not only read it, but also understand.
## Template Application
Our [template](https://github.com/tastejs/todomvc/tree/gh-pages/template) should be used as the base when implementing a todo app. Before implementing, we recommend you interact with some of the other apps to see how they're built and how they behave. Check out the [Backbone app](http://todomvc.com/architecture-examples/backbone) if you need a reference implementation. If something is unclear or could be improved, [let us know](https://github.com/tastejs/todomvc/issues).
## Structure
### Directory Structure
Recommended file structure:
```
index.html
bower.json
bower_components/
css
└── app.css
js/
├── app.js
├── controllers/
└── models/
readme.md
```
Try to follow this structure as close a possible while still keeping to the framework’s best practices.
Components should be split up into separate files and placed into folders where it makes the most sense.
Example:
```
js/
├── app.js
├── controllers/
│ └── todos.js
└── models/
└── todo.js
```
Keep in mind that framework best practices on how to structure your app comes first.
### README
All examples should include a README describing the framework, the general implementation and the build process if required. There is an [example readme](https://github.com/tastejs/todomvc/blob/gh-pages/template/readme.md) included in the [template](https://github.com/tastejs/todomvc/tree/gh-pages/template).
### Dependency Management
Unless it conflicts with the project's best practices, your example should use [bower](http://bower.io/) for package management. Specify your dependencies in a `bower.json` file in the root directory of your app. The name of the component must follow the schema `todomvc-[framework]` and must include `todomvc-common` as dependency. An example `bower.json` could look like this:
```json
{
"name": "todomvc-sample",
"version": "0.0.0",
"dependencies": {
"underscore": "~1.5.0",
"jquery": "~2.0.0",
"todomvc-common": "~0.1.0"
}
}
```
The files in `bower_components/` should be limited to the files actually used by your example. That means documentation, READMEs and tests should not be included in the pull request.
### Code
Please try to keep the HTML as close to the template as possible. Remove the comments from the HTML when done. The `base.css` file should be referenced from the assets folder and not be touched. If you need to change some styles, use the `app.css` file, but try to keep it to a minimum. Remember to update the relative paths when using the template.
Make sure to follow these:
- Follow our [code style](https://github.com/tastejs/todomvc/blob/gh-pages/contributing.md#code-style)
- Use double-quotes in HTML and single-quotes in JS and CSS.
- Use bower components for your third-party dependencies and manually remove files that aren't required for your app to run.
- Use a constant instead of the keyCode directly: `var ENTER_KEY = 13;`
- Apps should be written without any preprocessors (Sass/CoffeeScript/..) to reach the largest audience.
- To make it easy to compare frameworks, the app should look and behave exactly like the template and the other examples.
- We require apps to work in every browser we [support](https://github.com/tastejs/todomvc/blob/gh-pages/contributing.md#browser-compatibility).
## Functionality
### No todos
When there are no todos, `#main` and `#footer` should be hidden.
### New todo
New todos are entered in the input at the top of the app. Pressing Enter creates the todo, appends it to the todo list and clears the input. Make sure to `.trim()` the input and then check that it's not empty before creating a new todo.
### Mark all as complete
This checkbox toggles all the todos to the same state as itself. Make sure to clear the checked state after the the "Clear completed" button is clicked. The "Mark all as complete" checkbox should also be updated when single todo items are checked/unchecked. Eg. When all the todos are checked it should also get checked.
### Item
A todo item has three possible interactions:
1. Clicking the checkbox marks the todo as complete by updating its `completed` value and toggling the class `completed` on its parent `<li>`
2. Double-clicking the `<label>` activates editing mode, by toggling the `.editing` class on its `<li>`
3. Hovering over the todo shows the remove button (`.destroy`)
### Editing
When editing mode is activated it will hide the other controls and bring forward an input that contains the todo title, which should be focused (`.focus()`). The edit should be saved on both blur and enter, and the `editing` class should be removed. Make sure to `.trim()` the input and then check that it's not empty. If it's empty the todo should instead be destroyed. If escape is pressed during the edit, the edit state should be left and any changes be discarded.
### Counter
Displays the number of active todos in a pluralized form. Make sure the number is wrapped by a `<strong>` tag. Also make sure to pluralize the `item` word correctly: `0 items`, `1 item`, `2 items`. Example: **2** items left
### Clear completed button
Displays the number of completed todos, and when clicked, removes them. Should be hidden when there are no completed todos.
### Persistence
Your app should dynamically persist the todos to localStorage. If the framework has capabilities for persisting data (i.e. Backbone.sync), use that, otherwise vanilla localStorage. If possible, use the keys `id`, `title`, `completed` for each item. Make sure to use this format for the localStorage name: `todos-[framework]`. Editing mode should not be persisted.
### Routing
Routing is required for all frameworks. Use the built-in capabilities if supported, otherwise use the [Flatiron Director](https://github.com/flatiron/director) routing library located in the `/assets` folder. The following routes should be implemented: `#/` (all - default), `#/active` and `#/completed` (`#!/` is also allowed). When the route changes the todo list should be filtered on a model level and the `selected` class on the filter links should be toggled. When an item is updated while in a filtered state, it should be updated accordingly. E.g. if the filter is `Active` and the item is checked, it should be hidden. Make sure the active filter is persisted on reload.
{
"name": "todomvc",
"dependencies": {
"jquery": "~2.1.0",
"bootstrap": "~3.2.0"
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
/*!
* Bootstrap v3.2.0 (http://getbootstrap.com)
* Copyright 2011-2014 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){return a(b.target).is(this)?b.handleObj.handler.apply(this,arguments):void 0}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.2.0",d.prototype.close=function(b){function c(){f.detach().trigger("closed.bs.alert").remove()}var d=a(this),e=d.attr("data-target");e||(e=d.attr("href"),e=e&&e.replace(/.*(?=#[^\s]*$)/,""));var f=a(e);b&&b.preventDefault(),f.length||(f=d.hasClass("alert")?d:d.parent()),f.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(f.removeClass("in"),a.support.transition&&f.hasClass("fade")?f.one("bsTransitionEnd",c).emulateTransitionEnd(150):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.2.0",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),d[e](null==f[b]?this.options[b]:f[b]),setTimeout(a.proxy(function(){"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")&&(c.prop("checked")&&this.$element.hasClass("active")?a=!1:b.find(".active").removeClass("active")),a&&c.prop("checked",!this.$element.hasClass("active")).trigger("change")}a&&this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target);d.hasClass("btn")||(d=d.closest(".btn")),b.call(d,"toggle"),c.preventDefault()})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b).on("keydown.bs.carousel",a.proxy(this.keydown,this)),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=this.sliding=this.interval=this.$active=this.$items=null,"hover"==this.options.pause&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.2.0",c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0},c.prototype.keydown=function(a){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.to=function(b){var c=this,d=this.getItemIndex(this.$active=this.$element.find(".item.active"));return b>this.$items.length-1||0>b?void 0:this.sliding?this.$element.one("slid.bs.carousel",function(){c.to(b)}):d==b?this.pause().cycle():this.slide(b>d?"next":"prev",a(this.$items[b]))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){return this.sliding?void 0:this.slide("next")},c.prototype.prev=function(){return this.sliding?void 0:this.slide("prev")},c.prototype.slide=function(b,c){var d=this.$element.find(".item.active"),e=c||d[b](),f=this.interval,g="next"==b?"left":"right",h="next"==b?"first":"last",i=this;if(!e.length){if(!this.options.wrap)return;e=this.$element.find(".item")[h]()}if(e.hasClass("active"))return this.sliding=!1;var j=e[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:g});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,f&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(e)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:g});return a.support.transition&&this.$element.hasClass("slide")?(e.addClass(b),e[0].offsetWidth,d.addClass(g),e.addClass(g),d.one("bsTransitionEnd",function(){e.removeClass([b,g].join(" ")).addClass("active"),d.removeClass(["active",g].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(1e3*d.css("transition-duration").slice(0,-1))):(d.removeClass("active"),e.addClass("active"),this.sliding=!1,this.$element.trigger(m)),f&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this},a(document).on("click.bs.carousel.data-api","[data-slide], [data-slide-to]",function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}}),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.collapse"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b);!e&&f.toggle&&"show"==b&&(b=!b),e||d.data("bs.collapse",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.transitioning=null,this.options.parent&&(this.$parent=a(this.options.parent)),this.options.toggle&&this.toggle()};c.VERSION="3.2.0",c.DEFAULTS={toggle:!0},c.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},c.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var c=a.Event("show.bs.collapse");if(this.$element.trigger(c),!c.isDefaultPrevented()){var d=this.$parent&&this.$parent.find("> .panel > .in");if(d&&d.length){var e=d.data("bs.collapse");if(e&&e.transitioning)return;b.call(d,"hide"),e||d.data("bs.collapse",null)}var f=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[f](0),this.transitioning=1;var g=function(){this.$element.removeClass("collapsing").addClass("collapse in")[f](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return g.call(this);var h=a.camelCase(["scroll",f].join("-"));this.$element.one("bsTransitionEnd",a.proxy(g,this)).emulateTransitionEnd(350)[f](this.$element[0][h])}}},c.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse").removeClass("in"),this.transitioning=1;var d=function(){this.transitioning=0,this.$element.trigger("hidden.bs.collapse").removeClass("collapsing").addClass("collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(d,this)).emulateTransitionEnd(350):d.call(this)}}},c.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()};var d=a.fn.collapse;a.fn.collapse=b,a.fn.collapse.Constructor=c,a.fn.collapse.noConflict=function(){return a.fn.collapse=d,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(c){var d,e=a(this),f=e.attr("data-target")||c.preventDefault()||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""),g=a(f),h=g.data("bs.collapse"),i=h?"toggle":e.data(),j=e.attr("data-parent"),k=j&&a(j);h&&h.transitioning||(k&&k.find('[data-toggle="collapse"][data-parent="'+j+'"]').not(e).addClass("collapsed"),e[g.hasClass("in")?"addClass":"removeClass"]("collapsed")),b.call(g,i)})}(jQuery),+function(a){"use strict";function b(b){b&&3===b.which||(a(e).remove(),a(f).each(function(){var d=c(a(this)),e={relatedTarget:this};d.hasClass("open")&&(d.trigger(b=a.Event("hide.bs.dropdown",e)),b.isDefaultPrevented()||d.removeClass("open").trigger("hidden.bs.dropdown",e))}))}function c(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.2.0",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=c(e),g=f.hasClass("open");if(b(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a('<div class="dropdown-backdrop"/>').insertAfter(a(this)).on("click",b);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus"),f.toggleClass("open").trigger("shown.bs.dropdown",h)}return!1}},g.prototype.keydown=function(b){if(/(38|40|27)/.test(b.keyCode)){var d=a(this);if(b.preventDefault(),b.stopPropagation(),!d.is(".disabled, :disabled")){var e=c(d),g=e.hasClass("open");if(!g||g&&27==b.keyCode)return 27==b.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.divider):visible a",i=e.find('[role="menu"]'+h+', [role="listbox"]'+h);if(i.length){var j=i.index(i.filter(":focus"));38==b.keyCode&&j>0&&j--,40==b.keyCode&&j<i.length-1&&j++,~j||(j=0),i.eq(j).trigger("focus")}}}};var h=a.fn.dropdown;a.fn.dropdown=d,a.fn.dropdown.Constructor=g,a.fn.dropdown.noConflict=function(){return a.fn.dropdown=h,this},a(document).on("click.bs.dropdown.data-api",b).on("click.bs.dropdown.data-api",".dropdown form",function(a){a.stopPropagation()}).on("click.bs.dropdown.data-api",f,g.prototype.toggle).on("keydown.bs.dropdown.data-api",f+', [role="menu"], [role="listbox"]',g.prototype.keydown)}(jQuery),+function(a){"use strict";function b(b,d){return this.each(function(){var e=a(this),f=e.data("bs.modal"),g=a.extend({},c.DEFAULTS,e.data(),"object"==typeof b&&b);f||e.data("bs.modal",f=new c(this,g)),"string"==typeof b?f[b](d):g.show&&f.show(d)})}var c=function(b,c){this.options=c,this.$body=a(document.body),this.$element=a(b),this.$backdrop=this.isShown=null,this.scrollbarWidth=0,this.options.remote&&this.$element.find(".modal-content").load(this.options.remote,a.proxy(function(){this.$element.trigger("loaded.bs.modal")},this))};c.VERSION="3.2.0",c.DEFAULTS={backdrop:!0,keyboard:!0,show:!0},c.prototype.toggle=function(a){return this.isShown?this.hide():this.show(a)},c.prototype.show=function(b){var c=this,d=a.Event("show.bs.modal",{relatedTarget:b});this.$element.trigger(d),this.isShown||d.isDefaultPrevented()||(this.isShown=!0,this.checkScrollbar(),this.$body.addClass("modal-open"),this.setScrollbar(),this.escape(),this.$element.on("click.dismiss.bs.modal",'[data-dismiss="modal"]',a.proxy(this.hide,this)),this.backdrop(function(){var d=a.support.transition&&c.$element.hasClass("fade");c.$element.parent().length||c.$element.appendTo(c.$body),c.$element.show().scrollTop(0),d&&c.$element[0].offsetWidth,c.$element.addClass("in").attr("aria-hidden",!1),c.enforceFocus();var e=a.Event("shown.bs.modal",{relatedTarget:b});d?c.$element.find(".modal-dialog").one("bsTransitionEnd",function(){c.$element.trigger("focus").trigger(e)}).emulateTransitionEnd(300):c.$element.trigger("focus").trigger(e)}))},c.prototype.hide=function(b){b&&b.preventDefault(),b=a.Event("hide.bs.modal"),this.$element.trigger(b),this.isShown&&!b.isDefaultPrevented()&&(this.isShown=!1,this.$body.removeClass("modal-open"),this.resetScrollbar(),this.escape(),a(document).off("focusin.bs.modal"),this.$element.removeClass("in").attr("aria-hidden",!0).off("click.dismiss.bs.modal"),a.support.transition&&this.$element.hasClass("fade")?this.$element.one("bsTransitionEnd",a.proxy(this.hideModal,this)).emulateTransitionEnd(300):this.hideModal())},c.prototype.enforceFocus=function(){a(document).off("focusin.bs.modal").on("focusin.bs.modal",a.proxy(function(a){this.$element[0]===a.target||this.$element.has(a.target).length||this.$element.trigger("focus")},this))},c.prototype.escape=function(){this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.bs.modal",a.proxy(function(a){27==a.which&&this.hide()},this)):this.isShown||this.$element.off("keyup.dismiss.bs.modal")},c.prototype.hideModal=function(){var a=this;this.$element.hide(),this.backdrop(function(){a.$element.trigger("hidden.bs.modal")})},c.prototype.removeBackdrop=function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},c.prototype.backdrop=function(b){var c=this,d=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var e=a.support.transition&&d;if(this.$backdrop=a('<div class="modal-backdrop '+d+'" />').appendTo(this.$body),this.$element.on("click.dismiss.bs.modal",a.proxy(function(a){a.target===a.currentTarget&&("static"==this.options.backdrop?this.$element[0].focus.call(this.$element[0]):this.hide.call(this))},this)),e&&this.$backdrop[0].offsetWidth,this.$backdrop.addClass("in"),!b)return;e?this.$backdrop.one("bsTransitionEnd",b).emulateTransitionEnd(150):b()}else if(!this.isShown&&this.$backdrop){this.$backdrop.removeClass("in");var f=function(){c.removeBackdrop(),b&&b()};a.support.transition&&this.$element.hasClass("fade")?this.$backdrop.one("bsTransitionEnd",f).emulateTransitionEnd(150):f()}else b&&b()},c.prototype.checkScrollbar=function(){document.body.clientWidth>=window.innerWidth||(this.scrollbarWidth=this.scrollbarWidth||this.measureScrollbar())},c.prototype.setScrollbar=function(){var a=parseInt(this.$body.css("padding-right")||0,10);this.scrollbarWidth&&this.$body.css("padding-right",a+this.scrollbarWidth)},c.prototype.resetScrollbar=function(){this.$body.css("padding-right","")},c.prototype.measureScrollbar=function(){var a=document.createElement("div");a.className="modal-scrollbar-measure",this.$body.append(a);var b=a.offsetWidth-a.clientWidth;return this.$body[0].removeChild(a),b};var d=a.fn.modal;a.fn.modal=b,a.fn.modal.Constructor=c,a.fn.modal.noConflict=function(){return a.fn.modal=d,this},a(document).on("click.bs.modal.data-api",'[data-toggle="modal"]',function(c){var d=a(this),e=d.attr("href"),f=a(d.attr("data-target")||e&&e.replace(/.*(?=#[^\s]+$)/,"")),g=f.data("bs.modal")?"toggle":a.extend({remote:!/#/.test(e)&&e},f.data(),d.data());d.is("a")&&c.preventDefault(),f.one("show.bs.modal",function(a){a.isDefaultPrevented()||f.one("hidden.bs.modal",function(){d.is(":visible")&&d.trigger("focus")})}),b.call(f,g,this)})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tooltip"),f="object"==typeof b&&b;(e||"destroy"!=b)&&(e||d.data("bs.tooltip",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.type=this.options=this.enabled=this.timeout=this.hoverState=this.$element=null,this.init("tooltip",a,b)};c.VERSION="3.2.0",c.DEFAULTS={animation:!0,placement:"top",selector:!1,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(this.options.viewport.selector||this.options.viewport);for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show()},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var c=a.contains(document.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!c)return;var d=this,e=this.tip(),f=this.getUID(this.type);this.setContent(),e.attr("id",f),this.$element.attr("aria-describedby",f),this.options.animation&&e.addClass("fade");var g="function"==typeof this.options.placement?this.options.placement.call(this,e[0],this.$element[0]):this.options.placement,h=/\s?auto?\s?/i,i=h.test(g);i&&(g=g.replace(h,"")||"top"),e.detach().css({top:0,left:0,display:"block"}).addClass(g).data("bs."+this.type,this),this.options.container?e.appendTo(this.options.container):e.insertAfter(this.$element);var j=this.getPosition(),k=e[0].offsetWidth,l=e[0].offsetHeight;if(i){var m=g,n=this.$element.parent(),o=this.getPosition(n);g="bottom"==g&&j.top+j.height+l-o.scroll>o.height?"top":"top"==g&&j.top-o.scroll-l<0?"bottom":"right"==g&&j.right+k>o.width?"left":"left"==g&&j.left-k<o.left?"right":g,e.removeClass(m).addClass(g)}var p=this.getCalculatedOffset(g,j,k,l);this.applyPlacement(p,g);var q=function(){d.$element.trigger("shown.bs."+d.type),d.hoverState=null};a.support.transition&&this.$tip.hasClass("fade")?e.one("bsTransitionEnd",q).emulateTransitionEnd(150):q()}},c.prototype.applyPlacement=function(b,c){var d=this.tip(),e=d[0].offsetWidth,f=d[0].offsetHeight,g=parseInt(d.css("margin-top"),10),h=parseInt(d.css("margin-left"),10);isNaN(g)&&(g=0),isNaN(h)&&(h=0),b.top=b.top+g,b.left=b.left+h,a.offset.setOffset(d[0],a.extend({using:function(a){d.css({top:Math.round(a.top),left:Math.round(a.left)})}},b),0),d.addClass("in");var i=d[0].offsetWidth,j=d[0].offsetHeight;"top"==c&&j!=f&&(b.top=b.top+f-j);var k=this.getViewportAdjustedDelta(c,b,i,j);k.left?b.left+=k.left:b.top+=k.top;var l=k.left?2*k.left-e+i:2*k.top-f+j,m=k.left?"left":"top",n=k.left?"offsetWidth":"offsetHeight";d.offset(b),this.replaceArrow(l,d[0][n],m)},c.prototype.replaceArrow=function(a,b,c){this.arrow().css(c,a?50*(1-a/b)+"%":"")},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle();a.find(".tooltip-inner")[this.options.html?"html":"text"](b),a.removeClass("fade in top bottom left right")},c.prototype.hide=function(){function b(){"in"!=c.hoverState&&d.detach(),c.$element.trigger("hidden.bs."+c.type)}var c=this,d=this.tip(),e=a.Event("hide.bs."+this.type);return this.$element.removeAttr("aria-describedby"),this.$element.trigger(e),e.isDefaultPrevented()?void 0:(d.removeClass("in"),a.support.transition&&this.$tip.hasClass("fade")?d.one("bsTransitionEnd",b).emulateTransitionEnd(150):b(),this.hoverState=null,this)},c.prototype.fixTitle=function(){var a=this.$element;(a.attr("title")||"string"!=typeof a.attr("data-original-title"))&&a.attr("data-original-title",a.attr("title")||"").attr("title","")},c.prototype.hasContent=function(){return this.getTitle()},c.prototype.getPosition=function(b){b=b||this.$element;var c=b[0],d="BODY"==c.tagName;return a.extend({},"function"==typeof c.getBoundingClientRect?c.getBoundingClientRect():null,{scroll:d?document.documentElement.scrollTop||document.body.scrollTop:b.scrollTop(),width:d?a(window).width():b.outerWidth(),height:d?a(window).height():b.outerHeight()},d?{top:0,left:0}:b.offset())},c.prototype.getCalculatedOffset=function(a,b,c,d){return"bottom"==a?{top:b.top+b.height,left:b.left+b.width/2-c/2}:"top"==a?{top:b.top-d,left:b.left+b.width/2-c/2}:"left"==a?{top:b.top+b.height/2-d/2,left:b.left-c}:{top:b.top+b.height/2-d/2,left:b.left+b.width}},c.prototype.getViewportAdjustedDelta=function(a,b,c,d){var e={top:0,left:0};if(!this.$viewport)return e;var f=this.options.viewport&&this.options.viewport.padding||0,g=this.getPosition(this.$viewport);if(/right|left/.test(a)){var h=b.top-f-g.scroll,i=b.top+f-g.scroll+d;h<g.top?e.top=g.top-h:i>g.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;j<g.left?e.left=g.left-j:k>g.width&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){return this.$tip=this.$tip||a(this.options.template)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.validate=function(){this.$element[0].parentNode||(this.hide(),this.$element=null,this.options=null)},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){clearTimeout(this.timeout),this.hide().$element.off("."+this.type).removeData("bs."+this.type)};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;(e||"destroy"!=b)&&(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.2.0",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").empty()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")},c.prototype.tip=function(){return this.$tip||(this.$tip=a(this.options.template)),this.$tip};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){var e=a.proxy(this.process,this);this.$body=a("body"),this.$scrollElement=a(a(c).is("body")?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",e),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.2.0",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b="offset",c=0;a.isWindow(this.$scrollElement[0])||(b="position",c=this.$scrollElement.scrollTop()),this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight();var d=this;this.$body.find(this.selector).map(function(){var d=a(this),e=d.data("target")||d.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[b]().top+c,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){d.offsets.push(this[0]),d.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b<=e[0])return g!=(a=f[0])&&this.activate(a);for(a=e.length;a--;)g!=f[a]&&b>=e[a]&&(!e[a+1]||b<=e[a+1])&&this.activate(f[a])},b.prototype.activate=function(b){this.activeTarget=b,a(this.selector).parentsUntil(this.options.target,".active").removeClass("active");var c=this.selector+'[data-target="'+b+'"],'+this.selector+'[href="'+b+'"]',d=a(c).parents("li").addClass("active");d.parent(".dropdown-menu").length&&(d=d.closest("li.dropdown").addClass("active")),d.trigger("activate.bs.scrollspy")};var d=a.fn.scrollspy;a.fn.scrollspy=c,a.fn.scrollspy.Constructor=b,a.fn.scrollspy.noConflict=function(){return a.fn.scrollspy=d,this},a(window).on("load.bs.scrollspy.data-api",function(){a('[data-spy="scroll"]').each(function(){var b=a(this);c.call(b,b.data())})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.tab");e||d.data("bs.tab",e=new c(this)),"string"==typeof b&&e[b]()})}var c=function(b){this.element=a(b)};c.VERSION="3.2.0",c.prototype.show=function(){var b=this.element,c=b.closest("ul:not(.dropdown-menu)"),d=b.data("target");if(d||(d=b.attr("href"),d=d&&d.replace(/.*(?=#[^\s]*$)/,"")),!b.parent("li").hasClass("active")){var e=c.find(".active:last a")[0],f=a.Event("show.bs.tab",{relatedTarget:e});if(b.trigger(f),!f.isDefaultPrevented()){var g=a(d);this.activate(b.closest("li"),c),this.activate(g,g.parent(),function(){b.trigger({type:"shown.bs.tab",relatedTarget:e})})}}},c.prototype.activate=function(b,c,d){function e(){f.removeClass("active").find("> .dropdown-menu > .active").removeClass("active"),b.addClass("active"),g?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu")&&b.closest("li.dropdown").addClass("active"),d&&d()}var f=c.find("> .active"),g=d&&a.support.transition&&f.hasClass("fade");g?f.one("bsTransitionEnd",e).emulateTransitionEnd(150):e(),f.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this},a(document).on("click.bs.tab.data-api",'[data-toggle="tab"], [data-toggle="pill"]',function(c){c.preventDefault(),b.call(a(this),"show")})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=this.unpin=this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.2.0",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=a(document).height(),d=this.$target.scrollTop(),e=this.$element.offset(),f=this.options.offset,g=f.top,h=f.bottom;"object"!=typeof f&&(h=g=f),"function"==typeof g&&(g=f.top(this.$element)),"function"==typeof h&&(h=f.bottom(this.$element));var i=null!=this.unpin&&d+this.unpin<=e.top?!1:null!=h&&e.top+this.$element.height()>=b-h?"bottom":null!=g&&g>=d?"top":!1;if(this.affixed!==i){null!=this.unpin&&this.$element.css("top","");var j="affix"+(i?"-"+i:""),k=a.Event(j+".bs.affix");this.$element.trigger(k),k.isDefaultPrevented()||(this.affixed=i,this.unpin="bottom"==i?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(j).trigger(a.Event(j.replace("affix","affixed"))),"bottom"==i&&this.$element.offset({top:b-this.$element.height()-h}))}}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},d.offsetBottom&&(d.offset.bottom=d.offsetBottom),d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery);
\ No newline at end of file
/*! jQuery v2.1.1 | (c) 2005, 2014 jQuery Foundation, Inc. | jquery.org/license */
!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=c.slice,e=c.concat,f=c.push,g=c.indexOf,h={},i=h.toString,j=h.hasOwnProperty,k={},l=a.document,m="2.1.1",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return d.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:d.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a,b){return n.each(this,a,b)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor(null)},push:f,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(n.isPlainObject(d)||(e=n.isArray(d)))?(e?(e=!1,f=c&&n.isArray(c)?c:[]):f=c&&n.isPlainObject(c)?c:{},g[b]=n.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray,isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){return!n.isArray(a)&&a-parseFloat(a)>=0},isPlainObject:function(a){return"object"!==n.type(a)||a.nodeType||n.isWindow(a)?!1:a.constructor&&!j.call(a.constructor.prototype,"isPrototypeOf")?!1:!0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?h[i.call(a)]||"object":typeof a},globalEval:function(a){var b,c=eval;a=n.trim(a),a&&(1===a.indexOf("use strict")?(b=l.createElement("script"),b.text=a,l.head.appendChild(b).parentNode.removeChild(b)):c(a))},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b,c){var d,e=0,f=a.length,g=s(a);if(c){if(g){for(;f>e;e++)if(d=b.apply(a[e],c),d===!1)break}else for(e in a)if(d=b.apply(a[e],c),d===!1)break}else if(g){for(;f>e;e++)if(d=b.call(a[e],e,a[e]),d===!1)break}else for(e in a)if(d=b.call(a[e],e,a[e]),d===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):f.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:g.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;c>d;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,f=0,g=a.length,h=s(a),i=[];if(h)for(;g>f;f++)d=b(a[f],f,c),null!=d&&i.push(d);else for(f in a)d=b(a[f],f,c),null!=d&&i.push(d);return e.apply([],i)},guid:1,proxy:function(a,b){var c,e,f;return"string"==typeof b&&(c=a[b],b=a,a=c),n.isFunction(a)?(e=d.call(arguments,2),f=function(){return a.apply(b||this,e.concat(d.call(arguments)))},f.guid=a.guid=a.guid||n.guid++,f):void 0},now:Date.now,support:k}),n.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(a,b){h["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:1===a.nodeType&&b?!0:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+-new Date,v=a.document,w=0,x=0,y=gb(),z=gb(),A=gb(),B=function(a,b){return a===b&&(l=!0),0},C="undefined",D=1<<31,E={}.hasOwnProperty,F=[],G=F.pop,H=F.push,I=F.push,J=F.slice,K=F.indexOf||function(a){for(var b=0,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},L="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",M="[\\x20\\t\\r\\n\\f]",N="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=N.replace("w","w#"),P="\\["+M+"*("+N+")(?:"+M+"*([*^$|!~]?=)"+M+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+O+"))|)"+M+"*\\]",Q=":("+N+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+P+")*)|.*)\\)|)",R=new RegExp("^"+M+"+|((?:^|[^\\\\])(?:\\\\.)*)"+M+"+$","g"),S=new RegExp("^"+M+"*,"+M+"*"),T=new RegExp("^"+M+"*([>+~]|"+M+")"+M+"*"),U=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),V=new RegExp(Q),W=new RegExp("^"+O+"$"),X={ID:new RegExp("^#("+N+")"),CLASS:new RegExp("^\\.("+N+")"),TAG:new RegExp("^("+N.replace("w","w*")+")"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+Q),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+L+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,$=/^[^{]+\{\s*\[native \w/,_=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ab=/[+~]/,bb=/'|\\/g,cb=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),db=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:0>d?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)};try{I.apply(F=J.call(v.childNodes),v.childNodes),F[v.childNodes.length].nodeType}catch(eb){I={apply:F.length?function(a,b){H.apply(a,J.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function fb(a,b,d,e){var f,h,j,k,l,o,r,s,w,x;if((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,d=d||[],!a||"string"!=typeof a)return d;if(1!==(k=b.nodeType)&&9!==k)return[];if(p&&!e){if(f=_.exec(a))if(j=f[1]){if(9===k){if(h=b.getElementById(j),!h||!h.parentNode)return d;if(h.id===j)return d.push(h),d}else if(b.ownerDocument&&(h=b.ownerDocument.getElementById(j))&&t(b,h)&&h.id===j)return d.push(h),d}else{if(f[2])return I.apply(d,b.getElementsByTagName(a)),d;if((j=f[3])&&c.getElementsByClassName&&b.getElementsByClassName)return I.apply(d,b.getElementsByClassName(j)),d}if(c.qsa&&(!q||!q.test(a))){if(s=r=u,w=b,x=9===k&&a,1===k&&"object"!==b.nodeName.toLowerCase()){o=g(a),(r=b.getAttribute("id"))?s=r.replace(bb,"\\$&"):b.setAttribute("id",s),s="[id='"+s+"'] ",l=o.length;while(l--)o[l]=s+qb(o[l]);w=ab.test(a)&&ob(b.parentNode)||b,x=o.join(",")}if(x)try{return I.apply(d,w.querySelectorAll(x)),d}catch(y){}finally{r||b.removeAttribute("id")}}}return i(a.replace(R,"$1"),b,d,e)}function gb(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function hb(a){return a[u]=!0,a}function ib(a){var b=n.createElement("div");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function jb(a,b){var c=a.split("|"),e=a.length;while(e--)d.attrHandle[c[e]]=b}function kb(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&(~b.sourceIndex||D)-(~a.sourceIndex||D);if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function lb(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function mb(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function nb(a){return hb(function(b){return b=+b,hb(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function ob(a){return a&&typeof a.getElementsByTagName!==C&&a}c=fb.support={},f=fb.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return b?"HTML"!==b.nodeName:!1},m=fb.setDocument=function(a){var b,e=a?a.ownerDocument||a:v,g=e.defaultView;return e!==n&&9===e.nodeType&&e.documentElement?(n=e,o=e.documentElement,p=!f(e),g&&g!==g.top&&(g.addEventListener?g.addEventListener("unload",function(){m()},!1):g.attachEvent&&g.attachEvent("onunload",function(){m()})),c.attributes=ib(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ib(function(a){return a.appendChild(e.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=$.test(e.getElementsByClassName)&&ib(function(a){return a.innerHTML="<div class='a'></div><div class='a i'></div>",a.firstChild.className="i",2===a.getElementsByClassName("i").length}),c.getById=ib(function(a){return o.appendChild(a).id=u,!e.getElementsByName||!e.getElementsByName(u).length}),c.getById?(d.find.ID=function(a,b){if(typeof b.getElementById!==C&&p){var c=b.getElementById(a);return c&&c.parentNode?[c]:[]}},d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){return a.getAttribute("id")===b}}):(delete d.find.ID,d.filter.ID=function(a){var b=a.replace(cb,db);return function(a){var c=typeof a.getAttributeNode!==C&&a.getAttributeNode("id");return c&&c.value===b}}),d.find.TAG=c.getElementsByTagName?function(a,b){return typeof b.getElementsByTagName!==C?b.getElementsByTagName(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){return typeof b.getElementsByClassName!==C&&p?b.getElementsByClassName(a):void 0},r=[],q=[],(c.qsa=$.test(e.querySelectorAll))&&(ib(function(a){a.innerHTML="<select msallowclip=''><option selected=''></option></select>",a.querySelectorAll("[msallowclip^='']").length&&q.push("[*^$]="+M+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+M+"*(?:value|"+L+")"),a.querySelectorAll(":checked").length||q.push(":checked")}),ib(function(a){var b=e.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+M+"*[*^$|!~]?="),a.querySelectorAll(":enabled").length||q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=$.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ib(function(a){c.disconnectedMatch=s.call(a,"div"),s.call(a,"[s!='']:x"),r.push("!=",Q)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=$.test(o.compareDocumentPosition),t=b||$.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===e||a.ownerDocument===v&&t(v,a)?-1:b===e||b.ownerDocument===v&&t(v,b)?1:k?K.call(k,a)-K.call(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,f=a.parentNode,g=b.parentNode,h=[a],i=[b];if(!f||!g)return a===e?-1:b===e?1:f?-1:g?1:k?K.call(k,a)-K.call(k,b):0;if(f===g)return kb(a,b);c=a;while(c=c.parentNode)h.unshift(c);c=b;while(c=c.parentNode)i.unshift(c);while(h[d]===i[d])d++;return d?kb(h[d],i[d]):h[d]===v?-1:i[d]===v?1:0},e):n},fb.matches=function(a,b){return fb(a,null,null,b)},fb.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(U,"='$1']"),!(!c.matchesSelector||!p||r&&r.test(b)||q&&q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return fb(b,n,null,[a]).length>0},fb.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},fb.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&E.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},fb.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},fb.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=fb.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=fb.selectors={cacheLength:50,createPseudo:hb,match:X,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(cb,db),a[3]=(a[3]||a[4]||a[5]||"").replace(cb,db),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||fb.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&fb.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return X.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&V.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(cb,db).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+M+")"+a+"("+M+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||typeof a.getAttribute!==C&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=fb.attr(d,a);return null==e?"!="===b:b?(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e+" ").indexOf(c)>-1:"|="===b?e===c||e.slice(0,c.length+1)===c+"-":!1):!0}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h;if(q){if(f){while(p){l=b;while(l=l[p])if(h?l.nodeName.toLowerCase()===r:1===l.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){k=q[u]||(q[u]={}),j=k[a]||[],n=j[0]===w&&j[1],m=j[0]===w&&j[2],l=n&&q.childNodes[n];while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if(1===l.nodeType&&++m&&l===b){k[a]=[w,n,m];break}}else if(s&&(j=(b[u]||(b[u]={}))[a])&&j[0]===w)m=j[1];else while(l=++n&&l&&l[p]||(m=n=0)||o.pop())if((h?l.nodeName.toLowerCase()===r:1===l.nodeType)&&++m&&(s&&((l[u]||(l[u]={}))[a]=[w,m]),l===b))break;return m-=e,m===d||m%d===0&&m/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||fb.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?hb(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=K.call(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:hb(function(a){var b=[],c=[],d=h(a.replace(R,"$1"));return d[u]?hb(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),!c.pop()}}),has:hb(function(a){return function(b){return fb(a,b).length>0}}),contains:hb(function(a){return function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:hb(function(a){return W.test(a||"")||fb.error("unsupported lang: "+a),a=a.replace(cb,db).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:function(a){return a.disabled===!1},disabled:function(a){return a.disabled===!0},checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return Z.test(a.nodeName)},input:function(a){return Y.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:nb(function(){return[0]}),last:nb(function(a,b){return[b-1]}),eq:nb(function(a,b,c){return[0>c?c+b:c]}),even:nb(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:nb(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:nb(function(a,b,c){for(var d=0>c?c+b:c;--d>=0;)a.push(d);return a}),gt:nb(function(a,b,c){for(var d=0>c?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=lb(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=mb(b);function pb(){}pb.prototype=d.filters=d.pseudos,d.setFilters=new pb,g=fb.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){(!c||(e=S.exec(h)))&&(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=T.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(R," ")}),h=h.slice(c.length));for(g in d.filter)!(e=X[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?fb.error(a):z(a,i).slice(0)};function qb(a){for(var b=0,c=a.length,d="";c>b;b++)d+=a[b].value;return d}function rb(a,b,c){var d=b.dir,e=c&&"parentNode"===d,f=x++;return b.first?function(b,c,f){while(b=b[d])if(1===b.nodeType||e)return a(b,c,f)}:function(b,c,g){var h,i,j=[w,f];if(g){while(b=b[d])if((1===b.nodeType||e)&&a(b,c,g))return!0}else while(b=b[d])if(1===b.nodeType||e){if(i=b[u]||(b[u]={}),(h=i[d])&&h[0]===w&&h[1]===f)return j[2]=h[2];if(i[d]=j,j[2]=a(b,c,g))return!0}}}function sb(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function tb(a,b,c){for(var d=0,e=b.length;e>d;d++)fb(a,b[d],c);return c}function ub(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;i>h;h++)(f=a[h])&&(!c||c(f,d,e))&&(g.push(f),j&&b.push(h));return g}function vb(a,b,c,d,e,f){return d&&!d[u]&&(d=vb(d)),e&&!e[u]&&(e=vb(e,f)),hb(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||tb(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:ub(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=ub(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?K.call(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=ub(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):I.apply(g,r)})}function wb(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=rb(function(a){return a===b},h,!0),l=rb(function(a){return K.call(b,a)>-1},h,!0),m=[function(a,c,d){return!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d))}];f>i;i++)if(c=d.relative[a[i].type])m=[rb(sb(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;f>e;e++)if(d.relative[a[e].type])break;return vb(i>1&&sb(m),i>1&&qb(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(R,"$1"),c,e>i&&wb(a.slice(i,e)),f>e&&wb(a=a.slice(e)),f>e&&qb(a))}m.push(c)}return sb(m)}function xb(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,m,o,p=0,q="0",r=f&&[],s=[],t=j,u=f||e&&d.find.TAG("*",k),v=w+=null==t?1:Math.random()||.1,x=u.length;for(k&&(j=g!==n&&g);q!==x&&null!=(l=u[q]);q++){if(e&&l){m=0;while(o=a[m++])if(o(l,g,h)){i.push(l);break}k&&(w=v)}c&&((l=!o&&l)&&p--,f&&r.push(l))}if(p+=q,c&&q!==p){m=0;while(o=b[m++])o(r,s,g,h);if(f){if(p>0)while(q--)r[q]||s[q]||(s[q]=G.call(i));s=ub(s)}I.apply(i,s),k&&!f&&s.length>0&&p+b.length>1&&fb.uniqueSort(i)}return k&&(w=v,j=t),r};return c?hb(f):f}return h=fb.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=wb(b[c]),f[u]?d.push(f):e.push(f);f=A(a,xb(e,d)),f.selector=a}return f},i=fb.select=function(a,b,e,f){var i,j,k,l,m,n="function"==typeof a&&a,o=!f&&g(a=n.selector||a);if(e=e||[],1===o.length){if(j=o[0]=o[0].slice(0),j.length>2&&"ID"===(k=j[0]).type&&c.getById&&9===b.nodeType&&p&&d.relative[j[1].type]){if(b=(d.find.ID(k.matches[0].replace(cb,db),b)||[])[0],!b)return e;n&&(b=b.parentNode),a=a.slice(j.shift().value.length)}i=X.needsContext.test(a)?0:j.length;while(i--){if(k=j[i],d.relative[l=k.type])break;if((m=d.find[l])&&(f=m(k.matches[0].replace(cb,db),ab.test(j[0].type)&&ob(b.parentNode)||b))){if(j.splice(i,1),a=f.length&&qb(j),!a)return I.apply(e,f),e;break}}}return(n||h(a,o))(f,b,!p,e,ab.test(a)&&ob(b.parentNode)||b),e},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ib(function(a){return 1&a.compareDocumentPosition(n.createElement("div"))}),ib(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||jb("type|href|height|width",function(a,b,c){return c?void 0:a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ib(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||jb("value",function(a,b,c){return c||"input"!==a.nodeName.toLowerCase()?void 0:a.defaultValue}),ib(function(a){return null==a.getAttribute("disabled")})||jb(L,function(a,b,c){var d;return c?void 0:a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),fb}(a);n.find=t,n.expr=t.selectors,n.expr[":"]=n.expr.pseudos,n.unique=t.uniqueSort,n.text=t.getText,n.isXMLDoc=t.isXML,n.contains=t.contains;var u=n.expr.match.needsContext,v=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,w=/^.[^:#\[\.,]*$/;function x(a,b,c){if(n.isFunction(b))return n.grep(a,function(a,d){return!!b.call(a,d,a)!==c});if(b.nodeType)return n.grep(a,function(a){return a===b!==c});if("string"==typeof b){if(w.test(b))return n.filter(b,a,c);b=n.filter(b,a)}return n.grep(a,function(a){return g.call(b,a)>=0!==c})}n.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?n.find.matchesSelector(d,a)?[d]:[]:n.find.matches(a,n.grep(b,function(a){return 1===a.nodeType}))},n.fn.extend({find:function(a){var b,c=this.length,d=[],e=this;if("string"!=typeof a)return this.pushStack(n(a).filter(function(){for(b=0;c>b;b++)if(n.contains(e[b],this))return!0}));for(b=0;c>b;b++)n.find(a,e[b],d);return d=this.pushStack(c>1?n.unique(d):d),d.selector=this.selector?this.selector+" "+a:a,d},filter:function(a){return this.pushStack(x(this,a||[],!1))},not:function(a){return this.pushStack(x(this,a||[],!0))},is:function(a){return!!x(this,"string"==typeof a&&u.test(a)?n(a):a||[],!1).length}});var y,z=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,A=n.fn.init=function(a,b){var c,d;if(!a)return this;if("string"==typeof a){if(c="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:z.exec(a),!c||!c[1]&&b)return!b||b.jquery?(b||y).find(a):this.constructor(b).find(a);if(c[1]){if(b=b instanceof n?b[0]:b,n.merge(this,n.parseHTML(c[1],b&&b.nodeType?b.ownerDocument||b:l,!0)),v.test(c[1])&&n.isPlainObject(b))for(c in b)n.isFunction(this[c])?this[c](b[c]):this.attr(c,b[c]);return this}return d=l.getElementById(c[2]),d&&d.parentNode&&(this.length=1,this[0]=d),this.context=l,this.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this):n.isFunction(a)?"undefined"!=typeof y.ready?y.ready(a):a(n):(void 0!==a.selector&&(this.selector=a.selector,this.context=a.context),n.makeArray(a,this))};A.prototype=n.fn,y=n(l);var B=/^(?:parents|prev(?:Until|All))/,C={children:!0,contents:!0,next:!0,prev:!0};n.extend({dir:function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&n(a).is(c))break;d.push(a)}return d},sibling:function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c}}),n.fn.extend({has:function(a){var b=n(a,this),c=b.length;return this.filter(function(){for(var a=0;c>a;a++)if(n.contains(this,b[a]))return!0})},closest:function(a,b){for(var c,d=0,e=this.length,f=[],g=u.test(a)||"string"!=typeof a?n(a,b||this.context):0;e>d;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&n.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?n.unique(f):f)},index:function(a){return a?"string"==typeof a?g.call(n(a),this[0]):g.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(n.unique(n.merge(this.get(),n(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function D(a,b){while((a=a[b])&&1!==a.nodeType);return a}n.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return n.dir(a,"parentNode")},parentsUntil:function(a,b,c){return n.dir(a,"parentNode",c)},next:function(a){return D(a,"nextSibling")},prev:function(a){return D(a,"previousSibling")},nextAll:function(a){return n.dir(a,"nextSibling")},prevAll:function(a){return n.dir(a,"previousSibling")},nextUntil:function(a,b,c){return n.dir(a,"nextSibling",c)},prevUntil:function(a,b,c){return n.dir(a,"previousSibling",c)},siblings:function(a){return n.sibling((a.parentNode||{}).firstChild,a)},children:function(a){return n.sibling(a.firstChild)},contents:function(a){return a.contentDocument||n.merge([],a.childNodes)}},function(a,b){n.fn[a]=function(c,d){var e=n.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=n.filter(d,e)),this.length>1&&(C[a]||n.unique(e),B.test(a)&&e.reverse()),this.pushStack(e)}});var E=/\S+/g,F={};function G(a){var b=F[a]={};return n.each(a.match(E)||[],function(a,c){b[c]=!0}),b}n.Callbacks=function(a){a="string"==typeof a?F[a]||G(a):n.extend({},a);var b,c,d,e,f,g,h=[],i=!a.once&&[],j=function(l){for(b=a.memory&&l,c=!0,g=e||0,e=0,f=h.length,d=!0;h&&f>g;g++)if(h[g].apply(l[0],l[1])===!1&&a.stopOnFalse){b=!1;break}d=!1,h&&(i?i.length&&j(i.shift()):b?h=[]:k.disable())},k={add:function(){if(h){var c=h.length;!function g(b){n.each(b,function(b,c){var d=n.type(c);"function"===d?a.unique&&k.has(c)||h.push(c):c&&c.length&&"string"!==d&&g(c)})}(arguments),d?f=h.length:b&&(e=c,j(b))}return this},remove:function(){return h&&n.each(arguments,function(a,b){var c;while((c=n.inArray(b,h,c))>-1)h.splice(c,1),d&&(f>=c&&f--,g>=c&&g--)}),this},has:function(a){return a?n.inArray(a,h)>-1:!(!h||!h.length)},empty:function(){return h=[],f=0,this},disable:function(){return h=i=b=void 0,this},disabled:function(){return!h},lock:function(){return i=void 0,b||k.disable(),this},locked:function(){return!i},fireWith:function(a,b){return!h||c&&!i||(b=b||[],b=[a,b.slice?b.slice():b],d?i.push(b):j(b)),this},fire:function(){return k.fireWith(this,arguments),this},fired:function(){return!!c}};return k},n.extend({Deferred:function(a){var b=[["resolve","done",n.Callbacks("once memory"),"resolved"],["reject","fail",n.Callbacks("once memory"),"rejected"],["notify","progress",n.Callbacks("memory")]],c="pending",d={state:function(){return c},always:function(){return e.done(arguments).fail(arguments),this},then:function(){var a=arguments;return n.Deferred(function(c){n.each(b,function(b,f){var g=n.isFunction(a[b])&&a[b];e[f[1]](function(){var a=g&&g.apply(this,arguments);a&&n.isFunction(a.promise)?a.promise().done(c.resolve).fail(c.reject).progress(c.notify):c[f[0]+"With"](this===d?c.promise():this,g?[a]:arguments)})}),a=null}).promise()},promise:function(a){return null!=a?n.extend(a,d):d}},e={};return d.pipe=d.then,n.each(b,function(a,f){var g=f[2],h=f[3];d[f[1]]=g.add,h&&g.add(function(){c=h},b[1^a][2].disable,b[2][2].lock),e[f[0]]=function(){return e[f[0]+"With"](this===e?d:this,arguments),this},e[f[0]+"With"]=g.fireWith}),d.promise(e),a&&a.call(e,e),e},when:function(a){var b=0,c=d.call(arguments),e=c.length,f=1!==e||a&&n.isFunction(a.promise)?e:0,g=1===f?a:n.Deferred(),h=function(a,b,c){return function(e){b[a]=this,c[a]=arguments.length>1?d.call(arguments):e,c===i?g.notifyWith(b,c):--f||g.resolveWith(b,c)}},i,j,k;if(e>1)for(i=new Array(e),j=new Array(e),k=new Array(e);e>b;b++)c[b]&&n.isFunction(c[b].promise)?c[b].promise().done(h(b,k,c)).fail(g.reject).progress(h(b,j,i)):--f;return f||g.resolveWith(k,c),g.promise()}});var H;n.fn.ready=function(a){return n.ready.promise().done(a),this},n.extend({isReady:!1,readyWait:1,holdReady:function(a){a?n.readyWait++:n.ready(!0)},ready:function(a){(a===!0?--n.readyWait:n.isReady)||(n.isReady=!0,a!==!0&&--n.readyWait>0||(H.resolveWith(l,[n]),n.fn.triggerHandler&&(n(l).triggerHandler("ready"),n(l).off("ready"))))}});function I(){l.removeEventListener("DOMContentLoaded",I,!1),a.removeEventListener("load",I,!1),n.ready()}n.ready.promise=function(b){return H||(H=n.Deferred(),"complete"===l.readyState?setTimeout(n.ready):(l.addEventListener("DOMContentLoaded",I,!1),a.addEventListener("load",I,!1))),H.promise(b)},n.ready.promise();var J=n.access=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)n.access(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f};n.acceptData=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function K(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=n.expando+Math.random()}K.uid=1,K.accepts=n.acceptData,K.prototype={key:function(a){if(!K.accepts(a))return 0;var b={},c=a[this.expando];if(!c){c=K.uid++;try{b[this.expando]={value:c},Object.defineProperties(a,b)}catch(d){b[this.expando]=c,n.extend(a,b)}}return this.cache[c]||(this.cache[c]={}),c},set:function(a,b,c){var d,e=this.key(a),f=this.cache[e];if("string"==typeof b)f[b]=c;else if(n.isEmptyObject(f))n.extend(this.cache[e],b);else for(d in b)f[d]=b[d];return f},get:function(a,b){var c=this.cache[this.key(a)];return void 0===b?c:c[b]},access:function(a,b,c){var d;return void 0===b||b&&"string"==typeof b&&void 0===c?(d=this.get(a,b),void 0!==d?d:this.get(a,n.camelCase(b))):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d,e,f=this.key(a),g=this.cache[f];if(void 0===b)this.cache[f]={};else{n.isArray(b)?d=b.concat(b.map(n.camelCase)):(e=n.camelCase(b),b in g?d=[b,e]:(d=e,d=d in g?[d]:d.match(E)||[])),c=d.length;while(c--)delete g[d[c]]}},hasData:function(a){return!n.isEmptyObject(this.cache[a[this.expando]]||{})},discard:function(a){a[this.expando]&&delete this.cache[a[this.expando]]}};var L=new K,M=new K,N=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,O=/([A-Z])/g;function P(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(O,"-$1").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c="true"===c?!0:"false"===c?!1:"null"===c?null:+c+""===c?+c:N.test(c)?n.parseJSON(c):c}catch(e){}M.set(a,b,c)}else c=void 0;return c}n.extend({hasData:function(a){return M.hasData(a)||L.hasData(a)},data:function(a,b,c){return M.access(a,b,c)},removeData:function(a,b){M.remove(a,b)
},_data:function(a,b,c){return L.access(a,b,c)},_removeData:function(a,b){L.remove(a,b)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=M.get(f),1===f.nodeType&&!L.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));L.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){M.set(this,a)}):J(this,function(b){var c,d=n.camelCase(a);if(f&&void 0===b){if(c=M.get(f,a),void 0!==c)return c;if(c=M.get(f,d),void 0!==c)return c;if(c=P(f,d,void 0),void 0!==c)return c}else this.each(function(){var c=M.get(this,d);M.set(this,d,b),-1!==a.indexOf("-")&&void 0!==c&&M.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){M.remove(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=L.get(a,b),c&&(!d||n.isArray(c)?d=L.access(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return L.get(a,c)||L.access(a,c,{empty:n.Callbacks("once memory").add(function(){L.remove(a,[b+"queue",c])})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?n.queue(this[0],a):void 0===b?this:this.each(function(){var c=n.queue(this,a,b);n._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&n.dequeue(this,a)})},dequeue:function(a){return this.each(function(){n.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=n.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=L.get(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var Q=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,R=["Top","Right","Bottom","Left"],S=function(a,b){return a=b||a,"none"===n.css(a,"display")||!n.contains(a.ownerDocument,a)},T=/^(?:checkbox|radio)$/i;!function(){var a=l.createDocumentFragment(),b=a.appendChild(l.createElement("div")),c=l.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),k.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="<textarea>x</textarea>",k.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var U="undefined";k.focusinBubbles="onfocusin"in a;var V=/^key/,W=/^(?:mouse|pointer|contextmenu)|click/,X=/^(?:focusinfocus|focusoutblur)$/,Y=/^([^.]*)(?:\.(.+)|)$/;function Z(){return!0}function $(){return!1}function _(){try{return l.activeElement}catch(a){}}n.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.get(a);if(r){c.handler&&(f=c,c=f.handler,e=f.selector),c.guid||(c.guid=n.guid++),(i=r.events)||(i=r.events={}),(g=r.handle)||(g=r.handle=function(b){return typeof n!==U&&n.event.triggered!==b.type?n.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(E)||[""],j=b.length;while(j--)h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o&&(l=n.event.special[o]||{},o=(e?l.delegateType:l.bindType)||o,l=n.event.special[o]||{},k=n.extend({type:o,origType:q,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&n.expr.match.needsContext.test(e),namespace:p.join(".")},f),(m=i[o])||(m=i[o]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,p,g)!==!1||a.addEventListener&&a.addEventListener(o,g,!1)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),n.event.global[o]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,o,p,q,r=L.hasData(a)&&L.get(a);if(r&&(i=r.events)){b=(b||"").match(E)||[""],j=b.length;while(j--)if(h=Y.exec(b[j])||[],o=q=h[1],p=(h[2]||"").split(".").sort(),o){l=n.event.special[o]||{},o=(d?l.delegateType:l.bindType)||o,m=i[o]||[],h=h[2]&&new RegExp("(^|\\.)"+p.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&q!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,p,r.handle)!==!1||n.removeEvent(a,o,r.handle),delete i[o])}else for(o in i)n.event.remove(a,o+b[j],c,d,!0);n.isEmptyObject(i)&&(delete r.handle,L.remove(a,"events"))}},trigger:function(b,c,d,e){var f,g,h,i,k,m,o,p=[d||l],q=j.call(b,"type")?b.type:b,r=j.call(b,"namespace")?b.namespace.split("."):[];if(g=h=d=d||l,3!==d.nodeType&&8!==d.nodeType&&!X.test(q+n.event.triggered)&&(q.indexOf(".")>=0&&(r=q.split("."),q=r.shift(),r.sort()),k=q.indexOf(":")<0&&"on"+q,b=b[n.expando]?b:new n.Event(q,"object"==typeof b&&b),b.isTrigger=e?2:3,b.namespace=r.join("."),b.namespace_re=b.namespace?new RegExp("(^|\\.)"+r.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=d),c=null==c?[b]:n.makeArray(c,[b]),o=n.event.special[q]||{},e||!o.trigger||o.trigger.apply(d,c)!==!1)){if(!e&&!o.noBubble&&!n.isWindow(d)){for(i=o.delegateType||q,X.test(i+q)||(g=g.parentNode);g;g=g.parentNode)p.push(g),h=g;h===(d.ownerDocument||l)&&p.push(h.defaultView||h.parentWindow||a)}f=0;while((g=p[f++])&&!b.isPropagationStopped())b.type=f>1?i:o.bindType||q,m=(L.get(g,"events")||{})[b.type]&&L.get(g,"handle"),m&&m.apply(g,c),m=k&&g[k],m&&m.apply&&n.acceptData(g)&&(b.result=m.apply(g,c),b.result===!1&&b.preventDefault());return b.type=q,e||b.isDefaultPrevented()||o._default&&o._default.apply(p.pop(),c)!==!1||!n.acceptData(d)||k&&n.isFunction(d[q])&&!n.isWindow(d)&&(h=d[k],h&&(d[k]=null),n.event.triggered=q,d[q](),n.event.triggered=void 0,h&&(d[k]=h)),b.result}},dispatch:function(a){a=n.event.fix(a);var b,c,e,f,g,h=[],i=d.call(arguments),j=(L.get(this,"events")||{})[a.type]||[],k=n.event.special[a.type]||{};if(i[0]=a,a.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,a)!==!1){h=n.event.handlers.call(this,a,j),b=0;while((f=h[b++])&&!a.isPropagationStopped()){a.currentTarget=f.elem,c=0;while((g=f.handlers[c++])&&!a.isImmediatePropagationStopped())(!a.namespace_re||a.namespace_re.test(g.namespace))&&(a.handleObj=g,a.data=g.data,e=((n.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(a.result=e)===!1&&(a.preventDefault(),a.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,a),a.result}},handlers:function(a,b){var c,d,e,f,g=[],h=b.delegateCount,i=a.target;if(h&&i.nodeType&&(!a.button||"click"!==a.type))for(;i!==this;i=i.parentNode||this)if(i.disabled!==!0||"click"!==a.type){for(d=[],c=0;h>c;c++)f=b[c],e=f.selector+" ",void 0===d[e]&&(d[e]=f.needsContext?n(e,this).index(i)>=0:n.find(e,this,null,[i]).length),d[e]&&d.push(f);d.length&&g.push({elem:i,handlers:d})}return h<b.length&&g.push({elem:this,handlers:b.slice(h)}),g},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(a,b){return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}},mouseHooks:{props:"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(a,b){var c,d,e,f=b.button;return null==a.pageX&&null!=b.clientX&&(c=a.target.ownerDocument||l,d=c.documentElement,e=c.body,a.pageX=b.clientX+(d&&d.scrollLeft||e&&e.scrollLeft||0)-(d&&d.clientLeft||e&&e.clientLeft||0),a.pageY=b.clientY+(d&&d.scrollTop||e&&e.scrollTop||0)-(d&&d.clientTop||e&&e.clientTop||0)),a.which||void 0===f||(a.which=1&f?1:2&f?3:4&f?2:0),a}},fix:function(a){if(a[n.expando])return a;var b,c,d,e=a.type,f=a,g=this.fixHooks[e];g||(this.fixHooks[e]=g=W.test(e)?this.mouseHooks:V.test(e)?this.keyHooks:{}),d=g.props?this.props.concat(g.props):this.props,a=new n.Event(f),b=d.length;while(b--)c=d[b],a[c]=f[c];return a.target||(a.target=l),3===a.target.nodeType&&(a.target=a.target.parentNode),g.filter?g.filter(a,f):a},special:{load:{noBubble:!0},focus:{trigger:function(){return this!==_()&&this.focus?(this.focus(),!1):void 0},delegateType:"focusin"},blur:{trigger:function(){return this===_()&&this.blur?(this.blur(),!1):void 0},delegateType:"focusout"},click:{trigger:function(){return"checkbox"===this.type&&this.click&&n.nodeName(this,"input")?(this.click(),!1):void 0},_default:function(a){return n.nodeName(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,c,d){var e=n.extend(new n.Event,c,{type:a,isSimulated:!0,originalEvent:{}});d?n.event.trigger(e,null,b):n.event.dispatch.call(b,e),e.isDefaultPrevented()&&c.preventDefault()}},n.removeEvent=function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c,!1)},n.Event=function(a,b){return this instanceof n.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?Z:$):this.type=a,b&&n.extend(this,b),this.timeStamp=a&&a.timeStamp||n.now(),void(this[n.expando]=!0)):new n.Event(a,b)},n.Event.prototype={isDefaultPrevented:$,isPropagationStopped:$,isImmediatePropagationStopped:$,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=Z,a&&a.preventDefault&&a.preventDefault()},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=Z,a&&a.stopPropagation&&a.stopPropagation()},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=Z,a&&a.stopImmediatePropagation&&a.stopImmediatePropagation(),this.stopPropagation()}},n.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){n.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return(!e||e!==d&&!n.contains(d,e))&&(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),k.focusinBubbles||n.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){n.event.simulate(b,a.target,n.event.fix(a),!0)};n.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=L.access(d,b);e||d.addEventListener(a,c,!0),L.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=L.access(d,b)-1;e?L.access(d,b,e):(d.removeEventListener(a,c,!0),L.remove(d,b))}}}),n.fn.extend({on:function(a,b,c,d,e){var f,g;if("object"==typeof a){"string"!=typeof b&&(c=c||b,b=void 0);for(g in a)this.on(g,b,c,a[g],e);return this}if(null==c&&null==d?(d=b,c=b=void 0):null==d&&("string"==typeof b?(d=c,c=void 0):(d=c,c=b,b=void 0)),d===!1)d=$;else if(!d)return this;return 1===e&&(f=d,d=function(a){return n().off(a),f.apply(this,arguments)},d.guid=f.guid||(f.guid=n.guid++)),this.each(function(){n.event.add(this,a,d,c,b)})},one:function(a,b,c,d){return this.on(a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,n(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return(b===!1||"function"==typeof b)&&(c=b,b=void 0),c===!1&&(c=$),this.each(function(){n.event.remove(this,a,c,b)})},trigger:function(a,b){return this.each(function(){n.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];return c?n.event.trigger(a,b,c,!0):void 0}});var ab=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,bb=/<([\w:]+)/,cb=/<|&#?\w+;/,db=/<(?:script|style|link)/i,eb=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/^$|\/(?:java|ecma)script/i,gb=/^true\/(.*)/,hb=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g,ib={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ib.optgroup=ib.option,ib.tbody=ib.tfoot=ib.colgroup=ib.caption=ib.thead,ib.th=ib.td;function jb(a,b){return n.nodeName(a,"table")&&n.nodeName(11!==b.nodeType?b:b.firstChild,"tr")?a.getElementsByTagName("tbody")[0]||a.appendChild(a.ownerDocument.createElement("tbody")):a}function kb(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function lb(a){var b=gb.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function mb(a,b){for(var c=0,d=a.length;d>c;c++)L.set(a[c],"globalEval",!b||L.get(b[c],"globalEval"))}function nb(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(L.hasData(a)&&(f=L.access(a),g=L.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;d>c;c++)n.event.add(b,e,j[e][c])}M.hasData(a)&&(h=M.access(a),i=n.extend({},h),M.set(b,i))}}function ob(a,b){var c=a.getElementsByTagName?a.getElementsByTagName(b||"*"):a.querySelectorAll?a.querySelectorAll(b||"*"):[];return void 0===b||b&&n.nodeName(a,b)?n.merge([a],c):c}function pb(a,b){var c=b.nodeName.toLowerCase();"input"===c&&T.test(a.type)?b.checked=a.checked:("input"===c||"textarea"===c)&&(b.defaultValue=a.defaultValue)}n.extend({clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=n.contains(a.ownerDocument,a);if(!(k.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||n.isXMLDoc(a)))for(g=ob(h),f=ob(a),d=0,e=f.length;e>d;d++)pb(f[d],g[d]);if(b)if(c)for(f=f||ob(a),g=g||ob(h),d=0,e=f.length;e>d;d++)nb(f[d],g[d]);else nb(a,h);return g=ob(h,"script"),g.length>0&&mb(g,!i&&ob(a,"script")),h},buildFragment:function(a,b,c,d){for(var e,f,g,h,i,j,k=b.createDocumentFragment(),l=[],m=0,o=a.length;o>m;m++)if(e=a[m],e||0===e)if("object"===n.type(e))n.merge(l,e.nodeType?[e]:e);else if(cb.test(e)){f=f||k.appendChild(b.createElement("div")),g=(bb.exec(e)||["",""])[1].toLowerCase(),h=ib[g]||ib._default,f.innerHTML=h[1]+e.replace(ab,"<$1></$2>")+h[2],j=h[0];while(j--)f=f.lastChild;n.merge(l,f.childNodes),f=k.firstChild,f.textContent=""}else l.push(b.createTextNode(e));k.textContent="",m=0;while(e=l[m++])if((!d||-1===n.inArray(e,d))&&(i=n.contains(e.ownerDocument,e),f=ob(k.appendChild(e),"script"),i&&mb(f),c)){j=0;while(e=f[j++])fb.test(e.type||"")&&c.push(e)}return k},cleanData:function(a){for(var b,c,d,e,f=n.event.special,g=0;void 0!==(c=a[g]);g++){if(n.acceptData(c)&&(e=c[L.expando],e&&(b=L.cache[e]))){if(b.events)for(d in b.events)f[d]?n.event.remove(c,d):n.removeEvent(c,d,b.handle);L.cache[e]&&delete L.cache[e]}delete M.cache[c[M.expando]]}}}),n.fn.extend({text:function(a){return J(this,function(a){return void 0===a?n.text(this):this.empty().each(function(){(1===this.nodeType||11===this.nodeType||9===this.nodeType)&&(this.textContent=a)})},null,a,arguments.length)},append:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.appendChild(a)}})},prepend:function(){return this.domManip(arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=jb(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return this.domManip(arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},remove:function(a,b){for(var c,d=a?n.filter(a,this):this,e=0;null!=(c=d[e]);e++)b||1!==c.nodeType||n.cleanData(ob(c)),c.parentNode&&(b&&n.contains(c.ownerDocument,c)&&mb(ob(c,"script")),c.parentNode.removeChild(c));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(n.cleanData(ob(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function(){return n.clone(this,a,b)})},html:function(a){return J(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!db.test(a)&&!ib[(bb.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(ab,"<$1></$2>");try{for(;d>c;c++)b=this[c]||{},1===b.nodeType&&(n.cleanData(ob(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=arguments[0];return this.domManip(arguments,function(b){a=this.parentNode,n.cleanData(ob(this)),a&&a.replaceChild(b,this)}),a&&(a.length||a.nodeType)?this:this.remove()},detach:function(a){return this.remove(a,!0)},domManip:function(a,b){a=e.apply([],a);var c,d,f,g,h,i,j=0,l=this.length,m=this,o=l-1,p=a[0],q=n.isFunction(p);if(q||l>1&&"string"==typeof p&&!k.checkClone&&eb.test(p))return this.each(function(c){var d=m.eq(c);q&&(a[0]=p.call(this,c,d.html())),d.domManip(a,b)});if(l&&(c=n.buildFragment(a,this[0].ownerDocument,!1,this),d=c.firstChild,1===c.childNodes.length&&(c=d),d)){for(f=n.map(ob(c,"script"),kb),g=f.length;l>j;j++)h=c,j!==o&&(h=n.clone(h,!0,!0),g&&n.merge(f,ob(h,"script"))),b.call(this[j],h,j);if(g)for(i=f[f.length-1].ownerDocument,n.map(f,lb),j=0;g>j;j++)h=f[j],fb.test(h.type||"")&&!L.access(h,"globalEval")&&n.contains(i,h)&&(h.src?n._evalUrl&&n._evalUrl(h.src):n.globalEval(h.textContent.replace(hb,"")))}return this}}),n.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){n.fn[a]=function(a){for(var c,d=[],e=n(a),g=e.length-1,h=0;g>=h;h++)c=h===g?this:this.clone(!0),n(e[h])[b](c),f.apply(d,c.get());return this.pushStack(d)}});var qb,rb={};function sb(b,c){var d,e=n(c.createElement(b)).appendTo(c.body),f=a.getDefaultComputedStyle&&(d=a.getDefaultComputedStyle(e[0]))?d.display:n.css(e[0],"display");return e.detach(),f}function tb(a){var b=l,c=rb[a];return c||(c=sb(a,b),"none"!==c&&c||(qb=(qb||n("<iframe frameborder='0' width='0' height='0'/>")).appendTo(b.documentElement),b=qb[0].contentDocument,b.write(),b.close(),c=sb(a,b),qb.detach()),rb[a]=c),c}var ub=/^margin/,vb=new RegExp("^("+Q+")(?!px)[a-z%]+$","i"),wb=function(a){return a.ownerDocument.defaultView.getComputedStyle(a,null)};function xb(a,b,c){var d,e,f,g,h=a.style;return c=c||wb(a),c&&(g=c.getPropertyValue(b)||c[b]),c&&(""!==g||n.contains(a.ownerDocument,a)||(g=n.style(a,b)),vb.test(g)&&ub.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0!==g?g+"":g}function yb(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}!function(){var b,c,d=l.documentElement,e=l.createElement("div"),f=l.createElement("div");if(f.style){f.style.backgroundClip="content-box",f.cloneNode(!0).style.backgroundClip="",k.clearCloneStyle="content-box"===f.style.backgroundClip,e.style.cssText="border:0;width:0;height:0;top:0;left:-9999px;margin-top:1px;position:absolute",e.appendChild(f);function g(){f.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;display:block;margin-top:1%;top:1%;border:1px;padding:1px;width:4px;position:absolute",f.innerHTML="",d.appendChild(e);var g=a.getComputedStyle(f,null);b="1%"!==g.top,c="4px"===g.width,d.removeChild(e)}a.getComputedStyle&&n.extend(k,{pixelPosition:function(){return g(),b},boxSizingReliable:function(){return null==c&&g(),c},reliableMarginRight:function(){var b,c=f.appendChild(l.createElement("div"));return c.style.cssText=f.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:0",c.style.marginRight=c.style.width="0",f.style.width="1px",d.appendChild(e),b=!parseFloat(a.getComputedStyle(c,null).marginRight),d.removeChild(e),b}})}}(),n.swap=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};var zb=/^(none|table(?!-c[ea]).+)/,Ab=new RegExp("^("+Q+")(.*)$","i"),Bb=new RegExp("^([+-])=("+Q+")","i"),Cb={position:"absolute",visibility:"hidden",display:"block"},Db={letterSpacing:"0",fontWeight:"400"},Eb=["Webkit","O","Moz","ms"];function Fb(a,b){if(b in a)return b;var c=b[0].toUpperCase()+b.slice(1),d=b,e=Eb.length;while(e--)if(b=Eb[e]+c,b in a)return b;return d}function Gb(a,b,c){var d=Ab.exec(b);return d?Math.max(0,d[1]-(c||0))+(d[2]||"px"):b}function Hb(a,b,c,d,e){for(var f=c===(d?"border":"content")?4:"width"===b?1:0,g=0;4>f;f+=2)"margin"===c&&(g+=n.css(a,c+R[f],!0,e)),d?("content"===c&&(g-=n.css(a,"padding"+R[f],!0,e)),"margin"!==c&&(g-=n.css(a,"border"+R[f]+"Width",!0,e))):(g+=n.css(a,"padding"+R[f],!0,e),"padding"!==c&&(g+=n.css(a,"border"+R[f]+"Width",!0,e)));return g}function Ib(a,b,c){var d=!0,e="width"===b?a.offsetWidth:a.offsetHeight,f=wb(a),g="border-box"===n.css(a,"boxSizing",!1,f);if(0>=e||null==e){if(e=xb(a,b,f),(0>e||null==e)&&(e=a.style[b]),vb.test(e))return e;d=g&&(k.boxSizingReliable()||e===a.style[b]),e=parseFloat(e)||0}return e+Hb(a,b,c||(g?"border":"content"),d,f)+"px"}function Jb(a,b){for(var c,d,e,f=[],g=0,h=a.length;h>g;g++)d=a[g],d.style&&(f[g]=L.get(d,"olddisplay"),c=d.style.display,b?(f[g]||"none"!==c||(d.style.display=""),""===d.style.display&&S(d)&&(f[g]=L.access(d,"olddisplay",tb(d.nodeName)))):(e=S(d),"none"===c&&e||L.set(d,"olddisplay",e?c:n.css(d,"display"))));for(g=0;h>g;g++)d=a[g],d.style&&(b&&"none"!==d.style.display&&""!==d.style.display||(d.style.display=b?f[g]||"":"none"));return a}n.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=xb(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=n.camelCase(b),i=a.style;return b=n.cssProps[h]||(n.cssProps[h]=Fb(i,h)),g=n.cssHooks[b]||n.cssHooks[h],void 0===c?g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:i[b]:(f=typeof c,"string"===f&&(e=Bb.exec(c))&&(c=(e[1]+1)*e[2]+parseFloat(n.css(a,b)),f="number"),null!=c&&c===c&&("number"!==f||n.cssNumber[h]||(c+="px"),k.clearCloneStyle||""!==c||0!==b.indexOf("background")||(i[b]="inherit"),g&&"set"in g&&void 0===(c=g.set(a,c,d))||(i[b]=c)),void 0)}},css:function(a,b,c,d){var e,f,g,h=n.camelCase(b);return b=n.cssProps[h]||(n.cssProps[h]=Fb(a.style,h)),g=n.cssHooks[b]||n.cssHooks[h],g&&"get"in g&&(e=g.get(a,!0,c)),void 0===e&&(e=xb(a,b,d)),"normal"===e&&b in Db&&(e=Db[b]),""===c||c?(f=parseFloat(e),c===!0||n.isNumeric(f)?f||0:e):e}}),n.each(["height","width"],function(a,b){n.cssHooks[b]={get:function(a,c,d){return c?zb.test(n.css(a,"display"))&&0===a.offsetWidth?n.swap(a,Cb,function(){return Ib(a,b,d)}):Ib(a,b,d):void 0},set:function(a,c,d){var e=d&&wb(a);return Gb(a,c,d?Hb(a,b,d,"border-box"===n.css(a,"boxSizing",!1,e),e):0)}}}),n.cssHooks.marginRight=yb(k.reliableMarginRight,function(a,b){return b?n.swap(a,{display:"inline-block"},xb,[a,"marginRight"]):void 0}),n.each({margin:"",padding:"",border:"Width"},function(a,b){n.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+R[d]+b]=f[d]||f[d-2]||f[0];return e}},ub.test(a)||(n.cssHooks[a+b].set=Gb)}),n.fn.extend({css:function(a,b){return J(this,function(a,b,c){var d,e,f={},g=0;if(n.isArray(b)){for(d=wb(a),e=b.length;e>g;g++)f[b[g]]=n.css(a,b[g],!1,d);return f}return void 0!==c?n.style(a,b,c):n.css(a,b)},a,b,arguments.length>1)},show:function(){return Jb(this,!0)},hide:function(){return Jb(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){S(this)?n(this).show():n(this).hide()})}});function Kb(a,b,c,d,e){return new Kb.prototype.init(a,b,c,d,e)}n.Tween=Kb,Kb.prototype={constructor:Kb,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||"swing",this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(n.cssNumber[c]?"":"px")},cur:function(){var a=Kb.propHooks[this.prop];return a&&a.get?a.get(this):Kb.propHooks._default.get(this)},run:function(a){var b,c=Kb.propHooks[this.prop];return this.pos=b=this.options.duration?n.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):Kb.propHooks._default.set(this),this}},Kb.prototype.init.prototype=Kb.prototype,Kb.propHooks={_default:{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem.style[a.prop]?(b=n.css(a.elem,a.prop,""),b&&"auto"!==b?b:0):a.elem[a.prop]},set:function(a){n.fx.step[a.prop]?n.fx.step[a.prop](a):a.elem.style&&(null!=a.elem.style[n.cssProps[a.prop]]||n.cssHooks[a.prop])?n.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}},Kb.propHooks.scrollTop=Kb.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},n.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2}},n.fx=Kb.prototype.init,n.fx.step={};var Lb,Mb,Nb=/^(?:toggle|show|hide)$/,Ob=new RegExp("^(?:([+-])=|)("+Q+")([a-z%]*)$","i"),Pb=/queueHooks$/,Qb=[Vb],Rb={"*":[function(a,b){var c=this.createTween(a,b),d=c.cur(),e=Ob.exec(b),f=e&&e[3]||(n.cssNumber[a]?"":"px"),g=(n.cssNumber[a]||"px"!==f&&+d)&&Ob.exec(n.css(c.elem,a)),h=1,i=20;if(g&&g[3]!==f){f=f||g[3],e=e||[],g=+d||1;do h=h||".5",g/=h,n.style(c.elem,a,g+f);while(h!==(h=c.cur()/d)&&1!==h&&--i)}return e&&(g=c.start=+g||+d||0,c.unit=f,c.end=e[1]?g+(e[1]+1)*e[2]:+e[2]),c}]};function Sb(){return setTimeout(function(){Lb=void 0}),Lb=n.now()}function Tb(a,b){var c,d=0,e={height:a};for(b=b?1:0;4>d;d+=2-b)c=R[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function Ub(a,b,c){for(var d,e=(Rb[b]||[]).concat(Rb["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function Vb(a,b,c){var d,e,f,g,h,i,j,k,l=this,m={},o=a.style,p=a.nodeType&&S(a),q=L.get(a,"fxshow");c.queue||(h=n._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,l.always(function(){l.always(function(){h.unqueued--,n.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[o.overflow,o.overflowX,o.overflowY],j=n.css(a,"display"),k="none"===j?L.get(a,"olddisplay")||tb(a.nodeName):j,"inline"===k&&"none"===n.css(a,"float")&&(o.display="inline-block")),c.overflow&&(o.overflow="hidden",l.always(function(){o.overflow=c.overflow[0],o.overflowX=c.overflow[1],o.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],Nb.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(p?"hide":"show")){if("show"!==e||!q||void 0===q[d])continue;p=!0}m[d]=q&&q[d]||n.style(a,d)}else j=void 0;if(n.isEmptyObject(m))"inline"===("none"===j?tb(a.nodeName):j)&&(o.display=j);else{q?"hidden"in q&&(p=q.hidden):q=L.access(a,"fxshow",{}),f&&(q.hidden=!p),p?n(a).show():l.done(function(){n(a).hide()}),l.done(function(){var b;L.remove(a,"fxshow");for(b in m)n.style(a,b,m[b])});for(d in m)g=Ub(p?q[d]:0,d,l),d in q||(q[d]=g.start,p&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function Wb(a,b){var c,d,e,f,g;for(c in a)if(d=n.camelCase(c),e=b[d],f=a[c],n.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=n.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function Xb(a,b,c){var d,e,f=0,g=Qb.length,h=n.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=Lb||Sb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:n.extend({},b),opts:n.extend(!0,{specialEasing:{}},c),originalProperties:b,originalOptions:c,startTime:Lb||Sb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=n.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?h.resolveWith(a,[j,b]):h.rejectWith(a,[j,b]),this}}),k=j.props;for(Wb(k,j.opts.specialEasing);g>f;f++)if(d=Qb[f].call(j,a,k,j.opts))return d;return n.map(k,Ub,j),n.isFunction(j.opts.start)&&j.opts.start.call(a,j),n.fx.timer(n.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always)}n.Animation=n.extend(Xb,{tweener:function(a,b){n.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var c,d=0,e=a.length;e>d;d++)c=a[d],Rb[c]=Rb[c]||[],Rb[c].unshift(b)},prefilter:function(a,b){b?Qb.unshift(a):Qb.push(a)}}),n.speed=function(a,b,c){var d=a&&"object"==typeof a?n.extend({},a):{complete:c||!c&&b||n.isFunction(a)&&a,duration:a,easing:c&&b||b&&!n.isFunction(b)&&b};return d.duration=n.fx.off?0:"number"==typeof d.duration?d.duration:d.duration in n.fx.speeds?n.fx.speeds[d.duration]:n.fx.speeds._default,(null==d.queue||d.queue===!0)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){n.isFunction(d.old)&&d.old.call(this),d.queue&&n.dequeue(this,d.queue)},d},n.fn.extend({fadeTo:function(a,b,c,d){return this.filter(S).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=n.isEmptyObject(a),f=n.speed(b,c,d),g=function(){var b=Xb(this,n.extend({},a),f);(e||L.get(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=n.timers,g=L.get(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&Pb.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));(b||!c)&&n.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=L.get(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=n.timers,g=d?d.length:0;for(c.finish=!0,n.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;g>b;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),n.each(["toggle","show","hide"],function(a,b){var c=n.fn[b];n.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(Tb(b,!0),a,d,e)}}),n.each({slideDown:Tb("show"),slideUp:Tb("hide"),slideToggle:Tb("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){n.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),n.timers=[],n.fx.tick=function(){var a,b=0,c=n.timers;for(Lb=n.now();b<c.length;b++)a=c[b],a()||c[b]!==a||c.splice(b--,1);c.length||n.fx.stop(),Lb=void 0},n.fx.timer=function(a){n.timers.push(a),a()?n.fx.start():n.timers.pop()},n.fx.interval=13,n.fx.start=function(){Mb||(Mb=setInterval(n.fx.tick,n.fx.interval))},n.fx.stop=function(){clearInterval(Mb),Mb=null},n.fx.speeds={slow:600,fast:200,_default:400},n.fn.delay=function(a,b){return a=n.fx?n.fx.speeds[a]||a:a,b=b||"fx",this.queue(b,function(b,c){var d=setTimeout(b,a);c.stop=function(){clearTimeout(d)}})},function(){var a=l.createElement("input"),b=l.createElement("select"),c=b.appendChild(l.createElement("option"));a.type="checkbox",k.checkOn=""!==a.value,k.optSelected=c.selected,b.disabled=!0,k.optDisabled=!c.disabled,a=l.createElement("input"),a.value="t",a.type="radio",k.radioValue="t"===a.value}();var Yb,Zb,$b=n.expr.attrHandle;n.fn.extend({attr:function(a,b){return J(this,n.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){n.removeAttr(this,a)})}}),n.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(a&&3!==f&&8!==f&&2!==f)return typeof a.getAttribute===U?n.prop(a,b,c):(1===f&&n.isXMLDoc(a)||(b=b.toLowerCase(),d=n.attrHooks[b]||(n.expr.match.bool.test(b)?Zb:Yb)),void 0===c?d&&"get"in d&&null!==(e=d.get(a,b))?e:(e=n.find.attr(a,b),null==e?void 0:e):null!==c?d&&"set"in d&&void 0!==(e=d.set(a,c,b))?e:(a.setAttribute(b,c+""),c):void n.removeAttr(a,b))
},removeAttr:function(a,b){var c,d,e=0,f=b&&b.match(E);if(f&&1===a.nodeType)while(c=f[e++])d=n.propFix[c]||c,n.expr.match.bool.test(c)&&(a[d]=!1),a.removeAttribute(c)},attrHooks:{type:{set:function(a,b){if(!k.radioValue&&"radio"===b&&n.nodeName(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}}}),Zb={set:function(a,b,c){return b===!1?n.removeAttr(a,c):a.setAttribute(c,c),c}},n.each(n.expr.match.bool.source.match(/\w+/g),function(a,b){var c=$b[b]||n.find.attr;$b[b]=function(a,b,d){var e,f;return d||(f=$b[b],$b[b]=e,e=null!=c(a,b,d)?b.toLowerCase():null,$b[b]=f),e}});var _b=/^(?:input|select|textarea|button)$/i;n.fn.extend({prop:function(a,b){return J(this,n.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[n.propFix[a]||a]})}}),n.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(a,b,c){var d,e,f,g=a.nodeType;if(a&&3!==g&&8!==g&&2!==g)return f=1!==g||!n.isXMLDoc(a),f&&(b=n.propFix[b]||b,e=n.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){return a.hasAttribute("tabindex")||_b.test(a.nodeName)||a.href?a.tabIndex:-1}}}}),k.optSelected||(n.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null}}),n.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){n.propFix[this.toLowerCase()]=this});var ac=/[\t\r\n\f]/g;n.fn.extend({addClass:function(a){var b,c,d,e,f,g,h="string"==typeof a&&a,i=0,j=this.length;if(n.isFunction(a))return this.each(function(b){n(this).addClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ac," "):" ")){f=0;while(e=b[f++])d.indexOf(" "+e+" ")<0&&(d+=e+" ");g=n.trim(d),c.className!==g&&(c.className=g)}return this},removeClass:function(a){var b,c,d,e,f,g,h=0===arguments.length||"string"==typeof a&&a,i=0,j=this.length;if(n.isFunction(a))return this.each(function(b){n(this).removeClass(a.call(this,b,this.className))});if(h)for(b=(a||"").match(E)||[];j>i;i++)if(c=this[i],d=1===c.nodeType&&(c.className?(" "+c.className+" ").replace(ac," "):"")){f=0;while(e=b[f++])while(d.indexOf(" "+e+" ")>=0)d=d.replace(" "+e+" "," ");g=a?n.trim(d):"",c.className!==g&&(c.className=g)}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):this.each(n.isFunction(a)?function(c){n(this).toggleClass(a.call(this,c,this.className,b),b)}:function(){if("string"===c){var b,d=0,e=n(this),f=a.match(E)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else(c===U||"boolean"===c)&&(this.className&&L.set(this,"__className__",this.className),this.className=this.className||a===!1?"":L.get(this,"__className__")||"")})},hasClass:function(a){for(var b=" "+a+" ",c=0,d=this.length;d>c;c++)if(1===this[c].nodeType&&(" "+this[c].className+" ").replace(ac," ").indexOf(b)>=0)return!0;return!1}});var bc=/\r/g;n.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=n.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,n(this).val()):a,null==e?e="":"number"==typeof e?e+="":n.isArray(e)&&(e=n.map(e,function(a){return null==a?"":a+""})),b=n.valHooks[this.type]||n.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=n.valHooks[e.type]||n.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(bc,""):null==c?"":c)}}}),n.extend({valHooks:{option:{get:function(a){var b=n.find.attr(a,"value");return null!=b?b:n.trim(n.text(a))}},select:{get:function(a){for(var b,c,d=a.options,e=a.selectedIndex,f="select-one"===a.type||0>e,g=f?null:[],h=f?e+1:d.length,i=0>e?h:f?e:0;h>i;i++)if(c=d[i],!(!c.selected&&i!==e||(k.optDisabled?c.disabled:null!==c.getAttribute("disabled"))||c.parentNode.disabled&&n.nodeName(c.parentNode,"optgroup"))){if(b=n(c).val(),f)return b;g.push(b)}return g},set:function(a,b){var c,d,e=a.options,f=n.makeArray(b),g=e.length;while(g--)d=e[g],(d.selected=n.inArray(d.value,f)>=0)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),n.each(["radio","checkbox"],function(){n.valHooks[this]={set:function(a,b){return n.isArray(b)?a.checked=n.inArray(n(a).val(),b)>=0:void 0}},k.checkOn||(n.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})}),n.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(a,b){n.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),n.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)},bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}});var cc=n.now(),dc=/\?/;n.parseJSON=function(a){return JSON.parse(a+"")},n.parseXML=function(a){var b,c;if(!a||"string"!=typeof a)return null;try{c=new DOMParser,b=c.parseFromString(a,"text/xml")}catch(d){b=void 0}return(!b||b.getElementsByTagName("parsererror").length)&&n.error("Invalid XML: "+a),b};var ec,fc,gc=/#.*$/,hc=/([?&])_=[^&]*/,ic=/^(.*?):[ \t]*([^\r\n]*)$/gm,jc=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,kc=/^(?:GET|HEAD)$/,lc=/^\/\//,mc=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,nc={},oc={},pc="*/".concat("*");try{fc=location.href}catch(qc){fc=l.createElement("a"),fc.href="",fc=fc.href}ec=mc.exec(fc.toLowerCase())||[];function rc(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(E)||[];if(n.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function sc(a,b,c,d){var e={},f=a===oc;function g(h){var i;return e[h]=!0,n.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function tc(a,b){var c,d,e=n.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&n.extend(!0,a,d),a}function uc(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}return f?(f!==i[0]&&i.unshift(f),c[f]):void 0}function vc(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}n.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:fc,type:"GET",isLocal:jc.test(ec[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":pc,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":n.parseJSON,"text xml":n.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?tc(tc(a,n.ajaxSettings),b):tc(n.ajaxSettings,a)},ajaxPrefilter:rc(nc),ajaxTransport:rc(oc),ajax:function(a,b){"object"==typeof a&&(b=a,a=void 0),b=b||{};var c,d,e,f,g,h,i,j,k=n.ajaxSetup({},b),l=k.context||k,m=k.context&&(l.nodeType||l.jquery)?n(l):n.event,o=n.Deferred(),p=n.Callbacks("once memory"),q=k.statusCode||{},r={},s={},t=0,u="canceled",v={readyState:0,getResponseHeader:function(a){var b;if(2===t){if(!f){f={};while(b=ic.exec(e))f[b[1].toLowerCase()]=b[2]}b=f[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===t?e:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return t||(a=s[c]=s[c]||a,r[a]=b),this},overrideMimeType:function(a){return t||(k.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>t)for(b in a)q[b]=[q[b],a[b]];else v.always(a[v.status]);return this},abort:function(a){var b=a||u;return c&&c.abort(b),x(0,b),this}};if(o.promise(v).complete=p.add,v.success=v.done,v.error=v.fail,k.url=((a||k.url||fc)+"").replace(gc,"").replace(lc,ec[1]+"//"),k.type=b.method||b.type||k.method||k.type,k.dataTypes=n.trim(k.dataType||"*").toLowerCase().match(E)||[""],null==k.crossDomain&&(h=mc.exec(k.url.toLowerCase()),k.crossDomain=!(!h||h[1]===ec[1]&&h[2]===ec[2]&&(h[3]||("http:"===h[1]?"80":"443"))===(ec[3]||("http:"===ec[1]?"80":"443")))),k.data&&k.processData&&"string"!=typeof k.data&&(k.data=n.param(k.data,k.traditional)),sc(nc,k,b,v),2===t)return v;i=k.global,i&&0===n.active++&&n.event.trigger("ajaxStart"),k.type=k.type.toUpperCase(),k.hasContent=!kc.test(k.type),d=k.url,k.hasContent||(k.data&&(d=k.url+=(dc.test(d)?"&":"?")+k.data,delete k.data),k.cache===!1&&(k.url=hc.test(d)?d.replace(hc,"$1_="+cc++):d+(dc.test(d)?"&":"?")+"_="+cc++)),k.ifModified&&(n.lastModified[d]&&v.setRequestHeader("If-Modified-Since",n.lastModified[d]),n.etag[d]&&v.setRequestHeader("If-None-Match",n.etag[d])),(k.data&&k.hasContent&&k.contentType!==!1||b.contentType)&&v.setRequestHeader("Content-Type",k.contentType),v.setRequestHeader("Accept",k.dataTypes[0]&&k.accepts[k.dataTypes[0]]?k.accepts[k.dataTypes[0]]+("*"!==k.dataTypes[0]?", "+pc+"; q=0.01":""):k.accepts["*"]);for(j in k.headers)v.setRequestHeader(j,k.headers[j]);if(k.beforeSend&&(k.beforeSend.call(l,v,k)===!1||2===t))return v.abort();u="abort";for(j in{success:1,error:1,complete:1})v[j](k[j]);if(c=sc(oc,k,b,v)){v.readyState=1,i&&m.trigger("ajaxSend",[v,k]),k.async&&k.timeout>0&&(g=setTimeout(function(){v.abort("timeout")},k.timeout));try{t=1,c.send(r,x)}catch(w){if(!(2>t))throw w;x(-1,w)}}else x(-1,"No Transport");function x(a,b,f,h){var j,r,s,u,w,x=b;2!==t&&(t=2,g&&clearTimeout(g),c=void 0,e=h||"",v.readyState=a>0?4:0,j=a>=200&&300>a||304===a,f&&(u=uc(k,v,f)),u=vc(k,u,v,j),j?(k.ifModified&&(w=v.getResponseHeader("Last-Modified"),w&&(n.lastModified[d]=w),w=v.getResponseHeader("etag"),w&&(n.etag[d]=w)),204===a||"HEAD"===k.type?x="nocontent":304===a?x="notmodified":(x=u.state,r=u.data,s=u.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),v.status=a,v.statusText=(b||x)+"",j?o.resolveWith(l,[r,x,v]):o.rejectWith(l,[v,x,s]),v.statusCode(q),q=void 0,i&&m.trigger(j?"ajaxSuccess":"ajaxError",[v,k,j?r:s]),p.fireWith(l,[v,x]),i&&(m.trigger("ajaxComplete",[v,k]),--n.active||n.event.trigger("ajaxStop")))}return v},getJSON:function(a,b,c){return n.get(a,b,c,"json")},getScript:function(a,b){return n.get(a,void 0,b,"script")}}),n.each(["get","post"],function(a,b){n[b]=function(a,c,d,e){return n.isFunction(c)&&(e=e||d,d=c,c=void 0),n.ajax({url:a,type:b,dataType:e,data:c,success:d})}}),n.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){n.fn[b]=function(a){return this.on(b,a)}}),n._evalUrl=function(a){return n.ajax({url:a,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},n.fn.extend({wrapAll:function(a){var b;return n.isFunction(a)?this.each(function(b){n(this).wrapAll(a.call(this,b))}):(this[0]&&(b=n(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this)},wrapInner:function(a){return this.each(n.isFunction(a)?function(b){n(this).wrapInner(a.call(this,b))}:function(){var b=n(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=n.isFunction(a);return this.each(function(c){n(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(){return this.parent().each(function(){n.nodeName(this,"body")||n(this).replaceWith(this.childNodes)}).end()}}),n.expr.filters.hidden=function(a){return a.offsetWidth<=0&&a.offsetHeight<=0},n.expr.filters.visible=function(a){return!n.expr.filters.hidden(a)};var wc=/%20/g,xc=/\[\]$/,yc=/\r?\n/g,zc=/^(?:submit|button|image|reset|file)$/i,Ac=/^(?:input|select|textarea|keygen)/i;function Bc(a,b,c,d){var e;if(n.isArray(b))n.each(b,function(b,e){c||xc.test(a)?d(a,e):Bc(a+"["+("object"==typeof e?b:"")+"]",e,c,d)});else if(c||"object"!==n.type(b))d(a,b);else for(e in b)Bc(a+"["+e+"]",b[e],c,d)}n.param=function(a,b){var c,d=[],e=function(a,b){b=n.isFunction(b)?b():null==b?"":b,d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};if(void 0===b&&(b=n.ajaxSettings&&n.ajaxSettings.traditional),n.isArray(a)||a.jquery&&!n.isPlainObject(a))n.each(a,function(){e(this.name,this.value)});else for(c in a)Bc(c,a[c],b,e);return d.join("&").replace(wc,"+")},n.fn.extend({serialize:function(){return n.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=n.prop(this,"elements");return a?n.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!n(this).is(":disabled")&&Ac.test(this.nodeName)&&!zc.test(a)&&(this.checked||!T.test(a))}).map(function(a,b){var c=n(this).val();return null==c?null:n.isArray(c)?n.map(c,function(a){return{name:b.name,value:a.replace(yc,"\r\n")}}):{name:b.name,value:c.replace(yc,"\r\n")}}).get()}}),n.ajaxSettings.xhr=function(){try{return new XMLHttpRequest}catch(a){}};var Cc=0,Dc={},Ec={0:200,1223:204},Fc=n.ajaxSettings.xhr();a.ActiveXObject&&n(a).on("unload",function(){for(var a in Dc)Dc[a]()}),k.cors=!!Fc&&"withCredentials"in Fc,k.ajax=Fc=!!Fc,n.ajaxTransport(function(a){var b;return k.cors||Fc&&!a.crossDomain?{send:function(c,d){var e,f=a.xhr(),g=++Cc;if(f.open(a.type,a.url,a.async,a.username,a.password),a.xhrFields)for(e in a.xhrFields)f[e]=a.xhrFields[e];a.mimeType&&f.overrideMimeType&&f.overrideMimeType(a.mimeType),a.crossDomain||c["X-Requested-With"]||(c["X-Requested-With"]="XMLHttpRequest");for(e in c)f.setRequestHeader(e,c[e]);b=function(a){return function(){b&&(delete Dc[g],b=f.onload=f.onerror=null,"abort"===a?f.abort():"error"===a?d(f.status,f.statusText):d(Ec[f.status]||f.status,f.statusText,"string"==typeof f.responseText?{text:f.responseText}:void 0,f.getAllResponseHeaders()))}},f.onload=b(),f.onerror=b("error"),b=Dc[g]=b("abort");try{f.send(a.hasContent&&a.data||null)}catch(h){if(b)throw h}},abort:function(){b&&b()}}:void 0}),n.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return n.globalEval(a),a}}}),n.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),n.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(d,e){b=n("<script>").prop({async:!0,charset:a.scriptCharset,src:a.url}).on("load error",c=function(a){b.remove(),c=null,a&&e("error"===a.type?404:200,a.type)}),l.head.appendChild(b[0])},abort:function(){c&&c()}}}});var Gc=[],Hc=/(=)\?(?=&|$)|\?\?/;n.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=Gc.pop()||n.expando+"_"+cc++;return this[a]=!0,a}}),n.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(Hc.test(b.url)?"url":"string"==typeof b.data&&!(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&Hc.test(b.data)&&"data");return h||"jsonp"===b.dataTypes[0]?(e=b.jsonpCallback=n.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(Hc,"$1"+e):b.jsonp!==!1&&(b.url+=(dc.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||n.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,Gc.push(e)),g&&n.isFunction(f)&&f(g[0]),g=f=void 0}),"script"):void 0}),n.parseHTML=function(a,b,c){if(!a||"string"!=typeof a)return null;"boolean"==typeof b&&(c=b,b=!1),b=b||l;var d=v.exec(a),e=!c&&[];return d?[b.createElement(d[1])]:(d=n.buildFragment([a],b,e),e&&e.length&&n(e).remove(),n.merge([],d.childNodes))};var Ic=n.fn.load;n.fn.load=function(a,b,c){if("string"!=typeof a&&Ic)return Ic.apply(this,arguments);var d,e,f,g=this,h=a.indexOf(" ");return h>=0&&(d=n.trim(a.slice(h)),a=a.slice(0,h)),n.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(e="POST"),g.length>0&&n.ajax({url:a,type:e,dataType:"html",data:b}).done(function(a){f=arguments,g.html(d?n("<div>").append(n.parseHTML(a)).find(d):a)}).complete(c&&function(a,b){g.each(c,f||[a.responseText,b,a])}),this},n.expr.filters.animated=function(a){return n.grep(n.timers,function(b){return a===b.elem}).length};var Jc=a.document.documentElement;function Kc(a){return n.isWindow(a)?a:9===a.nodeType&&a.defaultView}n.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=n.css(a,"position"),l=n(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=n.css(a,"top"),i=n.css(a,"left"),j=("absolute"===k||"fixed"===k)&&(f+i).indexOf("auto")>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),n.isFunction(b)&&(b=b.call(a,c,h)),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},n.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){n.offset.setOffset(this,a,b)});var b,c,d=this[0],e={top:0,left:0},f=d&&d.ownerDocument;if(f)return b=f.documentElement,n.contains(b,d)?(typeof d.getBoundingClientRect!==U&&(e=d.getBoundingClientRect()),c=Kc(f),{top:e.top+c.pageYOffset-b.clientTop,left:e.left+c.pageXOffset-b.clientLeft}):e},position:function(){if(this[0]){var a,b,c=this[0],d={top:0,left:0};return"fixed"===n.css(c,"position")?b=c.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),n.nodeName(a[0],"html")||(d=a.offset()),d.top+=n.css(a[0],"borderTopWidth",!0),d.left+=n.css(a[0],"borderLeftWidth",!0)),{top:b.top-d.top-n.css(c,"marginTop",!0),left:b.left-d.left-n.css(c,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent||Jc;while(a&&!n.nodeName(a,"html")&&"static"===n.css(a,"position"))a=a.offsetParent;return a||Jc})}}),n.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(b,c){var d="pageYOffset"===c;n.fn[b]=function(e){return J(this,function(b,e,f){var g=Kc(b);return void 0===f?g?g[c]:b[e]:void(g?g.scrollTo(d?a.pageXOffset:f,d?f:a.pageYOffset):b[e]=f)},b,e,arguments.length,null)}}),n.each(["top","left"],function(a,b){n.cssHooks[b]=yb(k.pixelPosition,function(a,c){return c?(c=xb(a,b),vb.test(c)?n(a).position()[b]+"px":c):void 0})}),n.each({Height:"height",Width:"width"},function(a,b){n.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){n.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return J(this,function(b,c,d){var e;return n.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?n.css(b,c,g):n.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),n.fn.size=function(){return this.length},n.fn.andSelf=n.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return n});var Lc=a.jQuery,Mc=a.$;return n.noConflict=function(b){return a.$===n&&(a.$=Mc),b&&a.jQuery===n&&(a.jQuery=Lc),n},typeof b===U&&(a.jQuery=a.$=n),n});
//# sourceMappingURL=jquery.min.map
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
module.exports = function (grunt) {
'use strict';
grunt.loadNpmTasks('grunt-simple-mocha');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.initConfig({
simplemocha: {
options: {
reporter: 'mocha-known-issues-reporter',
enableTimeouts: false,
},
files: {
src: 'allTests.js'
}
}
});
// build tasks
grunt.registerTask('test', ['simplemocha']);
grunt.registerTask('dev', ['jshint']);
};
# TodoMVC Browser Tests
The TodoMVC project has a great many implementations of exactly the same app using different MV* frameworks. Each app should be functionally identical. The goal of these tests is to provide a fully automated browser-based test that can be used to ensure that the specification is being followed by each and every TodoMVC app.
## Todo
- [ ] Complete the test implementation (27 out of 28 are now complete). The only test that I am struggling with is to test that the delete button becomes visible on hover.
- [ ] Find a more elegant solution for TodoMVC apps that use RequireJS, currently there is a short 'sleep' statement in order to give the browser time to load dependencies. Yuck!
- [ ] Run JSHint over my code ;-)
- [ ] Make it work with PhantomJS. In practice, Phantom is only a little bit faster, but it should work. Currently there are a few Phantom specific failures.
- [ ] Allow testing of apps that require a server (see: https://github.com/tastejs/todomvc/pull/821/files#r9377070)
## Running the tests
These tests use Selenium 2 (WebDriver), via the JavaScript API (WebdriverJS). In order to run the tests you will need to install the dependencies. Run the following command from within the `browser-tests` folder:
```sh
$ npm install
```
The tests use Mocha, which must be installed as a command line module:
```sh
$ npm install -g mocha
```
You need to run a local server at the root of the TodoMVC project. On Mac OSX, you can do the following:
```sh
$ python -m SimpleHTTPServer 8000
```
or its Ruby equivalent:
```sh
$ ruby -run -e httpd . -p 8000
```
And for Windows, the node [http-server](https://github.com/nodeapps/http-server) is a simple, zero-configuration alternative.
To run the tests for all TodoMVC implementations, run the following:
```sh
$ mocha allTests.js --no-timeouts --reporter spec
```
Note that `--reporter spec` uses the mocha 'spec' reporter, which is quite informative. You can of course specify any other reporter.
In order to run tests for a single TodoMVC implementation, supply a framework argument as follows:
```sh
$ mocha allTests.js --no-timeouts --reporter spec --framework=angularjs
```
In order to run a specific test, use the mocha 'grep' function. For example:
```
$ mocha allTests.js --no-timeouts --reporter spec --framework=jquery \
--grep 'should trim entered text'
TodoMVC - jquery
Editing
✓ should trim entered text (1115ms)
1 passing (3s)
```
### Specifying the browser
You can also specify the browser that will be used to execute the tests via the `---browser` argument. The tests default to using Chrome (see the instructions below for installing ChromeDriver). For example, to run against phantomjs, use the following:
```sh
$ mocha allTests.js --no-timeouts --reporter spec --browser=phantomjs
```
You must install phantomjs first of course!
Valid browser names can be found within webdriver via the `webdriver.Browser` enumeration.
## Reporting against known issues
The `knownIssues.js` file details the currently known issues with the TodoMVC implementations. You can run the tests and compare against these issues using the `mocha-known-issues-reporter`. This reporter is a separate npm module, as a result the easiest way to run it using the supplied gruntfile:
```sh
$ grunt test --framework=angularjs
```
When run via grunt the suite supports exactly the same command line arguments.
An example output with the known issues reporter is shown below:
```
$ grunt test --framework=jquery
Running "simplemocha:files" (simplemocha) task
(1 of 27) pass: TodoMVC - jquery, No Todos, should hide #main and #footer
[...]
(17 of 27) pass: TodoMVC - jquery, Editing, should remove the item if an empty text string was entered
(18 of 27) known issue: TodoMVC - jquery, Editing, should cancel edits on escape -- error: undefined
(19 of 27) pass: TodoMVC - jquery, Counter, should display the current number of todo items
(20 of 27) pass: TodoMVC - jquery, Clear completed button, should display the number of completed items
(21 of 27) pass: TodoMVC - jquery, Clear completed button, should remove completed items when clicked
(22 of 27) pass: TodoMVC - jquery, Clear completed button, should be hidden when there are no items that are completed
(23 of 27) pass: TodoMVC - jquery, Persistence, should persist its data
(24 of 27) known issue: TodoMVC - jquery, Routing, should allow me to display active items -- error: Cannot call method 'click' of undefined
(25 of 27) known issue: TodoMVC - jquery, Routing, should allow me to display completed items -- error: Cannot call method 'click' of undefined
(26 of 27) known issue: TodoMVC - jquery, Routing, should allow me to display all items -- error: Cannot call method 'click' of undefined
(27 of 27) known issue: TodoMVC - jquery, Routing, should highlight the currently applied filter -- error: Cannot call method 'getAttribute' of undefined
passed: 22/27
failed: 5/27
new issues: 0
resolved issues: 0
```
The reporter indicates the number of passes, failed, new and resolved issues. This makes it ideal for regression testing.
### Chrome
In order to run the tests using the Chrome browser, you need to install ChromeDriver. Instructions for download and installation can be found on the [ChromeDriver homepage](http://code.google.com/p/selenium/wiki/ChromeDriver), or a simpler set of instructions is available [here](http://damien.co/resources/how-to-install-chromedriver-mac-os-x-selenium-python-7406).
### Example output
A test run with the 'spec' reporter looks something like the following:
```
$ mocha allTests.js --no-timeouts --reporter spec --framework=angularjs
angularjs
TodoMVC
No Todos
✓ should hide #main and #footer (201ms)
New Todo
✓ should allow me to add todo items (548ms)
✓ should clear text input field when an item is added (306ms)
✓ should trim text input (569ms)
✓ should show #main and #footer when items added (405ms)
Mark all as completed
✓ should allow me to mark all items as completed (1040ms)
✓ should allow me to clear the completion state of all items (1014ms)
✓ complete all checkbox should update state when items are completed (1413ms)
Item
✓ should allow me to mark items as complete (843ms)
✓ should allow me to un-mark items as complete (978ms)
✓ should allow me to edit an item (1155ms)
✓ should show the remove button on hover
Editing
✓ should hide other controls when editing (718ms)
✓ should save edits on enter (1093ms)
✓ should save edits on blur (1256ms)
✓ should trim entered text (1163ms)
✓ should remove the item if an empty text string was entered (1033ms)
✓ should cancel edits on escape (1115ms)
Counter
✓ should display the current number of todo items (462ms)
Clear completed button
✓ should display the number of completed items (873ms)
✓ should remove completed items when clicked (898ms)
✓ should be hidden when there are no items that are completed (893ms)
Persistence
✓ should persist its data (3832ms)
Routing
✓ should allow me to display active items (871ms)
✓ should allow me to display completed items (960ms)
✓ should allow me to display all items (1192ms)
✓ should highlight the currently applied filter (1095ms)
27 passing (1m)
```
## Speed mode
In order to keep each test case fully isolated, the browser is closed then re-opened in between each test. This does mean that the tests can take quite a long time to run. If you don't mind the risk of side-effects you can run the tests in speed mode by adding the `--speedMode` argument.
```sh
$ mocha allTests.js --no-timeouts --reporter spec --speedMode
```
Before each test all the todo items are checked as completed and the 'clear complete' button pressed. This make the tests run in around half the time, but with the obvious risk that the tear-down code may fail.
## Lax mode
There are certain implementations (e.g. GWT and Dojo) where the constraints of the framework mean that it is not possible to match exactly the HTML specification for TodoMVC. In these cases the tests can be run in a 'lax' mode where the XPath queries used to locate DOM elements are more general. For example, rather than looking for a checkbox `input` element with a class of `toggle`, in lax mode it simply looks for any `input` elements of type `checkbox`. To run the tests in lax mode, simply use the `--laxMode` argument:
```sh
$ mocha allTests.js --no-timeouts --reporter spec --laxMode
```
## Test design
Very briefly, the tests are designed as follows:
- `page.js` - provides an abstraction layer for the HTML template. All the code required to access elements from the DOM is found within this file. The XPaths used to locate elements are based on the TodoMVC specification, using the required element classes / ids.
- `pageLaxMode.js` - extends the above in order to relax the XPath constraints.
- `testOperations.js` - provides common assertions and operations.
- `test.js` - Erm … the tests! These are written to closely match the TodoMVC spec.
- `allTest.js` - A simple file that locates all of the framework examples, and runs the tests for each.
**NOTE:** All of the WebdriverJS methods return promises and are executed asynchronously. However, you do not have to 'chain' them using `then`, they are instead automagically added to a queue, then executed. This means that if you add non-WebdriverJS operations (asserts, log messages) these will not be executed at the point you might expect. This is why `TestOperations.js` uses an explicit `then` each time it asserts.
'use strict';
var testSuite = require('./test.js');
var fs = require('fs');
var argv = require('optimist').default('laxMode', false).default('browser', 'chrome').argv;
var rootUrl = 'http://localhost:8000/';
var frameworkNamePattern = /^[a-z-_]+$/;
var excludedFrameworks = [
// this implementation deviates from the specification to such an extent that they are
// not worth testing via a generic mechanism
'gwt',
// selenium webdriver cannot see the shadow dom
'polymer',
// these implementations cannot be run offline, because they are hosted
'derby', 'firebase-angular', 'meteor', 'socketstream',
// YUI is a special case here, it is not hosted, but fetches JS files dynamically
'yui',
// these frameworks take a long time to start-up, and there is no easy way to determine when they are ready
'cujo', 'montage',
// sammyjs fails intermittently, it would appear that its state is sometimes updated asynchronously?
'sammyjs',
// these are examples that have been removed or are empty folders
'emberjs_require', 'dermis'
];
// collect together the framework names from each of the subfolders
var list = fs.readdirSync('../architecture-examples/')
.map(function (folderName) {
return { name: folderName, path: 'architecture-examples/' + folderName };
})
.concat(fs.readdirSync('../labs/architecture-examples/')
.map(function (folderName) {
return { name: folderName, path: 'labs/architecture-examples/' + folderName };
})
)
.concat(fs.readdirSync('../labs/dependency-examples/')
.map(function (folderName) {
return { name: folderName, path: 'labs/dependency-examples/' + folderName };
})
)
.concat(fs.readdirSync('../dependency-examples/')
.map(function (folderName) {
return { name: folderName, path: 'dependency-examples/' + folderName };
})
);
// apps that are not hosted at the root of their folder need to be handled explicitly
var exceptions = [
{ name: 'chaplin-brunch', path: 'labs/dependency-examples/chaplin-brunch/public' },
{ name: 'angular-dart', path: 'labs/architecture-examples/angular-dart/web' },
{ name: 'duel', path: 'labs/architecture-examples/duel/www' },
{ name: 'dart', path: 'vanilla-examples/vanilladart/build/' },
{ name: 'canjs_require', path: 'labs/dependency-examples/canjs_require/' },
{ name: 'troopjs', path: 'labs/dependency-examples/troopjs_require/' },
{ name: 'thorax_lumbar', path: 'labs/dependency-examples/thorax_lumbar/public' },
];
list = list.map(function (framework) {
var exception = exceptions.filter(function (exFramework) {
return exFramework.name === framework.name;
});
return exception.length > 0 ? exception[0] : framework;
});
// filter out any folders that are not frameworks (.e.g hidden files)
list = list.filter(function (framework) {
return frameworkNamePattern.test(framework.name);
});
// filter out un-supported implementations
list = list.filter(function (framework) {
return excludedFrameworks.indexOf(framework.name) === -1;
});
// if a specific framework has been named, just run this one
if (argv.framework) {
list = list.filter(function (framework) {
return framework.name === argv.framework;
});
if (list.length === 0) {
console.log('You have either requested an unknown or an un-supported framework');
}
}
// run the tests for each framework
list.forEach(function (framework) {
testSuite.todoMVCTest(
framework.name,
rootUrl + framework.path + '/index.html', argv.speedMode,
argv.laxMode, argv.browser);
});
module.exports = [
// see: https://github.com/tastejs/todomvc/issues/832
// chapling brunch does not mark items as completed via the completed CSS class
'TodoMVC - chaplin-brunch, No Todos, should hide #main and #footer',
'TodoMVC - chaplin-brunch, Mark all as completed, should allow me to mark all items as completed',
'TodoMVC - chaplin-brunch, Mark all as completed, complete all checkbox should update state when items are completed / cleared',
'TodoMVC - chaplin-brunch, Item, should allow me to mark items as complete',
'TodoMVC - chaplin-brunch, Item, should allow me to un-mark items as complete',
'TodoMVC - chaplin-brunch, Item, should allow me to edit an item',
// durandal routing is very very slow.
// see: https://github.com/tastejs/todomvc/issues/831
'TodoMVC - durandal, Routing, should allow me to display active items',
'TodoMVC - durandal, Routing, should allow me to display completed items',
'TodoMVC - durandal, Routing, should allow me to display all items',
'TodoMVC - durandal, Routing, should highlight the currently applied filter',
// see: https://github.com/tastejs/todomvc/issues/830
// typescript-backbone has a nested div within the li element, and sets /li/div[@class=done]
'TodoMVC - typescript-backbone, Mark all as completed, should allow me to mark all items as completed / cleared',
'TodoMVC - typescript-backbone, Item, should allow me to mark items as complete',
'TodoMVC - typescript-backbone, Item, should allow me to un-mark items as complete',
'TodoMVC - typescript-backbone, Item, should allow me to edit an item',
// https://github.com/tastejs/todomvc/issues/829
// checkbox state is inverted
'TodoMVC - typescript-angular, Mark all as completed, should allow me to mark all items as completed',
'TodoMVC - typescript-angular, Mark all as completed, should allow me to clear the completion state of all items',
'TodoMVC - typescript-angular, Mark all as completed, complete all checkbox should update state when items are completed / cleared',
// https://github.com/tastejs/todomvc/issues/828
// routing should default to all
'TodoMVC - batman, Routing, should highlight the currently applied filter',
'TodoMVC - plastronjs, Routing, should highlight the currently applied filter',
'TodoMVC - sammyjs, Routing, should highlight the currently applied filter',
// https://github.com/tastejs/todomvc/issues/824
// this implementation has numerous edit experience issues
'TodoMVC - angularjs_require, Mark all as completed, should allow me to mark all items as completed',
'TodoMVC - angularjs_require, Mark all as completed, should allow me to clear the completion state of all items',
'TodoMVC - angularjs_require, Mark all as completed, complete all checkbox should update state when items are completed / cleared',
// https://github.com/tastejs/todomvc/issues/824
// this implementation has numerous edit experience issues
'TodoMVC - typescript-backbone, Editing, should save edits on enter',
'TodoMVC - typescript-backbone, Editing, should trim entered text',
'TodoMVC - typescript-backbone, Editing, should remove the item if an empty text string was entered',
'TodoMVC - typescript-backbone, Editing, should cancel edits on escape',
// https://github.com/tastejs/todomvc/issues/815
// does not hide other controls while editing
'TodoMVC - dojo, Editing, should hide other controls when editing',
// https://github.com/tastejs/todomvc/issues/816
// atma does not hide the main section, instead it hides the toggle-all checkbox
'TodoMVC - atmajs, No Todos, should hide #main and #footer',
// https://github.com/tastejs/todomvc/issues/817
// batman does not trim input
'TodoMVC - batman, New Todo, should trim text input',
'TodoMVC - typescript-backbone, New Todo, should trim text input',
// https://github.com/tastejs/todomvc/issues/819
// the edit experience with soma is quite broken. You can
// get multiple elements into an edit state
'TodoMVC - somajs, Editing, should remove the item if an empty text string was entered',
'TodoMVC - somajs_require, Editing, should remove the item if an empty text string was entered',
'TodoMVC - somajs_require, Editing, should cancel edits on escape',
// the following are covered by the following issue:
// https://github.com/tastejs/todomvc/issues/789
'TodoMVC - agilityjs, Editing, should cancel edits on escape',
'TodoMVC - angularjs-perf, Editing, should cancel edits on escape',
'TodoMVC - closure, Editing, should cancel edits on escape',
'TodoMVC - jquery, Editing, should cancel edits on escape',
'TodoMVC - knockback, Editing, should cancel edits on escape',
'TodoMVC - spine, Editing, should cancel edits on escape',
'TodoMVC - yui, Editing, should cancel edits on escape',
'TodoMVC - ariatemplates, Editing, should cancel edits on escape',
'TodoMVC - dermis, Editing, should cancel edits on escape',
'TodoMVC - duel, Editing, should cancel edits on escape',
'TodoMVC - epitome, Editing, should cancel edits on escape',
'TodoMVC - extjs_deftjs, Editing, should cancel edits on escape',
'TodoMVC - kendo, Editing, should cancel edits on escape',
'TodoMVC - olives, Editing, should cancel edits on escape',
'TodoMVC - plastronjs, Editing, should cancel edits on escape',
'TodoMVC - rappidjs, Editing, should cancel edits on escape',
'TodoMVC - serenadejs, Editing, should cancel edits on escape',
'TodoMVC - somajs, Editing, should cancel edits on escape',
'TodoMVC - thorax, Editing, should cancel edits on escape',
'TodoMVC - typescript-angular, Editing, should cancel edits on escape',
'TodoMVC - angularjs_require, Editing, should cancel edits on escape',
'TodoMVC - backbone_marionette_require, Editing, should cancel edits on escape',
'TodoMVC - flight, Editing, should cancel edits on escape',
'TodoMVC - thorax_lumbar, Editing, should cancel edits on escape',
'TodoMVC - backbone_require, Editing, should cancel edits on escape',
'TodoMVC - batman, Editing, should cancel edits on escape',
'TodoMVC - dijon, Editing, should cancel edits on escape',
'TodoMVC - knockoutjs_require, Editing, should cancel edits on escape',
// all the following are covered by this issue:
// https://github.com/tastejs/todomvc/issues/856
'TodoMVC - knockoutjs, Routing, should respect the back button',
'TodoMVC - spine, Routing, should respect the back button',
'TodoMVC - componentjs, Routing, should respect the back button',
'TodoMVC - serenadejs, Routing, should respect the back button',
'TodoMVC - flight, Routing, should respect the back button',
'TodoMVC - lavaca_require, Routing, should respect the back button',
'TodoMVC - somajs_require, Routing, should respect the back button',
'TodoMVC - agilityjs, Routing, should respect the back button',
'TodoMVC - maria, Routing, should respect the back button',
// the following are covered by this issue:
// https://github.com/tastejs/todomvc/issues/795
'TodoMVC - spine, Mark all as completed, complete all checkbox should update state when items are completed / cleared',
'TodoMVC - angularjs-perf, Mark all as completed, complete all checkbox should update state when items are completed / cleared',
'TodoMVC - kendo, Mark all as completed, complete all checkbox should update state when items are completed / cleared',
// the following implementations do not support routing
'TodoMVC - extjs_deftjs, Routing, should allow me to display active items',
'TodoMVC - extjs_deftjs, Routing, should allow me to display completed items',
'TodoMVC - extjs_deftjs, Routing, should allow me to display all items',
'TodoMVC - extjs_deftjs, Routing, should highlight the currently applied filter',
'TodoMVC - extjs_deftjs, Routing, should respect the back button',
'TodoMVC - olives, Routing, should allow me to display active items',
'TodoMVC - olives, Routing, should allow me to display completed items',
'TodoMVC - olives, Routing, should allow me to display all items',
'TodoMVC - olives, Routing, should highlight the currently applied filter',
'TodoMVC - olives, Routing, should respect the back button',
'TodoMVC - dijon, Routing, should allow me to display active items',
'TodoMVC - dijon, Routing, should allow me to display completed items',
'TodoMVC - dijon, Routing, should allow me to display all items',
'TodoMVC - dijon, Routing, should highlight the currently applied filter',
'TodoMVC - dijon, Routing, should respect the back button',
'TodoMVC - duel, Routing, should allow me to display active items',
'TodoMVC - duel, Routing, should allow me to display completed items',
'TodoMVC - duel, Routing, should allow me to display all items',
'TodoMVC - duel, Routing, should highlight the currently applied filter',
'TodoMVC - duel, Routing, should respect the back button',
'TodoMVC - knockoutjs_require, Routing, should allow me to display active items',
'TodoMVC - knockoutjs_require, Routing, should allow me to display completed items',
'TodoMVC - knockoutjs_require, Routing, should allow me to display all items',
'TodoMVC - knockoutjs_require, Routing, should highlight the currently applied filter',
'TodoMVC - knockoutjs_require, Routing, should respect the back button',
'TodoMVC - angular-dart, Routing, should allow me to display active items',
'TodoMVC - angular-dart, Routing, should allow me to display completed items',
'TodoMVC - angular-dart, Routing, should allow me to display all items',
'TodoMVC - angular-dart, Routing, should highlight the currently applied filter',
'TodoMVC - angular-dart, Routing, should respect the back button',
'TodoMVC - typescript-backbone, Routing, should allow me to display active items',
'TodoMVC - typescript-backbone, Routing, should allow me to display completed items',
'TodoMVC - typescript-backbone, Routing, should allow me to display all items',
'TodoMVC - typescript-backbone, Routing, should highlight the currently applied filter',
'TodoMVC - typescript-backbone, Routing, should respect the back button',
// EXTJS is not spec compliant (by a long way!)
'TodoMVC - extjs, New Todo, should show #main and #footer when items added',
'TodoMVC - extjs, Mark all as completed, should allow me to mark all items as completed',
'TodoMVC - extjs, Mark all as completed, complete all checkbox should update state when items are completed / cleared',
'TodoMVC - extjs, Item, should allow me to mark items as complete',
'TodoMVC - extjs, Item, should allow me to un-mark items as complete',
'TodoMVC - extjs, Editing, should save edits on blur',
'TodoMVC - extjs, Editing, should cancel edits on escape',
'TodoMVC - extjs, Counter, should display the current number of todo items',
'TodoMVC - extjs, Clear completed button, should display the number of completed items',
'TodoMVC - extjs, Clear completed button, should remove completed items when clicked',
'TodoMVC - extjs, Clear completed button, should be hidden when there are no items that are completed',
'TodoMVC - extjs, Persistence, should persist its data',
'TodoMVC - extjs, Routing, should allow me to display active items',
'TodoMVC - extjs, Routing, should allow me to display completed items',
'TodoMVC - extjs, Routing, should allow me to display all items',
'TodoMVC - extjs, Routing, should highlight the currently applied filter',
'TodoMVC - extjs, Routing, should respect the back button',
// stapes is completely broken!
// see: https://github.com/tastejs/todomvc/issues/808
'TodoMVC - stapes, Mark all as completed, should allow me to mark all items as completed',
'TodoMVC - stapes, Mark all as completed, should allow me to clear the completion state of all items',
'TodoMVC - stapes, Mark all as completed, complete all checkbox should update state when items are completed / cleared',
'TodoMVC - stapes, Item, should allow me to mark items as complete',
'TodoMVC - stapes, Item, should allow me to un-mark items as complete',
'TodoMVC - stapes, Item, should allow me to edit an item',
'TodoMVC - stapes, Editing, should hide other controls when editing',
'TodoMVC - stapes, Editing, should save edits on enter',
'TodoMVC - stapes, Editing, should save edits on blur',
'TodoMVC - stapes, Editing, should trim entered text',
'TodoMVC - stapes, Editing, should remove the item if an empty text string was entered',
'TodoMVC - stapes, Editing, should cancel edits on escape',
'TodoMVC - stapes, Counter, should display the current number of todo items',
'TodoMVC - stapes, Clear completed button, should display the number of completed items',
'TodoMVC - stapes, Clear completed button, should remove completed items when clicked',
'TodoMVC - stapes, Clear completed button, should be hidden when there are no items that are completed',
'TodoMVC - stapes, Persistence, should persist its data',
'TodoMVC - stapes, Routing, should allow me to display active items',
'TodoMVC - stapes, Routing, should allow me to display completed items',
'TodoMVC - stapes, Routing, should allow me to display all items',
'TodoMVC - stapes, Routing, should respect the back button',
'TodoMVC - stapes_require, No Todos, should hide #main and #footer',
'TodoMVC - stapes_require, New Todo, should allow me to add todo items',
'TodoMVC - stapes_require, New Todo, should append new items to the bottom of the list',
'TodoMVC - stapes_require, New Todo, should trim text input',
'TodoMVC - stapes_require, Mark all as completed, should allow me to mark all items as completed',
'TodoMVC - stapes_require, Mark all as completed, should allow me to clear the completion state of all items',
'TodoMVC - stapes_require, Mark all as completed, complete all checkbox should update state when items are completed / cleared',
'TodoMVC - stapes_require, Item, should allow me to mark items as complete',
'TodoMVC - stapes_require, Item, should allow me to un-mark items as complete',
'TodoMVC - stapes_require, Item, should allow me to edit an item',
'TodoMVC - stapes_require, Editing, should hide other controls when editing',
'TodoMVC - stapes_require, Editing, should save edits on enter',
'TodoMVC - stapes_require, Editing, should save edits on blur',
'TodoMVC - stapes_require, Editing, should trim entered text',
'TodoMVC - stapes_require, Editing, should remove the item if an empty text string was entered',
'TodoMVC - stapes_require, Editing, should cancel edits on escape',
'TodoMVC - stapes_require, Counter, should display the current number of todo items',
'TodoMVC - stapes_require, Clear completed button, should display the number of completed items',
'TodoMVC - stapes_require, Clear completed button, should remove completed items when clicked',
'TodoMVC - stapes_require, Clear completed button, should be hidden when there are no items that are completed',
'TodoMVC - stapes_require, Routing, should allow me to display active items',
'TodoMVC - stapes_require, Routing, should allow me to display completed items',
'TodoMVC - stapes_require, Routing, should allow me to display all items',
'TodoMVC - stapes_require, Routing, should respect the back button',
// mozart is not on the public website
'TodoMVC - mozart, New Todo, should allow me to add todo items',
'TodoMVC - mozart, New Todo, should trim text input',
// ----------------- Test framework issues -----------
// for some reason the persistence test fails for knockout, even though persistence is working
// just fine. Perhaps there is something asynchronous going on that is causing the assert
// to be executed early?
'TodoMVC - knockoutjs, Persistence, should persist its data',
// chaplin edit tests fail with the following:
// StaleElementReferenceError: stale element reference: element is not attached to the page document
'TodoMVC - chaplin-brunch, Editing, should save edits on enter',
'TodoMVC - chaplin-brunch, Editing, should save edits on blur',
'TodoMVC - chaplin-brunch, Editing, should trim entered text',
'TodoMVC - chaplin-brunch, Editing, should remove the item if an empty text string was entered',
'TodoMVC - chaplin-brunch, Editing, should cancel edits on escape'
];
{
"name": "todomvc-browser-tests",
"description": "An automated test suite for TodoMVC",
"private": true,
"devDependencies": {
"grunt": "^0.4.5",
"grunt-simple-mocha": "^0.4.0",
"mocha": "*",
"optimist": "^0.6.1",
"q": "^1.0.1",
"selenium-webdriver": "^2.42.1",
"mocha-known-issues-reporter" : "git+https://github.com/ColinEberhardt/mocha-known-issues-reporter.git#v0.0.0"
}
}
'use strict';
var webdriver = require('selenium-webdriver');
module.exports = function Page(browser) {
// ----------------- utility methods
this.tryFindByXpath = function (xpath) {
return browser.findElements(webdriver.By.xpath(xpath));
};
this.findByXpath = function (xpath) {
return browser.findElement(webdriver.By.xpath(xpath));
};
this.getTodoListXpath = function () {
return '//ul[@id="todo-list"]';
};
this.xPathForItemAtIndex = function (index) {
// why is XPath the only language silly enough to be 1-indexed?
return this.getTodoListXpath() + '/li[' + (index + 1) + ']';
};
// ----------------- navigation methods
this.back = function() {
return browser.navigate().back();
}
// ----------------- try / get methods
// unfortunately webdriver does not have a decent API for determining if an
// element exists. The standard approach is to obtain an array of elements
// and test that the length is zero. These methods are used to obtain
// elements which *might* be present in the DOM, hence the try/get name.
this.tryGetMainSectionElement = function () {
return this.tryFindByXpath('//section[@id="main"]');
};
this.tryGetFooterElement = function () {
return this.tryFindByXpath('//footer[@id="footer"]');
};
this.tryGetClearCompleteButton = function () {
return this.tryFindByXpath('//button[@id="clear-completed"]');
};
this.tryGetToggleForItemAtIndex = function (index) {
var xpath = this.xPathForItemAtIndex(index) + '//input[contains(@class,"toggle")]';
return this.tryFindByXpath(xpath);
};
this.tryGetItemLabelAtIndex = function (index) {
return this.tryFindByXpath(this.xPathForItemAtIndex(index) + '//label');
};
// ----------------- DOM element access methods
this.getEditInputForItemAtIndex = function (index) {
var xpath = this.xPathForItemAtIndex(index) + '//input[contains(@class,"edit")]';
return this.findByXpath(xpath);
};
this.getItemInputField = function () {
return this.findByXpath('//input[@id="new-todo"]');
};
this.getMarkAllCompletedCheckBox = function () {
return this.findByXpath('//input[@id="toggle-all"]');
};
this.getItemElements = function () {
return this.tryFindByXpath(this.getTodoListXpath() + '/li');
};
this.getNonCompletedItemElements = function () {
return this.tryFindByXpath(this.getTodoListXpath() + '/li[not(contains(@class,"completed"))]');
};
this.getItemsCountElement = function () {
return this.findByXpath('//span[@id="todo-count"]');
};
this.getItemLabelAtIndex = function (index) {
return this.findByXpath(this.xPathForItemAtIndex(index) + '//label');
};
this.getFilterElements = function () {
return this.tryFindByXpath('//ul[@id="filters"]//a');
};
this.getItemLabels = function () {
var xpath = this.getTodoListXpath() + '/li//label';
return this.tryFindByXpath(xpath);
};
// ----------------- page actions
this.clickMarkAllCompletedCheckBox = function () {
return this.getMarkAllCompletedCheckBox().then(function (checkbox) {
checkbox.click();
});
};
this.clickClearCompleteButton = function () {
return this.tryGetClearCompleteButton().then(function (elements) {
var button = elements[0];
button.click();
});
};
this.enterItem = function (itemText) {
var textField = this.getItemInputField();
textField.sendKeys(itemText);
textField.sendKeys(webdriver.Key.ENTER);
};
this.toggleItemAtIndex = function (index) {
return this.tryGetToggleForItemAtIndex(index).then(function (elements) {
var toggleElement = elements[0];
toggleElement.click();
});
};
this.editItemAtIndex = function (index, itemText) {
return this.getEditInputForItemAtIndex(index)
.then(function (itemEditField) {
// send 50 delete keypresses, just to be sure the item text is deleted
var deleteKeyPresses = '';
for (var i = 0; i < 50; i++) {
deleteKeyPresses += webdriver.Key.BACK_SPACE;
}
itemEditField.sendKeys(deleteKeyPresses);
// update the item with the new text.
itemEditField.sendKeys(itemText);
});
};
this.doubleClickItemAtIndex = function (index) {
return this.getItemLabelAtIndex(index).then(function (itemLabel) {
// double click is not 'natively' supported, so we need to send the
// event direct to the element see:
// http://stackoverflow.com/questions/3982442/selenium-2-webdriver-how-to-double-click-a-table-row-which-opens-a-new-window
browser.executeScript('var evt = document.createEvent("MouseEvents");' +
'evt.initMouseEvent("dblclick",true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0,null);' +
'arguments[0].dispatchEvent(evt);', itemLabel);
});
};
this.filterByActiveItems = function () {
return this.getFilterElements().then(function (filters) {
filters[1].click();
});
};
this.filterByCompletedItems = function () {
return this.getFilterElements().then(function (filters) {
filters[2].click();
});
};
this.filterByAllItems = function () {
return this.getFilterElements().then(function (filters) {
filters[0].click();
});
};
};
'use strict';
var webdriver = require('selenium-webdriver');
var Page = require('./page');
module.exports = function PageLaxMode(browser) {
Page.apply(this, [browser]);
this.tryGetMainSectionElement = function () {
return this.tryFindByXpath('//section//section');
};
this.tryGetFooterElement = function () {
return this.tryFindByXpath('//section//footer');
};
this.getTodoListXpath = function () {
return '(//section/ul | //section/div/ul | //ul[@id="todo-list"])';
};
this.getMarkAllCompletedCheckBox = function () {
var xpath = '(//section/input[@type="checkbox"] | //section/*/input[@type="checkbox"] | //input[@id="toggle-all"])';
return browser.findElement(webdriver.By.xpath(xpath));
};
this.tryGetClearCompleteButton = function () {
var xpath = '(//footer/button | //footer/*/button | //button[@id="clear-completed"])';
return browser.findElements(webdriver.By.xpath(xpath));
};
this.getItemsCountElement = function () {
var xpath = '(//footer/span | //footer/*/span)';
return browser.findElement(webdriver.By.xpath(xpath));
};
this.getFilterElements = function () {
return browser.findElements(webdriver.By.xpath('//footer//ul//a'));
};
this.getItemInputField = function () {
// allow a more generic method for locating the text getItemInputField
var xpath = '(//header/input | //header/*/input | //input[@id="new-todo"])';
return browser.findElement(webdriver.By.xpath(xpath));
};
this.tryGetToggleForItemAtIndex = function (index) {
// the specification dictates that the checkbox should have the 'toggle' CSS class. Some implementations deviate from
// this, hence in lax mode we simply look for any checkboxes within the specified 'li'.
var xpath = this.xPathForItemAtIndex(index) + '//input[@type="checkbox"]';
return browser.findElements(webdriver.By.xpath(xpath));
};
this.getEditInputForItemAtIndex = function (index) {
// the specification dictates that the input element that allows the user to edit a todo item should have a CSS
// class of 'edit'. In lax mode, we also look for an input of type 'text'.
var xpath = '(' + this.xPathForItemAtIndex(index) + '//input[@type="text"]' + '|' +
this.xPathForItemAtIndex(index) + '//input[contains(@class,"edit")]' + ')';
return browser.findElement(webdriver.By.xpath(xpath));
};
};
'use strict';
var webdriver = require('selenium-webdriver');
var test = require('selenium-webdriver/testing');
var Page = require('./page');
var PageLaxMode = require('./pageLaxMode');
var TestOperations = require('./testOperations');
module.exports.todoMVCTest = function (frameworkName, baseUrl, speedMode, laxMode, browserName) {
test.describe('TodoMVC - ' + frameworkName, function () {
var TODO_ITEM_ONE = 'buy some cheese';
var TODO_ITEM_TWO = 'feed the cat';
var TODO_ITEM_THREE = 'book a doctors appointment';
var browser, testOps, page;
// a number of tests use this set of ToDo items.
function createStandardItems() {
page.enterItem(TODO_ITEM_ONE);
page.enterItem(TODO_ITEM_TWO);
page.enterItem(TODO_ITEM_THREE);
}
function launchBrowser() {
browser = new webdriver.Builder()
.withCapabilities({browserName : browserName})
.build();
browser.get(baseUrl);
page = laxMode ? new PageLaxMode(browser) : new Page(browser);
testOps = new TestOperations(page);
// for apps that use require, we have to wait a while for the dependencies to
// be loaded. There must be a more elegant solution than this!
browser.sleep(200);
}
function closeBrowser() {
browser.quit();
}
if (speedMode) {
test.before(function () {
launchBrowser();
});
test.after(function () {
closeBrowser();
});
test.beforeEach(function () {
page.getItemElements().then(function (items) {
if (items.length > 0) {
// find any items that are not complete
page.getNonCompletedItemElements().then(function (nonCompleteItems) {
if (nonCompleteItems.length > 0) {
page.clickMarkAllCompletedCheckBox();
}
page.clickClearCompleteButton();
});
}
});
});
} else {
test.beforeEach(function () {
launchBrowser();
});
test.afterEach(function () {
closeBrowser();
});
}
test.describe('No Todos', function () {
test.it('should hide #main and #footer', function () {
testOps.assertItemCount(0);
testOps.assertMainSectionIsHidden();
testOps.assertFooterIsHidden();
});
});
test.describe('New Todo', function () {
test.it('should allow me to add todo items', function () {
page.enterItem(TODO_ITEM_ONE);
testOps.assertItems([TODO_ITEM_ONE]);
page.enterItem(TODO_ITEM_TWO);
testOps.assertItems([TODO_ITEM_ONE, TODO_ITEM_TWO]);
});
test.it('should clear text input field when an item is added', function () {
page.enterItem(TODO_ITEM_ONE);
testOps.assertItemInputFieldText('');
});
test.it('should append new items to the bottom of the list', function () {
createStandardItems();
testOps.assertItemCount(3);
testOps.assertItemText(0, TODO_ITEM_ONE);
testOps.assertItemText(1, TODO_ITEM_TWO);
testOps.assertItemText(2, TODO_ITEM_THREE);
});
test.it('should trim text input', function () {
page.enterItem(' ' + TODO_ITEM_ONE + ' ');
testOps.assertItemText(0, TODO_ITEM_ONE);
});
test.it('should show #main and #footer when items added', function () {
page.enterItem(TODO_ITEM_ONE);
testOps.assertMainSectionIsVisible();
testOps.assertFooterIsVisible();
});
});
test.describe('Mark all as completed', function () {
test.it('should allow me to mark all items as completed', function () {
createStandardItems();
page.clickMarkAllCompletedCheckBox();
testOps.assertItemAtIndexIsCompleted(0);
testOps.assertItemAtIndexIsCompleted(1);
testOps.assertItemAtIndexIsCompleted(2);
});
test.it('should allow me to clear the completion state of all items', function () {
createStandardItems();
page.clickMarkAllCompletedCheckBox();
page.clickMarkAllCompletedCheckBox();
testOps.assertItemAtIndexIsNotCompleted(0);
testOps.assertItemAtIndexIsNotCompleted(1);
testOps.assertItemAtIndexIsNotCompleted(2);
});
test.it('complete all checkbox should update state when items are completed / cleared', function () {
createStandardItems();
page.clickMarkAllCompletedCheckBox();
testOps.assertCompleteAllIsChecked();
// all items are complete, now mark one as not-complete
page.toggleItemAtIndex(0);
testOps.assertCompleteAllIsClear();
// now mark as complete, so that once again all items are completed
page.toggleItemAtIndex(0);
testOps.assertCompleteAllIsChecked();
});
});
test.describe('Item', function () {
test.it('should allow me to mark items as complete', function () {
page.enterItem(TODO_ITEM_ONE);
page.enterItem(TODO_ITEM_TWO);
page.toggleItemAtIndex(0);
testOps.assertItemAtIndexIsCompleted(0);
testOps.assertItemAtIndexIsNotCompleted(1);
page.toggleItemAtIndex(1);
testOps.assertItemAtIndexIsCompleted(0);
testOps.assertItemAtIndexIsCompleted(1);
});
test.it('should allow me to un-mark items as complete', function () {
page.enterItem(TODO_ITEM_ONE);
page.enterItem(TODO_ITEM_TWO);
page.toggleItemAtIndex(0);
testOps.assertItemAtIndexIsCompleted(0);
testOps.assertItemAtIndexIsNotCompleted(1);
page.toggleItemAtIndex(0);
testOps.assertItemAtIndexIsNotCompleted(0);
testOps.assertItemAtIndexIsNotCompleted(1);
});
test.it('should allow me to edit an item', function () {
createStandardItems();
page.doubleClickItemAtIndex(1);
page.editItemAtIndex(1, 'buy some sausages' + webdriver.Key.ENTER);
testOps.assertItems([TODO_ITEM_ONE, 'buy some sausages', TODO_ITEM_THREE]);
});
test.it('should show the remove button on hover', function () {
// assert(false);
});
});
test.describe('Editing', function () {
test.it('should hide other controls when editing', function () {
createStandardItems();
page.doubleClickItemAtIndex(1);
testOps.assertItemToggleIsHidden(1);
testOps.assertItemLabelIsHidden(1);
});
test.it('should save edits on enter', function () {
createStandardItems();
page.doubleClickItemAtIndex(1);
page.editItemAtIndex(1, 'buy some sausages' + webdriver.Key.ENTER);
testOps.assertItems([TODO_ITEM_ONE, 'buy some sausages', TODO_ITEM_THREE]);
});
test.it('should save edits on blur', function () {
createStandardItems();
page.doubleClickItemAtIndex(1);
page.editItemAtIndex(1, 'buy some sausages');
// click a toggle button so that the blur() event is fired
page.toggleItemAtIndex(0);
testOps.assertItems([TODO_ITEM_ONE, 'buy some sausages', TODO_ITEM_THREE]);
});
test.it('should trim entered text', function () {
createStandardItems();
page.doubleClickItemAtIndex(1);
page.editItemAtIndex(1, ' buy some sausages ' + webdriver.Key.ENTER);
testOps.assertItems([TODO_ITEM_ONE, 'buy some sausages', TODO_ITEM_THREE]);
});
test.it('should remove the item if an empty text string was entered', function () {
createStandardItems();
page.doubleClickItemAtIndex(1);
page.editItemAtIndex(1, webdriver.Key.ENTER);
testOps.assertItems([TODO_ITEM_ONE, TODO_ITEM_THREE]);
});
test.it('should cancel edits on escape', function () {
createStandardItems();
page.doubleClickItemAtIndex(1);
page.editItemAtIndex(1, 'foo' + webdriver.Key.ESCAPE);
testOps.assertItems([TODO_ITEM_ONE, TODO_ITEM_TWO, TODO_ITEM_THREE]);
});
});
test.describe('Counter', function () {
test.it('should display the current number of todo items', function () {
page.enterItem(TODO_ITEM_ONE);
testOps.assertItemCountText('1 item left');
page.enterItem(TODO_ITEM_TWO);
testOps.assertItemCountText('2 items left');
});
});
test.describe('Clear completed button', function () {
test.it('should display the number of completed items', function () {
createStandardItems();
page.toggleItemAtIndex(1);
testOps.assertClearCompleteButtonText('Clear completed (1)');
page.toggleItemAtIndex(2);
testOps.assertClearCompleteButtonText('Clear completed (2)');
});
test.it('should remove completed items when clicked', function () {
createStandardItems();
page.toggleItemAtIndex(1);
page.clickClearCompleteButton();
testOps.assertItemCount(2);
testOps.assertItems([TODO_ITEM_ONE, TODO_ITEM_THREE]);
});
test.it('should be hidden when there are no items that are completed', function () {
createStandardItems();
page.toggleItemAtIndex(1);
testOps.assertClearCompleteButtonIsVisible();
page.clickClearCompleteButton();
testOps.assertClearCompleteButtonIsHidden();
});
});
/*test.describe('Persistence', function () {
test.it('should persist its data', function () {
// set up state
page.enterItem(TODO_ITEM_ONE);
page.enterItem(TODO_ITEM_TWO);
page.toggleItemAtIndex(1);
function stateTest() {
testOps.assertItems([TODO_ITEM_ONE, TODO_ITEM_TWO]);
testOps.assertItemAtIndexIsCompleted(1);
testOps.assertItemAtIndexIsNotCompleted(0);
}
// test it
stateTest();
// navigate away and back again
browser.get(otherUrl);
browser.get(baseUrl);
// repeat the state test
stateTest();
});
});*/
test.describe('Routing', function () {
test.it('should allow me to display active items', function () {
createStandardItems();
page.toggleItemAtIndex(1);
page.filterByActiveItems();
testOps.assertItems([TODO_ITEM_ONE, TODO_ITEM_THREE]);
});
test.it('should respect the back button', function () {
createStandardItems();
page.toggleItemAtIndex(1);
page.filterByActiveItems();
page.filterByCompletedItems();
// should show completed items
testOps.assertItems([TODO_ITEM_TWO]);
// then active items
page.back();
testOps.assertItems([TODO_ITEM_ONE, TODO_ITEM_THREE]);
// then all items
page.back();
testOps.assertItems([TODO_ITEM_ONE, TODO_ITEM_TWO, TODO_ITEM_THREE]);
});
test.it('should allow me to display completed items', function () {
createStandardItems();
page.toggleItemAtIndex(1);
page.filterByCompletedItems();
testOps.assertItems([TODO_ITEM_TWO]);
});
test.it('should allow me to display all items', function () {
createStandardItems();
page.toggleItemAtIndex(1);
// apply the other filters first, before returning to the 'all' state
page.filterByActiveItems();
page.filterByCompletedItems();
page.filterByAllItems();
testOps.assertItems([TODO_ITEM_ONE, TODO_ITEM_TWO, TODO_ITEM_THREE]);
});
test.it('should highlight the currently applied filter', function () {
createStandardItems();
// initially 'all' should be selected
testOps.assertFilterAtIndexIsSelected(0);
page.filterByActiveItems();
testOps.assertFilterAtIndexIsSelected(1);
page.filterByCompletedItems();
testOps.assertFilterAtIndexIsSelected(2);
});
});
});
};
'use strict';
var assert = require('assert');
var Q = require('q');
function TestOperations(page) {
// unfortunately webdriver does not have a decent API for determining if an
// element exists. The standard approach is to obtain an array of elements
// and test that the length is zero. In this case the item is hidden if
// it is either not in the DOM, or is in the DOM but not visible.
function testIsHidden(elements, name) {
if (elements.length === 1) {
elements[0].isDisplayed().then(function (isDisplayed) {
assert(!isDisplayed, 'the ' + name + ' element should be hidden');
});
}
}
function testIsVisible(elements, name) {
assert.equal(1, elements.length);
elements[0].isDisplayed().then(function (isDisplayed) {
assert(isDisplayed, 'the ' + name + ' element should be displayed');
});
}
this.assertClearCompleteButtonIsHidden = function () {
page.tryGetClearCompleteButton().then(function (element) {
testIsHidden(element, 'clear completed items button');
});
};
this.assertClearCompleteButtonIsVisible = function () {
page.tryGetClearCompleteButton().then(function (element) {
testIsVisible(element, 'clear completed items button');
});
};
this.assertItemCount = function (itemCount) {
page.getItemElements().then(function (toDoItems) {
assert.equal(itemCount, toDoItems.length,
itemCount + ' items expected in the todo list, ' + toDoItems.length + ' items observed');
});
};
this.assertClearCompleteButtonText = function (buttonText) {
page.tryGetClearCompleteButton().then(function (elements) {
var button = elements[0];
button.getText().then(function (text) {
assert.equal(buttonText, text);
});
});
};
this.assertMainSectionIsHidden = function () {
page.tryGetMainSectionElement().then(function (mainSection) {
testIsHidden(mainSection, 'main');
});
};
this.assertFooterIsHidden = function () {
page.tryGetFooterElement().then(function (footer) {
testIsHidden(footer, 'footer');
});
};
this.assertMainSectionIsVisible = function () {
page.tryGetMainSectionElement().then(function (mainSection) {
testIsVisible(mainSection, 'main');
});
};
//TODO: fishy!
this.assertItemToggleIsHidden = function (index) {
page.tryGetToggleForItemAtIndex(index).then(function (toggleItem) {
testIsHidden(toggleItem, 'item-toggle');
});
};
this.assertItemLabelIsHidden = function (index) {
page.tryGetItemLabelAtIndex(index).then(function (toggleItem) {
testIsHidden(toggleItem, 'item-label');
});
};
this.assertFooterIsVisible = function () {
page.tryGetFooterElement().then(function (footer) {
testIsVisible(footer, 'footer');
});
};
this.assertItemInputFieldText = function (text) {
page.getItemInputField().getText().then(function (inputFieldText) {
assert.equal(text, inputFieldText);
});
};
this.assertItemText = function (itemIndex, textToAssert) {
page.getItemLabelAtIndex(itemIndex).getText().then(function (text) {
assert.equal(textToAssert, text,
'A todo item with text \'' + textToAssert + '\' was expected at index ' +
itemIndex + ', the text \'' + text + '\' was observed');
});
};
// tests that the list contains the following items, independant of order
this.assertItems = function (textArray) {
page.getItemLabels().then(function (labels) {
// obtain all the visible items
var visibleLabels = [];
var tests = [];
for (var i = 0; i < labels.length; i++) {
(function (index) {
// suppressing JSHint - the loop variable is not being used in the function.
/* jshint -W083 */
tests.push(labels[index].isDisplayed().then(function (isDisplayed) {
if (isDisplayed) {
visibleLabels.push(labels[index]);
}
}));
})(i);
}
// check that they match the supplied text
return Q.all(tests).then(function () {
assert.equal(textArray.length, visibleLabels.length,
textArray.length + ' items expected in the todo list, ' + visibleLabels.length + ' items observed');
// create an array of promises which check the presence of the
// label text within the 'textArray'
tests = [];
for (var i = 0; i < visibleLabels.length; i++) {
// suppressing JSHint - the loop variable is not being used in the function.
/* jshint -W083 */
tests.push(visibleLabels[i].getText().then(function (text) {
var index = textArray.indexOf(text);
assert(index !== -1, 'A todo item with text \'' + text + '\' was not expected');
// remove this item when found
textArray.splice(index, 1);
}));
}
// execute all the tests
return Q.all(tests);
})
});
};
this.assertItemCountText = function (textToAssert) {
page.getItemsCountElement().getText().then(function (text) {
assert.equal(textToAssert, text.trim(), 'the item count text was incorrect');
});
};
// tests for the presence of the 'completed' CSS class for the item at the given index
this.assertItemAtIndexIsCompleted = function (index) {
page.getItemElements().then(function (toDoItems) {
toDoItems[index].getAttribute('class').then(function (cssClass) {
assert(cssClass.indexOf('completed') !== -1,
'the item at index ' + index + ' should have been marked as completed');
});
});
};
this.assertItemAtIndexIsNotCompleted = function (index) {
page.getItemElements().then(function (toDoItems) {
toDoItems[index].getAttribute('class').then(function (cssClass) {
// the maria implementation uses an 'incompleted' CSS class which is redundant
// TODO: this should really be moved into the pageLaxMode
assert(cssClass.indexOf('completed') === -1 || cssClass.indexOf('incompleted') !== -1,
'the item at index ' + index + ' should not have been marked as completed');
});
});
};
function isSelected(cssClass) {
return cssClass.indexOf('selected') !== -1;
}
this.assertFilterAtIndexIsSelected = function (selectedIndex) {
page.getFilterElements().then(function (filterElements) {
// create an array of promises, each one holding a test
var tests = [];
// push a test into the array, avoiding the classic JS for loops + closures issue!
function pushTest(itemIndex) {
tests.push(filterElements[itemIndex].getAttribute('class').then(function (cssClass) {
assert(selectedIndex === itemIndex ? isSelected(cssClass) : !isSelected(cssClass),
'the filter / route at index ' + selectedIndex + ' should have been selected');
}));
}
for (var i = 0; i < 3; i++) {
pushTest(i);
}
// execute all the tests
return Q.all(tests);
});
};
this.assertCompleteAllIsClear = function () {
page.getMarkAllCompletedCheckBox().then(function (markAllCompleted) {
markAllCompleted.isSelected().then(function (isSelected) {
assert(!isSelected, 'the mark-all-completed checkbox should be clear');
});
});
};
this.assertCompleteAllIsChecked = function () {
page.getMarkAllCompletedCheckBox().then(function (markAllCompleted) {
markAllCompleted.isSelected().then(function (isSelected) {
assert(isSelected, 'the mark-all-completed checkbox should be checked');
});
});
};
}
module.exports = TestOperations;
# Changelog
## 1.3 - TBD
- New since 1.2:
- Durandal
- Exoskeleton
- Atma.js
- ComponentJS
- AngularDart
- Updates since 1.2:
- CanJS 2.0
- CanJS 2.0 + RequireJS
- VanillaJS refactored, tests, bug fixes
- knockoutjs_classBindingProvider example has been removed
- Backbone 1.1
- Backbone 1.1 + RequireJS
- Dart 1.0
- React graduated from Labs
- Removed since 1.2:
- Dermis.js
- ExtJS
## 1.2 - 2013-08-06
- New since 1.1:
- Polymer
- Flight
- DeftJS + ExtJS
- Aria Templates
- Enyo + Backbone.js
- React
- SAPUI5
- AngularJS + Firebase
- Updates since 1.1:
- Backbone 1.0
- cujoJS got updated
- Kendo UI Spring 2013 release
- Maria graduated from labs
- TroopJS 2.0
- The GWT example implemented routing
- The sammy.js example implemented routing
- Removed Ember.js + require.js example
## 1.1 - 2013-02-14
- We now have 18 stable apps and 36 in labs. New since 1.0.1:
- Dart
- TypeScript + Backbone.js
- TypeScript + AngularJS
- Serenade.js
- CanJS + RequireJS
- Chaplin + Brunch
- Thorax + Lumbar
- Kendo UI
- CanJS replaced the JavaScriptMVC app
- Many app frameworks and libraries have been upgraded to the latest version
- XSS issues in several apps have been resolved
- The homepage got reorganized with new categories
- Various consistency fixes across all apps
## 1.0.1 - 2012-10-09
- All main apps have been completely rewritten for consistency
- Routing has been added to many of these
- We now have 30+ apps being worked on in Labs
- We're using a kick-ass new template
- Framework authors and contributors have been consulted to ensure our apps adhere to best practices
- We're helping AMD users by adding AMD versions of many apps
# Code Style
We think it's best for the project if the code you write looks like the code the last developer wrote. Please read this document in its entirety, and be sure to refer back to it throughout the development of your contribution. We greatly appreciate your cooperation.
## General Rules
- Tab indentation
- Single-quotes
- Semicolon
- Strict mode
- No trailing whitespace
- Variables at the top of the scope
- Multiple variable statements
- Space after keywords and between arguments and operators
- Return early
- JSHint valid
- Consistency
Example:
```js
'use strict';
function foo(bar, fum) {
var i, l, ret;
var hello = 'Hello';
if (!bar) {
return;
}
for (i = 0, l = bar.length; i < l; i++) {
if (bar[i] === hello) {
ret += fum(bar[i]);
}
}
return ret;
}
```
Read [idiomatic.js](https://github.com/rwldrn/idiomatic.js) for general JavaScript code style best practices.
## Anonymous Functions
When using anonymous functions, leave a space between the function name and opening parenthesis.
Example:
```js
(function () {
'use strict';
var thanks = 'mate';
})();
```
## Strict mode
Strict mode should be used wherever possible, but must never be globally
applied. Instead, use it inside an IIFE as shown above.
## Comments
Inline comments are a great way of giving new users a better understanding of what you're doing and why.
It's also helpful to let your functions breathe, by leaving additional lines between statements.
Example:
```js
// Ok.
var removeTodo = function (todoItem) {
var todoModel = todoItem.getModel(); // Grab the model from the todoItem.
todoItem.find('.destroy').click(); // Trigger a click to remove the element from the <ul>.
todoModel.remove(); // Removes the todo model from localStorage.
};
// Better.
var removeTodo = function (todoItem) {
// Grab the model from the todoItem.
var todoModel = todoItem.getModel();
// Trigger a click to remove the element from the <ul>.
todoItem.find('.destroy').click();
// Removes the todo model from localStorage.
todoModel.remove();
};
```
## RequireJS
When using RequireJS, please format your code to these specifications:
```js
define('Block', [
'jQuery',
'Handlebars'
], function ($, Handlebars) {
'use strict';
// Code here.
});
```
## JSHint
When you submit your pull request, one of the first things we will do is run JSHint against your code.
You can help speed the process by running it yourself:
```
jshint path/to/your/app/js
```
Your JSHint code blocks must follow this style:
```js
/*global define, App */
/*jshint unused:false */
```
# Contribute
We're happy to accept contributions in the form of new apps, bug fixes, issues and so on. If you want to help out, add a comment on the issue you want to work on and hack way!.
Note: Before starting work on an app intended for submission, please open an issue to discuss it with the team. This will allow us to review the framework being used to determine if a spec-compatible app is likely to be accepted.
## Code Style
We think it's best for the project if the code you write looks like the code the last developer wrote, so we've put together [some guidelines we ask that you follow](https://github.com/tastejs/todomvc/tree/gh-pages/codestyle.md). We greatly appreciate your cooperation and contribution.
## Pull Request Guidelines
- Develop in a topic branch (not `master`) and submit against the `labs` folder in the default `gh-pages` branch
- Squash your commits
- Write a convincing description of your PR and why we should land it
## Submitting a New App
- **Read the [App Specification](app-spec.md) thoroughly**
- Use the [automated browser tests](/browser-tests) to ensure that your app meets the app specification requirements. For bonus points add the test output to your pull request!
- Make sure it hasn't already been submitted or declined by searching the issue tracker
- Looking at our most recent [reference app](https://github.com/tastejs/todomvc/tree/gh-pages/architecture-examples/backbone)
One of us will be happy to review your submission and discuss any changes that may be required before it can be included. Apps will typically land first in Labs, reaching the 'stable' mark once we and the community are happy with it.
## Browser Compatibility
Modern browser (latest: Chrome, Firefox, Opera, Safari, IE9)
## Unit Tests
At present, due to the large number of apps in the TodoMVC suite we haven't been mandating that unit tests be written in order for an application to be accepted.
We do however plan on addressing this in a future release as we feel it would both help further ensure consistency and provide developers with a reference for writing tests for each framework.
If you are a library author or contributor wishing to start work on writing tests for an implementation, we'll happily consider including them in the future. This may change based on how we specify unit tests must be structured and so on post 1.0.
## A Final Note
Note that due to the current number of MVC/MVVM/MV* frameworks in circulation, it's not always possible to include each one in TodoMVC, but we'll definitely discuss the merits of any framework prior to making a decision :)
For applications that we feel don't quite match the goals of the project, but which we feel still offer value, we're happy to include references to them in our official [wiki](https://github.com/tastejs/todomvc/wiki/Other-implementations).
'use strict';
// Include Gulp & Tools We'll Use
var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var del = require('del');
var runSequence = require('run-sequence');
var pagespeed = require('psi');
var AUTOPREFIXER_BROWSERS = [
'ie >= 10',
'ie_mob >= 10',
'ff >= 30',
'chrome >= 34',
'safari >= 7',
'opera >= 23',
'ios >= 7',
'android >= 4.4',
'bb >= 10'
];
// Lint JavaScript
gulp.task('jshint', function () {
return gulp.src('site-assets/*.js')
.pipe($.jshint())
.pipe($.jshint.reporter('jshint-stylish'));
});
// Optimize Images
gulp.task('images', function () {
return gulp.src('site-assets/*.{png,jpg,svg}')
.pipe($.cache($.imagemin({
progressive: true,
interlaced: true
})))
.pipe(gulp.dest('dist/site-assets'))
.pipe($.size({title: 'images'}));
});
// Copy All Files At The Root Level (app)
gulp.task('copy', function () {
return gulp.src([
'architecture-examples/**',
'dependency-examples/**',
'vanilla-examples/**',
'labs/**',
'learn.json',
'CNAME',
'.nojekyll'
], {
dot: true,
base: './'
}).pipe(gulp.dest('dist'))
.pipe($.size({title: 'copy'}));
});
// Compile and Automatically Prefix Stylesheets
gulp.task('styles', function () {
// For best performance, don't add Sass partials to `gulp.src`
return gulp.src([
'site-assets/*.css',
])
.pipe($.autoprefixer(AUTOPREFIXER_BROWSERS))
.pipe(gulp.dest('dist/site-assets'))
.pipe($.size({title: 'styles'}))
.pipe(gulp.dest('.tmp/site-assets'));
});
// Scan Your HTML For Assets & Optimize Them
gulp.task('html', function () {
var assets = $.useref.assets({searchPath: '{.tmp,.}'});
return gulp.src('index.html')
.pipe(assets)
// Concatenate And Minify JavaScript
.pipe($.if('*.js', $.uglify({preserveComments: 'some'})))
// Concatenate And Minify Styles
.pipe($.if('*.css', $.csso()))
.pipe(assets.restore())
.pipe($.useref())
// Minify Any HTML
.pipe($.if('*.html', $.minifyHtml()))
// Output Files
.pipe(gulp.dest('dist'))
.pipe($.size({title: 'html'}));
});
// Clean Output Directory
gulp.task('clean', del.bind(null, ['.tmp', 'dist']));
// Build Production Files, the Default Task
gulp.task('default', ['clean'], function (cb) {
runSequence('styles', ['jshint', 'html', 'images', 'copy'], cb);
});
// Run PageSpeed Insights
// Update `url` below to the public URL for your site
gulp.task('pagespeed', pagespeed.bind(null, {
// By default, we use the PageSpeed Insights
// free (no API key) tier. You can use a Google
// Developer API key if you have one. See
// http://goo.gl/RkN0vE for info key: 'YOUR_API_KEY'
url: 'https://todomvc.com',
strategy: 'mobile'
}));
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>TodoMVC</title>
<meta name="description" content="Helping you select an MV* framework - Todo apps for Backbone.js, Ember.js, AngularJS, Spine and many more">
<meta name="viewport" content="width=device-width,initial-scale=1">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="TodoMVC">
<meta name="twitter:site" content="@TasteJS">
<meta name="twitter:description" content="Helping you select an MV* framework - Todo apps for Backbone.js, Ember.js, AngularJS and many more">
<meta name="twitter:image" content="https://raw.githubusercontent.com/tastejs/todomvc/gh-pages/site-assets/screenshot.png">
<meta property="og:url" content="http://todomvc.com">
<meta property="og:title" content="TodoMVC">
<meta property="og:image" content="https://raw.github.com/tastejs/todomvc/gh-pages/site-assets/screenshot.png">
<meta property="og:description" content="Helping you select an MV* framework - Todo apps for Backbone.js, Ember.js, AngularJS, Spine and many more">
<link rel="shortcut icon" href="site-assets/favicon.ico">
<!-- build:css site-assets/main.min.css -->
<link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="site-assets/main.css">
<!-- endbuild -->
</head>
<body>
<div class="container">
<header class="row">
<div class="col-md-8">
<img class="logo" src="site-assets/logo.svg" width="500" height="86" alt="TodoMVC">
<p>Helping you <strong>select</strong> an MV* framework</p>
<nav>
<a href="https://github.com/tastejs/todomvc/zipball/1.2.0" class="zocial red">Download (1.2)</a>
<a href="https://github.com/tastejs/todomvc" class="zocial ltgray">View on GitHub</a>
<a href="http://blog.tastejs.com/" class="zocial ltgray">Blog</a>
</nav>
</div>
<div class="col-md-4">
<img class="logo-icon" src="site-assets/logo-icon.png" width="330" height="330" alt="TodoMVC">
</div>
</header>
<div class="row">
<div class="col-md-4">
<h2>Introduction</h2>
<p>Developers these days are spoiled with choice when it comes to <a href="http://coding.smashingmagazine.com/2012/07/27/journey-through-the-javascript-mvc-jungle/">selecting</a> an <strong>MV* framework</strong> for structuring and organizing their JavaScript web apps.</p>
<p>Backbone, Ember, AngularJS... the list of new and stable solutions continues to grow, but just how do you decide on which to use in a sea of so many options?</p>
<p>To help solve this problem, we created <a href="https://github.com/tastejs/todomvc">TodoMVC</a> - a project which offers the same Todo application implemented using MV* concepts in most of the popular JavaScript MV* frameworks of today.</p>
<a href="https://twitter.com/tastejs" class="twitter-follow-button" data-show-count="false" data-show-screen-name="false"></a>
<a href="https://twitter.com/share" class="twitter-share-button" data-via="tastejs" data-url="http://todomvc.com" data-text="TodoMVC - Helping you select an MV* framework - Todo apps for Backbone.js, Ember.js, AngularJS, and more"></a>
<div class="g-plusone" data-size="medium" data-annotation="none" data-href="http://todomvc.com"></div>
</div>
<div class="col-md-8">
<h2>JavaScript Apps</h2>
<ul class="applist js">
<li class="routing">
<a href="architecture-examples/backbone/" data-source="http://documentcloud.github.com/backbone/" data-content="Backbone.js gives structure to web applications by providing models with key-value binding and custom events, collections with a rich API of enumerable functions, views with declarative event handling, and connects it all to your existing API over a RESTful JSON interface.">Backbone.js</a>
</li>
<li class="routing">
<a href="architecture-examples/angularjs/" data-source="http://angularjs.org" data-content="What HTML would have been had it been designed for web apps">AngularJS</a>
</li>
<li class="routing">
<a href="architecture-examples/emberjs/" data-source="http://emberjs.com" data-content="Ember is a JavaScript framework for creating ambitious web applications that eliminates boilerplate and provides a standard application architecture.">Ember.js</a>
</li>
<li class="routing">
<a href="architecture-examples/knockoutjs/" data-source="http://knockoutjs.com" data-content="Simplify dynamic JavaScript UIs by applying the Model-View-View Model (MVVM) pattern">KnockoutJS</a>
</li>
<li class="routing">
<a href="architecture-examples/dojo/" data-source="http://dojotoolkit.org" data-content="Dojo saves you time and scales with your development process, using web standards as its platform. It’s the toolkit experienced developers turn to for building high quality desktop and mobile web applications.">Dojo</a>
</li>
<li class="routing">
<a href="architecture-examples/yui/" data-source="http://yuilibrary.com" data-content="YUI's lightweight core and modular architecture make it scalable, fast, and robust. Built by frontend engineers at Yahoo!, YUI powers the most popular websites in the world.">YUI</a>
</li>
<li class="routing">
<a href="architecture-examples/agilityjs/" data-source="http://agilityjs.com" data-content="Agility.js is an MVC library for Javascript that lets you write maintainable and reusable browser code without the infrastructural overhead found in other MVC libraries. The goal is to enable developers to write web apps at least as quickly as with jQuery, while simplifying long-term maintainability through MVC objects.">Agility.js</a>
</li>
<li class="routing">
<a href="architecture-examples/knockback/" data-source="http://kmalakoff.github.com/knockback/" data-content="Knockback.js provides Knockout.js magic for Backbone.js Models and Collections.">Knockback.js</a>
</li>
<li class="routing">
<a href="architecture-examples/canjs/" data-source="http://canjs.us" data-content="CanJS with jQuery. CanJS is a client-side, JavaScript framework that makes building rich web applications easy. It provides can.Model (for connecting to RESTful JSON interfaces), can.View (for template loading and caching), can.Observe (for key-value binding), can.EJS (live binding templates), can.Control (declarative event bindings) and can.route (routing support).">CanJS</a>
</li>
<li class="routing">
<a href="architecture-examples/maria/" data-source="https://github.com/petermichaux/maria" data-content="An MVC framework for JavaScript applications. The real MVC. The Smalltalk MVC. The Gang of Four MVC. The three core design patterns of MVC (observer, composite, and strategy) are embedded in Maria's Model, View, and Controller objects. Other patterns traditionally included in MVC implementations (e.g. factory method and template) make appearances too.">Maria</a>
</li>
<li class="routing">
<a href="architecture-examples/polymer/index.html" data-source="http://polymer-project.org" data-content="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.">Polymer</a>
</li>
<li class="routing">
<a href="architecture-examples/react/" data-source="http://facebook.github.io/react/" data-content="React is a JavaScript library for building user interfaces.">React</a>
</li>
<li class="labs">
<a href="labs/architecture-examples/cujo/index.html" data-source="http://cujojs.com" data-content="cujoJS is an architectural framework for building highly modular, scalable, maintainable applications in Javascript. It provides architectural plumbing, such as modules (AMD and CommonJS), declarative application composition, declarative connections, and aspect oriented programming.">cujoJS</a>
</li>
<li class="labs">
<a href="labs/architecture-examples/montage/" data-source="http://montagejs.org" data-content="Montage simplifies the development of rich HTML5 applications by providing modular components, real-time two-way data binding, CommonJS dependency management, and many more conveniences.">Montage</a>
</li>
<li class="routing labs">
<a href="labs/architecture-examples/sammyjs/" data-source="http://sammyjs.org" data-content="Sammy.js is a tiny JavaScript framework developed to ease the pain and provide a basic structure for developing JavaScript applications.">Sammy.js</a>
</li>
<li class="routing labs">
<a href="labs/architecture-examples/stapes/" data-source="http://hay.github.com/stapes" data-content="Stapes is a (really) tiny Javascript MVC micro-framework (1.7kb) that has all the building blocks you need when writing an MVC app. It includes a powerful event system, support for inheritance, use with AMD, plugin support and more. A RequireJS Todo application is <a href='labs/dependency-examples/stapes_require/index.html'>also</a> available.">Stapes</a>
</li>
<li class="routing labs">
<a href="labs/architecture-examples/epitome/" data-source="http://dimitarchristoff.github.com/Epitome" data-content="Epitome is a new extensible and modular open-source MVC framework, built out of MooTools Classes and Events.">Epitome</a>
</li>
<li class="labs">
<a href="labs/architecture-examples/somajs/" data-source="http://somajs.github.com/somajs" data-content="soma.js is a framework created to build scalable and maintainable javascript applications.">soma.js</a>
</li>
<li class="labs">
<a href="labs/architecture-examples/duel/www/" data-source="https://bitbucket.org/mckamey/duel/wiki/Home" data-content="DUEL is a dual-side templating engine using HTML for layout and 100% pure JavaScript as the binding language. The same views may be executed both directly in the browser (client-side template) and on the server (server-side template).">DUEL</a>
</li>
<li class="routing labs">
<a href="labs/architecture-examples/kendo/" data-source="http://www.kendoui.com/" data-content="Kendo UI is a comprehensive HTML5, JavaScript framework for modern web and mobile app development">Kendo UI</a>
</li>
<li class="routing labs">
<a href="labs/architecture-examples/puremvc/" data-source="http://puremvc.github.com" data-content="PureMVC is a lightweight framework for creating applications based upon the classic Model-View-Controller design meta-pattern.">PureMVC</a>
</li>
<li class="labs">
<a href="labs/architecture-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 class="routing labs">
<a href="labs/architecture-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 class="labs">
<a href="labs/architecture-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>
</li>
<li class="routing labs">
<a href="labs/architecture-examples/rappidjs/" data-source="http://www.rappidjs.com" data-content="rAppid.js is a declarative JavaScript framework for rapid web application development. It supports dependency loading, Model-View binding, View-Model binding, dependency injection and i18n.">rAppid.js</a>
</li>
<li class="labs">
<a href="labs/architecture-examples/extjs_deftjs/" data-source="http://deftjs.org/" data-content="Essential extensions for enterprise web and mobile application development with Ext JS and Sencha Touch">DeftJS + ExtJS</a>
</li>
<li class="routing labs">
<a href="labs/architecture-examples/ariatemplates/" data-source="http://ariatemplates.com/" data-content="Aria Templates has been designed for web apps that are used 8+ hours a day, and that need to display and process high amount of data with a minimum of bandwidth consumption.">Aria Templates</a>
</li>
<li class="routing labs">
<a href="labs/dependency-examples/enyo_backbone/" data-source="http://enyojs.com/" data-content="Enyo is a simple but powerful encapsulation model, which helps you factor application functionality into self-contained building blocks that are easy to reuse and maintain.">Enyo +<br>Backbone.js</a>
</li>
<li class="routing labs">
<a href="architecture-examples/angularjs-perf/" data-source="http://angularjs.org" data-content="What HTML would have been had it been designed for web apps. A version with several performance optimizations.">AngularJS <br>(optimized)</a>
</li>
<li class="routing labs">
<a href="labs/architecture-examples/sapui5/" data-source="http://scn.sap.com/community/developer-center/front-end" data-content="SAPUI5 is SAP's HTML5-based UI technology that allows you to build rich, interactive Web applications.">SAPUI5</a>
</li>
<li class="routing labs">
<a href="labs/architecture-examples/exoskeleton/" data-source="http://exosjs.com/" data-content="A faster and leaner Backbone for your HTML5 apps.">Exoskeleton</a>
</li>
<li class="routing labs">
<a href="labs/architecture-examples/atmajs/" data-source="http://atmajs.com/" data-content="HMVC and the component-based architecture for building client, server or hybrid applications">Atma.js</a>
</li>
<li class="labs">
<a href="labs/architecture-examples/ractive/" data-source="http://ractivejs.org" data-content="Ractive.js is a next-generation DOM manipulation library, optimised for developer sanity.">Ractive.js</a>
</li>
<li class="labs routing">
<a href="labs/architecture-examples/componentjs/" data-source="http://componentjs.com" data-content="ComponentJS is a stand-alone MPL-licensed Open Source library for JavaScript, providing a powerful run-time Component System for hierarchically structuring the User-Interface (UI) dialogs of complex HTML5-based Rich Clients (aka Single-Page-Apps) — under maximum applied Separation of Concerns (SoC) architecture principle, through optional Model, View and Controller component roles, with sophisticated hierarchical Event, Service, Hook, Model, Socket and Property mechanisms, and fully independent and agnostic of the particular UI widget toolkit.">ComponentJS</a>
</li>
<li class="labs routing">
<a href="labs/architecture-examples/vue/" data-source="http://vuejs.org" data-content="Vue.js provides the benefits of MVVM data binding and a composable component system with an extremely simple and flexible API.">Vue.js</a>
</li>
<li class="labs routing">
<a href="labs/architecture-examples/react-backbone/" data-source="http://facebook.github.io/react/" data-content="This React example integrates Backbone for its model and router. It is a showcase of third-party library integration for developers wishing to use React together with a different JavaScript framework.">React + <br>Backbone.js</a>
</li>
</ul>
<ul class="legend">
<li><b>*</b> <span class="label">R</span> = App also demonstrates routing</li>
<li><b>*</b> <strong>Maroon</strong> = App requires further work to comply with <a href="https://github.com/tastejs/todomvc/blob/gh-pages/app-spec.md">the spec</a></li>
</ul>
<hr>
<h2>Compile To JavaScript</h2>
<ul class="applist ctojs">
<li class="routing">
<a href="architecture-examples/spine/" data-source="http://spinejs.com" data-content="Spine is a lightweight framework for building JavaScript web applications. Spine gives you an MVC structure and then gets out of your way, allowing you to concentrate on the fun stuff, building awesome web applications.">Spine</a>
</li>
<li class="routing">
<a href="vanilla-examples/vanilladart/build/" data-source="http://dartlang.org" data-content="Dart firstly targets the development of modern and large scale browser-side web apps. It's an object oriented language with a C-style syntax. It has two run modes : it can be compiled to JS, and will later run in native VM in compliant browsers (just in a dedicated Chromium provided with Dart SDK for the moment).">Dart</a>
</li>
<li class="routing">
<a href="architecture-examples/gwt/" data-source="https://developers.google.com/web-toolkit/" data-content="Google Web Toolkit (GWT) is an MVP development toolkit for building and optimizing complex browser-based applications. GWT is used by many products at Google, including Google AdWords.">GWT</a>
</li>
<li class="routing">
<a href="architecture-examples/closure/" data-source="http://code.google.com/closure/library/" data-content="The Closure Library is a broad, well-tested, modular, and cross-browser JavaScript library. You can pull just what you need from a large set of reusable UI widgets and controls, and from lower-level utilities for DOM manipulation, server communication, animation, data structures, unit testing, rich-text editing, and more.">Closure</a>
</li>
<li class="labs">
<a href="labs/architecture-examples/angular-dart/web/" data-source="https://github.com/angular/angular.dart" data-content="Dart firstly targets the development of modern and large scale browser-side web apps. It's an object oriented language with a C-style syntax. AngularDart is a port of Angular to Dart.">AngularDart</a>
</li>
<li class="routing labs">
<a href="labs/architecture-examples/batman/" data-source="http://batmanjs.org" data-content="Batman.js is a framework for building rich web applications with CoffeeScript or JavaScript. App code is concise and declarative, thanks to a powerful system of view bindings and observable properties. The API is designed with developer and designer happiness as its first priority.">Batman.js</a>
</li>
<li class="labs">
<a href="labs/architecture-examples/typescript-backbone/" data-source="http://typescriptlang.org" data-content="TypeScript is a language for application-scale JavaScript development. It offers classes, modules, interfaces and type-checking at compile time to help you build robust components.">TypeScript <br>+ Backbone.js</a>
</li>
<li class="labs routing">
<a href="labs/architecture-examples/typescript-angular/" data-source="http://typescriptlang.org" data-content="An AngularJS + TypeScript implementation of TodoMVC. The only significant difference between this and the vanilla Angular app is that dependency injection is done via annotated constructors, which allows minification of JavaScript.">TypeScript <br>+ AngularJS</a>
</li>
<li class="labs">
<a href="labs/architecture-examples/serenadejs/" data-source="https://github.com/elabs/serenade.js" data-content="Serenade.js is yet another MVC client side JavaScript framework. Why do we indulge in recreating the wheel? We believe that Serenade.js more closely follows the ideas of classical MVC than competing frameworks.">Serenade.js</a>
</li>
</ul>
<hr>
<h2>MVC Extension Frameworks</h2>
<ul class="applist">
<li class="routing labs">
<a href="labs/architecture-examples/backbone_marionette/" data-source="http://marionettejs.com" data-content="Backbone.Marionette is a composite application library for Backbone.js that aims to simplify the construction of large scale JavaScript applications.">MarionetteJS</a>
</li>
<li class="routing labs">
<a href="labs/architecture-examples/thorax/" data-source="http://thoraxjs.org" data-content="An opinionated, battle tested Backbone + Handlebars framework to build large scale web applications.">Thorax</a>
</li>
<li class="routing labs">
<a href="labs/dependency-examples/chaplin-brunch/public/" data-source="http://chaplinjs.org" data-content="Chaplin is an architecture for JavaScript applications using the Backbone.js library. Chaplin addresses Backbone’s limitations by providing a lightweight and flexible structure that features well-proven design patterns and best practises.">Chaplin + Brunch</a>
</li>
</ul>
<hr>
<h2>Module Loaders</h2>
<ul class="applist">
<li class="routing">
<a href="dependency-examples/backbone_require/" data-source="http://requirejs.org" data-content="RequireJS is a JavaScript file and module loader. It is optimized for in-browser use, but it can be used in other JavaScript environments, like Rhino and Node. Using a modular script loader like RequireJS will improve the speed and quality of your code.">Backbone.js + RequireJS</a>
</li>
<li class="routing">
<a href="dependency-examples/flight/" data-source="http://twitter.github.com/flight" data-content="Flight is a lightweight, component-based JavaScript framework that maps behavior to DOM nodes. Twitter uses it for their web applications.">Flight</a>
</li>
<li class="labs">
<a href="labs/dependency-examples/knockoutjs_require/" data-source="http://knockoutjs.com" data-content="This project is an adaptation of /architecture-examples/knockoutjs with require.js.">KnockoutJS + RequireJS</a>
</li>
<li class="routing labs">
<a href="labs/dependency-examples/angularjs_require/" data-source="http://angularjs.org" data-content="What HTML would have been had it been designed for web apps. This is an example of using it with AMD modules.">AngularJS + RequireJS</a>
</li>
<li class="routing labs">
<a href="labs/dependency-examples/canjs_require/" data-source="http://canjs.us" data-content="CanJS is a client-side, JavaScript framework that makes building rich web applications easy. The AMD version lets you use the framework in a fully modular fashion and will only what you actually need.">CanJS + RequireJS</a>
</li>
<li class="routing labs">
<a href="labs/dependency-examples/troopjs_require/" data-source="https://github.com/troopjs/" data-content="TroopJS attempts to package popular front-end technologies and bind them with minimal effort for the developer. It includes jQuery for DOM manipulation, When.js for promises, RequireJS for modularity and Has.js for feature detection. On top, it includes Pub/Sub support, templating, weaving (widgets to DOM) and auto-wiring.">TroopJS + RequireJS</a>
</li>
<li class="routing labs">
<a href="labs/dependency-examples/thorax_lumbar/public/" data-source="http://walmartlabs.github.com/lumbar" data-content="An opinionated, battle tested Backbone + Handlebars framework to build large scale web applications. This implementation uses Lumbar, a route based module loader.">Thorax + Lumbar</a>
</li>
<li class="routing labs">
<a href="labs/dependency-examples/somajs_require/" data-source="http://somajs.github.com/somajs" data-content="soma.js is a framework created to build scalable and maintainable javascript applications.">soma.js + RequireJS</a>
</li>
<li class="routing labs">
<a href="labs/dependency-examples/durandal/" data-source="http://durandaljs.com/" data-content="Single Page Apps Done Right">Durandal</a>
</li>
<li class="routing labs">
<a href="labs/dependency-examples/lavaca_require/" data-source="http://getlavaca.com" data-content="A curated collection of tools for building mobile web applications.">Lavaca + RequireJS</a>
</li>
</ul>
<hr>
<h2>Real-time</h2>
<ul class="applist">
<li class="labs">
<a href="http://todomvcapp.meteor.com" data-source="http://meteor.com" data-content="Meteor is an ultra-simple environment for building modern websites. A Meteor application is a mix of JavaScript that runs inside a client web browser, JavaScript that runs on the Meteor server inside a Node.js container, and all the supporting HTML fragments, CSS rules, and static assets. Meteor automates the packaging and transmission of these different components. And, it is quite flexible about how you choose to structure those components in your file tree.">Meteor</a>
</li>
<li class="labs">
<a href="http://todomvc.derbyjs.com" data-source="http://derbyjs.com" data-content="MVC framework making it easy to write realtime, collaborative applications that run in both Node.js and browsers.">Derby</a>
</li>
<li class="routing labs">
<a href="http://todomvc-socketstream.herokuapp.com" data-source="http://www.socketstream.org" data-content="SocketStream is a fast, modular Node.js web framework dedicated to building realtime single-page apps">SocketStream</a>
</li>
<li class="routing labs">
<a href="labs/architecture-examples/firebase-angular/" data-source="https://www.firebase.com" data-content="Firebase is a scalable realtime backend that lets you build apps without managing servers. Firebase persists and updates JSON data in realtime and is best used in combination with a JavaScript MV* framework such as AngularJS or Backbone.">Firebase + AngularJS</a>
</li>
</ul>
<hr>
<h2>Compare these to a non-framework implementation</h2>
<ul class="applist">
<li class="routing">
<a href="vanilla-examples/vanillajs/" data-source="https://developer.mozilla.org/en/JavaScript" data-content="You know JavaScript right? :P">Vanilla JS</a>
</li>
<li class="routing">
<a href="architecture-examples/jquery/" data-source="http://jquery.com" data-content="jQuery is a fast and concise JavaScript Library that simplifies HTML document traversing, event handling, animating, and Ajax interactions for rapid web development. jQuery is designed to change the way that you write JavaScript.">jQuery</a>
</li>
</ul>
</div>
</div>
<hr>
<div class="row">
<div class="col-md-6 quotes">
<blockquote class="quote speech-bubble">
<p></p>
<footer>
<img width="40" height="40" alt="">
<a></a>
</footer>
</blockquote>
</div>
<div class="col-md-6">
<img class="screenshot" src="site-assets/screenshot.png" width="558" height="246" alt="Todo app screenshot">
</div>
</div>
<hr>
<div class="row">
<div class="col-md-4">
<h2>New in 1.2 - 2013-08-06</h2>
<ul class="whats-new">
<li>We now have 21 stable apps and 45 in labs.
<label class="link" for="news-expander">New since 1.1 ▼</label>
<input type="checkbox" id="news-expander">
<ul class="collapsed" id="new-apps">
<li><a href="architecture-examples/polymer/">Polymer</a></li>
<li><a href="dependency-examples/flight/">Flight</a></li>
<li><a href="architecture-examples/react/">React</a></li>
<li><a href="vanilla-examples/vanillajs">VanillaJS Rewrite</a></li>
<li><a href="labs/architecture-examples/sapui5/">SAPUI5</a></li>
<li><a href="labs/architecture-examples/firebase-angular/">AngularJS + Firebase</a></li>
</ul>
</li>
<li>We have a brand-new Info Bar</li>
<li>All application now use Bower for dependency management</li>
<li>Various consistency fixes across all apps</li>
<li>Many app frameworks and libraries have been upgraded to the latest version</li>
</ul>
</div>
<div class="col-md-4">
<h2>Selecting a Framework</h2>
<p>Once you've downloaded the latest release and played around with the apps, you'll want to decide on a specific framework to try out.</p>
<p>Study the syntax required for defining models, views and (where applicable) controllers and classes in the frameworks you're interested in and try your hand at editing the code to see how it feels using it first-hand.</p>
<p>Please ensure that if you're happy with this, you do spend more time investigating the framework (including reading the official docs, the source and its complete feature list). There's often a lot more to a framework than what we present in our examples.</p>
</div>
<div class="col-md-4">
<h2>Getting Involved</h2>
<p>Is there a bug we haven't fixed or an MV* framework you feel would benefit from being included in TodoMVC?</p>
<p>If so, feel free to fork the repo, read our <a href="https://github.com/tastejs/todomvc/wiki">contribution guidelines</a>, and submit a pull request &mdash; we'll be happy to review it for inclusion.</p>
<p>Make sure you use the <a href="https://github.com/tastejs/todomvc/tree/gh-pages/template">template</a> as a starting point and read the <a href="https://github.com/tastejs/todomvc/blob/gh-pages/app-spec.md">app specification</a>.</p>
<p>
<a class="zocial small ltgray" href="https://github.com/tastejs/todomvc/wiki">Submit Pull Request &raquo;</a>
</p>
</div>
</div>
<hr>
<footer class="credit">
<p>Brought to you by
<a href="https://github.com/addyosmani"><img src="http://gravatar.com/avatar/96270e4c3e5e9806cf7245475c00b275?s=80" width="40" height="40" alt="Addy Osmani">Addy Osmani</a>
<a href="https://github.com/sindresorhus"><img src="http://gravatar.com/avatar/d36a92237c75c5337c17b60d90686bf9.png?s=80" width="40" height="40" alt="Sindre Sorhus">Sindre Sorhus</a>
<a href="https://github.com/passy"><img src="http://gravatar.com/avatar/be451fcdbf0e5ff07f23ed16cb5c90a3.png?s=80" width="40" height="40" alt="Pascal Hartig">Pascal Hartig</a>
<a href="https://github.com/stephenplusplus"><img src="http://gravatar.com/avatar/098cfe2d360e77c3229f2cd5298354c4?s=80" width="40" height="40" alt="Stephen Sawchuk">Stephen Sawchuk</a>
<a href="https://github.com/colineberhardt"><img src="http://gravatar.com/avatar/73bba00b41ff1c9ecc3ee29487bace7d?s=80" width="40" height="40" alt="Colin Eberhardt">Colin Eberhardt</a>
</p>
</footer>
</div>
<!-- build:js site-assets/main.min.js -->
<script src="bower_components/jquery/dist/jquery.min.js"></script>
<script src="bower_components/bootstrap/dist/js/bootstrap.min.js"></script>
<script src="site-assets/main.js"></script>
<!-- endbuild -->
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.async=true;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
<script>(function(){var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;po.src = 'https://apis.google.com/js/plusone.js';var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);})();</script>
<script>var _gaq=[['_setAccount','UA-31081062-1'],['_trackPageview']];(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.src='//www.google-analytics.com/ga.js';s.parentNode.insertBefore(g,s)}(document,'script'));</script>
</body>
</html>
<!doctype html><html lang=en><head><meta charset=utf-8><title>TodoMVC</title><meta name=description content="Helping you select an MV* framework - Todo apps for Backbone.js, Ember.js, AngularJS, Spine and many more"><meta name=viewport content="width=device-width,initial-scale=1"><meta name=twitter:card content=summary><meta name=twitter:title content=TodoMVC><meta name=twitter:site content=@TasteJS><meta name=twitter:description content="Helping you select an MV* framework - Todo apps for Backbone.js, Ember.js, AngularJS and many more"><meta name=twitter:image content=https://raw.githubusercontent.com/tastejs/todomvc/gh-pages/site-assets/screenshot.png><meta property=og:url content=http://todomvc.com><meta property=og:title content=TodoMVC><meta property=og:image content=https://raw.github.com/tastejs/todomvc/gh-pages/site-assets/screenshot.png><meta property=og:description content="Helping you select an MV* framework - Todo apps for Backbone.js, Ember.js, AngularJS, Spine and many more"><link rel="shortcut icon" href=site-assets/favicon.ico><link rel=stylesheet href=site-assets/main.min.css></head><body><div class=container><header class=row><div class=col-md-8><img class=logo src=site-assets/logo.svg width=500 height=86 alt=TodoMVC><p>Helping you <strong>select</strong> an MV* framework</p><nav><a href=https://github.com/tastejs/todomvc/zipball/1.2.0 class="zocial red">Download (1.2)</a> <a href=https://github.com/tastejs/todomvc class="zocial ltgray">View on GitHub</a> <a href="http://blog.tastejs.com/" class="zocial ltgray">Blog</a></nav></div><div class=col-md-4><img class=logo-icon src=site-assets/logo-icon.png width=330 height=330 alt=TodoMVC></div></header><div class=row><div class=col-md-4><h2>Introduction</h2><p>Developers these days are spoiled with choice when it comes to <a href="http://coding.smashingmagazine.com/2012/07/27/journey-through-the-javascript-mvc-jungle/">selecting</a> an <strong>MV* framework</strong> for structuring and organizing their JavaScript web apps.</p><p>Backbone, Ember, AngularJS... the list of new and stable solutions continues to grow, but just how do you decide on which to use in a sea of so many options?</p><p>To help solve this problem, we created <a href=https://github.com/tastejs/todomvc>TodoMVC</a> - a project which offers the same Todo application implemented using MV* concepts in most of the popular JavaScript MV* frameworks of today.</p><a href=https://twitter.com/tastejs class=twitter-follow-button data-show-count=false data-show-screen-name=false></a> <a href=https://twitter.com/share class=twitter-share-button data-via=tastejs data-url=http://todomvc.com data-text="TodoMVC - Helping you select an MV* framework - Todo apps for Backbone.js, Ember.js, AngularJS, and more"></a><div class=g-plusone data-size=medium data-annotation=none data-href=http://todomvc.com></div></div><div class=col-md-8><h2>JavaScript Apps</h2><ul class="applist js"><li class=routing><a href="architecture-examples/backbone/" data-source="http://documentcloud.github.com/backbone/" data-content="Backbone.js gives structure to web applications by providing models with key-value binding and custom events, collections with a rich API of enumerable functions, views with declarative event handling, and connects it all to your existing API over a RESTful JSON interface.">Backbone.js</a></li><li class=routing><a href="architecture-examples/angularjs/" data-source=http://angularjs.org data-content="What HTML would have been had it been designed for web apps">AngularJS</a></li><li class=routing><a href="architecture-examples/emberjs/" data-source=http://emberjs.com data-content="Ember is a JavaScript framework for creating ambitious web applications that eliminates boilerplate and provides a standard application architecture.">Ember.js</a></li><li class=routing><a href="architecture-examples/knockoutjs/" data-source=http://knockoutjs.com data-content="Simplify dynamic JavaScript UIs by applying the Model-View-View Model (MVVM) pattern">KnockoutJS</a></li><li class=routing><a href="architecture-examples/dojo/" data-source=http://dojotoolkit.org data-content="Dojo saves you time and scales with your development process, using web standards as its platform. It’s the toolkit experienced developers turn to for building high quality desktop and mobile web applications.">Dojo</a></li><li class=routing><a href="architecture-examples/yui/" data-source=http://yuilibrary.com data-content="YUI's lightweight core and modular architecture make it scalable, fast, and robust. Built by frontend engineers at Yahoo!, YUI powers the most popular websites in the world.">YUI</a></li><li class=routing><a href="architecture-examples/agilityjs/" data-source=http://agilityjs.com data-content="Agility.js is an MVC library for Javascript that lets you write maintainable and reusable browser code without the infrastructural overhead found in other MVC libraries. The goal is to enable developers to write web apps at least as quickly as with jQuery, while simplifying long-term maintainability through MVC objects.">Agility.js</a></li><li class=routing><a href="architecture-examples/knockback/" data-source="http://kmalakoff.github.com/knockback/" data-content="Knockback.js provides Knockout.js magic for Backbone.js Models and Collections.">Knockback.js</a></li><li class=routing><a href="architecture-examples/canjs/" data-source=http://canjs.us data-content="CanJS with jQuery. CanJS is a client-side, JavaScript framework that makes building rich web applications easy. It provides can.Model (for connecting to RESTful JSON interfaces), can.View (for template loading and caching), can.Observe (for key-value binding), can.EJS (live binding templates), can.Control (declarative event bindings) and can.route (routing support).">CanJS</a></li><li class=routing><a href="architecture-examples/maria/" data-source=https://github.com/petermichaux/maria data-content="An MVC framework for JavaScript applications. The real MVC. The Smalltalk MVC. The Gang of Four MVC. The three core design patterns of MVC (observer, composite, and strategy) are embedded in Maria's Model, View, and Controller objects. Other patterns traditionally included in MVC implementations (e.g. factory method and template) make appearances too.">Maria</a></li><li class=routing><a href=architecture-examples/polymer/index.html data-source=http://polymer-project.org data-content="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.">Polymer</a></li><li class=routing><a href="architecture-examples/react/" data-source="http://facebook.github.io/react/" data-content="React is a JavaScript library for building user interfaces.">React</a></li><li class=labs><a href=labs/architecture-examples/cujo/index.html data-source=http://cujojs.com data-content="cujoJS is an architectural framework for building highly modular, scalable, maintainable applications in Javascript. It provides architectural plumbing, such as modules (AMD and CommonJS), declarative application composition, declarative connections, and aspect oriented programming.">cujoJS</a></li><li class=labs><a href="labs/architecture-examples/montage/" data-source=http://montagejs.org data-content="Montage simplifies the development of rich HTML5 applications by providing modular components, real-time two-way data binding, CommonJS dependency management, and many more conveniences.">Montage</a></li><li class="routing labs"><a href="labs/architecture-examples/sammyjs/" data-source=http://sammyjs.org data-content="Sammy.js is a tiny JavaScript framework developed to ease the pain and provide a basic structure for developing JavaScript applications.">Sammy.js</a></li><li class="routing labs"><a href="labs/architecture-examples/stapes/" data-source=http://hay.github.com/stapes data-content="Stapes is a (really) tiny Javascript MVC micro-framework (1.7kb) that has all the building blocks you need when writing an MVC app. It includes a powerful event system, support for inheritance, use with AMD, plugin support and more. A RequireJS Todo application is <a href='labs/dependency-examples/stapes_require/index.html'>also</a> available.">Stapes</a></li><li class="routing labs"><a href="labs/architecture-examples/epitome/" data-source=http://dimitarchristoff.github.com/Epitome data-content="Epitome is a new extensible and modular open-source MVC framework, built out of MooTools Classes and Events.">Epitome</a></li><li class=labs><a href="labs/architecture-examples/somajs/" data-source=http://somajs.github.com/somajs data-content="soma.js is a framework created to build scalable and maintainable javascript applications.">soma.js</a></li><li class=labs><a href="labs/architecture-examples/duel/www/" data-source=https://bitbucket.org/mckamey/duel/wiki/Home data-content="DUEL is a dual-side templating engine using HTML for layout and 100% pure JavaScript as the binding language. The same views may be executed both directly in the browser (client-side template) and on the server (server-side template).">DUEL</a></li><li class="routing labs"><a href="labs/architecture-examples/kendo/" data-source="http://www.kendoui.com/" data-content="Kendo UI is a comprehensive HTML5, JavaScript framework for modern web and mobile app development">Kendo UI</a></li><li class="routing labs"><a href="labs/architecture-examples/puremvc/" data-source=http://puremvc.github.com data-content="PureMVC is a lightweight framework for creating applications based upon the classic Model-View-Controller design meta-pattern.">PureMVC</a></li><li class=labs><a href="labs/architecture-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 class="routing labs"><a href="labs/architecture-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 class=labs><a href="labs/architecture-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></li><li class="routing labs"><a href="labs/architecture-examples/rappidjs/" data-source=http://www.rappidjs.com data-content="rAppid.js is a declarative JavaScript framework for rapid web application development. It supports dependency loading, Model-View binding, View-Model binding, dependency injection and i18n.">rAppid.js</a></li><li class=labs><a href="labs/architecture-examples/extjs_deftjs/" data-source="http://deftjs.org/" data-content="Essential extensions for enterprise web and mobile application development with Ext JS and Sencha Touch">DeftJS + ExtJS</a></li><li class="routing labs"><a href="labs/architecture-examples/ariatemplates/" data-source="http://ariatemplates.com/" data-content="Aria Templates has been designed for web apps that are used 8+ hours a day, and that need to display and process high amount of data with a minimum of bandwidth consumption.">Aria Templates</a></li><li class="routing labs"><a href="labs/dependency-examples/enyo_backbone/" data-source="http://enyojs.com/" data-content="Enyo is a simple but powerful encapsulation model, which helps you factor application functionality into self-contained building blocks that are easy to reuse and maintain.">Enyo +<br>Backbone.js</a></li><li class="routing labs"><a href="architecture-examples/angularjs-perf/" data-source=http://angularjs.org data-content="What HTML would have been had it been designed for web apps. A version with several performance optimizations.">AngularJS<br>(optimized)</a></li><li class="routing labs"><a href="labs/architecture-examples/sapui5/" data-source=http://scn.sap.com/community/developer-center/front-end data-content="SAPUI5 is SAP's HTML5-based UI technology that allows you to build rich, interactive Web applications.">SAPUI5</a></li><li class="routing labs"><a href="labs/architecture-examples/exoskeleton/" data-source="http://exosjs.com/" data-content="A faster and leaner Backbone for your HTML5 apps.">Exoskeleton</a></li><li class="routing labs"><a href="labs/architecture-examples/atmajs/" data-source="http://atmajs.com/" data-content="HMVC and the component-based architecture for building client, server or hybrid applications">Atma.js</a></li><li class=labs><a href="labs/architecture-examples/ractive/" data-source=http://ractivejs.org data-content="Ractive.js is a next-generation DOM manipulation library, optimised for developer sanity.">Ractive.js</a></li><li class="labs routing"><a href="labs/architecture-examples/componentjs/" data-source=http://componentjs.com data-content="ComponentJS is a stand-alone MPL-licensed Open Source library for JavaScript, providing a powerful run-time Component System for hierarchically structuring the User-Interface (UI) dialogs of complex HTML5-based Rich Clients (aka Single-Page-Apps) — under maximum applied Separation of Concerns (SoC) architecture principle, through optional Model, View and Controller component roles, with sophisticated hierarchical Event, Service, Hook, Model, Socket and Property mechanisms, and fully independent and agnostic of the particular UI widget toolkit.">ComponentJS</a></li><li class="labs routing"><a href="labs/architecture-examples/vue/" data-source=http://vuejs.org data-content="Vue.js provides the benefits of MVVM data binding and a composable component system with an extremely simple and flexible API.">Vue.js</a></li><li class="labs routing"><a href="labs/architecture-examples/react-backbone/" data-source="http://facebook.github.io/react/" data-content="This React example integrates Backbone for its model and router. It is a showcase of third-party library integration for developers wishing to use React together with a different JavaScript framework.">React +<br>Backbone.js</a></li></ul><ul class=legend><li><b>*</b> <span class=label>R</span> = App also demonstrates routing</li><li><b>*</b> <strong>Maroon</strong> = App requires further work to comply with <a href=https://github.com/tastejs/todomvc/blob/gh-pages/app-spec.md>the spec</a></li></ul><hr><h2>Compile To JavaScript</h2><ul class="applist ctojs"><li class=routing><a href="architecture-examples/spine/" data-source=http://spinejs.com data-content="Spine is a lightweight framework for building JavaScript web applications. Spine gives you an MVC structure and then gets out of your way, allowing you to concentrate on the fun stuff, building awesome web applications.">Spine</a></li><li class=routing><a href="vanilla-examples/vanilladart/build/" data-source=http://dartlang.org data-content="Dart firstly targets the development of modern and large scale browser-side web apps. It's an object oriented language with a C-style syntax. It has two run modes : it can be compiled to JS, and will later run in native VM in compliant browsers (just in a dedicated Chromium provided with Dart SDK for the moment).">Dart</a></li><li class=routing><a href="architecture-examples/gwt/" data-source="https://developers.google.com/web-toolkit/" data-content="Google Web Toolkit (GWT) is an MVP development toolkit for building and optimizing complex browser-based applications. GWT is used by many products at Google, including Google AdWords.">GWT</a></li><li class=routing><a href="architecture-examples/closure/" data-source="http://code.google.com/closure/library/" data-content="The Closure Library is a broad, well-tested, modular, and cross-browser JavaScript library. You can pull just what you need from a large set of reusable UI widgets and controls, and from lower-level utilities for DOM manipulation, server communication, animation, data structures, unit testing, rich-text editing, and more.">Closure</a></li><li class=labs><a href="labs/architecture-examples/angular-dart/web/" data-source=https://github.com/angular/angular.dart data-content="Dart firstly targets the development of modern and large scale browser-side web apps. It's an object oriented language with a C-style syntax. AngularDart is a port of Angular to Dart.">AngularDart</a></li><li class="routing labs"><a href="labs/architecture-examples/batman/" data-source=http://batmanjs.org data-content="Batman.js is a framework for building rich web applications with CoffeeScript or JavaScript. App code is concise and declarative, thanks to a powerful system of view bindings and observable properties. The API is designed with developer and designer happiness as its first priority.">Batman.js</a></li><li class=labs><a href="labs/architecture-examples/typescript-backbone/" data-source=http://typescriptlang.org data-content="TypeScript is a language for application-scale JavaScript development. It offers classes, modules, interfaces and type-checking at compile time to help you build robust components.">TypeScript<br>+ Backbone.js</a></li><li class="labs routing"><a href="labs/architecture-examples/typescript-angular/" data-source=http://typescriptlang.org data-content="An AngularJS + TypeScript implementation of TodoMVC. The only significant difference between this and the vanilla Angular app is that dependency injection is done via annotated constructors, which allows minification of JavaScript.">TypeScript<br>+ AngularJS</a></li><li class=labs><a href="labs/architecture-examples/serenadejs/" data-source=https://github.com/elabs/serenade.js data-content="Serenade.js is yet another MVC client side JavaScript framework. Why do we indulge in recreating the wheel? We believe that Serenade.js more closely follows the ideas of classical MVC than competing frameworks.">Serenade.js</a></li></ul><hr><h2>MVC Extension Frameworks</h2><ul class=applist><li class="routing labs"><a href="labs/architecture-examples/backbone_marionette/" data-source=http://marionettejs.com data-content="Backbone.Marionette is a composite application library for Backbone.js that aims to simplify the construction of large scale JavaScript applications.">MarionetteJS</a></li><li class="routing labs"><a href="labs/architecture-examples/thorax/" data-source=http://thoraxjs.org data-content="An opinionated, battle tested Backbone + Handlebars framework to build large scale web applications.">Thorax</a></li><li class="routing labs"><a href="labs/dependency-examples/chaplin-brunch/public/" data-source=http://chaplinjs.org data-content="Chaplin is an architecture for JavaScript applications using the Backbone.js library. Chaplin addresses Backbone’s limitations by providing a lightweight and flexible structure that features well-proven design patterns and best practises.">Chaplin + Brunch</a></li></ul><hr><h2>Module Loaders</h2><ul class=applist><li class=routing><a href="dependency-examples/backbone_require/" data-source=http://requirejs.org data-content="RequireJS is a JavaScript file and module loader. It is optimized for in-browser use, but it can be used in other JavaScript environments, like Rhino and Node. Using a modular script loader like RequireJS will improve the speed and quality of your code.">Backbone.js + RequireJS</a></li><li class=routing><a href="dependency-examples/flight/" data-source=http://twitter.github.com/flight data-content="Flight is a lightweight, component-based JavaScript framework that maps behavior to DOM nodes. Twitter uses it for their web applications.">Flight</a></li><li class=labs><a href="labs/dependency-examples/knockoutjs_require/" data-source=http://knockoutjs.com data-content="This project is an adaptation of /architecture-examples/knockoutjs with require.js.">KnockoutJS + RequireJS</a></li><li class="routing labs"><a href="labs/dependency-examples/angularjs_require/" data-source=http://angularjs.org data-content="What HTML would have been had it been designed for web apps. This is an example of using it with AMD modules.">AngularJS + RequireJS</a></li><li class="routing labs"><a href="labs/dependency-examples/canjs_require/" data-source=http://canjs.us data-content="CanJS is a client-side, JavaScript framework that makes building rich web applications easy. The AMD version lets you use the framework in a fully modular fashion and will only what you actually need.">CanJS + RequireJS</a></li><li class="routing labs"><a href="labs/dependency-examples/troopjs_require/" data-source="https://github.com/troopjs/" data-content="TroopJS attempts to package popular front-end technologies and bind them with minimal effort for the developer. It includes jQuery for DOM manipulation, When.js for promises, RequireJS for modularity and Has.js for feature detection. On top, it includes Pub/Sub support, templating, weaving (widgets to DOM) and auto-wiring.">TroopJS + RequireJS</a></li><li class="routing labs"><a href="labs/dependency-examples/thorax_lumbar/public/" data-source=http://walmartlabs.github.com/lumbar data-content="An opinionated, battle tested Backbone + Handlebars framework to build large scale web applications. This implementation uses Lumbar, a route based module loader.">Thorax + Lumbar</a></li><li class="routing labs"><a href="labs/dependency-examples/somajs_require/" data-source=http://somajs.github.com/somajs data-content="soma.js is a framework created to build scalable and maintainable javascript applications.">soma.js + RequireJS</a></li><li class="routing labs"><a href="labs/dependency-examples/durandal/" data-source="http://durandaljs.com/" data-content="Single Page Apps Done Right">Durandal</a></li><li class="routing labs"><a href="labs/dependency-examples/lavaca_require/" data-source=http://getlavaca.com data-content="A curated collection of tools for building mobile web applications.">Lavaca + RequireJS</a></li></ul><hr><h2>Real-time</h2><ul class=applist><li class=labs><a href=http://todomvcapp.meteor.com data-source=http://meteor.com data-content="Meteor is an ultra-simple environment for building modern websites. A Meteor application is a mix of JavaScript that runs inside a client web browser, JavaScript that runs on the Meteor server inside a Node.js container, and all the supporting HTML fragments, CSS rules, and static assets. Meteor automates the packaging and transmission of these different components. And, it is quite flexible about how you choose to structure those components in your file tree.">Meteor</a></li><li class=labs><a href=http://todomvc.derbyjs.com data-source=http://derbyjs.com data-content="MVC framework making it easy to write realtime, collaborative applications that run in both Node.js and browsers.">Derby</a></li><li class="routing labs"><a href=http://todomvc-socketstream.herokuapp.com data-source=http://www.socketstream.org data-content="SocketStream is a fast, modular Node.js web framework dedicated to building realtime single-page apps">SocketStream</a></li><li class="routing labs"><a href="labs/architecture-examples/firebase-angular/" data-source=https://www.firebase.com data-content="Firebase is a scalable realtime backend that lets you build apps without managing servers. Firebase persists and updates JSON data in realtime and is best used in combination with a JavaScript MV* framework such as AngularJS or Backbone.">Firebase + AngularJS</a></li></ul><hr><h2>Compare these to a non-framework implementation</h2><ul class=applist><li class=routing><a href="vanilla-examples/vanillajs/" data-source=https://developer.mozilla.org/en/JavaScript data-content="You know JavaScript right? :P">Vanilla JS</a></li><li class=routing><a href="architecture-examples/jquery/" data-source=http://jquery.com data-content="jQuery is a fast and concise JavaScript Library that simplifies HTML document traversing, event handling, animating, and Ajax interactions for rapid web development. jQuery is designed to change the way that you write JavaScript.">jQuery</a></li></ul></div></div><hr><div class=row><div class="col-md-6 quotes"><blockquote class="quote speech-bubble"><p></p><footer><img width=40 height=40> <a></a></footer></blockquote></div><div class=col-md-6><img class=screenshot src=site-assets/screenshot.png width=558 height=246 alt="Todo app screenshot"></div></div><hr><div class=row><div class=col-md-4><h2>New in 1.2 - 2013-08-06</h2><ul class=whats-new><li>We now have 21 stable apps and 45 in labs.<label class=link for=news-expander>New since 1.1 ▼</label><input type=checkbox id=news-expander><ul class=collapsed id=new-apps><li><a href="architecture-examples/polymer/">Polymer</a></li><li><a href="dependency-examples/flight/">Flight</a></li><li><a href="architecture-examples/react/">React</a></li><li><a href=vanilla-examples/vanillajs>VanillaJS Rewrite</a></li><li><a href="labs/architecture-examples/sapui5/">SAPUI5</a></li><li><a href="labs/architecture-examples/firebase-angular/">AngularJS + Firebase</a></li></ul></li><li>We have a brand-new Info Bar</li><li>All application now use Bower for dependency management</li><li>Various consistency fixes across all apps</li><li>Many app frameworks and libraries have been upgraded to the latest version</li></ul></div><div class=col-md-4><h2>Selecting a Framework</h2><p>Once you've downloaded the latest release and played around with the apps, you'll want to decide on a specific framework to try out.</p><p>Study the syntax required for defining models, views and (where applicable) controllers and classes in the frameworks you're interested in and try your hand at editing the code to see how it feels using it first-hand.</p><p>Please ensure that if you're happy with this, you do spend more time investigating the framework (including reading the official docs, the source and its complete feature list). There's often a lot more to a framework than what we present in our examples.</p></div><div class=col-md-4><h2>Getting Involved</h2><p>Is there a bug we haven't fixed or an MV* framework you feel would benefit from being included in TodoMVC?</p><p>If so, feel free to fork the repo, read our <a href=https://github.com/tastejs/todomvc/wiki>contribution guidelines</a>, and submit a pull request &mdash; we'll be happy to review it for inclusion.</p><p>Make sure you use the <a href=https://github.com/tastejs/todomvc/tree/gh-pages/template>template</a> as a starting point and read the <a href=https://github.com/tastejs/todomvc/blob/gh-pages/app-spec.md>app specification</a>.</p><p><a class="zocial small ltgray" href=https://github.com/tastejs/todomvc/wiki>Submit Pull Request &raquo;</a></p></div></div><hr><footer class=credit><p>Brought to you by <a href=https://github.com/addyosmani><img src="http://gravatar.com/avatar/96270e4c3e5e9806cf7245475c00b275?s=80" width=40 height=40 alt="Addy Osmani">Addy Osmani</a> <a href=https://github.com/sindresorhus><img src="http://gravatar.com/avatar/d36a92237c75c5337c17b60d90686bf9.png?s=80" width=40 height=40 alt="Sindre Sorhus">Sindre Sorhus</a> <a href=https://github.com/passy><img src="http://gravatar.com/avatar/be451fcdbf0e5ff07f23ed16cb5c90a3.png?s=80" width=40 height=40 alt="Pascal Hartig">Pascal Hartig</a> <a href=https://github.com/stephenplusplus><img src="http://gravatar.com/avatar/098cfe2d360e77c3229f2cd5298354c4?s=80" width=40 height=40 alt="Stephen Sawchuk">Stephen Sawchuk</a> <a href=https://github.com/colineberhardt><img src="http://gravatar.com/avatar/73bba00b41ff1c9ecc3ee29487bace7d?s=80" width=40 height=40 alt="Colin Eberhardt">Colin Eberhardt</a></p></footer></div><script src=site-assets/main.min.js></script><script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0];if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.async=true;js.src="//platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script><script>(function(){var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;po.src = 'https://apis.google.com/js/plusone.js';var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);})();</script><script>var _gaq=[['_setAccount','UA-31081062-1'],['_trackPageview']];(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.src='//www.google-analytics.com/ga.js';s.parentNode.insertBefore(g,s)}(document,'script'));</script></body></html>
\ No newline at end of file
define(['./system', './viewEngine', './composition', './widget', './modalDialog', './events'],
define(['./system', './viewEngine', './composition', './widget', './modalDialog', './events'],
function(system, viewEngine, composition, widget, modalDialog, Events) {
var app = {
......
define(['./viewLocator', './viewModelBinder', './viewEngine', './system', './viewModel'],
define(['./viewLocator', './viewModelBinder', './viewEngine', './system', './viewModel'],
function (viewLocator, viewModelBinder, viewEngine, system, viewModel) {
var dummyModel = {},
......
//heavily borrowed from backbone events, augmented by signals.js, added a little of my own code, cleaned up for better readability
//heavily borrowed from backbone events, augmented by signals.js, added a little of my own code, cleaned up for better readability
define(['./system'], function (system) {
var eventSplitter = /\s+/;
var Events = function() { };
......
define(['./composition', './system', './viewModel'],
define(['./composition', './system', './viewModel'],
function (composition, system, viewModel) {
var contexts = {},
......
define(['../system', '../viewModel', '../app'], function (system, viewModel, app) {
define(['../system', '../viewModel', '../app'], function (system, viewModel, app) {
//NOTE: Sammy.js is not required by the core of Durandal.
//However, this plugin leverages it to enable navigation.
......
define(['require'], function (require) {
define(['require'], function (require) {
var isDebugging = false,
nativeKeys = Object.keys,
hasOwnProperty = Object.prototype.hasOwnProperty,
......
define(['./system'], function (system) {
define(['./system'], function (system) {
var parseMarkupCore;
if ($.parseHTML) {
......
define(['./system', './viewEngine'],
define(['./system', './viewEngine'],
function (system, viewEngine) {
function findInElements(nodes, url) {
......
define(['./system'], function (system) {
define(['./system'], function (system) {
var viewModel;
function ensureSettings(settings) {
......
define(['./system'], function (system) {
define(['./system'], function (system) {
var viewModelBinder;
var insufficientInfoMessage = 'Insufficient Information to Bind';
var unexpectedViewMessage = 'Unexpected View Type';
......
define(['./system', './composition'], function (system, composition) {
define(['./system', './composition'], function (system, composition) {
var widgetPartAttribute = 'data-part',
widgetPartSelector = '[' + widgetPartAttribute + ']';
......
/*!
/*!
* jQuery JavaScript Library v1.9.1
* http://jquery.com/
*
......
.splash {
.splash {
text-align: center;
margin: 10% 0 0 0;
}
......
/*global requirejs, define, ko */
/*global requirejs, define, ko */
(function () {
'use strict';
......
/*global define */
/*global define */
define([
'bower_components/durandal/plugins/router',
], function (router) {
......
/*jshint strict:false */
/*jshint strict:false */
/*global enyo:false, ToDo:false, Backbone: false */
enyo.ready(function () {
ToDo.TaskCollection = Backbone.Collection.extend({
......
/*jshint strict:false */
/*jshint strict:false */
/*global enyo:false, $:false */
/*exported ENTER_KEY, ESC_KEY */
// This is based on Enyo 2.1.1. The next version (2.3) of Enyo will more tightly integrate MVC and should require less custom code.
......
/*jshint strict:false */
/*jshint strict:false */
/*global enyo:false, ToDo:false */
enyo.kind({
kind: 'enyo.Router',
......
/*jshint strict:false */
/*jshint strict:false */
/*global enyo:false, ToDo:false, Backbone:false */
enyo.ready(function () {
ToDo.TaskModel = Backbone.Model.extend({
......
/*jshint strict:false */
/*jshint strict:false */
/*global enyo:false */
// The footer section
enyo.kind({
......
/*jshint strict:false */
/*jshint strict:false */
/*global enyo:false */
enyo.kind({
name: 'ToDo.NotepadFooterView',
......
/*jshint strict:false */
/*jshint strict:false */
/*global enyo:false, ENTER_KEY:false */
// Header section for adding a new task.
enyo.kind({
......
/*jshint strict:false */
/*jshint strict:false */
/*global enyo:false, ENTER_KEY:false, ESC_KEY:false */
// The main task list view
enyo.kind({
......
/*jshint strict:false */
/*jshint strict:false */
/*global enyo:false */
// This is the notepad area
enyo.kind({
......
{
"framework": {
"name": "Framework Name",
"description": "",
"homepage": "",
"source_path": [{
"name": "__ Example",
"url": ""
}],
"link_groups": [{
"heading": "Official Resources",
"links": [{
"name": "Documentation",
"url": ""
}, {
"name": "API Reference",
"url": ""
}, {
"name": "Applications built with Framework Name",
"url": ""
}, {
"name": "Blog",
"url": ""
}, {
"name": "FAQ",
"url": ""
}, {
"name": "Framework Name on GitHub",
"url": "https://github.com/__"
}]
}, {
"heading": "Articles and Guides",
// Search blogs on google to help dig up articles.
// https://www.google.com/search?q=Framework Name&tbm=blg
"links": [{
"name": "Article 1",
"url": ""
}, {
"name": "Article 2",
"url": ""
}]
}, {
"heading": "Community",
"links": [{
"name": "Framework Name on StackOverflow",
"url": "http://stackoverflow.com/questions/tagged/__"
}, {
"name": "Mailing list on Google Groups",
"url": ""
}, {
"name": "Framework Name on Twitter",
"url": "http://twitter.com/__"
}, {
"name": "Framework Name on Google +",
"url": ""
}]
}]
}
}
Everything in this repo is MIT License unless otherwise specified.
Copyright (c) Addy Osmani, Sindre Sorhus, Pascal Hartig, Stephen Sawchuk.
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
<svg xmlns="http://www.w3.org/2000/svg" width="500" height="85.529" viewBox="0 0 500 85.529"><g fill="#2D2D2D"><path d="M115.936 74.479v-6.708l8.744-.594c1.188-.086 1.358-.425 1.358-1.698v-43.213h-8.743c-.935 0-1.189.083-1.359.933l-1.358 7.388h-9.339v-17.577h54.677v17.576h-9.255l-1.357-7.388c-.17-.85-.425-.933-1.358-.933h-8.746v43.214c0 1.188.085 1.527 1.359 1.612l9.34.68v6.708h-33.963zM151.076 75.659h-36.319v-8.989l9.843-.669.244-.026.015-.495v-42.036h-7.563l-.188.003-1.549 8.317h-11.499v-19.933h57.034v19.934h-11.417l-1.528-8.317-.204-.003h-7.566v42.035l.006.413.252.022 10.44.76v8.984zm-33.961-2.359h31.603v-4.433l-8.246-.599c-2.264-.151-2.453-1.46-2.453-2.789v-44.393h9.926c1.082 0 2.168.146 2.516 1.88l1.184 6.44h7.092v-15.217h-52.317v15.217h7.178l1.179-6.422c.354-1.753 1.438-1.898 2.521-1.898h9.924v44.394c0 1.307-.189 2.711-2.454 2.876l-7.649.517v4.427z"/></g><g fill="#2D2D2D"><path d="M158.563 52.659c0-14.095 7.385-23.263 22.923-23.263 15.705 0 21.817 9.338 21.817 22.33 0 14.433-7.302 23.77-22.923 23.77-15.533 0-21.817-9.508-21.817-22.837zm31.329-.509c0-10.021-3.057-13.586-8.574-13.586-5.604 0-9.34 3.482-9.34 13.67 0 10.273 3.311 14.35 8.997 14.35 5.52 0 8.917-3.82 8.917-14.434zM180.381 76.677c-14.829 0-22.997-8.53-22.997-24.018 0-15.532 8.785-24.441 24.103-24.441 14.829 0 22.998 8.35 22.998 23.509-.001 16.089-8.561 24.95-24.104 24.95zm1.105-46.101c-14.021 0-21.744 7.843-21.744 22.083 0 9.882 3.579 21.659 20.639 21.659 17.972 0 21.745-12.287 21.745-22.592 0-9.649-3.58-21.15-20.64-21.15zm-.511 37.187c-6.753 0-10.177-5.224-10.177-15.528 0-9.854 3.54-14.849 10.52-14.849 8.742 0 9.754 8.425 9.754 14.765-.001 10.505-3.304 15.612-10.097 15.612zm.342-28.019c-3.505 0-8.16 1.294-8.16 12.49 0 11.803 4.463 13.17 7.817 13.17 3.322 0 7.738-1.373 7.738-13.254.001-10.932-3.737-12.406-7.395-12.406z"/></g><g fill="#2D2D2D"><path d="M240.416 74.479l-.852-4.754-.594-.087c-3.565 3.482-7.726 5.857-13.922 5.857-10.019 0-16.475-6.364-16.475-22.582 0-17.065 8.578-23.518 18.003-23.518 4.922 0 8.745 1.697 11.97 4.075v-12.905c0-.848-.34-1.441-1.104-1.697l-4.668-1.612.933-6.878h17.066v55.187c0 1.271.081 1.442 1.357 1.613l4.072.594v6.708h-15.786zm-2.378-32.687c-2.122-1.445-4.84-2.546-7.303-2.546-6.281 0-8.745 5.855-8.745 13.413 0 8.233 2.376 12.82 7.725 12.82 2.89 0 6.031-1.697 8.323-3.65v-20.037zM225.049 76.677c-11.714 0-17.653-7.995-17.653-23.763 0-15.464 7.17-24.696 19.182-24.696 3.869 0 7.419.997 10.79 3.042v-10.695c0-.479-.139-.524-.3-.58l-5.591-1.931 1.201-8.856h19.275v56.366l.004.395.333.05 5.095.742v8.908h-17.957l-.741-4.147c-4.051 3.562-8.315 5.165-13.638 5.165zm1.528-46.101c-10.69 0-16.823 8.143-16.823 22.338 0 14.403 5.003 21.404 15.295 21.404 5.146 0 9.187-1.702 13.098-5.522l.417-.406 2.014.289.827 4.621h13.622v-4.507l-3.064-.448c-2.011-.269-2.367-1.11-2.367-2.78v-54.008h-14.858l-.662 4.899 3.753 1.297c1.203.403 1.898 1.431 1.898 2.812v15.239l-1.878-1.384c-3.562-2.623-7.141-3.844-11.272-3.844zm3.138 36.083c-5.906 0-8.905-4.711-8.905-14 0-9.274 3.62-14.593 9.926-14.593 2.495 0 5.399 1.003 7.967 2.751l.516.35v21.206l-.415.354c-1.388 1.182-5.05 3.932-9.089 3.932zm1.02-26.233c-6.582 0-7.565 7.666-7.565 12.233 0 11.642 4.928 11.642 6.545 11.642 2.131 0 4.771-1.124 7.145-3.027v-18.844c-2.029-1.263-4.278-2.004-6.125-2.004z"/></g><g fill="#2D2D2D"><path d="M259.098 52.659c0-14.095 7.388-23.263 22.925-23.263 15.707 0 21.821 9.338 21.821 22.33 0 14.433-7.303 23.77-22.926 23.77-15.536 0-21.82-9.508-21.82-22.837zm31.331-.509c0-10.021-3.059-13.586-8.578-13.586-5.602 0-9.336 3.482-9.336 13.67 0 10.273 3.31 14.35 8.997 14.35 5.519 0 8.917-3.82 8.917-14.434zM280.918 76.677c-14.832 0-22.999-8.53-22.999-24.018 0-15.532 8.786-24.441 24.104-24.441 14.831 0 22.999 8.35 22.999 23.509-.001 16.089-8.56 24.95-24.104 24.95zm1.104-46.101c-14.022 0-21.746 7.843-21.746 22.083 0 9.882 3.583 21.659 20.642 21.659 17.971 0 21.745-12.287 21.745-22.592 0-9.649-3.581-21.15-20.641-21.15zm-.51 37.187c-6.754 0-10.178-5.224-10.178-15.528 0-9.854 3.538-14.849 10.517-14.849 8.747 0 9.758 8.425 9.758 14.765-.001 10.505-3.303 15.612-10.097 15.612zm.339-28.019c-3.503 0-8.159 1.294-8.159 12.49 0 11.803 4.466 13.17 7.82 13.17 3.322 0 7.739-1.373 7.739-13.254 0-10.932-3.741-12.406-7.4-12.406z"/></g><g fill="#AF2F2F"><path d="M354.554 74.479v-6.623l6.963-.594c1.188-.171 1.358-.51 1.358-1.698v-32.262h-.339l-12.141 28.951h-13.843l-11.968-29.036h-.427v32.263c0 1.356.086 1.527 1.358 1.698l7.303.679v6.623h-25.81v-6.623l5.347-.594c1.191-.171 1.359-.427 1.359-1.698v-43.555c0-1.274-.168-1.527-1.359-1.697l-5.347-.595v-6.708h22.753l14.774 38.461h.339l15.536-38.461h22.076v6.623l-5.69.68c-1.272.17-1.358.338-1.358 1.611v43.641c0 1.104.254 1.442 1.358 1.613l5.69.679v6.623h-27.932zM383.668 75.659h-30.292v-8.885l8.04-.688.289-.06c-.019-.047-.011-.198-.011-.463v-27.21l-10.517 25.077h-15.414l-10.426-25.294v27.342l.008.479.328.05 8.325.771v8.879h-28.168v-8.857l6.396-.712.295-.053.017-.473v-43.552l-.017-.473-.332-.057-6.359-.707v-8.942h24.742l14.159 36.853 14.886-36.853h24.051v8.848l-6.729.804-.316.048-.004.394v43.641l.021.395.339.054 6.688.799v8.845zm-27.935-2.359h25.575v-4.396l-4.65-.556c-1.691-.261-2.397-1.093-2.397-2.784v-43.64c0-1.667.356-2.51 2.381-2.779l4.667-.558v-4.397h-20.103l-15.536 38.46h-1.944l-14.773-38.461h-20.764v4.473l4.301.478c2.021.29 2.406 1.271 2.406 2.87v43.555c0 1.599-.386 2.58-2.368 2.866l-4.339.481v4.388h23.452v-4.367l-6.231-.581c-2.088-.278-2.43-1.11-2.43-2.872v-33.443h2.395l11.968 29.037h12.269l12.144-28.953h2.3v33.443c0 1.56-.396 2.582-2.367 2.866l-5.953.508v4.362z"/></g><g fill="#AF2F2F"><path d="M411.176 74.479l-17.066-52.469c-.34-1.021-1.017-1.189-2.038-1.444l-3.821-.933.85-6.623h25.728v6.623l-6.879.763 12.733 42.451h.682l12.311-42.451-6.79-.763.848-6.623h21.988v6.623l-3.566.933c-1.019.255-1.865.595-2.12 1.612l-15.537 52.302h-17.323zM429.377 75.659h-19.059l-17.329-53.285c-.116-.342-.131-.396-1.198-.663l-4.845-1.182 1.118-8.698h27.943v8.856l-6.521.724 11.523 38.423 11.142-38.423-6.589-.74 1.129-8.84h24.208v8.711l-4.445 1.164c-1.077.271-1.21.485-1.275.76l-15.802 53.193zm-17.345-2.359h15.584l15.286-51.458c.45-1.788 2.148-2.217 2.965-2.421l2.675-.698v-4.533h-19.771l-.565 4.403 6.991.786-12.945 44.647h-2.446l-13.392-44.647 7.235-.801v-4.389h-23.513l-.582 4.547 2.797.685c1.102.273 2.334.582 2.879 2.216l16.802 51.663z"/></g><g fill="#AF2F2F"><path d="M498.821 70.829c-5.011 3.057-13.502 4.667-21.228 4.667-21.141 0-29.801-12.308-29.801-32.007 0-18.083 10.442-31.585 31.583-31.585 7.047 0 14.603 1.783 19.273 4.842v16.64l-9.338-.764-1.358-8.32c-.171-.848-.512-1.273-1.36-1.53-1.867-.594-4.753-1.018-7.554-1.018-10.785 0-17.664 7.302-17.664 21.735 0 15.027 6.54 22.329 17.069 22.329 2.802 0 6.281-.425 8.489-1.103 1.02-.256 1.273-.51 1.528-1.783l1.273-7.896h9.086v15.793zM477.594 76.677c-20.558 0-30.979-11.167-30.979-33.188 0-20.21 12.553-32.765 32.762-32.765 7.545 0 15.179 1.929 19.919 5.036l.533.348v18.559l-11.532-.945-1.507-9.229c-.088-.427-.15-.475-.537-.593-1.854-.589-4.68-.967-7.213-.967-10.629 0-16.482 7.3-16.482 20.556 0 13.836 5.492 21.149 15.888 21.149 2.783 0 6.132-.433 8.142-1.05.415-.105.502-.157.524-.171.005-.013.079-.15.194-.718l1.426-8.843h11.268v17.632l-.564.346c-4.896 2.987-13.265 4.843-21.842 4.843zm1.782-63.593c-19.037 0-30.404 11.367-30.404 30.405 0 20.457 9.63 30.829 28.622 30.829 7.718 0 15.475-1.625 20.047-4.166v-13.936h-6.901l-1.115 6.906c-.344 1.731-.905 2.359-2.401 2.737-2.188.673-5.74 1.138-8.778 1.138-11.769 0-18.247-8.35-18.247-23.508 0-14.562 6.867-22.915 18.842-22.915 2.798 0 5.829.413 7.911 1.074 1.226.368 1.896 1.116 2.158 2.421l1.22 7.451 7.143.585v-14.708c-4.368-2.632-11.375-4.313-18.097-4.313z"/></g><g fill="#2D2D2D"><path d="M12.83 5.701h8.781v-5.701h-8.781c-2.433 0-4.801.683-6.849 1.979l3.046 4.815c1.136-.715 2.448-1.093 3.803-1.093"/><path d="M5.704 12.827c0-1.042.216-2.042.646-2.979l-5.178-2.389c-.778 1.692-1.172 3.498-1.172 5.368v10.095h5.704v-10.095zM0 28.68h5.704v14.37h-5.704zM76.782 6.979c1.718-1.091 3.432-2.121 5.13-3.079-.97-1-2.104-1.842-3.336-2.478-1.803-.93-3.837-1.422-5.875-1.422h-5.048v5.701h5.048c1.494 0 2.904.449 4.081 1.278"/><path d="M0 48.81h5.704v14.397h-5.704zM27.369 0h14.371v5.701h-14.371zM47.497 0h14.396v5.701h-14.396zM53.855 79.824h14.367v5.705h-14.367zM79.827 32.387h5.701v14.398h-5.701zM79.827 52.542h5.701v14.372h-5.701zM5.704 72.699v-3.738h-5.704v3.738c0 4.668 2.54 8.976 6.631 11.236l2.758-4.99c-2.274-1.259-3.685-3.65-3.685-6.246M79.827 22.847v3.778h5.701v-8.467c-1.875 1.399-3.772 2.96-5.701 4.689"/><path d="M79.827 72.699c0 3.575-2.667 6.614-6.203 7.07l.726 5.655c3.07-.396 5.897-1.894 7.956-4.22 2.078-2.347 3.223-5.366 3.223-8.506v-.028h-5.701v.029zM13.542 79.824h14.398v5.705h-14.398zM33.696 79.824h14.399v5.705h-14.399z"/></g><path fill="#AF2F2F" d="M13.059 45.396l26.744 26.744s26.745-51.453 55.662-62.994l-1.084-8.144c-15.749 6.244-39.648 22.673-57.294 47.787l-18.6-10.996-5.428 7.603z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="3348.477" height="3000" viewBox="0 0 3348.477 3000"><g fill="#383838"><path d="M450 200h308v-200h-308.001c-85.296 0-168.349 24-240.179 69.403l106.86 169.059c39.807-25.162 85.909-38.462 133.32-38.462zM200 450c0-36.534 7.671-71.695 22.799-104.509l-181.626-83.737c-27.321 59.258-41.173 122.593-41.173 188.246v354h200v-354zM0 1006h200v504h-200zM2693.184 244.82c60.299-38.185 120.381-74.26 179.885-108.002-34.01-35.025-73.675-64.589-116.941-86.915-63.27-32.647-134.548-49.903-206.128-49.903h-177v200h177c52.391 0 101.865 15.829 143.184 44.82zM0 1712h200v505h-200zM960 0h504v200h-504zM1666 0h505v200h-505zM1889 2800h504v200h-504zM2800 1136h200v505h-200zM2800 1843h200v504h-200zM200 2550v-131h-200v131c0 163.793 89.126 314.793 232.597 394.074l96.732-175.051c-79.773-44.083-129.329-128.006-129.329-219.023zM2800 801.374v132.626h200v-297.03c-65.743 48.947-132.47 103.807-200 164.404zM2800 2550c0 125.372-93.562 231.961-217.635 247.936l25.539 198.363c107.655-13.861 206.741-66.413 279.005-147.977 72.928-82.313 113.091-188.26 113.091-298.322v-1h-200v1zM475 2800h505v200h-505zM1182 2800h505v200h-505z"/></g><path fill="#AF2F2F" d="M458 1592.333l938.096 938.095s938.096-1804.761 1952.381-2209.523l-38.096-285.715c-552.381 219.048-1390.477 795.238-2009.524 1676.191l-652.382-385.714-190.475 266.666z"/></svg>
\ No newline at end of file
{
"devDependencies": {
"del": "^0.1.1",
"gulp": "^3.8.5",
"gulp-autoprefixer": "^0.0.8",
"gulp-cache": "^0.2.0",
"gulp-csso": "^0.2.9",
"gulp-if": "^1.2.1",
"gulp-imagemin": "^1.0.0",
"gulp-jshint": "^1.6.3",
"gulp-load-plugins": "^0.5.3",
"gulp-minify-html": "^0.1.4",
"gulp-rename": "^1.2.0",
"gulp-replace": "^0.4.0",
"gulp-size": "^1.0.0",
"gulp-uglify": "^0.3.1",
"gulp-uncss": "^0.4.4",
"gulp-useref": "^0.6.0",
"jshint-stylish": "^0.4.0",
"psi": "^0.1.1",
"run-sequence": "^0.3.6"
},
"engines": {
"node": ">=0.10.0"
},
"private": true
}
# ![TodoMVC](media/logo.png)
> Helping you select an MV\* framework
### [Website](http://todomvc.com)&nbsp;&nbsp;&nbsp;&nbsp;[Blog](http://blog.tastejs.com)&nbsp;&nbsp;&nbsp;&nbsp;[TasteJS](http://tastejs.com)
Developers these days are spoiled with choice when it comes to selecting an MV\* framework for structuring and organizing JavaScript web apps.
Backbone, Ember, AngularJS... the list of new and stable solutions goes on and on, but just how do you decide on which to use in a sea of so many options?
To help solve this problem, we created TodoMVC - a project which offers the same Todo application implemented using MV* concepts in most of the popular JavaScript MV\* frameworks of today.
## View & Run in Web IDE
Click on the button below to view the code in a Web IDE. Feel free to edit the code and then run it all from your browser.
[![IDE](site-assets/editcloud9.png)](https://c9.io/open/git/?url=git://github.com/tastejs/todomvc.git)
[![IDE](https://codio-public.s3.amazonaws.com/sharing/demo-in-ide.png)](https://codio.com/p/create/?from_github=tastejs/todomvc)
## Team
TodoMVC would not be possible without a strong team of [contributors](https://github.com/tastejs/todomvc/contributors) helping push the project forward each day. In addition, we have a core project team composed of:
#### [Addy Osmani](http://github.com/addyosmani) - Founder/Lead
<img align="left" width="40" height="40" src="http://www.gravatar.com/avatar/96270e4c3e5e9806cf7245475c00b275.png?s=40">
Addy is a Developer Platform Engineer at Google who originally created TodoMVC. He oversees the project direction, drives expansion and helps lead core development with Sindre Sorhus (by far our most active contributor!).
#### [Sindre Sorhus](https://github.com/sindresorhus) - Lead Developer
<img align="left" width="40" height="40" src="http://www.gravatar.com/avatar/d36a92237c75c5337c17b60d90686bf9.png?s=40">
Sindre is a Web Developer who drives core development, quality control and application design for the project. His contributions have helped us ensure consistency and best practices are enforced wherever possible.
#### [Pascal Hartig](https://github.com/passy) - Developer
<img align="left" width="40" height="40" src="http://www.gravatar.com/avatar/be451fcdbf0e5ff07f23ed16cb5c90a3.png?s=40">
Pascal is a Front-end Engineer at Twitter with a deep passion for consistency. He watches pull requests and helps developers getting their contributions integrated with TodoMVC.
#### [Stephen Sawchuk](https://github.com/stephenplusplus) - Developer
<img align="left" width="40" height="40" src="https://secure.gravatar.com/avatar/098cfe2d360e77c3229f2cd5298354c4?s=40">
Stephen is a Front-end Engineer at Quicken Loans that cares about improving the maintainability and developer experience of open-source projects. His recent contributions include helping us move all apps over to using Bower and implementing the new information bar.
#### [Colin Eberhardt](https://github.com/colineberhardt) - Developer
<img align="left" width="40" height="40" src="https://secure.gravatar.com/avatar/73bba00b41ff1c9ecc3ee29487bace7d?s=40">
Colin is a software consultant at Scott Logic who is passionate about all software - from JavaScript to Java, and C# to Objective-C. His recent contribution to the project has been a fully automated test suite.
#### [Gianni Chiappetta](https://github.com/gf3) - Logo designer
<img align="left" width="40" height="40" src="http://www.gravatar.com/avatar/4b0209ae3652cc5a7d53545e759fbe39.png?s=40">
Gianni is a programmer and designer currently working as the Chief Rigger at MetaLab.
## Disclaimer
<img align="right" width="230" height="230" src="media/icon-small.png">
TodoMVC has been called many things including the 'Speed-dating' and 'Rosetta Stone' of MV* frameworks. Whilst we hope that this project is able to offer assistance in deciding what frameworks are worth spending more time looking at, remember that the Todo application offers a limited view of what a framework may be capable of.
It is meant to be used as a gateway to reviewing how a basic application using a framework may be structured and we heavily recommend investing time researching a solution in more depth before opting to use it.
## Getting Involved
Whilst we enjoy implementing and improving existing Todo apps, we're always interested in speaking to framework authors (and users) wishing to share Todo app implementations in their framework/solution of choice.
Check out our [contribution docs](contributing.md) for more info.
## License
Everything in this repo is MIT License unless otherwise specified.
MIT © Addy Osmani, Sindre Sorhus, Pascal Hartig, Stephen Sawchuk.
<svg xmlns="http://www.w3.org/2000/svg" width="500" height="85.529"><path d="M115.936 74.479v-6.708l8.744-.594c1.188-.086 1.358-.425 1.358-1.698v-43.213h-8.743c-.935 0-1.189.083-1.359.933l-1.358 7.388h-9.339v-17.577h54.677v17.576h-9.255l-1.357-7.388c-.17-.85-.425-.933-1.358-.933h-8.746v43.214c0 1.188.085 1.527 1.359 1.612l9.34.68v6.708h-33.963zm35.14 1.18h-36.319v-8.989l9.843-.669.244-.026.015-.495v-42.036h-7.563l-.188.003-1.549 8.317h-11.499v-19.933h57.034v19.934h-11.417l-1.528-8.317-.204-.003h-7.566v42.035l.006.413.252.022 10.44.76v8.984zm-33.961-2.359h31.603v-4.433l-8.246-.599c-2.264-.151-2.453-1.46-2.453-2.789v-44.393h9.926c1.082 0 2.168.146 2.516 1.88l1.184 6.44h7.092v-15.217h-52.317v15.217h7.178l1.179-6.422c.354-1.753 1.438-1.898 2.521-1.898h9.924v44.394c0 1.307-.189 2.711-2.454 2.876l-7.649.517v4.427zM158.563 52.659c0-14.095 7.385-23.263 22.923-23.263 15.705 0 21.817 9.338 21.817 22.33 0 14.433-7.302 23.77-22.923 23.77-15.533 0-21.817-9.508-21.817-22.837zm31.329-.509c0-10.021-3.057-13.586-8.574-13.586-5.604 0-9.34 3.482-9.34 13.67 0 10.273 3.311 14.35 8.997 14.35 5.52 0 8.917-3.82 8.917-14.434zm-9.511 24.527c-14.829 0-22.997-8.53-22.997-24.018 0-15.532 8.785-24.441 24.103-24.441 14.829 0 22.998 8.35 22.998 23.509-.001 16.089-8.561 24.95-24.104 24.95zm1.105-46.101c-14.021 0-21.744 7.843-21.744 22.083 0 9.882 3.579 21.659 20.639 21.659 17.972 0 21.745-12.287 21.745-22.592 0-9.649-3.58-21.15-20.64-21.15zm-.511 37.187c-6.753 0-10.177-5.224-10.177-15.528 0-9.854 3.54-14.849 10.52-14.849 8.742 0 9.754 8.425 9.754 14.765-.001 10.505-3.304 15.612-10.097 15.612zm.342-28.019c-3.505 0-8.16 1.294-8.16 12.49 0 11.803 4.463 13.17 7.817 13.17 3.322 0 7.738-1.373 7.738-13.254.001-10.932-3.737-12.406-7.395-12.406zM240.416 74.479l-.852-4.754-.594-.087c-3.565 3.482-7.726 5.857-13.922 5.857-10.019 0-16.475-6.364-16.475-22.582 0-17.065 8.578-23.518 18.003-23.518 4.922 0 8.745 1.697 11.97 4.075v-12.905c0-.848-.34-1.441-1.104-1.697l-4.668-1.612.933-6.878h17.066v55.187c0 1.271.081 1.442 1.357 1.613l4.072.594v6.708h-15.786zm-2.378-32.687c-2.122-1.445-4.84-2.546-7.303-2.546-6.281 0-8.745 5.855-8.745 13.413 0 8.233 2.376 12.82 7.725 12.82 2.89 0 6.031-1.697 8.323-3.65v-20.037zm-12.989 34.885c-11.714 0-17.653-7.995-17.653-23.763 0-15.464 7.17-24.696 19.182-24.696 3.869 0 7.419.997 10.79 3.042v-10.695c0-.479-.139-.524-.3-.58l-5.591-1.931 1.201-8.856h19.275v56.366l.004.395.333.05 5.095.742v8.908h-17.957l-.741-4.147c-4.051 3.562-8.315 5.165-13.638 5.165zm1.528-46.101c-10.69 0-16.823 8.143-16.823 22.338 0 14.403 5.003 21.404 15.295 21.404 5.146 0 9.187-1.702 13.098-5.522l.417-.406 2.014.289.827 4.621h13.622v-4.507l-3.064-.448c-2.011-.269-2.367-1.11-2.367-2.78v-54.008h-14.858l-.662 4.899 3.753 1.297c1.203.403 1.898 1.431 1.898 2.812v15.239l-1.878-1.384c-3.562-2.623-7.141-3.844-11.272-3.844zm3.138 36.083c-5.906 0-8.905-4.711-8.905-14 0-9.274 3.62-14.593 9.926-14.593 2.495 0 5.399 1.003 7.967 2.751l.516.35v21.206l-.415.354c-1.388 1.182-5.05 3.932-9.089 3.932zm1.02-26.233c-6.582 0-7.565 7.666-7.565 12.233 0 11.642 4.928 11.642 6.545 11.642 2.131 0 4.771-1.124 7.145-3.027v-18.844c-2.029-1.263-4.278-2.004-6.125-2.004zM259.098 52.659c0-14.095 7.388-23.263 22.925-23.263 15.707 0 21.821 9.338 21.821 22.33 0 14.433-7.303 23.77-22.926 23.77-15.536 0-21.82-9.508-21.82-22.837zm31.331-.509c0-10.021-3.059-13.586-8.578-13.586-5.602 0-9.336 3.482-9.336 13.67 0 10.273 3.31 14.35 8.997 14.35 5.519 0 8.917-3.82 8.917-14.434zm-9.511 24.527c-14.832 0-22.999-8.53-22.999-24.018 0-15.532 8.786-24.441 24.104-24.441 14.831 0 22.999 8.35 22.999 23.509-.001 16.089-8.56 24.95-24.104 24.95zm1.104-46.101c-14.022 0-21.746 7.843-21.746 22.083 0 9.882 3.583 21.659 20.642 21.659 17.971 0 21.745-12.287 21.745-22.592 0-9.649-3.581-21.15-20.641-21.15zm-.51 37.187c-6.754 0-10.178-5.224-10.178-15.528 0-9.854 3.538-14.849 10.517-14.849 8.747 0 9.758 8.425 9.758 14.765-.001 10.505-3.303 15.612-10.097 15.612zm.339-28.019c-3.503 0-8.159 1.294-8.159 12.49 0 11.803 4.466 13.17 7.82 13.17 3.322 0 7.739-1.373 7.739-13.254 0-10.932-3.741-12.406-7.4-12.406z" fill="#2D2D2D"/><path d="M354.554 74.479v-6.623l6.963-.594c1.188-.171 1.358-.51 1.358-1.698v-32.262h-.339l-12.141 28.951h-13.843l-11.968-29.036h-.427v32.263c0 1.356.086 1.527 1.358 1.698l7.303.679v6.623h-25.81v-6.623l5.347-.594c1.191-.171 1.359-.427 1.359-1.698v-43.555c0-1.274-.168-1.527-1.359-1.697l-5.347-.595v-6.708h22.753l14.774 38.461h.339l15.536-38.461h22.076v6.623l-5.69.68c-1.272.17-1.358.338-1.358 1.611v43.641c0 1.104.254 1.442 1.358 1.613l5.69.679v6.623h-27.932zm29.114 1.18h-30.292v-8.885l8.04-.688.289-.06c-.019-.047-.011-.198-.011-.463v-27.21l-10.517 25.077h-15.414l-10.426-25.294v27.342l.008.479.328.05 8.325.771v8.879h-28.168v-8.857l6.396-.712.295-.053.017-.473v-43.552l-.017-.473-.332-.057-6.359-.707v-8.942h24.742l14.159 36.853 14.886-36.853h24.051v8.848l-6.729.804-.316.048-.004.394v43.641l.021.395.339.054 6.688.799v8.845zm-27.935-2.359h25.575v-4.396l-4.65-.556c-1.691-.261-2.397-1.093-2.397-2.784v-43.64c0-1.667.356-2.51 2.381-2.779l4.667-.558v-4.397h-20.103l-15.536 38.46h-1.944l-14.773-38.461h-20.764v4.473l4.301.478c2.021.29 2.406 1.271 2.406 2.87v43.555c0 1.599-.386 2.58-2.368 2.866l-4.339.481v4.388h23.452v-4.367l-6.231-.581c-2.088-.278-2.43-1.11-2.43-2.872v-33.443h2.395l11.968 29.037h12.269l12.144-28.953h2.3v33.443c0 1.56-.396 2.582-2.367 2.866l-5.953.508v4.362zM411.176 74.479l-17.066-52.469c-.34-1.021-1.017-1.189-2.038-1.444l-3.821-.933.85-6.623h25.728v6.623l-6.879.763 12.733 42.451h.682l12.311-42.451-6.79-.763.848-6.623h21.988v6.623l-3.566.933c-1.019.255-1.865.595-2.12 1.612l-15.537 52.302h-17.323zm18.201 1.18h-19.059l-17.329-53.285c-.116-.342-.131-.396-1.198-.663l-4.845-1.182 1.118-8.698h27.943v8.856l-6.521.724 11.523 38.423 11.142-38.423-6.589-.74 1.129-8.84h24.208v8.711l-4.445 1.164c-1.077.271-1.21.485-1.275.76l-15.802 53.193zm-17.345-2.359h15.584l15.286-51.458c.45-1.788 2.148-2.217 2.965-2.421l2.675-.698v-4.533h-19.771l-.565 4.403 6.991.786-12.945 44.647h-2.446l-13.392-44.647 7.235-.801v-4.389h-23.513l-.582 4.547 2.797.685c1.102.273 2.334.582 2.879 2.216l16.802 51.663zM498.821 70.829c-5.011 3.057-13.502 4.667-21.228 4.667-21.141 0-29.801-12.308-29.801-32.007 0-18.083 10.442-31.585 31.583-31.585 7.047 0 14.603 1.783 19.273 4.842v16.64l-9.338-.764-1.358-8.32c-.171-.848-.512-1.273-1.36-1.53-1.867-.594-4.753-1.018-7.554-1.018-10.785 0-17.664 7.302-17.664 21.735 0 15.027 6.54 22.329 17.069 22.329 2.802 0 6.281-.425 8.489-1.103 1.02-.256 1.273-.51 1.528-1.783l1.273-7.896h9.086v15.793zm-21.227 5.848c-20.558 0-30.979-11.167-30.979-33.188 0-20.21 12.553-32.765 32.762-32.765 7.545 0 15.179 1.929 19.919 5.036l.533.348v18.559l-11.532-.945-1.507-9.229c-.088-.427-.15-.475-.537-.593-1.854-.589-4.68-.967-7.213-.967-10.629 0-16.482 7.3-16.482 20.556 0 13.836 5.492 21.149 15.888 21.149 2.783 0 6.132-.433 8.142-1.05.415-.105.502-.157.524-.171.005-.013.079-.15.194-.718l1.426-8.843h11.268v17.632l-.564.346c-4.896 2.987-13.265 4.843-21.842 4.843zm1.782-63.593c-19.037 0-30.404 11.367-30.404 30.405 0 20.457 9.63 30.829 28.622 30.829 7.718 0 15.475-1.625 20.047-4.166v-13.936h-6.901l-1.115 6.906c-.344 1.731-.905 2.359-2.401 2.737-2.188.673-5.74 1.138-8.778 1.138-11.769 0-18.247-8.35-18.247-23.508 0-14.562 6.867-22.915 18.842-22.915 2.798 0 5.829.413 7.911 1.074 1.226.368 1.896 1.116 2.158 2.421l1.22 7.451 7.143.585v-14.708c-4.368-2.632-11.375-4.313-18.097-4.313z" fill="#AF2F2F"/><g fill="#2D2D2D"><path d="M12.83 5.701h8.781v-5.701h-8.781c-2.433 0-4.801.683-6.849 1.979l3.046 4.815c1.136-.715 2.448-1.093 3.803-1.093"/><path d="M5.704 12.827c0-1.042.216-2.042.646-2.979l-5.178-2.389c-.778 1.692-1.172 3.498-1.172 5.368v10.095h5.704v-10.095zM0 28.68h5.704v14.37h-5.704zM76.782 6.979c1.718-1.091 3.432-2.121 5.13-3.079-.97-1-2.104-1.842-3.336-2.478-1.803-.93-3.837-1.422-5.875-1.422h-5.048v5.701h5.048c1.494 0 2.904.449 4.081 1.278"/><path d="M0 48.81h5.704v14.397h-5.704zM27.369 0h14.371v5.701h-14.371zM47.497 0h14.396v5.701h-14.396zM53.855 79.824h14.367v5.705h-14.367zM79.827 32.387h5.701v14.398h-5.701zM79.827 52.542h5.701v14.372h-5.701zM5.704 72.699v-3.738h-5.704v3.738c0 4.668 2.54 8.976 6.631 11.236l2.758-4.99c-2.274-1.259-3.685-3.65-3.685-6.246M79.827 22.847v3.778h5.701v-8.467c-1.875 1.399-3.772 2.96-5.701 4.689"/><path d="M79.827 72.699c0 3.575-2.667 6.614-6.203 7.07l.726 5.655c3.07-.396 5.897-1.894 7.956-4.22 2.078-2.347 3.223-5.366 3.223-8.506v-.028h-5.701v.029zM13.542 79.824h14.398v5.705h-14.398zM33.696 79.824h14.399v5.705h-14.399z"/></g><path fill="#AF2F2F" d="M13.059 45.396l26.744 26.744s26.745-51.453 55.662-62.994l-1.084-8.144c-15.749 6.244-39.648 22.673-57.294 47.787l-18.6-10.996-5.428 7.603z"/></svg>
\ No newline at end of file
<svg xmlns="http://www.w3.org/2000/svg" width="500" height="85.529"><path d="M115.936 74.48v-6.71l8.744-.593c1.188-.086 1.358-.425 1.358-1.698V22.265h-8.743c-.935 0-1.19.083-1.36.933l-1.357 7.387h-9.34V13.01h54.678v17.576h-9.255l-1.356-7.388c-.17-.85-.425-.933-1.358-.933H139.2V65.48c0 1.187.085 1.526 1.36 1.61l9.34.68v6.71h-33.964zm35.14 1.18h-36.32v-8.99L124.6 66l.244-.025.015-.495V23.444h-7.564l-.188.003-1.55 8.317H104.06V11.83h57.034v19.935h-11.417l-1.528-8.317-.205-.003h-7.566V65.48l.005.413.252.022 10.44.76v8.984zm-33.96-2.36h31.602v-4.433l-8.246-.6c-2.264-.15-2.453-1.46-2.453-2.788V21.085h9.925c1.082 0 2.168.146 2.516 1.88l1.185 6.44h7.092V14.19H106.42v15.216h7.178l1.18-6.422c.353-1.753 1.437-1.898 2.52-1.898h9.924V65.48c0 1.307-.19 2.71-2.454 2.876l-7.65.517V73.3zm41.447-20.64c0-14.096 7.385-23.264 22.923-23.264 15.705 0 21.817 9.338 21.817 22.33 0 14.433-7.302 23.77-22.923 23.77-15.533 0-21.817-9.508-21.817-22.837zm31.33-.51c0-10.02-3.058-13.586-8.575-13.586-5.604 0-9.34 3.482-9.34 13.67 0 10.273 3.31 14.35 8.997 14.35 5.52 0 8.917-3.82 8.917-14.434zm-9.512 24.527c-14.828 0-22.996-8.53-22.996-24.018 0-15.533 8.785-24.442 24.103-24.442 14.83 0 22.998 8.35 22.998 23.51 0 16.088-8.56 24.95-24.104 24.95zm1.106-46.1c-14.02 0-21.744 7.842-21.744 22.082 0 9.88 3.58 21.658 20.64 21.658 17.97 0 21.744-12.287 21.744-22.592 0-9.65-3.58-21.15-20.64-21.15zm-.51 37.186c-6.754 0-10.178-5.224-10.178-15.528 0-9.854 3.54-14.85 10.52-14.85 8.742 0 9.754 8.426 9.754 14.766 0 10.506-3.304 15.613-10.097 15.613zm.34-28.02c-3.504 0-8.16 1.295-8.16 12.49 0 11.804 4.464 13.17 7.818 13.17 3.322 0 7.738-1.372 7.738-13.253 0-10.932-3.737-12.406-7.395-12.406zm59.1 34.736l-.852-4.755-.594-.087c-3.565 3.482-7.726 5.857-13.922 5.857-10.02 0-16.475-6.364-16.475-22.582 0-17.065 8.578-23.518 18.003-23.518 4.922 0 8.745 1.697 11.97 4.075V20.565c0-.848-.34-1.44-1.104-1.697l-4.668-1.612.933-6.878h17.066v55.187c0 1.27.08 1.442 1.357 1.613l4.072.594v6.708h-15.786zm-2.378-32.688c-2.122-1.445-4.84-2.546-7.303-2.546-6.28 0-8.745 5.855-8.745 13.413 0 8.232 2.376 12.82 7.725 12.82 2.89 0 6.03-1.698 8.323-3.65V41.79zm-12.99 34.885c-11.713 0-17.652-7.995-17.652-23.763 0-15.464 7.17-24.696 19.182-24.696 3.87 0 7.42.997 10.79 3.042V20.565c0-.48-.14-.524-.3-.58l-5.59-1.93 1.2-8.857h19.275v56.366l.004.395.333.05 5.095.74v8.91h-17.957l-.74-4.148c-4.052 3.562-8.316 5.165-13.64 5.165zm1.53-46.1c-10.69 0-16.824 8.142-16.824 22.337 0 14.403 5.003 21.404 15.295 21.404 5.145 0 9.186-1.702 13.097-5.522l.417-.406 2.014.29.827 4.62h13.622v-4.507l-3.064-.448c-2.01-.27-2.367-1.11-2.367-2.78V11.557h-14.858l-.662 4.9 3.753 1.296c1.202.403 1.897 1.43 1.897 2.812v15.24l-1.878-1.385c-3.563-2.623-7.142-3.844-11.273-3.844zm3.137 36.082c-5.906 0-8.905-4.712-8.905-14 0-9.275 3.62-14.594 9.926-14.594 2.495 0 5.4 1.003 7.967 2.75l.516.35v21.207l-.416.354c-1.388 1.182-5.05 3.932-9.09 3.932zm1.02-26.234c-6.582 0-7.565 7.666-7.565 12.233 0 11.64 4.928 11.64 6.545 11.64 2.13 0 4.77-1.123 7.145-3.026V42.43c-2.03-1.263-4.278-2.004-6.125-2.004zm28.363 12.233c0-14.096 7.388-23.264 22.925-23.264 15.707 0 21.82 9.338 21.82 22.33 0 14.433-7.302 23.77-22.925 23.77-15.536 0-21.82-9.508-21.82-22.837zm31.33-.51c0-10.02-3.058-13.586-8.577-13.586-5.6 0-9.335 3.482-9.335 13.67 0 10.273 3.31 14.35 8.997 14.35 5.52 0 8.917-3.82 8.917-14.434zm-9.51 24.527c-14.832 0-23-8.53-23-24.018 0-15.533 8.787-24.442 24.105-24.442 14.83 0 23 8.35 23 23.51-.002 16.088-8.56 24.95-24.105 24.95zm1.104-46.1c-14.022 0-21.746 7.842-21.746 22.082 0 9.88 3.583 21.658 20.642 21.658 17.97 0 21.745-12.287 21.745-22.592 0-9.65-3.58-21.15-20.64-21.15zm-.51 37.186c-6.754 0-10.178-5.224-10.178-15.528 0-9.854 3.538-14.85 10.517-14.85 8.748 0 9.76 8.426 9.76 14.766-.002 10.506-3.304 15.613-10.098 15.613zm.34-28.02c-3.504 0-8.16 1.295-8.16 12.49 0 11.804 4.466 13.17 7.82 13.17 3.322 0 7.74-1.372 7.74-13.253 0-10.932-3.742-12.406-7.4-12.406z" fill="#2D2D2D"/><path d="M354.554 74.48v-6.624l6.963-.594c1.188-.17 1.358-.51 1.358-1.698V33.302h-.34l-12.14 28.95h-13.843l-11.968-29.035h-.427V65.48c0 1.356.086 1.527 1.358 1.698l7.303.68v6.622h-25.81v-6.623l5.347-.594c1.19-.17 1.36-.427 1.36-1.698V22.01c0-1.274-.17-1.527-1.36-1.697l-5.347-.595V13.01h22.753l14.775 38.46h.34l15.535-38.46h22.076v6.623l-5.69.68c-1.272.17-1.358.338-1.358 1.61v43.642c0 1.104.254 1.442 1.358 1.613l5.69.68v6.622h-27.932zm29.114 1.18h-30.292v-8.886l8.04-.688.29-.06c-.02-.047-.012-.198-.012-.463v-27.21L351.177 63.43h-15.414l-10.426-25.294v27.342l.008.48.328.05 8.325.77v8.88H305.83V66.8l6.396-.712.295-.053.018-.473V22.01l-.017-.473-.33-.057-6.36-.707V11.83h24.742l14.16 36.854 14.885-36.853h24.05v8.85l-6.728.803-.317.048-.004.395v43.64l.02.396.34.055 6.687.8v8.844zm-27.935-2.36h25.575v-4.396l-4.65-.556c-1.69-.26-2.397-1.093-2.397-2.784v-43.64c0-1.667.357-2.51 2.382-2.78l4.667-.557V14.19h-20.104L345.67 52.65h-1.944l-14.773-38.46H308.19v4.472l4.3.478c2.02.29 2.406 1.27 2.406 2.87v43.555c0 1.6-.386 2.58-2.368 2.866l-4.34.482V73.3h23.453v-4.367l-6.23-.58c-2.088-.28-2.43-1.11-2.43-2.873V32.037h2.395l11.968 29.037h12.27l12.143-28.953h2.3v33.444c0 1.56-.396 2.582-2.367 2.866l-5.954.508V73.3zm55.443 1.18L394.11 22.01c-.34-1.02-1.017-1.19-2.038-1.444l-3.82-.933.85-6.623h25.727v6.623l-6.88.763 12.733 42.45h.682l12.31-42.45-6.79-.763.85-6.623h21.987v6.623l-3.566.933c-1.02.255-1.865.595-2.12 1.612L428.5 74.48h-17.324zm18.2 1.18H410.32l-17.33-53.286c-.115-.342-.13-.396-1.197-.663l-4.844-1.18 1.118-8.7h27.943v8.857l-6.52.724 11.522 38.424 11.14-38.423-6.588-.74 1.13-8.84h24.207v8.712l-4.446 1.164c-1.077.27-1.21.485-1.275.76L429.376 75.66zm-17.344-2.36h15.584l15.286-51.458c.45-1.788 2.148-2.217 2.965-2.42l2.675-.7V14.19h-19.77l-.566 4.403 6.99.786-12.944 44.646h-2.446L406.414 19.38l7.235-.802v-4.39h-23.514l-.582 4.548 2.797.685c1.103.274 2.335.583 2.88 2.217L412.032 73.3zm86.79-2.47c-5.012 3.056-13.503 4.666-21.23 4.666-21.14 0-29.8-12.308-29.8-32.007 0-18.084 10.442-31.586 31.583-31.586 7.047 0 14.603 1.783 19.273 4.842v16.64l-9.338-.764-1.358-8.32c-.17-.848-.512-1.273-1.36-1.53-1.867-.594-4.753-1.018-7.554-1.018-10.785 0-17.664 7.302-17.664 21.735 0 15.026 6.54 22.328 17.07 22.328 2.8 0 6.28-.425 8.488-1.103 1.02-.256 1.273-.51 1.528-1.783l1.273-7.896h9.086V70.83zm-21.228 5.847c-20.558 0-30.98-11.167-30.98-33.188 0-20.21 12.554-32.766 32.763-32.766 7.545 0 15.18 1.93 19.92 5.036l.532.348v18.56l-11.533-.946-1.507-9.23c-.088-.426-.15-.474-.537-.592-1.854-.59-4.68-.967-7.213-.967-10.63 0-16.482 7.3-16.482 20.556 0 13.835 5.492 21.148 15.888 21.148 2.783 0 6.132-.433 8.142-1.05.415-.105.502-.157.524-.17.005-.014.08-.15.194-.72l1.426-8.842H500v17.632l-.564.346c-4.896 2.987-13.265 4.843-21.842 4.843zm1.782-63.593c-19.037 0-30.404 11.367-30.404 30.405 0 20.456 9.63 30.828 28.622 30.828 7.718 0 15.475-1.625 20.047-4.166V56.216h-6.9l-1.115 6.906c-.344 1.73-.905 2.36-2.4 2.737-2.19.672-5.74 1.137-8.78 1.137-11.768 0-18.246-8.35-18.246-23.508 0-14.563 6.866-22.916 18.84-22.916 2.8 0 5.83.413 7.912 1.074 1.226.368 1.896 1.116 2.158 2.42l1.22 7.452 7.143.585V17.397c-4.368-2.632-11.375-4.313-18.097-4.313z" fill="#AF2F2F"/><g fill="#2D2D2D"><path d="M12.83 5.7h8.78V0h-8.78c-2.433 0-4.8.683-6.85 1.98l3.047 4.814C10.163 6.08 11.475 5.7 12.83 5.7M5.704 12.827c0-1.042.216-2.042.646-2.98L1.172 7.46C.394 9.15 0 10.956 0 12.826v10.095h5.704V12.827zM0 28.68h5.704v14.37H0zm76.782-21.7c1.718-1.092 3.432-2.122 5.13-3.08-.97-1-2.104-1.842-3.336-2.478C76.773.492 74.74 0 72.7 0h-5.047v5.7H72.7c1.495 0 2.905.45 4.082 1.28M0 48.81h5.704v14.397H0zM27.37 0h14.37v5.7H27.37zm20.127 0h14.396v5.7H47.497zm6.358 79.824h14.367v5.705H53.855zm25.972-47.437h5.7v14.398h-5.7zm0 20.155h5.7v14.372h-5.7zM5.704 72.7v-3.74H0v3.74c0 4.667 2.54 8.975 6.63 11.235l2.76-4.99c-2.275-1.26-3.686-3.65-3.686-6.246m74.123-49.853v3.778h5.7v-8.467c-1.874 1.4-3.77 2.96-5.7 4.69"/><path d="M79.827 72.7c0 3.574-2.667 6.613-6.203 7.07l.726 5.654c3.07-.396 5.897-1.894 7.956-4.22 2.078-2.347 3.223-5.366 3.223-8.506v-.028h-5.702v.03zm-66.285 7.124H27.94v5.705H13.542zm20.154 0h14.4v5.705h-14.4z"/></g><path fill="#AF2F2F" d="M13.06 45.396L39.802 72.14S66.548 20.687 95.465 9.146L94.38 1.002C78.633 7.246 54.734 23.675 37.088 48.79l-18.6-10.997-5.428 7.603z"/></svg>
\ No newline at end of file
......@@ -122,6 +122,8 @@ header nav a:not(:last-child) {
list-style: none;
margin: 0;
padding: 0;
-webkit-columns: 1;
-moz-columns: 1;
columns: 1;
font-size: 17px;
}
......@@ -182,6 +184,7 @@ header nav a:not(:last-child) {
.collapsed {
overflow: hidden;
max-height: 0;
-webkit-transition: max-height 0.7s ease-out;
transition: max-height 0.7s ease-out;
}
......@@ -191,6 +194,7 @@ header nav a:not(:last-child) {
#news-expander:checked ~ .collapsed {
max-height: 999px;
-webkit-transition: max-height 0.7s ease-in;
transition: max-height 0.7s ease-in;
}
......@@ -318,6 +322,9 @@ a.zocial {
text-align: center;
text-decoration: none;
text-shadow: 0 1px 0 rgba(0, 0, 0, 0.5);
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
position: relative;
border-radius: .3em;
......@@ -325,6 +332,8 @@ a.zocial {
@media (max-width: 480px) {
body .applist {
-webkit-columns: auto !important;
-moz-columns: auto !important;
columns: auto !important;
}
......@@ -356,12 +365,16 @@ a.zocial {
@media (min-width: 480px) {
.applist {
-webkit-columns: 2;
-moz-columns: 2;
columns: 2;
}
}
@media (min-width: 640px) and (max-width: 770px) {
.applist {
-webkit-columns: 3;
-moz-columns: 3;
columns: 3;
}
}
......@@ -370,6 +383,8 @@ a.zocial {
@media (min-width: 771px) {
.js,
.ctojs {
-webkit-columns: 4;
-moz-columns: 4;
columns: 4;
}
}
......
/*global $ */
(function () {
'use strict';
var date = new Date();
if (date.getDate() === 1 && date.getMonth() === 3) {
['', '-webkit-', '-moz-'].forEach(function (prefix) {
document.body.style[prefix + 'filter'] = 'blur(1px)';
});
}
$.fn.persistantPopover = function () {
var popoverTimeout;
function delay() {
popoverTimeout = setTimeout(function () {
$('.popover').hide();
}, 100);
}
return this.each(function () {
var $this = $(this);
$this.popover({
trigger: 'manual',
placement: 'right',
animation: false,
html: true,
title: this.firstChild.textContent + '<a href="' + $this.data('source') + '">Website</a>'
});
})
.mouseenter(function () {
clearTimeout(popoverTimeout);
$('.popover').remove();
$(this).popover('show');
})
.mouseleave(function () {
delay();
$('.popover').mouseenter(function () {
clearTimeout(popoverTimeout);
}).mouseleave(function () {
delay();
});
});
};
function redirect() {
if (location.hostname === 'addyosmani.github.io') {
location.href = location.href.replace('addyosmani.github.io/todomvc', 'todomvc.com');
}
}
var Quotes = {};
Quotes.build = function (quotes, template) {
var quoteContainer = document.createElement('q');
var quoteElemCount = 0;
var quoteCount = quotes.length;
var createQuoteElems = function () {
var quote = quotes[quoteElemCount];
var el = $(template).hide();
el.children('p').text(quote.quote);
el.find('a').text(quote.person.name).attr('href', quote.person.link);
el.find('img').attr('src', quote.person.gravatar);
quoteContainer.appendChild(el[0]);
if (quoteCount > ++quoteElemCount) {
createQuoteElems();
}
return quoteContainer.innerHTML;
};
return createQuoteElems();
};
Quotes.random = function (quotes) {
var quoteCount = quotes.length;
var randomQuotes = [];
var randomQuote = function () {
var randomQuoteIndex = Math.floor(Math.random() * quoteCount);
if ($.inArray(randomQuoteIndex, randomQuotes) > -1) {
return randomQuote();
}
if (randomQuotes.length === quoteCount - 1) {
randomQuotes = [];
}
randomQuotes.push(randomQuoteIndex);
return randomQuoteIndex;
};
return randomQuote;
};
Quotes.animate = function (container, animSpeed) {
var fader = function (fadeOut, fadeIn) {
var fadeOutCallback = function () {
fadeIn.fadeIn(500, fadeInCallback);
};
var fadeInCallback = function () {
window.setTimeout(swap, animSpeed);
};
fadeOut.fadeOut(500, fadeOutCallback);
};
var quotes = container.children();
var selectRandomQuoteIndex = Quotes.random(quotes);
var quoteElems = {};
var activeQuoteIndex = selectRandomQuoteIndex();
var prevQuoteElem = $(quotes[activeQuoteIndex]);
var swap = function () {
if (!quoteElems[activeQuoteIndex]) {
quoteElems[activeQuoteIndex] = $(quotes[activeQuoteIndex]);
}
var activeQuoteElem = quoteElems[activeQuoteIndex];
fader(prevQuoteElem, activeQuoteElem);
activeQuoteIndex = selectRandomQuoteIndex();
prevQuoteElem = activeQuoteElem;
};
return swap();
};
Quotes.init = function (quotes) {
var container = $(this);
var template = $(this).html();
var quotesHTML = Quotes.build(quotes, template);
container.html(quotesHTML);
Quotes.animate(container, 25000);
};
$.fn.quote = function (quotes) {
return this.each(function () {
Quotes.init.call(this, quotes);
});
};
// Redirect if not on main site.
redirect();
// Apps popover
$('.applist a').persistantPopover();
// Quotes
$('.quotes').quote([{
quote: 'TodoMVC is a godsend for helping developers find what well-developed frameworks match their mental model of application architecture.',
person: {
name: 'Paul Irish',
gravatar: 'http://gravatar.com/avatar/ffe68d6f71b225f7661d33f2a8908281?s=40',
link: 'https://github.com/paulirish'
}
}, {
quote: 'Modern JavaScript developers realise an MVC framework is essential for managing the complexity of their apps. TodoMVC is a fabulous community contribution that helps developers compare frameworks on the basis of actual project code, not just claims and anecdotes.',
person: {
name: 'Michael Mahemoff',
gravatar: 'http://gravatar.com/avatar/cabf735ce7b8b4471ef46ea54f71832d?s=40',
link: 'https://github.com/mahemoff'
}
}, {
quote: 'TodoMVC is an immensely valuable attempt at a difficult problem - providing a structured way of comparing JS libraries and frameworks. TodoMVC is a lone data point in a sea of conjecture and opinion.',
person: {
name: 'Justin Meyer',
gravatar: 'http://gravatar.com/avatar/70ee60f32937b52758869488d5753259?s=40',
link: 'https://github.com/justinbmeyer'
}
}, {
quote: 'It can be hard to make the leap from hacking together code that works to writing code that`s organized, maintainable, reusable, and a joy to work on. The TodoMVC project does a great job of introducing developers to different approaches to code organization, and to the various libraries that can help them along the way. If you`re trying to get your bearings in the world of client-side application development, the TodoMVC project is a great place to get started.',
person: {
name: 'Rebecca Murphey',
gravatar: 'http://gravatar.com/avatar/0177cdce6af15e10db15b6bf5dc4e0b0?s=40',
link: 'https://github.com/rmurphey'
}
}]);
}());
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
module.exports = function (grunt) {
var bower = require('bower');
var wrench = require('wrench');
grunt.registerTask('todomvc-common', function () {
// For some reason, I began trusting Batman to be my test directory for
// `todomvc-common`. If you work on changes in ...
//
// labs/architecture-examples/batman/bower_components/todomvc-common
//
// ... or even just drop the latest `todomvc-common` there, this task will
// find all of the other `bower_components/todomvc-common` directories, and
// update them with what Batman has.
//
// I also added Bower up top for in the future, as that might come in handy
// to correctly fetch and install the latest todomvc-common, without relying
// on this weird Batman system.
var sourceTodoMvcCommon = 'labs/architecture-examples/batman/bower_components/todomvc-common';
var sourceIdentifierRegex = /batman/;
grunt.file.setBase('../');
var directories = grunt.file.expand({
filter: function (src) {
return grunt.file.isDir(src) && src.substr(-14) === 'todomvc-common' && !src.match(sourceIdentifierRegex);
}
}, ['*/**']);
directories.forEach(function (destPath) {
wrench.copyDirSyncRecursive(
sourceTodoMvcCommon,
destPath,
{
forceDelete: true,
preserveFiles: false
},
function () {
console.log(arguments);
});
});
});
};
{
"name": "TodoMVC-Testing-Grounds",
"private": true,
"version": "0.0.0",
"devDependencies": {
"grunt": "~0.4.1",
"bower": "~0.9.2",
"wrench": "~1.5.1"
}
}
{
"name": "todomvc-template",
"version": "0.0.0",
"dependencies": {
"todomvc-common": "~0.1.4"
}
}
html,
body {
margin: 0;
padding: 0;
}
button {
margin: 0;
padding: 0;
border: 0;
background: none;
font-size: 100%;
vertical-align: baseline;
font-family: inherit;
color: inherit;
-webkit-appearance: none;
-ms-appearance: none;
-o-appearance: none;
appearance: none;
}
body {
font: 14px 'Helvetica Neue', Helvetica, Arial, sans-serif;
line-height: 1.4em;
background: #eaeaea url('bg.png');
color: #4d4d4d;
width: 550px;
margin: 0 auto;
-webkit-font-smoothing: antialiased;
-moz-font-smoothing: antialiased;
-ms-font-smoothing: antialiased;
-o-font-smoothing: antialiased;
font-smoothing: antialiased;
}
button,
input[type="checkbox"] {
outline: none;
}
#todoapp {
background: #fff;
background: rgba(255, 255, 255, 0.9);
margin: 130px 0 40px 0;
border: 1px solid #ccc;
position: relative;
border-top-left-radius: 2px;
border-top-right-radius: 2px;
box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.2),
0 25px 50px 0 rgba(0, 0, 0, 0.15);
}
#todoapp:before {
content: '';
border-left: 1px solid #f5d6d6;
border-right: 1px solid #f5d6d6;
width: 2px;
position: absolute;
top: 0;
left: 40px;
height: 100%;
}
#todoapp input::-webkit-input-placeholder {
font-style: italic;
}
#todoapp input::-moz-placeholder {
font-style: italic;
color: #a9a9a9;
}
#todoapp h1 {
position: absolute;
top: -120px;
width: 100%;
font-size: 70px;
font-weight: bold;
text-align: center;
color: #b3b3b3;
color: rgba(255, 255, 255, 0.3);
text-shadow: -1px -1px rgba(0, 0, 0, 0.2);
-webkit-text-rendering: optimizeLegibility;
-moz-text-rendering: optimizeLegibility;
-ms-text-rendering: optimizeLegibility;
-o-text-rendering: optimizeLegibility;
text-rendering: optimizeLegibility;
}
#header {
padding-top: 15px;
border-radius: inherit;
}
#header:before {
content: '';
position: absolute;
top: 0;
right: 0;
left: 0;
height: 15px;
z-index: 2;
border-bottom: 1px solid #6c615c;
background: #8d7d77;
background: -webkit-gradient(linear, left top, left bottom, from(rgba(132, 110, 100, 0.8)),to(rgba(101, 84, 76, 0.8)));
background: -webkit-linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8));
background: linear-gradient(top, rgba(132, 110, 100, 0.8), rgba(101, 84, 76, 0.8));
filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#9d8b83', EndColorStr='#847670');
border-top-left-radius: 1px;
border-top-right-radius: 1px;
}
#new-todo,
.edit {
position: relative;
margin: 0;
width: 100%;
font-size: 24px;
font-family: inherit;
line-height: 1.4em;
border: 0;
outline: none;
color: inherit;
padding: 6px;
border: 1px solid #999;
box-shadow: inset 0 -1px 5px 0 rgba(0, 0, 0, 0.2);
-moz-box-sizing: border-box;
-ms-box-sizing: border-box;
-o-box-sizing: border-box;
box-sizing: border-box;
-webkit-font-smoothing: antialiased;
-moz-font-smoothing: antialiased;
-ms-font-smoothing: antialiased;
-o-font-smoothing: antialiased;
font-smoothing: antialiased;
}
#new-todo {
padding: 16px 16px 16px 60px;
border: none;
background: rgba(0, 0, 0, 0.02);
z-index: 2;
box-shadow: none;
}
#main {
position: relative;
z-index: 2;
border-top: 1px dotted #adadad;
}
label[for='toggle-all'] {
display: none;
}
#toggle-all {
position: absolute;
top: -42px;
left: -4px;
width: 40px;
text-align: center;
/* Mobile Safari */
border: none;
}
#toggle-all:before {
content: '»';
font-size: 28px;
color: #d9d9d9;
padding: 0 25px 7px;
}
#toggle-all:checked:before {
color: #737373;
}
#todo-list {
margin: 0;
padding: 0;
list-style: none;
}
#todo-list li {
position: relative;
font-size: 24px;
border-bottom: 1px dotted #ccc;
}
#todo-list li:last-child {
border-bottom: none;
}
#todo-list li.editing {
border-bottom: none;
padding: 0;
}
#todo-list li.editing .edit {
display: block;
width: 506px;
padding: 13px 17px 12px 17px;
margin: 0 0 0 43px;
}
#todo-list li.editing .view {
display: none;
}
#todo-list li .toggle {
text-align: center;
width: 40px;
/* auto, since non-WebKit browsers doesn't support input styling */
height: auto;
position: absolute;
top: 0;
bottom: 0;
margin: auto 0;
/* Mobile Safari */
border: none;
-webkit-appearance: none;
-ms-appearance: none;
-o-appearance: none;
appearance: none;
}
#todo-list li .toggle:after {
content: '✔';
/* 40 + a couple of pixels visual adjustment */
line-height: 43px;
font-size: 20px;
color: #d9d9d9;
text-shadow: 0 -1px 0 #bfbfbf;
}
#todo-list li .toggle:checked:after {
color: #85ada7;
text-shadow: 0 1px 0 #669991;
bottom: 1px;
position: relative;
}
#todo-list li label {
white-space: pre;
word-break: break-word;
padding: 15px 60px 15px 15px;
margin-left: 45px;
display: block;
line-height: 1.2;
-webkit-transition: color 0.4s;
transition: color 0.4s;
}
#todo-list li.completed label {
color: #a9a9a9;
text-decoration: line-through;
}
#todo-list li .destroy {
display: none;
position: absolute;
top: 0;
right: 10px;
bottom: 0;
width: 40px;
height: 40px;
margin: auto 0;
font-size: 22px;
color: #a88a8a;
-webkit-transition: all 0.2s;
transition: all 0.2s;
}
#todo-list li .destroy:hover {
text-shadow: 0 0 1px #000,
0 0 10px rgba(199, 107, 107, 0.8);
-webkit-transform: scale(1.3);
-ms-transform: scale(1.3);
transform: scale(1.3);
}
#todo-list li .destroy:after {
content: '✖';
}
#todo-list li:hover .destroy {
display: block;
}
#todo-list li .edit {
display: none;
}
#todo-list li.editing:last-child {
margin-bottom: -1px;
}
#footer {
color: #777;
padding: 0 15px;
position: absolute;
right: 0;
bottom: -31px;
left: 0;
height: 20px;
z-index: 1;
text-align: center;
}
#footer:before {
content: '';
position: absolute;
right: 0;
bottom: 31px;
left: 0;
height: 50px;
z-index: -1;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.3),
0 6px 0 -3px rgba(255, 255, 255, 0.8),
0 7px 1px -3px rgba(0, 0, 0, 0.3),
0 43px 0 -6px rgba(255, 255, 255, 0.8),
0 44px 2px -6px rgba(0, 0, 0, 0.2);
}
#todo-count {
float: left;
text-align: left;
}
#filters {
margin: 0;
padding: 0;
list-style: none;
position: absolute;
right: 0;
left: 0;
}
#filters li {
display: inline;
}
#filters li a {
color: #83756f;
margin: 2px;
text-decoration: none;
}
#filters li a.selected {
font-weight: bold;
}
#clear-completed {
float: right;
position: relative;
line-height: 20px;
text-decoration: none;
background: rgba(0, 0, 0, 0.1);
font-size: 11px;
padding: 0 10px;
border-radius: 3px;
box-shadow: 0 -1px 0 0 rgba(0, 0, 0, 0.2);
}
#clear-completed:hover {
background: rgba(0, 0, 0, 0.15);
box-shadow: 0 -1px 0 0 rgba(0, 0, 0, 0.3);
}
#info {
margin: 65px auto 0;
color: #a6a6a6;
font-size: 12px;
text-shadow: 0 1px 0 rgba(255, 255, 255, 0.7);
text-align: center;
}
#info a {
color: inherit;
}
/*
Hack to remove background from Mobile Safari.
Can't use it globally since it destroys checkboxes in Firefox and Opera
*/
@media screen and (-webkit-min-device-pixel-ratio:0) {
#toggle-all,
#todo-list li .toggle {
background: none;
}
#todo-list li .toggle {
height: 40px;
}
#toggle-all {
top: -56px;
left: -15px;
width: 65px;
height: 41px;
-webkit-transform: rotate(90deg);
-ms-transform: rotate(90deg);
transform: rotate(90deg);
-webkit-appearance: none;
appearance: none;
}
}
.hidden {
display: none;
}
hr {
margin: 20px 0;
border: 0;
border-top: 1px dashed #C5C5C5;
border-bottom: 1px dashed #F7F7F7;
}
.learn a {
font-weight: normal;
text-decoration: none;
color: #b83f45;
}
.learn a:hover {
text-decoration: underline;
color: #787e7e;
}
.learn h3,
.learn h4,
.learn h5 {
margin: 10px 0;
font-weight: 500;
line-height: 1.2;
color: #000;
}
.learn h3 {
font-size: 24px;
}
.learn h4 {
font-size: 18px;
}
.learn h5 {
margin-bottom: 0;
font-size: 14px;
}
.learn ul {
padding: 0;
margin: 0 0 30px 25px;
}
.learn li {
line-height: 20px;
}
.learn p {
font-size: 15px;
font-weight: 300;
line-height: 1.3;
margin-top: 0;
margin-bottom: 0;
}
.quote {
border: none;
margin: 20px 0 60px 0;
}
.quote p {
font-style: italic;
}
.quote p:before {
content: '“';
font-size: 50px;
opacity: .15;
position: absolute;
top: -20px;
left: 3px;
}
.quote p:after {
content: '”';
font-size: 50px;
opacity: .15;
position: absolute;
bottom: -42px;
right: 3px;
}
.quote footer {
position: absolute;
bottom: -40px;
right: 0;
}
.quote footer img {
border-radius: 3px;
}
.quote footer a {
margin-left: 5px;
vertical-align: middle;
}
.speech-bubble {
position: relative;
padding: 10px;
background: rgba(0, 0, 0, .04);
border-radius: 5px;
}
.speech-bubble:after {
content: '';
position: absolute;
top: 100%;
right: 30px;
border: 13px solid transparent;
border-top-color: rgba(0, 0, 0, .04);
}
.learn-bar > .learn {
position: absolute;
width: 272px;
top: 8px;
left: -300px;
padding: 10px;
border-radius: 5px;
background-color: rgba(255, 255, 255, .6);
-webkit-transition-property: left;
transition-property: left;
-webkit-transition-duration: 500ms;
transition-duration: 500ms;
}
@media (min-width: 899px) {
.learn-bar {
width: auto;
margin: 0 0 0 300px;
}
.learn-bar > .learn {
left: 8px;
}
.learn-bar #todoapp {
width: 550px;
margin: 130px auto 40px auto;
}
}
(function () {
'use strict';
// Underscore's Template Module
// Courtesy of underscorejs.org
var _ = (function (_) {
_.defaults = function (object) {
if (!object) {
return object;
}
for (var argsIndex = 1, argsLength = arguments.length; argsIndex < argsLength; argsIndex++) {
var iterable = arguments[argsIndex];
if (iterable) {
for (var key in iterable) {
if (object[key] == null) {
object[key] = iterable[key];
}
}
}
}
return object;
}
// By default, Underscore uses ERB-style template delimiters, change the
// following template settings to use alternative delimiters.
_.templateSettings = {
evaluate : /<%([\s\S]+?)%>/g,
interpolate : /<%=([\s\S]+?)%>/g,
escape : /<%-([\s\S]+?)%>/g
};
// When customizing `templateSettings`, if you don't want to define an
// interpolation, evaluation or escaping regex, we need one that is
// guaranteed not to match.
var noMatch = /(.)^/;
// Certain characters need to be escaped so that they can be put into a
// string literal.
var escapes = {
"'": "'",
'\\': '\\',
'\r': 'r',
'\n': 'n',
'\t': 't',
'\u2028': 'u2028',
'\u2029': 'u2029'
};
var escaper = /\\|'|\r|\n|\t|\u2028|\u2029/g;
// JavaScript micro-templating, similar to John Resig's implementation.
// Underscore templating handles arbitrary delimiters, preserves whitespace,
// and correctly escapes quotes within interpolated code.
_.template = function(text, data, settings) {
var render;
settings = _.defaults({}, settings, _.templateSettings);
// Combine delimiters into one regular expression via alternation.
var matcher = new RegExp([
(settings.escape || noMatch).source,
(settings.interpolate || noMatch).source,
(settings.evaluate || noMatch).source
].join('|') + '|$', 'g');
// Compile the template source, escaping string literals appropriately.
var index = 0;
var source = "__p+='";
text.replace(matcher, function(match, escape, interpolate, evaluate, offset) {
source += text.slice(index, offset)
.replace(escaper, function(match) { return '\\' + escapes[match]; });
if (escape) {
source += "'+\n((__t=(" + escape + "))==null?'':_.escape(__t))+\n'";
}
if (interpolate) {
source += "'+\n((__t=(" + interpolate + "))==null?'':__t)+\n'";
}
if (evaluate) {
source += "';\n" + evaluate + "\n__p+='";
}
index = offset + match.length;
return match;
});
source += "';\n";
// If a variable is not specified, place data values in local scope.
if (!settings.variable) source = 'with(obj||{}){\n' + source + '}\n';
source = "var __t,__p='',__j=Array.prototype.join," +
"print=function(){__p+=__j.call(arguments,'');};\n" +
source + "return __p;\n";
try {
render = new Function(settings.variable || 'obj', '_', source);
} catch (e) {
e.source = source;
throw e;
}
if (data) return render(data, _);
var template = function(data) {
return render.call(this, data, _);
};
// Provide the compiled function source as a convenience for precompilation.
template.source = 'function(' + (settings.variable || 'obj') + '){\n' + source + '}';
return template;
};
return _;
})({});
if (location.hostname === 'todomvc.com') {
window._gaq = [['_setAccount','UA-31081062-1'],['_trackPageview']];(function(d,t){var g=d.createElement(t),s=d.getElementsByTagName(t)[0];g.src='//www.google-analytics.com/ga.js';s.parentNode.insertBefore(g,s)}(document,'script'));
}
function redirect() {
if (location.hostname === 'tastejs.github.io') {
location.href = location.href.replace('tastejs.github.io/todomvc', 'todomvc.com');
}
}
function findRoot() {
var base;
[/labs/, /\w*-examples/].forEach(function (href) {
var match = location.href.match(href);
if (!base && match) {
base = location.href.indexOf(match);
}
});
return location.href.substr(0, base);
}
function getFile(file, callback) {
if (!location.host) {
return console.info('Miss the info bar? Run TodoMVC from a server to avoid a cross-origin error.');
}
var xhr = new XMLHttpRequest();
xhr.open('GET', findRoot() + file, true);
xhr.send();
xhr.onload = function () {
if (xhr.status === 200 && callback) {
callback(xhr.responseText);
}
};
}
function Learn(learnJSON, config) {
if (!(this instanceof Learn)) {
return new Learn(learnJSON, config);
}
var template, framework;
if (typeof learnJSON !== 'object') {
try {
learnJSON = JSON.parse(learnJSON);
} catch (e) {
return;
}
}
if (config) {
template = config.template;
framework = config.framework;
}
if (!template && learnJSON.templates) {
template = learnJSON.templates.todomvc;
}
if (!framework && document.querySelector('[data-framework]')) {
framework = document.querySelector('[data-framework]').getAttribute('data-framework');
}
if (template && learnJSON[framework]) {
this.frameworkJSON = learnJSON[framework];
this.template = template;
this.append();
}
}
Learn.prototype.append = function () {
var aside = document.createElement('aside');
aside.innerHTML = _.template(this.template, this.frameworkJSON);
aside.className = 'learn';
// Localize demo links
var demoLinks = aside.querySelectorAll('.demo-link');
Array.prototype.forEach.call(demoLinks, function (demoLink) {
demoLink.setAttribute('href', findRoot() + demoLink.getAttribute('href'));
});
document.body.className = (document.body.className + ' learn-bar').trim();
document.body.insertAdjacentHTML('afterBegin', aside.outerHTML);
};
redirect();
getFile('learn.json', Learn);
})();
/* base.css overrides */
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Template • TodoMVC</title>
<link rel="stylesheet" href="bower_components/todomvc-common/base.css">
<!-- CSS overrides - remove if you don't need it -->
<link rel="stylesheet" href="css/app.css">
</head>
<body>
<section id="todoapp">
<header id="header">
<h1>todos</h1>
<input id="new-todo" placeholder="What needs to be done?" autofocus>
</header>
<!-- This section should be hidden by default and shown when there are todos -->
<section id="main">
<input id="toggle-all" type="checkbox">
<label for="toggle-all">Mark all as complete</label>
<ul id="todo-list">
<!-- These are here just to show the structure of the list items -->
<!-- List items should get the class `editing` when editing and `completed` when marked as completed -->
<li class="completed">
<div class="view">
<input class="toggle" type="checkbox" checked>
<label>Create a TodoMVC template</label>
<button class="destroy"></button>
</div>
<input class="edit" value="Create a TodoMVC template">
</li>
<li>
<div class="view">
<input class="toggle" type="checkbox">
<label>Rule the web</label>
<button class="destroy"></button>
</div>
<input class="edit" value="Rule the web">
</li>
</ul>
</section>
<!-- This footer should hidden by default and shown when there are todos -->
<footer id="footer">
<!-- This should be `0 items left` by default -->
<span id="todo-count"><strong>1</strong> item left</span>
<!-- Remove this if you don't implement routing -->
<ul id="filters">
<li>
<a class="selected" href="#/">All</a>
</li>
<li>
<a href="#/active">Active</a>
</li>
<li>
<a href="#/completed">Completed</a>
</li>
</ul>
<!-- Hidden if no completed items are left ↓ -->
<button id="clear-completed">Clear completed (1)</button>
</footer>
</section>
<footer id="info">
<p>Double-click to edit a todo</p>
<!-- Remove the below line ↓ -->
<p>Template by <a href="http://github.com/sindresorhus">Sindre Sorhus</a></p>
<!-- Change this out with your name and url ↓ -->
<p>Created by <a href="http://todomvc.com">you</a></p>
<p>Part of <a href="http://todomvc.com">TodoMVC</a></p>
</footer>
<!-- Scripts here. Don't remove this ↓ -->
<script src="bower_components/todomvc-common/base.js"></script>
<script src="js/app.js"></script>
</body>
</html>
(function( window ) {
'use strict';
// Your starting point. Enjoy the ride!
})( window );
# Framework Name TodoMVC Example
> Short description of the framework provided by the official website.
> _[Framework Name - framework.com](link-to-framework)_
## Learning Framework Name
The [Framework Name website]() is a great resource for getting started.
Here are some links you may find helpful:
* [Documentation]()
* [API Reference]()
* [Applications built with Framework Name]()
* [Blog]()
* [FAQ]()
* [Framework Name on GitHub]()
Articles and guides from the community:
* [Article 1]()
* [Article 2]()
Get help from other Framework Name users:
* [Framework Name on StackOverflow](http://stackoverflow.com/questions/tagged/____)
* [Mailing list on Google Groups]()
* [Framework Name on Twitter](http://twitter.com/____)
* [Framework Name on Google +]()
_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)._
## Implementation
How is the app structured? Are there deviations from the spec? If so, why?
## Running
If there is a build step required to get the example working, explain it here.
To run the app, spin up an HTTP server and visit http://localhost/.../myexample/.
## Credit
This TodoMVC application was created by [you]().
# Template • [TodoMVC](http://todomvc.com)
## Getting Started
Read the [App Specification](https://github.com/tastejs/todomvc/wiki/App-Specification) before touching the template.
## Need help?
Feel free to contact [Sindre](https://github.com/sindresorhus) or [Pascal](https://github.com/passy) if you have any questions or need help with the template.
## Credit
Created by [Sindre Sorhus](http://sindresorhus.com)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment