[
  {
    "path": ".gitignore",
    "content": "*.swp\n*.swo\n.idea\n*.DS_Store\n*.pyc\ncompiled/*\n/atlassian-ide-plugin.xml\ncompiled.js\nSpecRunnerCompiled.html\nnode_modules\ndocs\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"tools\"]\n\tpath = tools\n\turl = https://github.com/tart/GUI-Tools.git\n[submodule \"third_party/jasmine\"]\n\tpath = third_party/jasmine\n\turl = https://github.com/pivotal/jasmine.git\n[submodule \"third_party/goog\"]\n\tpath = third_party/goog\n\turl = https://github.com/tart/closure-library.git\n"
  },
  {
    "path": ".travis.yml",
    "content": "sudo: false\nlanguage: node_js\nnode_js:\n- '0.12'\ninstall:\n- npm -d install\n- npm install -g gulp\nbefore_script:\n- git config --global user.email \"travis@travis-ci.org\"\n- git config --global user.name \"Travis-CI\"\nscript:\n- gulp travis\nenv:\n  global:\n  - secure: DeieQoup1BuwAfLvz+2oRNQKEf2mrO65MsgMoBpWZirhRZvoYnzuWFVonByA6EyNPAzgzZI5Kk64aZaogbg9CzZu+mhkAuJE7m4+KgouE517wjbba8IseEFdyZ951I/VdaFp0PC33Xff32SB8L5xlzY+GnIzIUqTwa2rlogD7RA=\n"
  },
  {
    "path": "README.md",
    "content": "tartJS\n======\n\ntartJS is a performance-focused JavaScript framework based on well-tested Google Closure Tools suite.\nIt provides rapid and responsive mobile app infrastructure.\n\nCheck out [the documentation](http://tart.js.org/docs) and join us on [![tartJS Slack](http://slack.tartjs.org/badge.svg)](http://slack.tartjs.org) for anything about tartJS.\n\nTrack issues on [![tartJS HuBoard](https://img.shields.io/github/issues/tart/tartjs.svg?style=flat&label=HuBoard)](https://huboard.com/tart/tartJS)\n\nClosure Compiler optimizes, checks and cleans up your annotated JavaScript code with best minification rates while helping you to catch errors.\n\n\n## Getting Started\n\n### From scratch\n\nAdd tartJS to your project as a submodule:\n\n```sh\n    git submodule add git@github.com:tart/tartJS.git js/lib/tartJS\n```\n\n### Boilerplates/Examples\n\n* For TodoMVC implementation and generic boilerplate:\n\n    http://github.com/tart/tartjs-todomvc\n\n* For working mobile project:\n\n    https://github.com/tart/tartjs-mobile-demo\n\n* Generic boilerplate:\n\n    https://github.com/tart/BoilerPlate\n\n\n## Documentation\n\n(More coming soon)\n\n\n### Annotation\n\nWith help of Closure Compiler, class based inheritance and type safety is widely used in tartJS.\nSee [Annotating JavaScript for the Closure Compiler](https://developers.google.com/closure/compiler/docs/js-for-compiler) how JSDoc annotation works.\n\n\n### Directory structure\n\n* [tart](https://github.com/tart/tartJS/tree/master/tart) : Contains core Tart libraries\n* tools : Contains tools like Google Closure Compiler, Google Closure Linter etc (submodule to [tart/GUI-Tools](https://github.com/tart/GUI-Tools))\n* [third_party](https://github.com/tart/tartJS/tree/master/third_party) : Contains third party libraries like Google Closure Library, Jasmine, jQuery etc. \n\n\n## Examples\n\n* Outstanding web audio processor for guitar players:\n\n    [Pedalboard.js](http://dashersw.github.io/pedalboard.js/)\n\n* Example TodoMVC application (useful as a web application boilerplate):\n\n    [tartjs-todomvc](https://github.com/tart/tartjs-todomvc)\n\n* Example TV show mobile app (useful as a mobile boilerplate):\n\n    [tartjs-mobile-demo](https://github.com/tart/tartjs-mobile-demo)\n\n## Contributing\n\nWant to contribute? Great! Fork it, create a branch, make your changes, push and [open pull request](https://github.com/tart/tartJS/pulls) to contribute.\nYour pull request may not be merged immediately until necessary changes were made to match coding-style, pass tests.\nWe do follow [Google JavaScript Style Guide](https://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml).\n\n\n\n## License\n\nCopyright 2014 Startup Kitchen. All Rights Reserved.\n\nLicensed under the Apache License, Version 2.0 (the \"License\");\nyou may not use this file except in compliance with the License.\nYou may obtain a copy of the License at\n\n     http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing, software\ndistributed under the License is distributed on an \"AS-IS\" BASIS,\nWITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\nSee the License for the specific language governing permissions and\nlimitations under the License.\n"
  },
  {
    "path": "gulpfile.js",
    "content": "var gulp = require('gulp');\nvar shell = require(\"gulp-shell\");\nvar runSequence = require('run-sequence');\n\nvar GH_TOKEN = process.env.GH_TOKEN || '';\n\ngulp.task('jsdoc', shell.task([\n    'rm -rf ./docs',\n    'jsdoc -c ./scripts/jsdoc-conf.json'\n]));\n\ngulp.task('gh-pages', ['jsdoc'], shell.task([\n    'mv docs docs_new',\n    'git remote add upstream https://' + GH_TOKEN + '@github.com/tart/tartJS.git/',\n    'git fetch upstream',\n    'git checkout -b gh-pages upstream/gh-pages',\n    'rm -rf docs',\n    'mv docs_new docs',\n    'git add docs',\n    'git commit -m \"Update documentation\"',\n    'git push upstream gh-pages',\n    'git checkout master'\n]));\n\ngulp.task('travis-master', ['gh-pages']);\n\ngulp.task('travis-pull-request', []);\n\ngulp.task('travis', function(callback) { \n    var task = process.env.TRAVIS_PULL_REQUEST != 'false' ? 'travis-pull-request' : 'travis-master';\n    runSequence(task, callback);\t\n});\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"tartJS\",\n  \"description\": \"A performance-obsessed JavaScript framework for desktop, mobile and web applications.\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/tart/tartJS\"\n  },\n  \"dependencies\": {},\n  \"devDependencies\": {\n    \"gulp\": \"^3.9.0\",\n    \"gulp-shell\": \"^0.4.2\",\n    \"jaguarjs-jsdoc\": \"git://github.com/davidshimjs/jaguarjs-jsdoc\",\n    \"jsdoc\": \"^3.3.2\",\n    \"run-sequence\": \"^1.1.2\"\n  }\n}\n"
  },
  {
    "path": "scripts/build.sh",
    "content": "#!/bin/bash\n\n#usage : scripts/build.sh ply.components.AnimatedCarouselExample.SpecRunner ply/components/AnimatedCarouselExample/spec/compiled.js\n\nnamespace=$1\noutputFile=$2\n\nthird_party/goog/closure/bin/build/closurebuilder.py \\\n--root=\"third_party/goog/\" \\\n--root=\"tart/\" \\\n--namespace=\"${namespace}\" \\\n--compiler_flags=\"--externs=tart/externs/tart.externs.js\" \\\n--compiler_flags=\"--externs=tart/externs/jasmine.externs.js\" \\\n--compiler_flags=\"--externs=tart/externs/jquery-1.4.4.externs.js\"  \\\n--output_mode=\"compiled\"  --compiler_jar=tools/compiler/compiler.jar  \\\n--output_file=${outputFile}  \\\n--compiler_flags=\"--compilation_level=ADVANCED_OPTIMIZATIONS\" \\\n--compiler_flags=\"--output_wrapper='(function(){%output%})()'\" \\\n--compiler_flags=\"--create_source_map='compiled/source_map.js'\" \\\n--compiler_flags=\"--property_renaming_report='compiled/properties.out'\" \\\n--compiler_flags=\"--variable_renaming_report='compiled/variables.out'\" \\\n--compiler_flags=\"--warning_level=VERBOSE\" \\\n--compiler_flags=\"--formatting=PRETTY_PRINT\" \\\n--compiler_flags=\"--formatting=PRINT_INPUT_DELIMITER\" \\\n--compiler_flags=\"--jscomp_warning=accessControls\" \\\n--compiler_flags=\"--jscomp_error=checkRegExp\" \\\n--compiler_flags=\"--jscomp_error=checkTypes\" \\\n--compiler_flags=\"--jscomp_error=nonStandardJsDocs\" \\\n--compiler_flags=\"--jscomp_error=strictModuleDepCheck\"\n"
  },
  {
    "path": "scripts/compileAllSpecRunners.sh",
    "content": "#!/bin/bash\n\nfor i in `find * -type f | grep -i spec | grep -i \"SpecRunner.html$\" | grep -v \"third_party\"`; \ndo\n    compiledJs=`echo $i | sed -e 's/SpecRunner.html/compiled.js/'`\n    echo -e \"========= COMPILING $compiledJs =========\" ; \n    scripts/compileForSpecRunner.sh $compiledJs 2> /dev/null; \n    echo -e \"========= FINISHED $? =========\\n\"; \ndone\n"
  },
  {
    "path": "scripts/compileForSpecRunner.sh",
    "content": "#!/bin/bash\n\n#usage : scripts/compileForSpecRunner.sh ply/components/AnimatedCarouselExample/spec/compiled.js\n\noutputFile=$1\n\nif [[ $outputFile == *spec/compiled.js* ]]\nthen\n    namespace=`echo $outputFile | sed -e 's/\\/spec\\/compiled.js//g' | sed -e 's/\\//\\./g'`\n    namespace=${namespace}.SpecRunner\nelse\n    echo \"ERROR : Path should containt spec/compiled.js\";\n    exit 1;\nfi\n\nthird_party/goog/closure/bin/build/closurebuilder.py --root=\"third_party/goog/\"  --root=\"tart/\"  --root=\"ply/\"   --namespace=\"${namespace}\"  --compiler_flags=\"--externs=tart/externs/tart.externs.js\" --compiler_flags=\"--externs=tart/externs/jasmine.externs.js\" \\\n--compiler_flags=\"--externs=tart/externs/jquery-1.4.4.externs.js\"  \\\n--output_mode=\"compiled\"  --compiler_jar=tools/compiler/compiler.jar  \\\n--output_file=${outputFile}  \\\n--compiler_flags=\"--compilation_level=ADVANCED_OPTIMIZATIONS\" \\\n--compiler_flags=\"--output_wrapper='(function(){%output%})()'\" \\\n--compiler_flags=\"--create_source_map='compiled/source_map.js'\" \\\n--compiler_flags=\"--property_renaming_report='compiled/properties.out'\" \\\n--compiler_flags=\"--variable_renaming_report='compiled/variables.out'\" \\\n--compiler_flags=\"--warning_level=VERBOSE\" \\\n--compiler_flags=\"--formatting=PRETTY_PRINT\" \\\n--compiler_flags=\"--formatting=PRINT_INPUT_DELIMITER\" \\\n--compiler_flags=\"--jscomp_warning=accessControls\" \\\n--compiler_flags=\"--jscomp_error=checkRegExp\" \\\n--compiler_flags=\"--jscomp_error=checkTypes\" \\\n--compiler_flags=\"--jscomp_error=nonStandardJsDocs\" \\\n--compiler_flags=\"--jscomp_error=strictModuleDepCheck\"\n"
  },
  {
    "path": "scripts/deps.sh",
    "content": "#!/bin/bash\n\n#usage : scripts/deps.sh\n\nthird_party/goog/closure/bin/build/depswriter.py --root_with_prefix='tart/ ../../../../tart/' --output_file='tart/deps.js'\n"
  },
  {
    "path": "scripts/jsdoc-conf.json",
    "content": "{\n    \"tags\": {\n        \"allowUnknownTags\": true,\n        \"dictionaries\": [\"closure\", \"jsdoc\"]\n    },\n    \"source\": {\n\t\"include\": [\"tart\", \"README.md\"],\n        \"includePattern\": \".+\\\\.js(doc)?$\",\n        \"excludePattern\": \"(^|\\\\/|\\\\\\\\)_\"\n    },\n    \"opts\": {\n        \"template\": \"node_modules/jaguarjs-jsdoc\",\n        \"encoding\": \"utf8\",\n        \"destination\": \"docs/\",\n        \"recurse\": true\n    },\n    \"plugins\": [\"plugins/markdown\"],\n    \"templates\": {\n        \"cleverLinks\": true,\n        \"monospaceLinks\": false,\n        \"default\": {\n            \"outputSourceFiles\": true\n        },\n    \t\"applicationName\": \"TartJS\",\n    \t\"disqus\": \"\",\n    \t\"googleAnalytics\": \"\",\n    \t\"openGraph\": {\n      \t    \"title\": \"\",\n            \"type\": \"\",\n            \"image\": \"\",\n            \"site_name\": \"\",\n            \"url\": \"\"\n    \t},\n    \t\"meta\": {\n            \"title\": \"tartJS\",\n            \"description\": \"\",\n            \"keyword\": \"\"\n    \t},\n        \"linenums\": true\n    },\n    \"markdown\": {\n\t\"tags\": []\n    }\n}\n"
  },
  {
    "path": "scripts/runAllSpecRunners.sh",
    "content": "#!/bin/bash\n\n#run all SpecRunner*html files using qasmine\n\nfor i in `find * -type f | grep -v third_party | grep -i SpecRunner | grep -i \"\\.html\"`; \ndo\n    echo -e \"========= RUNNUNG $i =========\" ; \n    qasmine $i 2> /dev/null; \n    echo -e \"========= FINISHED $? =========\\n\"; \ndone\n"
  },
  {
    "path": "tart/Builder.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview Generic builder class to build and modify DOM elements.\n */\n\ngoog.provide('tart.Builder');\ngoog.require('tart.Err');\n\n\n\n/**\n * Constructor method\n *\n * @constructor\n * @param {string} id id for the builder. Can be used as the id of the DOM element this builder will build.\n * @return {tart.Builder} A builder object.\n */\ntart.Builder = function(id) {\n    this.id_ = id || '';\n    return this;\n};\n\n\n/**\n * @type {jQueryObject}\n * @protected\n */\ntart.Builder.prototype.$dom = null;\n\n\n/**\n * @type {Object} Templates holder object.\n */\ntart.Builder.templates = {};\n\n\n/**\n * Builds the DOM element.\n * @param {*} owner Owner class for the builder.\n */\ntart.Builder.prototype.buildDOM = goog.abstractMethod;\n\n\n/**\n * Returns built ready-to-use DOM part in jQuery object format.\n *\n * @return {?jQueryObject} the DOM object built by the builder.\n */\ntart.Builder.prototype.getDOM = function() {\n    return this.$dom;\n};\n\n\n/**\n * Removes the DOM part from document.\n */\ntart.Builder.prototype.removeDOM = goog.abstractMethod;\n"
  },
  {
    "path": "tart/Carousel/Carousel.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview tart.Carousel is an event driven Carousel/Image Slider class\n * which handles next and previous events and gets visible items on viewport.\n *\n * Example usage:\n *\n *     var items = [\n *         {name : 'one'},\n *         {name : 'two'},\n *         {name : 'three'},\n *         {name : 'four'},\n *         {name : 'five'},\n *         {name : 'six'},\n *         {name : 'seven'}\n *     ]; //seven items\n *\n *     var carousel = new tart.Carousel(items);\n *\n *     carousel.setItemPerViewport(2); //only 2 items is visibile\n *\n *     goog.events.listen(carousel, tart.Carousel.EventTypes.NEXT, function (e) {\n *         console.info('items moved next');\n *         console.log (e.itemsToBeRemoved);\n *         console.log (e.itemsToBeInserted);\n *         console.info(carousel.getVisibleItems());\n *     });\n *\n *     goog.events.listen(carousel, tart.Carousel.EventTypes.PREV, function (e) {\n *         console.info('items moved prev');\n *         console.log (e.itemsToBeRemoved);\n *         console.log (e.itemsToBeInserted);\n *         console.info(carousel.getVisibleItems());\n *     });\n *\n *     //items : 'one', 'two'\n *     carousel.next(1);\n *     //items : 'two', 'three'\n *     carousel.next(4);\n *     //items : 'six', 'seven'\n *     carousel.next(1);\n *     //items : 'six', 'seven' which is end of items, for circular navigation use tart.CircularCarousel instead\n *     carousel.prev(1);\n *     //items : 'five', 'six'\n *     carousel.prev(99999);\n *     //items : 'one', 'two'\n */\n\ngoog.provide('tart.Carousel');\ngoog.provide('tart.Carousel.EventTypes');\n\ngoog.require('goog.debug.ErrorHandler');\ngoog.require('goog.events.EventHandler');\ngoog.require('goog.events.EventTarget');\n\n\n\n/**\n * Pagination class to handle all paging events\n *\n * @param {Array.<*>=} items array of items.\n * @extends {goog.events.EventTarget}\n * @constructor\n */\ntart.Carousel = function(items) {\n    goog.events.EventTarget.call(this);\n\n    /** @protected */\n    this.items = items;\n\n    /** @protected */\n    this.itemCount = this.items.length;\n\n    /** @protected */\n    this.itemPerViewport = 1;\n\n    /**\n     * First visible item index in viewport\n     *\n     * @protected\n     * */\n    this.firstVisible = 0;\n\n    /**\n     * Last visible item index in viewport\n     *\n     * @protected\n     * */\n    this.lastVisible = this.firstVisible + this.itemPerViewport;\n\n\n};\ngoog.inherits(tart.Carousel, goog.events.EventTarget);\n\n\n/**\n * Event types enumaration\n *\n * @enum {string}\n */\ntart.Carousel.EventTypes = {\n    MOVED: 'moved',\n    PREV: 'prev',\n    NEXT: 'next'\n};\n\n\n/**\n * Item per visible viewport\n *\n * @param {number} itemPerViewport number of visible items.\n * @return {tart.Carousel} itself for chaining.\n */\ntart.Carousel.prototype.setItemPerViewport = function(itemPerViewport) {\n    this.itemPerViewport = itemPerViewport;\n    this.lastVisible = this.firstVisible + itemPerViewport;\n    return this;\n};\n\n\n/**\n * Get number of visible items in viewport\n *\n * @return {number} number of visible items.\n */\ntart.Carousel.prototype.getItemPerViewport = function() {\n    return this.itemPerViewport;\n};\n\n\n/**\n * Get visible items\n *\n * @return {Array.<*>} visible items array.\n */\ntart.Carousel.prototype.getVisibleItems = function() {\n    return this.items.slice(this.firstVisible, this.lastVisible);\n};\n\n\n/**\n * Get visible items indexes\n *\n * @return {Object} visible items array.\n */\ntart.Carousel.prototype.getVisibleItemIndexes = function() {\n    var indexes = {\n        first: this.firstVisible,\n        last: this.lastVisible\n    };\n\n    return indexes;\n};\n\n\n/**\n * Calculate max move count\n *\n * @param {string} direction 'next' or 'prev' direction.\n * @param {number} moveCount number of movement.\n * @return {number}  max move count.\n * @private\n */\ntart.Carousel.prototype.getMaxMoveCount_ = function(direction, moveCount) {\n    var maxMoveCount;\n\n    if (direction == 'next') {\n        maxMoveCount = this.itemCount - this.lastVisible;\n    }\n    else {\n        maxMoveCount = this.firstVisible;\n    }\n\n    return maxMoveCount;\n};\n\n\n/**\n * Find which items to be removed and inserted after move\n *\n * @param {number} moveCount item move count.\n * @return {Object} object literal which has itemsToBeInserted and itemsToBeRemoved nodes.\n */\ntart.Carousel.prototype.getItemsToBeInsertedAndRemoved = function(moveCount) {\n    var i,\n        previousItemsIndex = [],\n        nextItemsIndex = [];\n\n    for (i = this.firstVisible; i < this.lastVisible; i++) {\n        previousItemsIndex.push(i);\n        nextItemsIndex.push(i + moveCount);\n    }\n\n    var moveDiff = this.getMoveDiff(previousItemsIndex, nextItemsIndex, moveCount);\n\n    return moveDiff;\n};\n\n\n/**\n * Get difference between visible items, after move and before move\n *\n * @param {Array.<number>} a1 first array.\n * @param {Array.<number>} a2 second array.\n * @param {number} moveCount item move count.\n * @return {Object} generated diff.\n * @protected\n */\ntart.Carousel.prototype.getMoveDiff = function(a1, a2, moveCount) {\n\n    var direction = (moveCount > 0) ? 'next' : 'prev';\n\n    moveCount = Math.abs(moveCount);\n\n    var i = 0,\n        index = 0,\n        itemsToBeInserted = [],\n        itemsToBeRemoved = [],\n        itemCount = this.itemCount;\n\n    var tmpItems;\n\n    if (direction == 'prev') {\n        tmpItems = {\n            toBeInserted: a2.slice(0, moveCount),\n            toBeRemoved: a1.slice(-1 * moveCount, a1.length)\n        };\n    }\n    else {\n        tmpItems = {\n            toBeRemoved: a1.slice(0, moveCount),\n            toBeInserted: a2.slice(-1 * moveCount, a2.length)\n        };\n    }\n\n    for (i = 0; i < tmpItems.toBeInserted.length; i++) {\n        index = (tmpItems.toBeInserted[i] + itemCount) % itemCount;\n        itemsToBeInserted.push(this.items[index]);\n    }\n\n    for (i = 0; i < tmpItems.toBeRemoved.length; i++) {\n        index = (tmpItems.toBeRemoved[i] + itemCount) % itemCount;\n        itemsToBeRemoved.push(this.items[index]);\n    }\n\n    return {\n        itemsToBeInserted: itemsToBeInserted,\n        itemsToBeRemoved: itemsToBeRemoved\n    };\n};\n\n\n/**\n * Move cursor to next or previous item\n *\n * @param {string} direction 'next' or 'prev' movement direction.\n * @param {*} moveCount cursor move count.\n * @protected\n */\ntart.Carousel.prototype.move = function(direction, moveCount) {\n    moveCount = moveCount || 1;\n    moveCount = Math.abs(moveCount);\n\n    var maxMoveCount = this.getMaxMoveCount_(direction, moveCount);\n    moveCount = moveCount <= maxMoveCount ? moveCount : maxMoveCount;\n\n    var eventToDispatch = tart.Carousel.EventTypes.NEXT;\n\n    if (direction == 'prev') {\n        moveCount = moveCount * -1;\n        eventToDispatch = tart.Carousel.EventTypes.PREV;\n    }\n\n    var moveDiff = this.getItemsToBeInsertedAndRemoved(moveCount);\n\n    this.firstVisible = this.firstVisible + moveCount;\n    this.lastVisible = this.lastVisible + moveCount;\n\n\n    var eventObj = {type: eventToDispatch,\n        itemsToBeRemoved: moveDiff.itemsToBeRemoved,\n        itemsToBeInserted: moveDiff.itemsToBeInserted};\n\n    this.dispatchEvent(eventObj);\n};\n\n\n/**\n * Move cursor to next\n *\n * @param {number|*} moveCount cursor move count.\n */\ntart.Carousel.prototype.next = function(moveCount) {\n    this.move('next', moveCount);\n};\n\n\n/**\n * Move cursor to previous\n *\n * @param {number|*} moveCount cursor move count.\n */\ntart.Carousel.prototype.prev = function(moveCount) {\n    this.move('prev', moveCount);\n};\n"
  },
  {
    "path": "tart/Carousel/spec/CarouselSpec.js",
    "content": "goog.require('tart.Carousel');\n\ngoog.provide('tart.Carousel.SpecRunner');\n\ndescribe('Carousel', function() {\n    var carousel;\n\n    var items = [\n        {name: 'one'},\n        {name: 'two'},\n        {name: 'three'},\n        {name: 'four'},\n        {name: 'five'},\n        {name: 'six'},\n        {name: 'seven'}\n    ];\n\n\n    beforeEach(function() {\n        carousel = new tart.Carousel(items);\n    });\n\n    describe('some parameters should be set and get', function() {\n        it('should set itemPerViewport', function() {\n            carousel.setItemPerViewport(10);\n            expect(carousel.getItemPerViewport()).toEqual(10);\n        });\n\n\n        it('should return visible items', function() {\n            carousel.setItemPerViewport(2);\n            var visibleItems = carousel.getVisibleItems();\n\n            expect(visibleItems[0].name == 'one' && visibleItems[1].name == 'two').toBeTruthy();\n        });\n    });\n\n    describe('will navigate through items', function() {\n\n        it('should move one item next', function() {\n            carousel.setItemPerViewport(3);\n\n            var previousItems = carousel.getVisibleItems(),\n                visibleItems;\n\n\n            goog.events.listen(carousel, tart.Carousel.EventTypes.NEXT, function(e) {\n                visibleItems = carousel.getVisibleItems();\n            });\n\n            carousel.next(1);\n\n            expect(visibleItems[0].name == 'two' && visibleItems[1].name == 'three').toBeTruthy();\n\n        });\n\n\n\n        it('should move more than item next', function() {\n            carousel.setItemPerViewport(3);\n\n            var visibleItems;\n\n            goog.events.listen(carousel, tart.Carousel.EventTypes.NEXT, function(e) {\n                visibleItems = carousel.getVisibleItems();\n            });\n\n            carousel.next(3);\n\n            expect(visibleItems[0].name == 'four' && visibleItems[1].name == 'five').toBeTruthy();\n        });\n\n        it('should not move more than item count', function() {\n            carousel.setItemPerViewport(2);\n\n            var visibleItems;\n\n            goog.events.listen(carousel, tart.Carousel.EventTypes.NEXT, function(e) {\n                visibleItems = carousel.getVisibleItems();\n            });\n\n            carousel.next(99999);\n            expect(visibleItems[0].name == 'six' && visibleItems[1].name == 'seven').toBeTruthy();\n        });\n    });\n});\n\n\n/**\n * Run jasmine spec\n */\ntart.Carousel.SpecRunner = function() {\n    jasmine.getEnv()['addReporter'](new jasmine.TrivialReporter());\n    jasmine.getEnv()['execute']();\n}();\n\n"
  },
  {
    "path": "tart/Carousel/spec/SpecRunner.html",
    "content": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\n  \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n    <title>Jasmine Test Runner</title>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../../../third_party/jasmine/lib/jasmine.css\">\n    <script type=\"text/javascript\" src=\"../../../third_party/jasmine/lib/jasmine.js\"></script>\n    <script type=\"text/javascript\" src=\"../../../third_party/jasmine/lib/jasmine-html.js\"></script>\n\n    <!-- include source files here... -->\n    <script type=\"text/javascript\" src=\"../../../third_party/jquery/jquery-1.5.2.js\"></script>\n    <script type=\"text/javascript\" src=\"../../../third_party/goog/goog/base.js\"></script>\n\n    <script type=\"text/javascript\">\n        goog.require(\"goog.events.EventTarget\");\n    </script>\n\n    <script type=\"text/javascript\" src=\"../../Pagination.js\"></script>\n    <script type=\"text/javascript\" src=\"../Carousel.js\"></script>\n</head>\n<body>\n    <!-- include spec files here... -->\n    <script type=\"text/javascript\" src=\"CarouselSpec.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "tart/CircularCarousel/CircularCarousel.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview tart.CircularCarousel is an event driven Carousel/Image Slider class which\n * handles next and previous events and gets visible items on viewport.\n *\n * Example usage:\n *\n *     var items = [\n *         {name : 'one'},\n *         {name : 'two'},\n *         {name : 'three'},\n *         {name : 'four'},\n *         {name : 'five'},\n *         {name : 'six'},\n *         {name : 'seven'}\n *     ]; //seven items\n *\n *     var carousel = new tart.CircularCarousel(items);\n *\n *     carousel.setItemPerViewport(2); //only 2 items is visibile\n *\n *     goog.events.listen(carousel, tart.Carousel.EventTypes.NEXT, function (e) {\n *         console.info('items moved next');\n *         console.log (e.itemsToBeRemoved);\n *         console.log (e.itemsToBeInserted);\n *         console.info(carousel.getVisibleItems());\n *     });\n *\n *     goog.events.listen(carousel, tart.Carousel.EventTypes.PREV, function (e) {\n *         console.info('items moved prev');\n *         console.log (e.itemsToBeRemoved);\n *         console.log (e.itemsToBeInserted);\n *         console.info(carousel.getVisibleItems());\n *     });\n *\n *     carousel.prev(3);\n *     carousel.next(1);\n */\n\ngoog.provide('tart.CircularCarousel');\n\ngoog.require('goog.events.EventTarget');\ngoog.require('tart.Carousel');\n\n\n\n/**\n * Pagination class to handle all paging events\n *\n * @param {Array.<*>=} items array of items.\n * @extends {tart.Carousel}\n * @constructor\n */\ntart.CircularCarousel = function(items) {\n    goog.base(this, items);\n};\ngoog.inherits(tart.CircularCarousel, tart.Carousel);\n\n\n/**\n * Find which items to be removed and inserted after move\n *\n * @param {number} moveCount item move count.\n * @return {Object} object literal which has itemsToBeInserted and itemsToBeRemoved nodes.\n */\ntart.CircularCarousel.prototype.getItemsToBeInsertedAndRemoved = function(moveCount) {\n    var i,\n        previousItemsIndex = [],\n        nextItemsIndex = [],\n        start = this.firstVisible + moveCount;\n\n\n    for (i = 0; i < this.lastVisible; i++) {\n        previousItemsIndex.push(i);\n    }\n\n    for (i = start; i < start + this.itemPerViewport; i++) {\n        nextItemsIndex.push(i);\n    }\n\n    var moveDiff = this.getMoveDiff(previousItemsIndex, nextItemsIndex, moveCount);\n\n    return moveDiff;\n};\n\n\n/**\n * low level move which handles next and prev methods\n *\n * @param {string} direction 'next' or 'prev' direction of movement.\n * @param {*} moveCount item move count.\n * @override\n * @protected\n */\ntart.CircularCarousel.prototype.move = function(direction, moveCount) {\n    moveCount = moveCount || 1;\n    moveCount = Math.abs(moveCount);\n    moveCount = moveCount % this.itemCount;\n\n    var tmpCursor = 0;\n\n    //default event dispatched\n    var eventToDispatch = tart.Carousel.EventTypes.NEXT;\n\n    if (direction == 'prev') {\n        moveCount = moveCount * -1;\n        tmpCursor = this.itemCount;\n        eventToDispatch = tart.Carousel.EventTypes.PREV;\n    }\n\n    var tmp = [].concat(this.items).concat(this.items);\n\n    var moveDiff = this.getItemsToBeInsertedAndRemoved(moveCount);\n\n    this.firstVisible = this.firstVisible + tmpCursor + moveCount;\n    this.lastVisible = this.lastVisible + tmpCursor + moveCount;\n\n    this.items = tmp.slice(this.firstVisible, this.firstVisible + this.itemCount);\n\n    this.firstVisible = 0;\n    this.lastVisible = this.itemPerViewport;\n\n    var eventObj = {type: eventToDispatch,\n        itemsToBeRemoved: moveDiff.itemsToBeRemoved,\n        itemsToBeInserted: moveDiff.itemsToBeInserted};\n\n    this.dispatchEvent(eventObj);\n};\n"
  },
  {
    "path": "tart/CircularCarousel/spec/CircularCarouselSpec.js",
    "content": "goog.require('tart.CircularCarousel');\n\ngoog.provide('tart.CircularCarousel.SpecRunner');\n\ndescribe('CircularCarousel', function() {\n    var carousel;\n\n    var items = [\n        {name: 'one'},\n        {name: 'two'},\n        {name: 'three'},\n        {name: 'four'},\n        {name: 'five'},\n        {name: 'six'},\n        {name: 'seven'}\n    ];\n\n    beforeEach(function() {\n        carousel = new tart.CircularCarousel(items);\n    });\n\n    describe('extends from tart.Carousel', function() {\n        it('is an isstance of tart.Carousel', function() {\n            expect(carousel instanceof tart.Carousel).toBeTruthy();\n        });\n    });\n\n    describe('has circular navigation', function() {\n\n        it('will navigate to seventh element after prev if current item is first item', function() {\n            carousel.setItemPerViewport(2);\n\n            var previousItems = carousel.getVisibleItems(),\n                nextItems;\n\n\n            goog.events.listen(carousel, tart.Carousel.EventTypes.PREV, function(e) {\n                nextItems = carousel.getVisibleItems();\n            });\n\n            carousel.prev(1);\n\n            expect(previousItems[0].name == 'one' && nextItems[0].name == 'seven').toBeTruthy();\n        });\n\n\n        it('will navigate to second element after 6 previous steps', function() {\n            carousel.setItemPerViewport(2);\n\n            var previousItems = carousel.getVisibleItems(),\n                nextItems;\n\n\n            goog.events.listen(carousel, tart.Carousel.EventTypes.PREV, function(e) {\n                nextItems = carousel.getVisibleItems();\n            });\n\n            carousel.prev(6);\n\n            expect(previousItems[0].name == 'one' && nextItems[0].name == 'two').toBeTruthy();\n        });\n\n\n        it('will navigate to seventh element after 8 previous steps which it means circular', function() {\n            carousel.setItemPerViewport(2);\n\n            var previousItems = carousel.getVisibleItems(),\n                nextItems;\n\n\n            goog.events.listen(carousel, tart.Carousel.EventTypes.PREV, function(e) {\n                nextItems = carousel.getVisibleItems();\n            });\n\n            carousel.prev(8);\n\n            expect(previousItems[0].name == 'one' && nextItems[0].name == 'seven').toBeTruthy();\n        });\n\n\n        it('will navigate to second element after 8 next steps which it means circular', function() {\n            carousel.setItemPerViewport(2);\n\n            var previousItems = carousel.getVisibleItems(),\n                nextItems;\n\n            goog.events.listen(carousel, tart.Carousel.EventTypes.NEXT, function(e) {\n                nextItems = carousel.getVisibleItems();\n            });\n\n            carousel.next(8);\n\n            expect(previousItems[0].name == 'one' && nextItems[0].name == 'two').toBeTruthy();\n        });\n\n        it('will navigate to third element after 2 next steps', function() {\n            carousel.setItemPerViewport(2);\n\n            var previousItems = carousel.getVisibleItems(),\n                nextItems;\n\n            goog.events.listen(carousel, tart.Carousel.EventTypes.NEXT, function(e) {\n                nextItems = carousel.getVisibleItems();\n            });\n\n            carousel.next(2);\n\n            expect(previousItems[0].name == 'one' && nextItems[0].name == 'three').toBeTruthy();\n        });\n\n    });\n\n});\n\n\n/**\n * Run jasmine spec\n */\ntart.CircularCarousel.SpecRunner = function() {\n    jasmine.getEnv()['addReporter'](new jasmine.TrivialReporter());\n    jasmine.getEnv()['execute']();\n}();\n"
  },
  {
    "path": "tart/CircularCarousel/spec/SpecRunner.html",
    "content": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\n  \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n    <title>Jasmine Test Runner</title>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../../../third_party/jasmine/lib/jasmine.css\">\n    <script type=\"text/javascript\" src=\"../../../third_party/jasmine/lib/jasmine.js\"></script>\n    <script type=\"text/javascript\" src=\"../../../third_party/jasmine/lib/jasmine-html.js\"></script>\n\n    <!-- include source files here... -->\n    <script type=\"text/javascript\" src=\"../../../third_party/jquery/jquery-1.5.2.js\"></script>\n    <script type=\"text/javascript\" src=\"../../../third_party/goog/goog/base.js\"></script>\n\n    <script type=\"text/javascript\">\n        goog.require(\"goog.events.EventTarget\");\n    </script>\n\n    <script type=\"text/javascript\" src=\"../../Carousel/Carousel.js\"></script>\n\n    <script type=\"text/javascript\" src=\"../CircularCarousel.js\"></script>\n</head>\n<body>\n    <!-- include spec files here... -->\n    <script type=\"text/javascript\" src=\"CircularCarouselSpec.js\"></script>\n\n</body>\n</html>\n"
  },
  {
    "path": "tart/Collection.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview tart.Collection is a useful data construct that also features an \"active item\". It is a key-value pair\n * collection with easy to use methods. It is also event-driven, so observers are notified when the index of the\n * active item changes.\n *\n * Example usage:\n *\n *     var items = { foo : 'bar' };\n *     var list = new tart.Collection(items);\n *\n * OR\n *\n *     var items = ['A','B', 'C', 'D'];\n *     var list = new tart.Collection(items);\n *\n * OR\n *\n *     var items = { foo : 'bar', baz:'zoo' };\n *     var list = new tart.Collection(items, 1); // Set activeItemIndex to 1\n */\n\ngoog.provide('tart.Collection');\ngoog.require('goog.array');\ngoog.require('goog.pubsub.PubSub');\ngoog.require('tart.Err');\n\n\n\n/**\n * Constructor method\n *\n * @constructor\n * @extends {goog.pubsub.PubSub}\n * @param {tart.JSON=} initialList Default list items in JSON format.\n * @param {number=} activeItem Default selected item index.\n * @return {tart.Collection} A list object.\n */\ntart.Collection = function(initialList, activeItem) {\n    // define privileged methods and properties here...\n    goog.base(this);\n    var initials = initialList || [];\n    this.activeItemIndex_ = (activeItem === undefined) ? -1 : activeItem;\n    this.values_ = []; // Values of all list elements.\n    this.keys_ = []; // Keys of all list elements.\n    this.items_ = []; // All key-val pairs in collection. Format [{a:1},{b:2},{c:x}]\n\n    // Initial values given like this: {a:b,c:d,e:f}\n    //@todo This loop should be coded in generic javascript instead of jQuery.\n    var _self = this;\n    $.each(initials, function(a, b) {\n        _self.addItem(a, b);\n    });\n    this.setActiveItemIndex(this.activeItemIndex_);\n    return this;\n};\ngoog.inherits(tart.Collection, goog.pubsub.PubSub);\n\n\n/**\n * Adds a new key-value pair to the collection.\n *\n * @param {number|string} key Key for the pair.\n * @param {*} value Value for the pair.\n * @return {boolean} Returns true if the add operation was successful.\n */\ntart.Collection.prototype.addItem = function(key, value) {\n    if (key === undefined || value === undefined) {\n        throw new tart.Err('Missing arguments (key: ' + key + ' value: ' + value + ')- you must give a key' +\n                'and a value to add a new item.');\n    } else if (this.getByKey(key)) {\n        // Deffensive check: key's must be unique\n        throw new tart.Err('Key \"' + key + '\" already in collection. Keys should be unique.');\n    } else {\n        var item = {};\n        item[key] = value;\n        this.keys_.push(key);\n        this.values_.push(value);\n        this.items_.push(item);\n        return true;\n    }\n};\n\n\n/**\n * Returns active item as JSON object.\n *\n * @return {tart.JSON} returns the active key-value pair from the collection.\n */\ntart.Collection.prototype.getActiveItem = function() {\n    return this.items_[this.getActiveItemIndex()];\n};\n\n\n/**\n * Returns active item's key.\n *\n * @return {string|number} returns the active key from the collection.\n */\ntart.Collection.prototype.getActiveItemKey = function() {\n    return this.keys_[this.getActiveItemIndex()];\n};\n\n\n/**\n * Returns active item's value.\n *\n * @return {*} returns the active value from the collection.\n */\ntart.Collection.prototype.getActiveItemValue = function() {\n    return this.values_[this.getActiveItemIndex()];\n};\n\n\n/**\n * Returns active item's index.\n * @return {number} returns the active index in the collection.\n */\ntart.Collection.prototype.getActiveItemIndex = function() {\n    return this.activeItemIndex_;\n};\n\n\n/**\n * Returns item by given key. If not found, returns boolean false.\n *\n * @param {string|number} key key to search for.\n * @return {tart.JSON} returns the key-value pair given a specific key.\n */\ntart.Collection.prototype.getByKey = function(key) {\n    return this.items_[goog.array.indexOf(this.keys_, key)];\n};\n\n\n/**\n * Returns item by given value. If not found, returns boolean false.\n *\n * @param {string|number} val value to search for.\n * @return {tart.JSON} returns the key-value pair given a specific value.\n */\ntart.Collection.prototype.getByValue = function(val) {\n    return this.items_[goog.array.indexOf(this.values_, val)];\n};\n\n\n/**\n * Returns item by given index.\n *\n * @param {number} index Index to search in the collection.\n * @return {tart.JSON|boolean|undefined} returns the key-value pair given an index.\n */\ntart.Collection.prototype.getByIndex = function(index) {\n    if (index >= this.keys_.length || index < 0 || index === undefined || isNaN(index)) {\n        return undefined;\n    } else {\n        return this.items_[index];\n    }\n};\n\n\n/**\n * Dumps all items in an array.\n * @return {Array} returns all pairs as an array.\n */\ntart.Collection.prototype.getAll = function() {\n    return this.items_;\n};\n\n\n/** Returns all values in an array.\n * @return {Array} returns all values in an array.\n */\ntart.Collection.prototype.getValues = function() {\n    return this.values_;\n};\n\n\n/** Returns all keys in an array.\n * @return {Array} returns all keys in an array.\n */\ntart.Collection.prototype.getKeys = function() {\n    return this.keys_;\n};\n\n\n/**\n * Returns all items in a kvp format.\n * @return {tart.JSON} obj returns an object that contains keys as its keys and values as its values.\n */\ntart.Collection.prototype.getItems = function() {\n    var obj = {};\n    for (var i = 0, l = this.items_.length; i < l; i++) {\n        var item = this.items_[i];\n        $.each(item, function(key, value) {\n            obj[key] = value;\n        });\n    }\n    return obj;\n};\n\n\n/**\n * Removes an item from collection which given by index and rebuilds the item collection.\n * Returns new activeItemIndex if item successfully removed or FALSE if not.\n *\n * @param {number} index Index to remove.\n * @return {number|boolean|undefined} Condition of the operation or the active item index.\n */\ntart.Collection.prototype.removeByIndex = function(index) {\n    if (index >= this.keys_.length || index < 0 || index === undefined || isNaN(index)) {\n        return undefined;\n    } else {\n        var oldActiveKey = this.getActiveItemKey();\n        this.items_.splice(index, 1);\n        this.keys_.splice(index, 1);\n        this.values_.splice(index, 1);\n        var oldActiveIndex = goog.array.indexOf(this.keys_, oldActiveKey);\n        if (oldActiveIndex > -1) {\n            this.setActiveItemIndex(oldActiveIndex);\n        } else {\n            this.setActiveItemIndex(-1);\n        }\n        return this.activeItemIndex_;\n    }\n};\n\n\n/**\n * Removes items by key.\n * @param {string} key Game items key.\n */\ntart.Collection.prototype.removeByKey = function(key) {\n    var keys = this.getKeys();\n    var index = goog.array.indexOf(keys, key);\n    this.removeByIndex(index);\n};\n\n\n/**\n * Sets active item index.\n * @param {number} newIndex index to set as the new active item.\n * @return {boolean} Whether the method was able to set the item.\n */\ntart.Collection.prototype.setActiveItemIndex = function(newIndex) {\n    // Deffensive check; active item index should not greater than total items in collection.\n    if (newIndex > this.values_.length - 1 || newIndex === undefined || isNaN(newIndex) || newIndex == this.activeItemIndex_) {\n        return false;\n    } else {\n        var oldIndex = this.activeItemIndex_;\n        this.activeItemIndex_ = newIndex;\n        this.publish('indexChanged', this.activeItemIndex_, oldIndex);\n        return true;\n    }\n};\n"
  },
  {
    "path": "tart/DropdownList/DropdownBuilder.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview Builder class for dropdown lists.\n */\ngoog.require('tart.Builder');\ngoog.provide('tart.DropdownBuilder');\n\n\n\n/**\n * DropdownBuilder class builds the DOM for DropdownList class.\n *\n * @constructor\n * @extends {tart.Builder}\n * @param {string} id id for the builder. Can be used as the id of the DOM element this builder will build.\n * @return {tart.DropdownBuilder} A builder object.\n */\ntart.DropdownBuilder = function(id) {\n    goog.base(this, id);\n    this.owner = null;\n    return this;\n};\ngoog.inherits(tart.DropdownBuilder, tart.Builder);\n\n\n/**\n * Main namespace of HTML templates for DOM structure.\n */\ntart.DropdownBuilder.templates = {};\n\n\n/**\n * Select menu template.\n * @param {string} id Id of the container.\n * @param {string} optionListHTML HTML of the list of options.\n * @return {string} the container HTML.\n */\ntart.DropdownBuilder.templates.container = function(id, optionListHTML) {\n    return '<select id=\"' + id + '\">' + optionListHTML + '</select>';\n};\n\n\n/**\n * Generates a select menu element, converts it to a jQuery object and passes to this.$dom.\n *\n * @param {tart.Collection} owner Owner tart.Collection instance.\n */\ntart.DropdownBuilder.prototype.buildDOM = function(owner) {\n    this.owner = owner;\n    var opts = [];\n    for (var k = 0, z = this.owner.keys_.length; k < z; k++) {\n        var option = tart.DropdownBuilder.templates.option(\n            this.owner.keys_[k], this.owner.values_[k], (k == this.owner.getActiveItemIndex()));\n        opts.push(option);\n    }\n    var finalDOM = tart.DropdownBuilder.templates.container(this.id_, opts.join(''));\n    this.$dom = $(finalDOM);\n    this.$dom.change(function() {\n        owner.switchIndex($(this).attr('selectedIndex'));\n    });\n};\n\n\n/**\n * Generates a single option element which ready-to-use in a HTML select menu element.\n *\n * @param {string|number} key Option value.\n * @param {string|number} value Option value.\n * @param {boolean} selected Whether the option is selected.\n * @return {string} the option HTML.\n */\ntart.DropdownBuilder.templates.option = function(key, value, selected) {\n    var active = (selected) ? ' selected=\"selected\"' : '';\n    return '<option value=\"' + key + '\"' + active + '>' + value + '</option>';\n};\n\n\n/**\n * Sets an select option's \"selected\" property to True.\n *\n * @param {number} newIndex the new index of the element to set the dropdown list to.\n */\ntart.DropdownBuilder.prototype.changeActiveItem = function(newIndex) {\n    this.$dom.attr('selectedIndex', newIndex).change();\n};\n\n\n/**\n * Removes a single select option from DOM by index which given as parameter.\n *\n * @param {number} index the index of the element to remove from the list.\n */\ntart.DropdownBuilder.prototype.removeOption = function(index) {\n    this.$dom.children().eq(index).remove();\n};\n\n\n/**\n * Creates a single select option and attachs it to the current DOM.\n *\n * @param {string|number} key value for the option.\n * @param {string|number} value Text for the option.\n * @return {jQueryObject} the jQuery object that holds the DOM object of the dropdown list.\n */\ntart.DropdownBuilder.prototype.addOption = function(key, value) {\n    return this.$dom.append(tart.DropdownBuilder.templates.option(key, value, false));\n};\n\n\n/**\n * @inheritDoc\n */\ntart.DropdownBuilder.prototype.removeDOM = function() {\n    this.$dom.remove();\n};\n"
  },
  {
    "path": "tart/DropdownList/DropdownList.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview Dropdown list class is an example of an HTML select box.\n *\n * Example usage:\n *\n *     var items        = {key1:'val1',key2:'val2',key3:'val3'};\n *     var builder      = new tart.DropdownBuilder('elementId');\n *     var selectedItem = 1;\n *     var list = new tart.DropdownList(items, builder, selectedItem);\n *     list.getAll(); // Outputs [{key1:'val1'},{key2:'val2'},{key3:'val3'}]\n *     list.getDOM(); // Returns a select (dropdown) menu in jquery format jQuery(select#elementId)\n *     list.setActiveItemIndex(2); // Sets key3:val3 option element selected property to TRUE;\n *     list.getActiveItemIndex(); // Returns an Object { key3=\"val3\" }\n */\n\ngoog.provide('tart.DropdownList');\ngoog.require('tart.Collection');\ngoog.require('tart.DropdownBuilder');\n\n\n\n/**\n * Constructor method for DropdownList.\n *\n * @constructor\n * @extends {tart.Collection}\n * @param {Object|Array}  initialList    initial list of items.\n * @param {tart.Builder=} opt_builder    builder class.\n * @param {number=}       opt_activeItem index of the active item.\n */\ntart.DropdownList = function(initialList, opt_builder, opt_activeItem) {\n    goog.base(this, initialList, opt_activeItem);\n    this.builder = opt_builder || new tart.DropdownBuilder('');\n    this.builder.buildDOM(this);\n};\ngoog.inherits(tart.DropdownList, tart.Collection);\n\n\n/**\n * @inheritDoc\n */\ntart.DropdownList.prototype.removeByIndex = function(index) {\n    var result = this.constructor.superClass_.removeByIndex.call(this, index);\n\n    if (result === false) {\n        return -1;\n    } else if (result === -1) {\n        this.setActiveItemIndex(0);\n        return 0;\n    } else {\n        if (this.builder) {\n            this.builder.removeOption(result);\n        }\n        return result;\n    }\n};\n\n\n/**\n * Removes current DOM element of dropdownlist instance from window.document.\n */\ntart.DropdownList.prototype.removeDOM = function() {\n    this.builder.removeDOM();\n};\n\n\n/**\n * Returns current DOM element of dropdownlist instance.\n *\n * @return {jQueryObject} The jQuery object that wraps the DOM.\n */\ntart.DropdownList.prototype.getDOM = function() {\n    return this.builder.getDOM();\n};\n\n\n/**\n * @inheritDoc\n */\ntart.DropdownList.prototype.setActiveItemIndex = function(newIndex) {\n    this.switchIndex(newIndex);\n    if (this.builder) {\n        this.builder.changeActiveItem(this.getActiveItemIndex());\n        return true;\n    }\n    return false;\n};\n\n\n/**\n * Set active item belongs to value parameter.\n * @param {(string|number)} value of an array.\n */\ntart.DropdownList.prototype.setActiveItemByValue = function(value) {\n    var that = this;\n\n    var items = this.getValues();\n    var index = goog.array.findIndex(items, function(item) {\n        return value == item;\n    });\n\n    that.setActiveItemIndex(index);\n};\n\n\n\n/**\n * Triggered by this.builder.dom_ element when user change the index by non-programatically way.\n * Important: This method shouldn't be called in any implementation code. Developers should use\n *            this.setActiveItemIndex() method instead of this.\n *\n * @param {number} newIndex index of the item to set as active.\n */\n\ntart.DropdownList.prototype.switchIndex = function(newIndex) {\n    this.constructor.superClass_.setActiveItemIndex.call(this, ((newIndex < 0) ? 0 : newIndex));\n};\n\n\n/**\n * @inheritDoc\n */\ntart.DropdownList.prototype.addItem = function(key, value) {\n    var added = this.constructor.superClass_.addItem.call(this, key, value);\n    if (this.builder && added === true) {\n        this.builder.addOption(key, value);\n        return true;\n    }\n    return false;\n};\n"
  },
  {
    "path": "tart/Err.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview tartJS error library and utility functions.\n */\n\ngoog.provide('tart.Err');\ngoog.require('tart');\n\n\n/**\n * Returns a new Error object which contains a custom error name and message.\n *\n * @param {string=} message Message to set as the error message.\n * @param {string=} name Optional error name.\n * @extends {Error}\n * @constructor\n */\n\ntart.Err = function(message, name) {\n    this.name = name || 'Error';\n    this.message = message || '';\n};\ngoog.inherits(tart.Err, Error);\n\n\n/**\n * Returns a new Error object which contains a implementation error message.\n *\n * @param {string} methodName Name of the unimplemented method. This will be set as the error message.\n * @throws {Error} Error object containing the details.\n */\ntart.Err.unimplementedMethod = function(methodName) {\n    throw new tart.Err('Wrong implementation',\n        'You should implement your own ' + methodName + ' method in child class which you want to use.');\n};\n"
  },
  {
    "path": "tart/FormValidator/FormValidator.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview tart.FormValidator is a form validation library which uses tart.Validation instance as validator.\n *\n * Example usage:\n *\n *     var form = $(\"form\");\n *     var validationForSubmit = function (errors) {\n *         //do some stuff with 'errors' object\n *     };\n *     var validationForBlur = function (errors) {\n *         //do some stuff with 'errors' object\n *     };\n *     tart.FormValidator(form).validateOnSubmit(validationForSubmit);\n *     tart.FormValidator(form).validateOnBlur(validateOnBlur);\n *\n * More examples can be seen from spec/FormValidationSpec.js file\n */\n\ngoog.require('tart.Validation');\n\ngoog.provide('tart.FormValidator');\n\n\n\n/**\n * Attach validator to formEl\n *\n * @param {Object} formEl jQuery element for selected form.\n * @constructor\n * @return {tart.FormValidator} .\n */\ntart.FormValidator = function(formEl) {\n    //TODO: this is tightly coupled to tart.Validation\n    /* @protected */\n    this.validator = tart.Validation;\n    /* @protected */\n    this.form = formEl;\n    /* @protected */\n    this.errors = [];\n    return this;\n};\n\n\n/**\n * Set validation rules to attached form\n *\n * @param {Object} rules given rules in object literal notation.\n * @return {tart.FormValidator} .\n * @this {tart.FormValidator} .\n */\ntart.FormValidator.prototype.setRules = function(rules) {\n    this.rules = rules;\n    return this;\n};\n\n\n/**\n * Find element with elementName in given form object\n *\n * @param {string} elementName name of element which to be find in form.\n * @return {Object} jQuery object for given element.\n */\ntart.FormValidator.prototype.getFormElementByName = function(elementName) {\n    var el = this.form.find('input[name=' + elementName + ']');\n    return el;\n};\n\n\n/**\n * Find related element attribute for given input type\n *\n * @param {Object} el jQuery object of element.\n * @return {string} elements value for related input type.\n */\ntart.FormValidator.prototype.getElementAttributeToCheck = function(el) {\n    //TODO: this can vary on elements type such has \"attr\"\n    return el.val();\n};\n\n\n/**\n * Rule key for tart.Validation\n *\n * @param {string} ruleKey key of rule.\n * @return {Function} elements value for related input type.\n */\ntart.FormValidator.prototype.getValidationRuleByKey = function(ruleKey) {\n    var rule;\n    //TODO: this swich case should be looked up from an object literal\n    switch (ruleKey) {\n        case 'isEmail' : rule = this.validator.is.email; break;\n        case 'isNotOnlySpace' : rule = this.validator.is.notOnlySpace; break;\n        case 'isNumeric' : rule = this.validator.is.numeric; break;\n        case 'isDigitAndNonDigit' : rule = this.validator.is.digitAndNonDigit; break;\n        case 'hasMaxLength' : rule = this.validator.has.maxLength; break;\n        case 'hasMinLength' : rule = this.validator.has.minLength; break;\n        case 'hasMaxValue' : rule = this.validator.has.maxValue; break;\n        case 'hasMinValue' : rule = this.validator.has.minValue; break;\n    }\n\n    return rule;\n};\n\n\n/**\n * Get rule key and rule options from rule object\n *\n * @param {Object} rule rule object whom key is ruleName and value is rule options.\n * @return {Object} object which has .key and .options nodes.\n */\ntart.FormValidator.prototype.getRuleKeyAndOptions = function(rule) {\n    var results = [];\n\n    //TODO: there should be a smarter way to do this\n    for (var i in rule) {\n        results.push({key: i, options: rule[i]});\n    }\n\n    return results;\n};\n\n\n/**\n * Apply rule and generate result in object literal\n *\n * @param {Object} el jQuery object to rule rule object whom key is ruleName and value is rule options.\n * @param {Object} rule rule to be applied to el.\n * @return {Object} result object which has .success and .item nodes.\n */\ntart.FormValidator.prototype.applyRule = function(el, rule) {\n    var value = this.getElementAttributeToCheck(el);\n    var keyAndOptionsArray = this.getRuleKeyAndOptions(rule);\n\n    var keyAndOptions,\n        key,\n        validationRule,\n        options,\n        result,\n        failed = false;\n\n    for (var i = 0; i < keyAndOptionsArray.length; i++) {\n        keyAndOptions = keyAndOptionsArray[i];\n        key = keyAndOptions.key;\n        options = keyAndOptions.options;\n        validationRule = this.getValidationRuleByKey(key);\n        result = validationRule(value, options.value);\n\n        //return on first error\n        if (!result) {\n            break;\n        }\n    }\n\n    return {success: result, item: {el: el, text: options.text}};\n};\n\n\n/**\n * Validate given form object with given rules, if any errors occured this.errors array will be populated\n *\n * @return {tart.FormValidator} .\n */\ntart.FormValidator.prototype.validate = function() {\n    this.errors = [];\n    var el,\n        rule,\n        result;\n\n    for (var i in this.rules) {\n        el = this.getFormElementByName(i);\n        rule = this.rules[i];\n\n        result = this.applyRule(el, rule);\n\n        if (!result.success) {\n            this.errors.push(result.item);\n            break;\n        }\n    }\n\n    return this;\n};\n\n\n/**\n * Check if validation operation is successful or not by looking at this.errors array\n *\n * @return {boolean} validation is successful or not.\n */\ntart.FormValidator.prototype.isValid = function() {\n    if (this.errors.length == 0) {\n        return true;\n    }\n    else {\n        return false;\n    }\n};\n\n\n/**\n * Get generated errors array which contains element (el) and error text(text)\n *\n * @return {Array} errors array.\n */\ntart.FormValidator.prototype.getErrors = function() {\n    return this.errors;\n};\n\n\n/**\n * Validate form on submit\n *\n * @param {Function} callback callback function after submit.\n */\ntart.FormValidator.prototype.validateOnSubmit = function(callback) {\n    callback = callback || function() {};\n\n    var that = this;\n\n    this.form.submit(function(e) {\n        that.validate();\n        if (!that.isValid()) { //if an error occured\n            e.preventDefault();\n            e.stopImmediatePropagation(); //stop other events propagation\n            callback(that.getErrors());\n        }\n    });\n};\n"
  },
  {
    "path": "tart/FormValidator/README.md",
    "content": "# Tart FormValidator\n\nA JavaScript validation library which validates form elements using tart.Validation\n\n## Testing specs\n\nYou need [jasmine](http://pivotal.github.com/jasmine/) to run the specs\nYou better have [qasmine](https://github.com/tart/qasmine) to automatize the testing process\n\n### How to run qasmine\n\nSimlpy, run\n    \n    qasmine spec/SpecRunner.html\n\n\n## Validation checks\n\n* Rules should be written in object literal like this\n\n<pre>\nvar rules = {\n    testInput1 : {\n        isNumeric : {\n            text : \"Input is not numeric\"\n        },\n        hasMaxLength : {\n            text : \"Input's length is more than 9\",\n            value : 9\n        },\n        hasMinLength : {\n            text : \"Input's length is less than 6\",\n            value : 6\n        }\n    }\n};\n\n</pre>\n\n<pre>\nvar form = $(\"form\");\n\nvar rules = {\n    testInput1 : {\n        isNumeric : {\n            text : \"Input is not numeric\"\n        },\n        hasMaxLength : {\n            text : \"Input's length is more than 9\",\n            value : 9\n        },\n        hasMinLength : {\n            text : \"Input's length is less than 6\",\n            value : 6\n        }\n    }\n};\n\n\nvar validator = new tart.FormValidator(form);\n\nvalidator.setRules(rules).validate();\n\nif(validator.isValid()) {\n    //its valid\n}\nelse {\n    //its not valid, do some stuff with error object\n    var errors = validator.getErrors();\n}\n</pre>\n\n### Form bindings\nIt can also binded before form submit and validation process can be done automatically and \nresults will be returned to a callback function\n\n\n\n"
  },
  {
    "path": "tart/FormValidator/spec/FormValidatorSpec.js",
    "content": "goog.require('tart.FormValidator');\n\ngoog.provide('tart.FormValidator.SpecRunner');\n\ndescribe('Form Validator', function() {\n    var validator,\n        form,\n        formFields = [];\n\n    beforeEach(function() {\n        //create mock form object\n        form = $('<form>');\n        formFields[0] = $('<input>').attr('name', 'testInput1').appendTo(form);\n        formFields[1] = $('<input>').attr('name', 'testInput2').appendTo(form);\n\n        validator = new tart.FormValidator(form);\n    });\n\n    it('validator should be object', function() {\n        expect(typeof validator).toEqual('object');\n    });\n\n    describe('Form validator for email', function() {\n        var ruleErrorText = 'Not a valid email';\n\n        var rules = {\n            'testInput1': {\n                'isEmail': {\n                    'text': ruleErrorText\n                }\n            }\n        };\n\n\n        it(\"should validate an input which has 'foo@bar.com' as valid email\", function() {\n            formFields[0].val('foo@bar.com');\n\n            validator.setRules(rules).validate();\n            expect(validator.isValid()).toBeTruthy();\n        });\n\n\n        it(\"should not validate in input which has 'foo@bar.xxxxx' as valid email\", function() {\n            formFields[0].val('foo@bar.xxxxx');\n            validator.setRules(rules).validate();\n            expect(validator.isValid()).toBeFalsy();\n        });\n\n        it(\"should not validate in input which has 'foo@bar.xxxxx' with text 'Not a valid email'\", function() {\n            formFields[0].val('foo@bar.xxxxx');\n            validator.setRules(rules).validate();\n\n            var errorText = validator.getErrors()[0].text;\n            expect(errorText).toEqual(ruleErrorText);\n        });\n\n        it(\"should not validate in input which has '' an errr text should be 'Not a valid email'\", function() {\n            formFields[0].val(' ');\n            validator.setRules(rules).validate();\n\n            var errorText = validator.getErrors()[0].text;\n            expect(errorText).toEqual(ruleErrorText);\n        });\n\n    });\n\n\n    describe('Form validator for not only space', function() {\n        var ruleErrorText = 'You have ve to write at least one char or digit';\n\n        var rules = {\n            'testInput1': {\n                'isNotOnlySpace': {\n                    'text': ruleErrorText\n                }\n            }\n        };\n\n        it(\"should validate an input which starts with space but has some chars like '  foo   bar   '\", function() {\n            formFields[0].val('   foo   bar    ');\n\n            validator.setRules(rules).validate();\n            expect(validator.isValid()).toBeTruthy();\n        });\n\n\n        it(\"should not validate an input which has only spaces like '    '\", function() {\n            formFields[0].val('   ');\n\n            validator.setRules(rules).validate();\n            expect(validator.isValid()).toBeFalsy();\n        });\n\n        it(\"should not validate an empty string ''\", function() {\n            formFields[0].val('');\n\n            validator.setRules(rules).validate();\n            expect(validator.isValid()).toBeFalsy();\n        });\n\n        it(\"should return error text 'You have ve to write at least one char or digit' on error\", function() {\n            formFields[0].val('');\n\n            validator.setRules(rules).validate();\n            var errorText = validator.getErrors()[0].text;\n            expect(errorText).toEqual(ruleErrorText);\n        });\n\n\n\n    });\n\n    describe('Form validator for numeric control', function() {\n        var ruleErrorText = 'You can type only numbers between 0-9';\n\n        var rules = {\n            'testInput1': {\n                'isNumeric': {\n                    'text': ruleErrorText\n                }\n            }\n        };\n\n        it(\"should validate an input which has only numbers like '12345'\", function() {\n            formFields[0].val('12345');\n\n            validator.setRules(rules).validate();\n            expect(validator.isValid()).toBeTruthy();\n        });\n\n        it(\"should not validate an input which has numbers and space like ' 1234 5'\", function() {\n            formFields[0].val(' 1234 5');\n\n            validator.setRules(rules).validate();\n            expect(validator.isValid()).toBeFalsy();\n        });\n\n        it(\"should not validate an input which has numbers and chars  like '12345foo'\", function() {\n            formFields[0].val('12345foo');\n\n\n            validator.setRules(rules).validate();\n            expect(validator.isValid()).toBeFalsy();\n        });\n\n\n        it(\"should not validate input with text 'You can type only numbers between 0-9' for 'foo12345bar'\", function() {\n            formFields[0].val('foo12345foo');\n\n            validator.setRules(rules).validate();\n            var errorText = validator.getErrors()[0].text;\n            expect(errorText).toEqual(ruleErrorText);\n        });\n\n    });\n\n\n\n\n    describe('Form validator for input which contains both digit and non digit char', function() {\n        var ruleErrorText = 'Your input must contain both digit and non digit char';\n\n        var rules = {\n            'testInput1': {\n                'isDigitAndNonDigit': {\n                    'text': ruleErrorText\n                }\n            }\n        };\n\n        it(\"should not validate an input which has only numbers like '12345'\", function() {\n            formFields[0].val('12345');\n\n            validator.setRules(rules).validate();\n            expect(validator.isValid()).toBeFalsy();\n        });\n\n        it(\"should not validate an input which has only alpha chars 'foobar'\", function() {\n            formFields[0].val('foobar');\n\n            validator.setRules(rules).validate();\n            expect(validator.isValid()).toBeFalsy();\n        });\n\n        it(\"should not validate an input which has only spaces '    '\", function() {\n            formFields[0].val('    ');\n\n            validator.setRules(rules).validate();\n            expect(validator.isValid()).toBeFalsy();\n        });\n\n\n        it(\"should validate an input which has both digit and alpha chars 'foo12345bar'\", function() {\n            formFields[0].val('foo12345foo');\n\n            validator.setRules(rules).validate();\n            expect(validator.isValid()).toBeTruthy();\n        });\n\n        it(\"should validate an input which has both digit, alpha chars,no nalpha chars 'foo12345bar-_`'\", function() {\n            formFields[0].val('foo12345foo-_`');\n\n            validator.setRules(rules).validate();\n            expect(validator.isValid()).toBeTruthy();\n        });\n\n        it(\"should validate an input which has both digit and space chars like '12345 '\", function() {\n            formFields[0].val('12345 ');\n\n            validator.setRules(rules).validate();\n            expect(validator.isValid()).toBeTruthy();\n        });\n\n\n        it(\"should  not validate an input which has both alpha and space chars like 'foobar '\", function() {\n            formFields[0].val('foobar ');\n\n            validator.setRules(rules).validate();\n            expect(validator.isValid()).toBeFalsy();\n        });\n\n\n        it(\"should not validate an input which has non alpha chars and space chars like '~-? '\", function() {\n            formFields[0].val('~-? ');\n\n            validator.setRules(rules).validate();\n            expect(validator.isValid()).toBeFalsy();\n        });\n\n        it(\"should return text 'Your input must contain both digit and non digit char' for invalid input\", function() {\n            formFields[0].val('~-? ');\n\n            validator.setRules(rules).validate();\n            var errorText = validator.getErrors()[0].text;\n            expect(errorText).toEqual(ruleErrorText);\n        });\n\n    });\n\n\n    describe('Form validator to check inputs max length', function() {\n        var ruleErrorText = 'Your inputs lenght is more than 7';\n\n        var rules = {\n            'testInput1': {\n                'hasMaxLength': {\n                    'text': ruleErrorText,\n                    'value': 7\n                }\n            }\n        };\n\n        it(\"should validate an input like '12345'\", function() {\n            formFields[0].val('12345');\n\n            validator.setRules(rules).validate();\n            expect(validator.isValid()).toBeTruthy();\n        });\n\n        it(\"should not validate an input like '12345   '\", function() {\n            formFields[0].val('12345   ');\n\n            validator.setRules(rules).validate();\n            expect(validator.isValid()).toBeFalsy();\n        });\n\n        it(\"should not validate an input like '        '\", function() {\n            formFields[0].val('        ');\n\n            validator.setRules(rules).validate();\n            expect(validator.isValid()).toBeFalsy();\n        });\n\n        it(\"should validate an input like '123 5 7'\", function() {\n            formFields[0].val('123 5 7');\n\n            validator.setRules(rules).validate();\n            expect(validator.isValid()).toBeTruthy();\n        });\n\n\n        it(\"should return 'Your inputs lenght is more than 7' text on error\", function() {\n            formFields[0].val('123 5 7 foo bar');\n\n            validator.setRules(rules).validate();\n            var errorText = validator.getErrors()[0].text;\n            expect(errorText).toEqual(ruleErrorText);\n\n        });\n    });\n\n\n    describe('Form validator to check inputs min length', function() {\n        var ruleErrorText = 'Your inputs lenght is less than 3';\n\n        var rules = {\n            'testInput1': {\n                'hasMinLength': {\n                    'text': ruleErrorText,\n                    'value': 3\n                }\n            }\n        };\n\n        it(\"should validate an input like '12345'\", function() {\n            formFields[0].val('12345');\n\n            validator.setRules(rules).validate();\n            expect(validator.isValid()).toBeTruthy();\n        });\n\n        it(\"should not validate an input like '12'\", function() {\n            formFields[0].val('12');\n\n            validator.setRules(rules).validate();\n            expect(validator.isValid()).toBeFalsy();\n        });\n\n        it(\"should not validate an input like '  '\", function() {\n            formFields[0].val('  ');\n\n            validator.setRules(rules).validate();\n            expect(validator.isValid()).toBeFalsy();\n        });\n\n        it(\"should validate an input like '1  '\", function() {\n            formFields[0].val('1  ');\n\n            validator.setRules(rules).validate();\n            expect(validator.isValid()).toBeTruthy();\n        });\n\n\n        it(\"should return 'Your inputs lenght is less than 3' text on error\", function() {\n            formFields[0].val('12');\n\n            validator.setRules(rules).validate();\n\n            var errorText = validator.getErrors()[0].text;\n            expect(errorText).toEqual(ruleErrorText);\n        });\n    });\n\n\n    describe(\"Form validator to check input's numeric value\", function() {\n        var ruleErrorText = 'Your inputs value is more than 10';\n\n        var rules = {\n            'testInput1': {\n                'hasMaxValue': {\n                    'text': ruleErrorText,\n                    'value': 10\n                }\n            }\n        };\n\n\n        it(\"should validate an input like '1'\", function() {\n            formFields[0].val('1');\n\n            validator.setRules(rules).validate();\n            expect(validator.isValid()).toBeTruthy();\n        });\n\n        it(\"should not validate an input like '12'\", function() {\n            formFields[0].val('12');\n\n            validator.setRules(rules).validate();\n            expect(validator.isValid()).toBeFalsy();\n        });\n\n\n        it(\"should return 'Your inputs value is more than 10' text on error\", function() {\n            formFields[0].val('12');\n\n            validator.setRules(rules).validate();\n\n            var errorText = validator.getErrors()[0].text;\n            expect(errorText).toEqual(ruleErrorText);\n        });\n    });\n\n    describe(\"Form validator to check input's numeric value\", function() {\n        var ruleErrorText = 'Your inputs value is less than 10';\n\n        var rules = {\n            'testInput1': {\n                'hasMinValue': {\n                    'text': ruleErrorText,\n                    'value': 10\n                }\n            }\n        };\n\n\n        it(\"should not validate an input like '1'\", function() {\n            formFields[0].val('1');\n\n            validator.setRules(rules).validate();\n            expect(validator.isValid()).toBeFalsy();\n        });\n\n        it(\"should validate an input like '12'\", function() {\n            formFields[0].val('12');\n\n            validator.setRules(rules).validate();\n            expect(validator.isValid()).toBeTruthy();\n        });\n\n\n        it(\"should return 'Your inputs value is less than 10' text on error\", function() {\n            formFields[0].val('1');\n\n            validator.setRules(rules).validate();\n\n            var errorText = validator.getErrors()[0].text;\n            expect(errorText).toEqual(ruleErrorText);\n        });\n    });\n\n\n    describe('Form validator for multiple rules', function() {\n        var rules = {\n            'testInput1': {\n                'isNumeric': {\n                    'text': 'Input is not numeric'\n                },\n                'hasMaxLength': {\n                    'text': \"Input's length is more than 9\",\n                    'value': 9\n                },\n                'hasMinLength': {\n                    'text': \"Input's length is less than 6\",\n                    'value': 6\n                }\n            }\n        };\n\n\n        it(\"should not validate an input like 'fooobar'\", function() {\n            formFields[0].val('fooobar');\n\n            validator.setRules(rules).validate();\n            expect(validator.isValid()).toBeFalsy();\n        });\n\n        it(\"should validate an input like '123456'\", function() {\n            formFields[0].val('123456');\n\n            validator.setRules(rules).validate();\n            expect(validator.isValid()).toBeTruthy();\n        });\n\n\n        it(\"should not validate an input like '12345'\", function() {\n            formFields[0].val('12345');\n\n            validator.setRules(rules).validate();\n            expect(validator.isValid()).toBeFalsy();\n        });\n\n\n        it(\"should not validate an input like '12345678910'\", function() {\n            formFields[0].val('12345678910');\n\n            validator.setRules(rules).validate();\n            expect(validator.isValid()).toBeFalsy();\n        });\n\n\n        it(\"error text should be 'Input is not numeric' for 'foobar'\", function() {\n            formFields[0].val('foobar');\n            validator.setRules(rules).validate();\n\n            var errorText = validator.getErrors()[0].text;\n            expect(errorText).toEqual('Input is not numeric');\n        });\n\n\n        it(\"error text should be 'Input\\'s length is more than 9' for '1234567890'\", function() {\n            formFields[0].val('1234567890');\n            validator.setRules(rules).validate();\n\n            var errorText = validator.getErrors()[0].text;\n            expect(errorText).toEqual(\"Input's length is more than 9\");\n        });\n\n        it(\"error text should be 'Input\\'s length is less than 6' for '12345'\", function() {\n            formFields[0].val('12345');\n            validator.setRules(rules).validate();\n\n            var errorText = validator.getErrors()[0].text;\n            expect(errorText).toEqual(\"Input's length is less than 6\");\n        });\n\n    });\n\n\n    describe(\"Form validate validates form before form's submit\", function() {\n        var rules = {\n            'testInput1': {\n                'isNumeric': {\n                    'text': 'Input is not numeric'\n                },\n                'hasMaxLength': {\n                    'text': \"Input's length is more than 9\",\n                    'value': 9\n                },\n                'hasMinLength': {\n                    'text': \"Input's length is less than 6\",\n                    'value': 6\n                }\n            }\n        };\n\n\n        it('should validate form on submit and return generated errors in callback', function() {\n            formFields[0].val('foobar');\n\n            var errorObjects;\n\n            validator.setRules(rules).validateOnSubmit(function(errors) {\n                errorObjects = errors;\n            });\n\n            form.trigger('submit');\n\n            expect(errorObjects[0].el.get(0)).toEqual(formFields[0].get(0));\n            expect(errorObjects[0].text).toEqual('Input is not numeric');\n        });\n\n\n\n    });\n\n\n\n});\n\n\n/**\n * Run jasmine spec\n */\ntart.FormValidator.SpecRunner = function() {\n    jasmine.getEnv()['addReporter'](new jasmine.TrivialReporter());\n    jasmine.getEnv()['execute']();\n}();\n"
  },
  {
    "path": "tart/FormValidator/spec/SpecRunner.html",
    "content": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\n  \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n    <title>Jasmine Test Runner</title>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../../../third_party/jasmine/lib/jasmine.css\">\n    <script type=\"text/javascript\" src=\"../../../third_party/jasmine/lib/jasmine.js\"></script>\n    <script type=\"text/javascript\" src=\"../../../third_party/jasmine/lib/jasmine-html.js\"></script>\n\n    <!-- include source files here... -->\n    <script type=\"text/javascript\" src=\"../../../third_party/jquery/jquery-1.5.2.js\"></script>\n    <script type=\"text/javascript\" src=\"../../../third_party/goog/goog/base.js\"></script>\n    <script type=\"text/javascript\" src=\"../../Validation/Validation.js\"></script>\n    <script type=\"text/javascript\" src=\"../FormValidator.js\"></script>\n</head>\n<body>\n    <script type=\"text/javascript\" src=\"FormValidatorSpec.js\"></script>\n\n</body>\n</html>\n"
  },
  {
    "path": "tart/List.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview tart.List to handle List typed data structures extended from tart.Collection.\n */\n\ngoog.provide('tart.List');\n\ngoog.require('tart.Collection');\n\n\n\n/**\n * List data structure\n *\n * @extends {tart.Collection}\n * @constructor\n */\ntart.List = function() {\n    goog.base(this);\n\n    /** @private **/\n    this.keyCount_ = 0;\n};\ngoog.inherits(tart.List, tart.Collection);\n\n\n/**\n * Adds a new item to list .\n *\n * @param {*} value Value for the pair.\n * @return {boolean} .\n */\ntart.List.prototype.addItem = function(value) {\n    return tart.Collection.prototype.addItem.call(this, this.keyCount_++, value);\n};\n"
  },
  {
    "path": "tart/Pagination/CircularPagination.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\ngoog.require('tart.Pagination');\ngoog.provide('tart.CircularPagination');\n\n\n\n/**\n * CircularPagination class to handle circular paging events\n *\n * @constructor\n * @extends {tart.Pagination}\n */\ntart.CircularPagination = function() {\n\n    goog.base(this);\n};\ngoog.inherits(tart.CircularPagination, tart.Pagination);\n\n\n/**\n * Overriding tart.Pagination's hasPrev method, to return true for all conditions to make circular pages.\n *\n * @override\n * @return {boolean} Whether previous page is available .\n */\ntart.CircularPagination.prototype.hasPrev = function() {\n    return true;\n};\n\n\n/**\n * Overriding tart.Pagination's hasNext method, to return true for all conditions to make circular pages.\n *\n * @override\n * @return {boolean} Whether next page is available .\n */\ntart.CircularPagination.prototype.hasNext = function() {\n    return true;\n};\n\n\n/**\n * @override\n */\ntart.CircularPagination.prototype.getNext = function() {\n    return this.currentPage == this.getTotalPage() ? 1 : this.currentPage + 1;\n};\n\n\n/**\n * @override\n */\ntart.CircularPagination.prototype.getPrev = function() {\n    return this.currentPage == 1 ? this.getTotalPage() : this.currentPage - 1;\n};\n\n\n/**\n * @override\n */\ntart.CircularPagination.prototype.setCurrentPage = function(page) {\n    if (this.getTotalItems() > this.getItemPerPage()) {\n        var oldValue = this.currentPage;\n        this.currentPage = page;\n\n        this.triggerPageChange_(oldValue, page);\n    }\n\n    return this;\n};\n"
  },
  {
    "path": "tart/Pagination/Pagination.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview tart.Pagination is an event driven Pagination object.\n *\n * Example usage:\n *\n *     var paginator = new tart.Pagination();\n *\n *     paginator.setTotalPage(5);\n *     paginator.setCurrentPage(2);\n *\n *     goog.events.listen(paginator, tart.Pagination.EventTypes.PAGE_CHANGED, function (e) {\n *         console.log(\"page changed\");\n *         console.log(\"old page : \" + e.oldValue);\n *         console.log(\"new page : \" + e.newValue);\n *     });\n *\n *     paginator.setCurrentPage(4); // oldPage : 2, newPage : 4\n *     paginator.setCurrentPage(7); // oldPage : 4, newpage : 5 (totalPage)\n *     paginator.prev(); // oldPage : 5, newPage: 4\n *     paginator.setCurrentPage(0); // oldPage : 4, newpage : 1 (at least 1)\n *     paginator.next(); // oldPage : 1, newPage : 2\n *\n */\n\n\ngoog.require('goog.debug.ErrorHandler');\ngoog.require('goog.events.EventHandler');\ngoog.require('goog.events.EventTarget');\n\ngoog.provide('tart.Pagination');\n\n\n\n/**\n * Pagination class to handle all paging events\n *\n * @constructor\n * @extends {goog.events.EventTarget}\n */\ntart.Pagination = function() {\n\n    goog.events.EventTarget.call(this);\n\n    /** @private */\n    this.totalPage_ = 1;\n\n    /** @protected */\n    this.currentPage = 1;\n\n    /** @private */\n    this.itemPerPage_ = 1;\n\n    /** @private */\n    this.totalItems_ = 1;\n};\ngoog.inherits(tart.Pagination, goog.events.EventTarget);\n\n\n/**\n * Event types enumaration\n *\n * @enum {string}\n */\ntart.Pagination.EventTypes = {\n    PAGE_CHANGED: 'pageChanged'\n};\n\n\n/**\n * Trigger page change event\n *\n * @param {string|number} oldValue old page value.\n * @param {string|number} newValue new page value.\n * @protected\n */\ntart.Pagination.prototype.triggerPageChange_ = function(oldValue, newValue) {\n    if (oldValue != newValue)\n        this.dispatchEvent({type: tart.Pagination.EventTypes.PAGE_CHANGED, oldValue: oldValue, newValue: newValue});\n};\n\n\n/**\n * Get total page count\n *\n * @return {number} page count.\n */\ntart.Pagination.prototype.getTotalPage = function() {\n    return this.totalPage_;\n};\n\n\n/**\n * Set total page count\n *\n * @param {number} page page count.\n * @return {tart.Pagination} .\n */\ntart.Pagination.prototype.setTotalPage = function(page) {\n    this.totalPage_ = page;\n    this.totalItems_ = page * this.itemPerPage_;\n    return this;\n};\n\n\n/**\n * Get current page\n *\n * @return {number} current page.\n */\ntart.Pagination.prototype.getCurrentPage = function() {\n    return this.currentPage;\n};\n\n\n/**\n * Set current page\n *\n * @param {number} page current page.\n * @return {tart.Pagination} .\n */\ntart.Pagination.prototype.setCurrentPage = function(page) {\n    var oldValue = this.currentPage;\n\n    //if page > totalPage\n    page = (page > this.totalPage_) ? this.totalPage_ : page;\n\n    //if page < 1\n    page = (page < 1) ? 1 : page;\n\n    this.currentPage = page;\n\n    this.triggerPageChange_(oldValue, page);\n\n    return this;\n};\n\n\n/**\n * Get total item count\n *\n * @return {number} number of items.\n */\ntart.Pagination.prototype.getTotalItems = function() {\n    return this.totalItems_;\n};\n\n\n/**\n * Set number of items\n *\n * @param {number} itemCount number of items.\n * @return {tart.Pagination} .\n */\ntart.Pagination.prototype.setTotalItems = function(itemCount) {\n    this.totalItems_ = itemCount;\n    this.totalPage_ = Math.ceil(itemCount / this.itemPerPage_);\n    return this;\n};\n\n\n/**\n * Get number of items to be listed in a page\n *\n * @return {number} number of items in a page.\n */\ntart.Pagination.prototype.getItemPerPage = function() {\n    return this.itemPerPage_;\n};\n\n\n/**\n * set number of items to be listed in a page\n *\n * @param {number} itemPerPage number of items in a page.\n * @return {tart.Pagination} .\n */\ntart.Pagination.prototype.setItemPerPage = function(itemPerPage) {\n    this.itemPerPage_ = itemPerPage;\n    return this;\n};\n\n\n/**\n * Determine if next page is available\n *\n * @return {boolean} is next page available.\n */\ntart.Pagination.prototype.hasNext = function() {\n    return this.currentPage + 1 <= this.totalPage_;\n};\n\n\n/**\n * Get next page\n *\n * @return {number} next page number.\n */\ntart.Pagination.prototype.getNext = function() {\n    return this.hasNext() ? this.currentPage + 1 : this.currentPage;\n};\n\n\n/**\n * Determine if previous page is available\n *\n * @return {boolean} is previous page available.\n */\ntart.Pagination.prototype.hasPrev = function() {\n    return this.currentPage - 1 >= 1;\n};\n\n\n/**\n * Get previous page\n *\n * @return {number} previous page number.\n */\ntart.Pagination.prototype.getPrev = function() {\n    return this.hasPrev() ? this.currentPage - 1 : this.currentPage;\n};\n\n\n/**\n * Change page to next page\n */\ntart.Pagination.prototype.next = function() {\n    var oldValue = this.currentPage;\n    this.currentPage = this.getNext();\n    this.triggerPageChange_(oldValue, this.currentPage);\n};\n\n\n/**\n * Change page to previous page\n */\ntart.Pagination.prototype.prev = function() {\n    var oldValue = this.currentPage;\n    this.currentPage = this.getPrev();\n    this.triggerPageChange_(oldValue, this.currentPage);\n};\n"
  },
  {
    "path": "tart/Pagination/spec/PaginationSpec.js",
    "content": "goog.require('tart.Pagination');\n\ngoog.provide('tart.Pagination.SpecRunner');\n\ndescribe('Pagination', function() {\n    var paginator;\n\n    beforeEach(function() {\n        paginator = new tart.Pagination();\n    });\n\n\n    describe('should contain required parameters', function()  {\n\n        it('should have totalPage', function() {\n            expect(paginator.getTotalPage()).toBeGreaterThan(0);\n        });\n\n        it('should have currentPage', function() {\n            expect(paginator.getCurrentPage()).toBeGreaterThan(0);\n        });\n\n        it('should have itemPerPage', function() {\n            expect(paginator.getItemPerPage()).toBeGreaterThan(0);\n        });\n\n        it('should have totalItems', function() {\n            expect(paginator.getTotalItems()).toBeGreaterThan(0);\n        });\n\n\n\n        it('should set totalPage', function() {\n            paginator.setTotalPage(5);\n            expect(paginator.getTotalPage()).toEqual(5);\n        });\n\n        it('should set currentPage', function() {\n            paginator.setTotalPage(5);\n            paginator.setCurrentPage(5);\n            expect(paginator.getCurrentPage()).toEqual(5);\n        });\n\n        it('should set itemPerPage', function() {\n            paginator.setItemPerPage(2);\n            expect(paginator.getItemPerPage()).toEqual(2);\n        });\n\n        it('should set totalItems', function() {\n            paginator.setTotalItems(2);\n            expect(paginator.getTotalItems()).toEqual(2);\n        });\n\n\n        it('should change page count when totalItem count set', function() {\n            paginator.setItemPerPage(2);\n            paginator.setTotalItems(5);\n            expect(paginator.getTotalPage()).toEqual(3);\n        });\n\n\n        it('should change item count when totalPage count set', function() {\n            paginator.setItemPerPage(2);\n            paginator.setTotalPage(4);\n            expect(paginator.getTotalItems()).toEqual(8);\n        });\n\n        it('should set page count to totalPageCount if page > totalPageCount', function() {\n            paginator.setTotalPage(5);\n            paginator.setCurrentPage(6);\n            expect(paginator.getCurrentPage()).toEqual(5);\n        });\n\n        it('should set page count to 1 if page < 1', function() {\n            paginator.setTotalPage(5);\n            paginator.setCurrentPage(0);\n            expect(paginator.getCurrentPage()).toEqual(1);\n        });\n\n\n\n    });\n\n    describe('controls navigation', function() {\n        it('should have a next element if currentPage < totalPage', function() {\n            paginator.setCurrentPage(3);\n            paginator.setTotalPage(4);\n            expect(paginator.hasNext()).toBeTruthy();\n        });\n\n        it('should not have a next element if currentPage >= totalPage', function() {\n            paginator.setTotalPage(4).setCurrentPage(4);\n            paginator.setTotalPage(4);\n            expect(paginator.hasNext()).toBeFalsy();\n        });\n\n        it('should have a previous element if currentPage > 1', function() {\n            paginator.setTotalPage(4).setCurrentPage(2);\n            expect(paginator.hasPrev()).toBeTruthy();\n        });\n\n        it('should not have a next element if currentPage <= 1', function() {\n            paginator.setCurrentPage(1);\n            paginator.setTotalPage(4);\n            expect(paginator.hasPrev()).toBeFalsy();\n        });\n\n    });\n\n    describe('triggers pageChanged event on some conditions', function() {\n        it('should trigger event on setCurrentPage', function() {\n\n            var triggeredObject = {};\n\n            goog.events.listen(paginator, tart.Pagination.EventTypes.PAGE_CHANGED, function(e) {\n                triggeredObject = e;\n            });\n\n            paginator.setCurrentPage(10);\n\n            //check if newValue and oldValue exists\n            expect(triggeredObject.oldValue && triggeredObject.newValue).toBeTruthy();\n\n        });\n\n\n        it('should trigger event on next()', function() {\n            paginator.setTotalPage(12);\n            paginator.setCurrentPage(10);\n\n            var triggeredObject = {};\n\n            goog.events.listen(paginator, tart.Pagination.EventTypes.PAGE_CHANGED, function(e) {\n                triggeredObject = e;\n            });\n\n            paginator.next();\n\n            //check if newValue and oldValue exists\n            expect(triggeredObject.oldValue && triggeredObject.newValue).toBeTruthy();\n\n        });\n\n        it('should trigger event on prev()', function() {\n            paginator.setTotalPage(12);\n            paginator.setCurrentPage(10);\n\n            var triggeredObject = {};\n\n            goog.events.listen(paginator, tart.Pagination.EventTypes.PAGE_CHANGED, function(e) {\n                triggeredObject = e;\n            });\n\n            paginator.prev();\n\n            //check if newValue and oldValue exists\n            expect(triggeredObject.oldValue && triggeredObject.newValue).toBeTruthy();\n\n        });\n    });\n});\n\n\n/**\n * Run jasmine spec\n */\ntart.Pagination.SpecRunner = function() {\n    jasmine.getEnv()['addReporter'](new jasmine.TrivialReporter());\n    jasmine.getEnv()['execute']();\n}();\n"
  },
  {
    "path": "tart/Pagination/spec/SpecRunner.html",
    "content": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\n  \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n    <title>Jasmine Test Runner</title>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../../../third_party/jasmine/lib/jasmine.css\">\n    <script type=\"text/javascript\" src=\"../../../third_party/jasmine/lib/jasmine.js\"></script>\n    <script type=\"text/javascript\" src=\"../../../third_party/jasmine/lib/jasmine-html.js\"></script>\n\n    <!-- include source files here... -->\n    <script type=\"text/javascript\" src=\"../../../third_party/jquery/jquery-1.5.2.js\"></script>\n    <script type=\"text/javascript\" src=\"../../../third_party/goog/goog/base.js\"></script>\n\n    <script type=\"text/javascript\">\n        goog.require(\"goog.events.EventTarget\");\n    </script>\n\n    <script type=\"text/javascript\" src=\"../Pagination.js\"></script>\n</head>\n<body>\n    <!-- include spec files here... -->\n    <script type=\"text/javascript\" src=\"PaginationSpec.js\"></script>\n\n</body>\n</html>\n"
  },
  {
    "path": "tart/Registry.js",
    "content": "// Copyright (c) 2009-2010 Techinox Information Technologies (http://www.techinox.com)\n// Techinox Commercial License\n//\n// @author Armagan Amcalar <armagan@tart.com.tr>\n\n/**\n * @fileoverview tart.Registry is a convenience class that wraps goog.structs.Map and is intended to use as\n * a global registry across a web application.\n */\n\ngoog.provide('tart.Registry');\ngoog.require('goog.structs.Map');\n\n\n\n/**\n * tart Registry class.\n * @constructor\n * @extends {goog.structs.Map}\n */\ntart.Registry = function() {\n    goog.base(this);\n};\ngoog.inherits(tart.Registry, goog.structs.Map);\n"
  },
  {
    "path": "tart/StateMachine/State.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview State class is used in conjunction with tart.StateMachine. It is a value object that holds two\n * properties; a function that is executed when the state machine is in this state, and a transitions object for\n * events that may happen in this state.\n */\n\ngoog.provide('tart.State');\n\n\n\n/**\n * Tart State class for state machines.\n * @constructor\n * @param {function()} fn The state function to be executed.\n */\ntart.State = function(fn) {\n    this.fn = fn;\n    this.transitions = {};\n};\n"
  },
  {
    "path": "tart/StateMachine/StateMachine.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview This class is an implementation of a Moore state machine that is common in digital electronics, etc.\n *\n * The state machine is by it's nature an event-driven system. Events that come at the right state will put the state\n * machine in another expected state.\n *\n * To keep the implementation simple, many details are omitted. The state machine doesn't keep a record of its\n * states, new states cannot be added after a state machine is started, etc. These rules do not prevent\n * the functioning of the machine though.\n *\n * This class is a base class and not intended to be used on its own. To use a state machine, the developer has to\n * subclass this base class and override the <code>createStates_</code> method. This method should hold the\n * initialization of states in the state machine and should return the first state the machine should begin with.\n *\n * This implementation features lazy loading in the sense that the <code>createStates_</code> method is not called\n * until the first call to <code>startMachine</code> method.\n *\n * Example usage:\n *\n *     Foo.MooreMachine = function(){\n *         goog.base(this);\n *     }\n *     goog.inherits(Foo.MooreMachine, tart.StateMachine);\n *\n *     // Having an enumerated type for events helps readability\n *     Foo.MooreMachine.Events = {\n *         CLICK: '0',\n *         DOUBLECLICK: '1'\n *     }\n *\n *     Foo.MooreMachine.prototype.createStates_ = function(){\n *         var STATE1 = new tart.State(function(){\n *             console.log(\"state 1\");\n *         });\n *\n *         var STATE2 = new tart.State(function(){\n *             console.log(\"state 2\");\n *         });\n *\n *         STATE1.transitions[Foo.MooreMachine.Events.CLICK] = STATE2;\n *         STATE2.transitions[Foo.MooreMachine.Events.DOUBLECLICK] = STATE1;\n *\n *         this.addState_(STATE1);\n *         this.addState_(STATE2);\n *\n *         return STATE1;\n *     }\n *\n *     var myMachine = new Foo.MooreMachine();\n *     myMachine.startMachine();\n *\n */\n\ngoog.require('goog.array');\ngoog.require('goog.pubsub.PubSub');\ngoog.require('tart.State');\ngoog.provide('tart.StateMachine');\n\n\n\n/**\n * Tart State Machine Class\n * @constructor\n * @extends {goog.pubsub.PubSub}\n */\ntart.StateMachine = function() {\n    goog.base(this);\n    /**\n     * @type {Array.<string>}\n     * @private\n     */\n    this.events_ = [];\n    this.currentState = undefined;\n};\ngoog.inherits(tart.StateMachine, goog.pubsub.PubSub);\n\n\n/**\n * Adds a state to the state machine.\n * @param {tart.State} state State to be added.\n * @protected\n */\ntart.StateMachine.prototype.addState = function(state) {\n    for (var event in state.transitions) {\n        goog.array.insert(this.events_, event);\n    }\n};\n\n\n/**\n * Sets the current state disregarding the previous one, and executes it's function.\n * @param {tart.State} state State to be set as the current state.\n * @param {Array.<*>=} opt_args Arguments to pass to the new state.\n * @protected\n */\ntart.StateMachine.prototype.setCurrentState = function(state, opt_args) {\n    opt_args = opt_args || [];\n    this.currentState = state;\n    this.currentState.fn.apply(this, opt_args);\n};\n\n\n/**\n * Starts the state machine. If it's the first time this function is called, it also lazy loads the states via\n * <code>createStates</code> method.\n */\ntart.StateMachine.prototype.startMachine = function() {\n    if (this.currentState == undefined) {\n        this.firstState = this.createStates();\n        this.bindEvents_();\n        this.setCurrentState(this.firstState);\n    }\n};\n\n\ntart.StateMachine.prototype.reset = function() {\n    this.firstState && this.setCurrentState(this.firstState);\n};\n\n\n/**\n * This should be overridden by child classes. It holds the initialization of states and is called when the\n * <code>startMachine</code> method is called for the first time.\n * @return {tart.State} The first state that the machine will start with.\n */\ntart.StateMachine.prototype.createStates = goog.abstractMethod;\n\n\n/**\n * Subscribes its <code>handleEvent_</code> function to its every event\n * @private\n */\ntart.StateMachine.prototype.bindEvents_ = function() {\n    var self = this;\n    for (var i = 0, l = self.events_.length; i < l; i++) {\n        var eventName = self.events_[i];\n        self.subscribe(eventName, self.handleEvent_(self, eventName));\n    }\n};\n\n\n/**\n * Handles incoming events. If any of the events are in the transitions list for the current state, that transition's\n * target state becomes the current state.\n * @param {tart.StateMachine} self The State Machine instance (due to the nature of goog.pubsub.PubSub.subscribe,\n *                                 this function loses its scope. This variable corrects it).\n * @param {string} event The event to handle.\n * @return {function()} Returns a closure to use as an eventHandler.\n * @private\n */\ntart.StateMachine.prototype.handleEvent_ = function(self, event) {\n    return function() {\n        var nextState = self.currentState.transitions[event];\n        if (nextState) {\n            self.setCurrentState(nextState, Array.prototype.slice.call(arguments));\n        }\n    }\n};\n"
  },
  {
    "path": "tart/Tabs/TabPanel.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview Creates an instance with a tab and panel for using with an existing tabpanel.\n *\n * Example Usage:\n *\n *     var panel1 = new tart.TabPanel({\n *         title: 'Tab 1',\n *         html: 'This is a basic text'\n *     });\n *\n*/\n\ngoog.provide('tart.TabPanel');\ngoog.require('goog.pubsub.PubSub');\n\n\n\n/**\n * Returns an instance of tab and panel for using it in an tabpanel\n * Options object should include a title as tab's title and html as panel's default html\n * If Options object is ommited, an empty string will appended as tab title and panel html\n * @constructor\n * @extends {goog.pubsub.PubSub}\n * @param {Object=} options Customized options for panel instance.\n */\ntart.TabPanel = function(options) {\n    goog.base(this);\n    this.initOptions(options);\n    this.$tab = $(this.templates_tab());\n    this.$panel = $(this.templates_panel());\n};\ngoog.inherits(tart.TabPanel, goog.pubsub.PubSub);\n\n\n/**\n * Merges custom options object with defaults\n * @protected\n * @param {Object=} options Custom config object.\n */\ntart.TabPanel.prototype.initOptions = function(options) {\n    this.props = {};\n    options = options || {};\n    this.props.panelCssClass = options['panelCssClass'] || '';\n    this.props.tabCssClass = options['tabCssClass'] || '';\n    this.props.title = options.title || '';\n    this.props.html = options.html || '';\n};\n\n\n/**\n * @return {string} Tab markup.\n */\ntart.TabPanel.prototype.templates_tab = function() {\n    return '<div class=\"tartTab ' + this.props.tabCssClass + '\">' + this.props.title + '</div>';\n};\n\n\n/**\n * @return {string} Panel markup.\n */\ntart.TabPanel.prototype.templates_panel = function() {\n    return '<div class=\"tartPanel ' + this.props.panelCssClass + '\">' + this.props.html + '</div>';\n};\n\n\n/**\n * Callback function that will be triggered before a TabPanel instance is shown.\n * @type {Function|undefined}\n */\ntart.TabPanel.prototype.onShow = undefined;\n\n\n/**\n * Callback function that will be triggered before a TabPanel instance is shown.\n * @type {Function|undefined}\n */\ntart.TabPanel.prototype.onClose = undefined;\n"
  },
  {
    "path": "tart/Tabs/Tabs.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview Tabs is a fully working and customizable tab panel creator class.\n *\n * Example Usage:\n *\n *\n *     var tabPanel = new tart.Tabs({\n *         activeTab: 1\n *     });\n *\n *     var panel1 = new tart.TabPanel({\n *         title: 'Tab 1',\n *         html: 'This is a basic text'\n *     });\n *     var panel2 = new tart.TabPanel({\n *         title: 'Tab 2',\n *         html: 'Lorem ipsum dolor sit amet'\n *     });\n *     var panel3 = new tart.TabPanel({\n *         title: 'Tab 3',\n *         html: 'Lorem ipsum dolor sit amet is a dummy text'\n *     });\n *\n *     tabPanel.addTabPanel(panel1);\n *     tabPanel.addTabPanel(panel2);\n *     tabPanel.addTabPanel(panel3);\n *\n *     var dom = tabPanel.buildDOM();\n *     $('body').append(dom);\n *\n*/\n\ngoog.provide('tart.Tabs');\ngoog.require('goog.pubsub.PubSub');\ngoog.require('tart.TabPanel');\n\n\n\n/**\n * Tabs is a fully working and customizable tab panel creator class\n * @constructor\n * @param {Object=} options Customized initial options for tabpanel.\n * @extends {goog.pubsub.PubSub}\n */\ntart.Tabs = function(options) {\n    goog.base(this);\n    options = options || {};\n    this.initOptions(options);\n\n    this.$tabContainer = $(this.templates_tabContainer());\n    this.$panelContainer = $(this.templates_panelContainer());\n\n    /**\n     * Holds TabPanel objects associated with the tabpanel\n     * @type {Array.<tart.TabPanel>}\n     * @protected\n     */\n    this.tabPanels = [];\n\n    /**\n     * State of tab panel\n     * @protected\n     */\n    this.rendered = false;\n\n    this.initialize(this.props.renderConfig);\n};\ngoog.inherits(tart.Tabs, goog.pubsub.PubSub);\n\n\n/**\n * Initialize the tabpanel with calling buildDOM method\n * @param {!string} renderCfg Where to container will be appended.\n */\ntart.Tabs.prototype.initialize = function(renderCfg) {\n    var panelDOM = this.buildDOM();\n    if (renderCfg.insertAfter) {\n        panelDOM.insertAfter(renderCfg.insertAfter);\n    }\n    else if (renderCfg.insertBefore) {\n        panelDOM.insertBefore(renderCfg.insertBefore);\n    }\n    else if (renderCfg.append) {\n        renderCfg.append.append(panelDOM);\n    }\n};\n\n\n/**\n * Adds new tab to existing tab panel\n * @param {!(Array|tart.TabPanel)} tabPanels An array that holds instance of TabPanel Class to add new tab.\n * Also tabPanels argument should be a tab panel instance instead of array.\n */\ntart.Tabs.prototype.addTabPanel = function(tabPanels) {\n    var that = this;\n    if (goog.isArray(tabPanels)) {\n        for (var i = 0, len = tabPanels.length; i < len; i++) {\n            that.addTab(tabPanels[i]);\n        }\n    } else {\n        that.addTab(tabPanels);\n    }\n    this.setActiveTab(this.activeTab);\n};\n\n\n/**\n * Adds a new tab to a Tabs instance.\n * @param {tart.TabPanel} tabPanel instance that's going to be added to a Tabs instance.\n */\ntart.Tabs.prototype.addTab = function(tabPanel) {\n    this.tabPanels.push(tabPanel);\n    this.$tabContainer.append(tabPanel.$tab);\n    this.$panelContainer.append(tabPanel.$panel);\n    this.bindTabPanelEvents(tabPanel);\n};\n\n\n/**\n * Removes the tab with the given index.\n * @param {!number} index Index number of the tab that you want to remove.\n */\ntart.Tabs.prototype.removeTab = function(index) {\n    var tabsLength = this.getTabsLength();\n\n    if (index >= tabsLength || tabsLength === 0) {\n        return;\n    }\n\n    this.tabPanels[index].$tab.remove();\n    this.tabPanels[index].$panel.remove();\n    this.tabPanels.splice(index, 1);\n\n    try {\n        if (index <= this.activeTab) {\n            if (index === this.activeTab) {\n                this.setActiveTab(index - 1);\n            } else {\n                this.setActiveTab(this.activeTab - 1);\n            }\n        }\n    } catch (e) {}\n};\n\n\n/**\n * Sets the tab as active with the given index.\n * @param {!number} index Index number of the tab that you want to set as active.\n */\ntart.Tabs.prototype.setActiveTab = function(index) {\n    if (index >= this.getTabsLength()) {\n        return false;\n    }\n\n    var deActivatedTab = this.getActiveTab();\n\n    for (var i = 0, len = this.tabPanels.length; i < len; i++) {\n        if (index != i) {\n            this.tabPanels[i].$tab.removeClass(this.props.activeTabCssClass);\n            this.tabPanels[i].$panel.removeClass(this.props.activePanelCssClass);\n        }\n    }\n    this.tabPanels[index].$tab.addClass(this.props.activeTabCssClass);\n    this.tabPanels[index].$panel.addClass(this.props.activePanelCssClass);\n    this.activeTab = index;\n\n    var newlyActivatedTab = this.getActiveTab();\n\n    if (deActivatedTab.onClose && deActivatedTab != newlyActivatedTab) /* prevent double fn call on initialize */\n\t        deActivatedTab.onClose(this);\n\n\tnewlyActivatedTab.onShow && newlyActivatedTab.onShow(this); // call newly activated tab's onShow function\n\tthis.publish('tabChange', this.getActiveTab(), this);\n};\n\n\n/**\n * Returns the active tab object contains tab and panel elements and templates that used in tab and panel.\n * @return {tart.TabPanel} The active tab.\n */\ntart.Tabs.prototype.getActiveTab = function() {\n    return this.tabPanels[this.activeTab];\n};\n\n\n/**\n * Binds required events of tabpanel.\n * @param {!tart.TabPanel} tabPanel Tabpanel instance for binding events to it.\n */\ntart.Tabs.prototype.bindTabPanelEvents = function(tabPanel) {\n    var that = this;\n\n    var setMeActive = function() {\n        var myIndex = goog.array.indexOf(that.tabPanels, tabPanel);\n        that.setActiveTab(myIndex);\n    };\n\n    tabPanel.$tab.click(setMeActive);\n};\n\n\n/**\n * Builds DOM elements for tabpanel and returns DOM as ready to append to a container\n * @return {jQueryObject} DOM element of the Tabs instance.\n */\ntart.Tabs.prototype.buildDOM = function() {\n    this.$dom = $(this.templates_dom());\n    this.$dom.append(this.$tabContainer);\n    this.$dom.append(this.$panelContainer);\n    this.rendered = true;\n    return this.$dom;\n};\n\n\n/**\n * @return {boolean} The status of tabpanel, rendered or not.\n */\ntart.Tabs.prototype.isRendered = function() {\n    return this.rendered;\n};\n\n\n/**\n * @return {number} number of tabs associated with the Tabs instance.\n */\ntart.Tabs.prototype.getTabsLength = function() {\n    return this.tabPanels.length;\n};\n\n\n/**\n * Merges custom options object with defaults\n * @protected\n * @param {Object=} options Customized options for Tabs instance.\n */\ntart.Tabs.prototype.initOptions = function(options) {\n    var props = this.props = {};\n    props.axis = options.axis || 'x';\n    this.activeTab = options.activeTab || 0;\n\n    props.renderConfig = options.renderConfig || {};\n\n    props.tabPanelCssClass = options.tabPanelCssClass || '';\n    props.tabContainerCssClass = options.tabContainerCssClass || '';\n    props.panelContainerCssClass = options.panelContainerCssClass || '';\n    props.activeTabCssClass = options.activeTabCssClass || 'tartActiveTab';\n    props.activePanelCssClass = options.activePanelCssClass || 'tartActivePanel';\n    props.panelWrapperCssClass = options.panelWrapperCssClass || '';\n};\n\n\n/**\n * @return {string} Main container markup.\n */\ntart.Tabs.prototype.templates_dom = function() {\n    return '<div class=\"tartTabPanelContainer ' + this.props.tabPanelCssClass + '\"></div>';\n};\n\n\n/**\n * @return {string} Tab container markup.\n */\ntart.Tabs.prototype.templates_tabContainer = function() {\n    return '<div class=\"tartTabContainer ' + this.props.tabContainerCssClass + '\"></div>';\n};\n\n\n/**\n * @return {string} Panel container markup.\n */\ntart.Tabs.prototype.templates_panelContainer = function() {\n    return '<div class=\"tartPanelContainer ' + this.props.panelContainerCssClass + '\"></div>';\n};\n"
  },
  {
    "path": "tart/Validation/README.md",
    "content": "# Tart Validator\n\nA JavaScript validation library\n\n## Testing specs\n\nYou need [jasmine](http://pivotal.github.com/jasmine/) to run the specs\nYou better have [qasmine](https://github.com/tart/qasmine) to automatize the testing process\n\n### How to run qasmine\n\nSimlpy, run\n    \n    qasmine spec/SpecRunner.html\n\n\n## Validation checks\n\n* is.email(string) : Checks string as a valid email\n* is.notOnlySpace(string) : Checks string that it doesnt contains only from whitespaces\n* is.numeric(string) : Checks string that only contains numeric values\n* is.digitAndNonDigit(string) : Checks string which contains both digits and non-digit chars, can be useful to check passwords' strength\n* has.maxLength(string, value) : Checks string for max length\n* has.minlength(string, value) : Checks string for min length\n* has.minValue(number, value) : Cheks number for its min value\n* has.maxValue(number, value) : Cheks number for its max value\n"
  },
  {
    "path": "tart/Validation/Validation.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview tart.Validation is a validation library which checks for variable's format (such as email, number) or\n * attribute (such as char length).\n *\n * Example usage:\n *\n *     var validator = tart.Validation;\n *     var isValidEmail = validator.is.email(\"foo@bar.com\"); //returns boolean true\n *     var isNumeric = validator.is.numeric(\"123foo\"); // returns boolean false\n *     var hasMaxLength10 = validator.has.maxLength(\"foobar\", 10); //returns boolean true\n *\n *\n * More examples can be seen from spec/ValidationSpec.js file\n */\n\ngoog.provide('tart.Validation');\n\ngoog.provide('tart.Validation.has');\ngoog.provide('tart.Validation.is');\n\n\n/**\n * Checks if given text is valid email\n *\n * @param {string} text email text to be validated.\n * @return {boolean} true if its valid email.\n */\ntart.Validation.is.email = function(text) {\n    var pattern = /^([A-Za-z0-9_\\-\\.])+\\@([A-Za-z0-9_\\-\\.])+\\.([A-Za-z]{2,4})$/;\n    return pattern.test(text);\n};\n\n\n/**\n * Checks if a value is true.\n *\n * @param {boolean} value value to check.\n * @return {boolean} true if value evaluates to true.\n */\ntart.Validation.is.truthy = function(value) {\n    return value == true;\n};\n\n\n/**\n * Checks if given text doesnt contains only white spaces but some chars or numbers\n *\n * @param {string} text text to be validated.\n * @return {boolean} true if text contains any char or number.\n */\ntart.Validation.is.notOnlySpace = function(text) {\n    var result = text.replace(/^\\s+|\\s+$/g, '').length > 0;\n    return result;\n};\n\n\n/**\n * Checks if given text contains only numeric chars\n *\n * @param {string} text text to be validated.\n * @return {boolean} true if text contains only numbers.\n */\ntart.Validation.is.numeric = function(text) {\n    var pattern = /^[0-9]+$/;\n    return pattern.test(text);\n};\n\n\n/**\n * Checks if given text contains both digit and non-digit chars\n *\n * @param {string} text text to be validated.\n * @return {boolean} true if text contains both digit and non-digit chars.\n */\ntart.Validation.is.digitAndNonDigit = function(text) {\n    var pattern = /(\\d\\D)|(\\D\\d)/;\n    return pattern.test(text);\n};\n\n\n/**\n * Checks if both given arguments  are equal\n *\n * @param {*} arg1 item to be validated.\n * @param {*} arg2 item to be validated.\n * @return {boolean} true if both arguments are equal.\n */\ntart.Validation.is.equal = function(arg1, arg2) {\n    return arg1 == arg2;\n};\n\n\n/**\n * Checks for strings' min length\n *\n * @param {string} text string to check for char length.\n * @param {number} value char length value.\n * @return {boolean} true if string's length > value.\n */\ntart.Validation.has.minLength = function(text, value) {\n    return (text.length >= value);\n};\n\n\n/**\n * Checks for string's max length\n *\n * @param {string} text string to check for char length.\n * @param {number} value char length value.\n * @return {boolean} true if string's length < value.\n */\ntart.Validation.has.maxLength = function(text, value) {\n    return (text.length <= value);\n};\n\n\n/**\n * Checks for string or number's min numeric value\n *\n * @param {string|number} num number to check value for.\n * @param {number} value value to check.\n * @return {boolean} true if string's num < value.\n */\ntart.Validation.has.minValue = function(num, value) {\n    return num >= value;\n};\n\n\n/**\n * Checks for string or number's max numeric value\n *\n * @param {string|number} num number to check value for.\n * @param {number} value value to check.\n * @return {boolean} true if string's num > value.\n */\ntart.Validation.has.maxValue = function(num, value) {\n    return num <= value;\n};\n"
  },
  {
    "path": "tart/Validation/spec/SpecRunner.html",
    "content": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\n  \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n    <title>Jasmine Test Runner</title>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../../../third_party/jasmine/lib/jasmine.css\">\n    <script type=\"text/javascript\" src=\"../../../third_party/jasmine/lib/jasmine.js\"></script>\n    <script type=\"text/javascript\" src=\"../../../third_party/jasmine/lib/jasmine-html.js\"></script>\n    \n    <!-- include source files here... -->\n    <script type=\"text/javascript\" src=\"../../../third_party/jquery/jquery-1.5.2.js\"></script>\n    <script type=\"text/javascript\" src=\"../../../third_party/goog/goog/base.js\"></script>\n    <script type=\"text/javascript\" src=\"../Validation.js\"></script>\n</head>\n<body>\n    <script type=\"text/javascript\" src=\"ValidationSpec.js\"></script>\n    \n</body>\n</html>\n"
  },
  {
    "path": "tart/Validation/spec/ValidationSpec.js",
    "content": "goog.require('tart.Validation');\n\ngoog.provide('tart.Validation.SpecRunner');\n\ndescribe('Validation', function() {\n    var validator;\n\n    beforeEach(function() {\n        validator = tart.Validation;\n    });\n\n    it('validator should be object', function() {\n        expect(typeof validator).toEqual('object');\n    });\n\n\n    describe('Validation.is', function() {\n\n        describe('Validation.is.email', function() {\n\n            it('regular email like alnum1@alnum2.tld should pass', function() {\n                var result = validator.is.email('alnum1@alnum2.tld');\n                expect(result).toBeTruthy();\n            });\n\n\n            it('should not validate an email which has alnum1@alnum2.tldmorethan4chars', function() {\n                var result = validator.is.email('alnum1@alnum2.tldmorethan4chars');\n                expect(result).toBeFalsy();\n            });\n\n\n            it('should not validate an email which containts non@alhanümeric.çars ', function() {\n                var result = validator.is.email('non@alhanümeric.çars');\n                expect(result).toBeFalsy();\n            });\n\n            it('should validate an email which belongs@to.a.sub.dom.ain', function() {\n                var result = validator.is.email('belongs@to.a.sub.dom.ain');\n                expect(result).toBeTruthy();\n            });\n\n            it('should not validate email which contains@space.com', function() {\n                var result = validator.is.email('which contains@space.com');\n                expect(result).toBeFalsy();\n            });\n\n        });\n\n        describe('Validation.is.notOnlySpace', function() {\n            it('should not validate an input which has only white space', function() {\n                var result = validator.is.notOnlySpace('   ');\n                expect(result).toBeFalsy();\n            });\n\n            it('should validate an input which starts with whitespace but has other chars', function() {\n                var result = validator.is.notOnlySpace('   foobar');\n                expect(result).toBeTruthy();\n            });\n\n            it('should validate an input which starts and ends with whitespace but has other chars', function() {\n                var result = validator.is.notOnlySpace('   foobar    ');\n                expect(result).toBeTruthy();\n            });\n        });\n\n\n        describe('Validation.is.numeric', function() {\n            it('should not validate text which has non numeric chars', function() {\n                var result = validator.is.numeric('foo123bar');\n                expect(result).toBeFalsy();\n            });\n\n            it('should not validate text which starts with numeric but has non numeric chars', function() {\n                var result = validator.is.numeric('123bar');\n                expect(result).toBeFalsy();\n            });\n\n\n            it('should not validate text which starts with space but has only numeric chars', function() {\n                var result = validator.is.numeric('   123');\n                expect(result).toBeFalsy();\n            });\n\n\n            it('should validate text which has only numeric chars', function() {\n                var result = validator.is.numeric('123');\n                expect(result).toBeTruthy();\n            });\n\n        });\n\n\n        //TODO: add more tests\n        describe('Validation.is.equal', function() {\n            it('should validate same strings', function () {\n                var result = validator.is.equal(\"osman\", \"osman\");\n                expect(result).toBeTruthy();\n            });\n\n            it('should validate same numbers', function () {\n                var result = validator.is.equal(1453, 1453);\n                expect(result).toBeTruthy();\n            });\n\n            it('should validate numeric strings', function () {\n                var result = validator.is.equal(\"1453\", 1453);\n                expect(result).toBeTruthy();\n            });\n\n\n\n\n            it('should validate empty strings', function () {\n                var result = validator.is.equal(\"\", \"\");\n                expect(result).toBeTruthy();\n            });\n\n            it('should validate falsy values', function () {\n                var result = validator.is.equal(\"\", false);\n                expect(result).toBeTruthy();\n            });\n\n            it('should not validate falsy values with null', function () {\n                var result = validator.is.equal(null, false);\n                expect(result).toBeFalsy();\n            });\n\n\n        });\n\n\n        describe('Validation.is.digitAndNonDigit', function() {\n            it('should not validate text which has chars but numbers', function() {\n                var result = validator.is.digitAndNonDigit('foobar');\n                expect(result).toBeFalsy();\n            });\n\n            it('should not validate text which has chars only numbers', function() {\n                var result = validator.is.digitAndNonDigit('1234');\n                expect(result).toBeFalsy();\n            });\n\n            it('should not validate text which has only whitespaces', function() {\n                var result = validator.is.digitAndNonDigit('   ');\n                expect(result).toBeFalsy();\n            });\n\n\n            it('should validate text which contains both numbers and chars', function() {\n                var result = validator.is.digitAndNonDigit('foo123bar');\n                expect(result).toBeTruthy();\n            });\n\n            it('should validate text which contains both numbers, chars and whitespaces', function() {\n                var result = validator.is.digitAndNonDigit('foo 123 bar');\n                expect(result).toBeTruthy();\n            });\n\n        });\n\n    });\n\n\n    describe('Validation.has', function() {\n        describe('Validation.has.minLength', function() {\n            it(\"should validate 'abc' has minLength 3\", function() {\n                var result = validator.has.minLength('abc', 3);\n                expect(result).toBeTruthy();\n            });\n\n            it(\"should validate 'abc' has minLength 2\", function() {\n                var result = validator.has.minLength('abc', 2);\n                expect(result).toBeTruthy();\n            });\n\n\n            it(\"should not validate 'abc' has minLength 4\", function() {\n                var result = validator.has.minLength('abc', 4);\n                expect(result).toBeFalsy();\n            });\n\n            it(\"should validate ' ' has minLength 1\", function() {\n                var result = validator.has.minLength(' ', 1);\n                expect(result).toBeTruthy();\n            });\n\n            it(\"should not validate '' has minLength 1\", function() {\n                var result = validator.has.minLength('', 1);\n                expect(result).toBeFalsy();\n            });\n\n        });\n\n\n        describe('Validation.has.maxLength', function() {\n            it(\"should not validate 'abc' has max length 2\", function() {\n                var result = validator.has.maxLength('abc', 2);\n                expect(result).toBeFalsy();\n            });\n\n            it(\"should validate 'ab' has max length 2\", function() {\n                var result = validator.has.maxLength('ab', 2);\n                expect(result).toBeTruthy();\n            });\n\n            it(\"should not validate '   ' has max length 2\", function() {\n                var result = validator.has.maxLength('   ', 2);\n                expect(result).toBeFalsy();\n            });\n\n            it(\"should validate '' has max length 0\", function() {\n                var result = validator.has.maxLength('', 0);\n                expect(result).toBeTruthy();\n            });\n        });\n\n\n        describe('Validation.has.minValue', function() {\n            it('should validate 3 has min value 1', function() {\n                var result = validator.has.minValue(3, 1);\n                expect(result).toBeTruthy();\n            });\n\n            it('should not validate 3 has min value 4', function() {\n                var result = validator.has.minValue(3, 4);\n                expect(result).toBeFalsy();\n            });\n        });\n\n        describe('Validation.has.maxValue', function() {\n            it('should validate 3 has max value 4', function() {\n                var result = validator.has.maxValue(3, 4);\n                expect(result).toBeTruthy();\n            });\n\n            it('should not validate 3 has max value 2', function() {\n                var result = validator.has.maxValue(3, 2);\n                expect(result).toBeFalsy();\n            });\n        });\n\n    });\n\n});\n\n\n/**\n * Run jasmine spec\n */\ntart.Validation.SpecRunner = function() {\n    jasmine.getEnv()['addReporter'](new jasmine.TrivialReporter());\n    jasmine.getEnv()['execute']();\n}();\n"
  },
  {
    "path": "tart/XhrManager.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview tart.XhrManager static class to handle XHR requests.\n */\n\ngoog.provide('tart.XhrManager');\n\n\n/**\n * jQuery GET's wrapper\n *\n * @param {string} url url to send request.\n * @param {Object} params POST/GET parameters.\n * @param {?function(Object)} success success callback.\n * @param {?function(Object)=} opt_fail fail callback.\n * @param {string=} opt_dataType data type.\n * @return {Object} .\n */\ntart.XhrManager.get = function(url, params, success, opt_fail, opt_dataType) {\n    return tart.XhrManager.ajax('GET', url, params, success, opt_fail, opt_dataType);\n};\n\n\n/**\n * jQuery POST's wrapper\n *\n * @param {string} url url to send request.\n * @param {Object} params POST/GET parameters.\n * @param {?function(Object)} success success callback.\n * @param {?function(Object)=} opt_fail fail callback.\n * @param {string=} opt_dataType data type.\n * @return {Object} .\n */\ntart.XhrManager.post = function(url, params, success, opt_fail, opt_dataType) {\n    return tart.XhrManager.ajax('POST', url, params, success, opt_fail, opt_dataType);\n};\n\n\n/**\n * jQuery POST's wrapper\n *\n * @param {string} type request type.\n * @param {string} url url to send request.\n * @param {Object} params POST/GET parameters.\n * @param {?function(Object)} success success callback.\n * @param {?function(Object)=} opt_fail fail callback.\n * @param {string=} opt_dataType data type.\n * @return {Object} .\n */\ntart.XhrManager.ajax = function(type, url, params, success, opt_fail, opt_dataType) {\n    return $.ajax({\n        'type': type,\n        'url': url,\n        'data': params,\n        'dataType': opt_dataType || 'json',\n        'xhrFields': {\n               'withCredentials': true\n        },\n        'success': function(response) {\n            success && success(response);\n        },\n        'error': function(response) {\n            opt_fail && opt_fail(response);\n        }\n    });\n};\n"
  },
  {
    "path": "tart/base/Model.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview tart.base.Model base model.\n */\n\ngoog.provide('tart.base.Model');\n\ngoog.require('goog.structs.Map');\ngoog.require('goog.debug.ErrorHandler');\ngoog.require('goog.events.EventHandler');\ngoog.require('goog.events.EventTarget');\n\n\n/**\n * Base model\n *\n * @extends {goog.events.EventTarget}\n * @constructor\n */\ntart.base.Model = function() {\n    goog.events.EventTarget.call(this);\n\n    /** @private **/\n    this.items_ = null;\n\n    /** @private **/\n    this.totalItemCount_ = 0;\n\n    this.params = new goog.structs.Map();\n};\ngoog.inherits(tart.base.Model, goog.events.EventTarget);\n\n\n/**\n * Abstract method to load data from any resource\n * @param {Function=} opt_callback method after load.\n */\ntart.base.Model.prototype.load = function (opt_callback) {\n    goog.abstractMethod();\n};\n\n\n/**\n * getter for items\n * @param {boolean=} dispatchEvent Whether this method should throw an event when its items are loaded. This may be used in classes that\n * extend tart.base.Model.\n * @return {Object} items all items.\n */\ntart.base.Model.prototype.getItems = function(dispatchEvent) {\n    return this.items_;\n};\n\n\n/**\n * Setter for items\n * @param {Object} items items to be set.\n */\ntart.base.Model.prototype.setItems = function(items) {\n    this.items_ = items;\n};\n\n/**\n * Set total item count\n * @param {number} itemCount total item count for this model.\n */\ntart.base.Model.prototype.setTotalItemCount = function(itemCount) {\n    this.totalItemCount_ = itemCount;\n};\n\n/**\n * Get total item count\n * @return {number} total item count for this model.\n */\ntart.base.Model.prototype.getTotalItemCount = function() {\n    return this.totalItemCount_;\n};\n\n/** @typedef {{type: string, oldValue, newValue}} */\ntart.base.Model.Event;\n\n\n/**\n * Overriding goog.events.EventTarget's dispatchEvent method, to make this event consistent in application\n *\n * @param {Object|string} modelEvent event object which has type, oldValue and newValue fields.\n * @return {boolean} .\n * @override\n */\ntart.base.Model.prototype.dispatchEvent = function(modelEvent) {\n    return goog.base(this, 'dispatchEvent', modelEvent);\n};\n\n"
  },
  {
    "path": "tart/base/plugin/BasePlugin.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview tart.base.plugin.BasePlugin to get common properties for a plugin in one class.\n */\n\ngoog.provide('tart.base.plugin.BasePlugin');\n\ngoog.require('goog.debug.ErrorHandler');\ngoog.require('goog.events.EventHandler');\ngoog.require('goog.events.EventTarget');\ngoog.require('goog.structs.Map');\n\n\n/**\n * @param {tart.base.Model} model\n * @extends {goog.events.EventTarget}\n * @constructor\n */\ntart.base.plugin.BasePlugin = function (model) {\n    goog.events.EventTarget.call(this);\n\n    /** @protected */\n    this.model = model;\n\n    /** @protected **/\n    this.map = new goog.structs.Map();\n    \n    this.model.params.set(this.key, this.map);\n};\ngoog.inherits(tart.base.plugin.BasePlugin, goog.events.EventTarget);\n\n/**\n * clear map for plugin\n */\ntart.base.plugin.BasePlugin.prototype.clear = function () {\n    this.map.clear();\n};\n\n/**\n * Getter for model\n */\ntart.base.plugin.BasePlugin.prototype.getModel = function () {\n    return this.model;\n};\n\n\n\n/**\n * models key\n */\ntart.base.plugin.BasePlugin.prototype.key = undefined;\n"
  },
  {
    "path": "tart/base/plugin/Filter.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview tart.base.plugin.Filter model filter plugin.\n */\n\ngoog.provide('tart.base.plugin.Filter');\n\ngoog.require('tart.base.plugin.BasePlugin');\n\n\n/**\n * @param {tart.base.Model} model\n *\n * @extends {tart.base.plugin.BasePlugin}\n * @constructor\n */\ntart.base.plugin.Filter = function (model) {\n    goog.base(this, model);\n};\ngoog.inherits(tart.base.plugin.Filter, tart.base.plugin.BasePlugin);\n\n/**\n * Set plugins param key\n */\ntart.base.plugin.Filter.prototype.key = \"filterParams\";\n\n\n\n/**\n * @param {string} field field to be filtereded.\n * @param {string} condition condition operator.\n * @param {string} value field value to filter field for.\n */\ntart.base.plugin.Filter.prototype.addFilter = function (field, condition, value) {\n\n    /**\n     * There can be multiple condition-value pair for a field\n     */\n    var fieldFilter = this.map.get(field);\n\n    //and if this field did not set before create a new object\n    if (!fieldFilter) {\n        fieldFilter = {};\n    }\n\n    fieldFilter[condition] = value;\n\n    this.map.set(field, fieldFilter);\n};\n"
  },
  {
    "path": "tart/base/plugin/Pager.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview tart.base.plugin.Pager model pager plugin to handle pagination.\n */\n\ngoog.provide('tart.base.plugin.Pager');\n\ngoog.require('tart.Pagination');\ngoog.require('tart.base.plugin.BasePlugin');\n\n\n/**\n * @param {tart.base.Model} model tart.base.Model instance to set pager params.\n * @param {tart.Pagination=} pagination optional tart.Pagination instance to handle pagination.\n *\n * @extends {tart.base.plugin.BasePlugin}\n * @constructor\n */\ntart.base.plugin.Pager = function(model, pagination) {\n    goog.base(this, model);\n\n    var that = this;\n\n    /** @private */\n    that.pagination_ = pagination || new tart.Pagination();\n    that.pagination_.setParentEventTarget(this);\n\n    /**\n     * Change offset on page change events\n     */\n    goog.events.listen(that.pagination_, tart.Pagination.EventTypes.PAGE_CHANGED, function(e) {\n        var limit = parseInt(that.map.get('limit'), 10);\n        var newOffset = (e.newValue - 1) * limit;\n        that.map.set('offset', newOffset);\n        that.model.params.set(that.key, that.map);\n    });\n};\ngoog.inherits(tart.base.plugin.Pager, tart.base.plugin.BasePlugin);\n\n/**\n * Plugin's parameter key which is inherited from BasePlugin and should be defined\n */\ntart.base.plugin.Pager.prototype.key = 'paginationParams';\n\n\n/**\n * @param {number} pageCount number of pages.\n */\ntart.base.plugin.Pager.prototype.setTotalPageCount = function(pageCount) {\n    this.map.set('pageCount', pageCount);\n};\n\n/**\n * @param {number} offset cursor start point for paging.\n */\ntart.base.plugin.Pager.prototype.setOffset = function(offset) {\n    this.map.set('offset', offset);\n};\n\n\n/**\n *\n * @param {number} limit item count to fetch.\n */\ntart.base.plugin.Pager.prototype.setLimit = function(limit) {\n    this.map.set('limit', limit);\n    this.pagination_.setItemPerPage(limit);\n};\n\n/**\n *\n * @return {number} current limit.\n */\ntart.base.plugin.Pager.prototype.getLimit = function() {\n    return this.pagination_.getItemPerPage();\n};\n\n\n/**\n * @param {number} totalItemCount set total item count for paginator.\n */\ntart.base.plugin.Pager.prototype.setTotalItems = function(totalItemCount) {\n    this.pagination_.setTotalItems(totalItemCount);\n};\n\n/**\n * Next wrapper for paginator.\n */\ntart.base.plugin.Pager.prototype.next = function() {\n    this.pagination_.next();\n};\n\n/**\n * Prev wrapper for paginator.\n */\ntart.base.plugin.Pager.prototype.prev = function() {\n    this.pagination_.prev();\n};\n\n/**\n * setCurrentPage wrapper for paginator.\n * @param {number} currentPageNum current page number.\n */\ntart.base.plugin.Pager.prototype.setCurrentPage = function(currentPageNum) {\n    this.pagination_.setCurrentPage(currentPageNum);\n};\n\n/**\n * @return {number} number of pages.\n */\ntart.base.plugin.Pager.prototype.getTotalPage = function() {\n    return this.pagination_.getTotalPage();\n};\n\n/**\n * @return {number} current page number.\n */\ntart.base.plugin.Pager.prototype.getCurrentPage = function() {\n    return this.pagination_.getCurrentPage();\n};\n\n\n/**\n * @return {boolean} Whether there is a previous page available.\n */\ntart.base.plugin.Pager.prototype.hasPrev = function() {\n    return this.pagination_.hasPrev();\n};\n\n\n/**\n * @return {boolean} Whether there is a next page available.\n */\ntart.base.plugin.Pager.prototype.hasNext = function() {\n    return this.pagination_.hasNext();\n};\n"
  },
  {
    "path": "tart/base/plugin/Sorter.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview tart.base.plugin.Sorter model sorter plugin.\n */\n\ngoog.provide('tart.base.plugin.Sorter');\n\ngoog.require('tart.base.plugin.BasePlugin');\n\n\n/**\n * @param {tart.base.Model} model\n *\n * @extends {tart.base.plugin.BasePlugin}\n * @constructor\n */\ntart.base.plugin.Sorter = function (model) {\n    goog.events.EventTarget.call(this);\n\n    /** @protected */\n    this.model = model;\n\n    /** @protected **/\n    this.sorts = [];\n\n    this.model.params.set(this.key, this.sorts);\n};\ngoog.inherits(tart.base.plugin.Sorter, tart.base.plugin.BasePlugin);\n\n/**\n * Set plugin's param\n */\ntart.base.plugin.Sorter.prototype.key = \"sortParams\";\n\n\n/**\n * @param {string} field field to be sorted.\n * @param {string} order order by directive, which is asc or desc.\n */\ntart.base.plugin.Sorter.prototype.addSort = function (field, order) {\n\n    /**\n     * There can be multiple condition-value pair for a field\n     */\n    var fieldSorter = goog.array.find(this.sorts, function(item){\n        return goog.object.getAnyKey(item) == field;\n    });\n\n    //and if this field did not set before create a new object\n    if (!fieldSorter) {\n        fieldSorter = {};\n    }\n\n    fieldSorter[field] = order;\n    this.model.params.get(this.key).push(fieldSorter);\n};\n\n/**\n * clear map for plugin\n */\ntart.base.plugin.Sorter.prototype.clear = function () {\n    this.sorts = [];\n    this.model.params.set(this.key, this.sorts);\n};\n"
  },
  {
    "path": "tart/components/Carousel/Controller.js",
    "content": "// Copyright 2012 Tart. All Rights Reserved.\n//\n// @author Firat Yalavuz firat.yalavuz@tart.com.tr\n\n/**\n * @fileoverview tart.components.Carousel.Controller is a base class for all carousel Controller's.\n */\n\n\ngoog.require('goog.events.EventTarget');\ngoog.require('goog.events.EventTarget');\ngoog.require('tart.Pagination');\ngoog.require('tart.base.plugin.Pager');\ngoog.require('tart.components.Carousel.Model');\ngoog.require('tart.components.Carousel.Template');\ngoog.require('tart.components.Carousel.View');\ngoog.require('tart.components.Controller');\n\ngoog.provide('tart.components.Carousel.Controller');\n\n\n\n/**\n * Example controller class\n *\n * @extends {tart.components.Controller}\n *\n * @constructor\n */\ntart.components.Carousel.Controller = function() {\n    this.model = this.model || new this.modelClass();\n    this.modelPager = new tart.base.plugin.Pager(this.model, new this.paginationClass());\n    this.modelPager.setOffset(0);\n    this.modelPager.setLimit(this.itemCount);\n    this.view = new this.viewClass();\n    this.buildDOM();\n    this.bindEvents();\n};\ngoog.inherits(tart.components.Carousel.Controller, tart.components.Controller);\n\n/**\n * Carousel's View Class\n */\ntart.components.Carousel.Controller.prototype.viewClass = tart.components.Carousel.View;\n\n/**\n * Carousel's Model Class\n */\ntart.components.Carousel.Controller.prototype.modelClass = tart.components.Carousel.Model;\n\n/**\n * Carousel's Pagination Class\n */\ntart.components.Carousel.Controller.prototype.paginationClass = tart.Pagination;\n\n/**\n * Number of carousel items\n */\ntart.components.Carousel.Controller.prototype.itemCount = 5;\n\n\n/**\n * Build carousel after items' loaded\n * @param {Object} visibleItems visible items.\n * @param {number} totalItemCount total item count.\n */\ntart.components.Carousel.Controller.prototype.buildCarouselAction = function(visibleItems, totalItemCount) {\n    if (visibleItems.length == 0)\n\t\tthis.view.noResults();\n\telse {\n\t    //build carousel\n\t    this.view.buildCarouselItems(visibleItems);\n\t    //build pagination\n\t    this.modelPager.setTotalItems(totalItemCount);\n\t    if (totalItemCount > this.itemCount) {\n\t        this.view.buildPager(this.modelPager);\n\t    }\n\t}\n    \n\tthis.view.handleNavigationButtons(this.modelPager.hasNext(), this.modelPager.hasPrev());\n};\n\n\n/**\n * Go to page in given direction\n * @param {string} direction move direction.\n * @param {Number} pageNumber page number to go.\n */\ntart.components.Carousel.Controller.prototype.goToPageAction = function(direction, pageNumber) {\n    var items = this.model.getItems();\n    this.view.move(direction, items, this.modelPager.getLimit());\n    this.view.setPageSelected(pageNumber);\n};\n\n\n/**\n * move next page\n */\ntart.components.Carousel.Controller.prototype.nextAction = function() {\n    this.modelPager.next();\n};\n\n\n/**\n * move previous page\n *\n */\ntart.components.Carousel.Controller.prototype.prevAction = function() {\n    this.modelPager.prev();\n};\n\n\n/**\n * Bind controller events\n * @protected\n */\ntart.components.Carousel.Controller.prototype.bindEvents = function() {\n    var that = this;\n\n    //triggered when model.getItems() called\n    goog.events.listen(that.model, tart.components.Carousel.Model.EventTypes.ITEMS_LOADED, function(e) {\n        that.buildCarouselAction(e.visibleItems, e.totalItemCount);\n        if (e.visibleItems.length > 0) {\n            goog.style.setStyle(that.view.getDOM(), 'display', 'block');\n        }\n    });\n\n    //Triggered when page changed\n    goog.events.listen(that.modelPager, tart.Pagination.EventTypes.PAGE_CHANGED, function(e) {\n\n        //dont do anything if page not changed\n\n        if (e.oldValue != e.newValue) {\n            var direction;\n            if (e.newValue > e.oldValue) {\n                direction = 'next';\n            }\n            else {\n                direction = 'prev';\n            }\n            that.goToPageAction(direction, e.newValue);\n        }\n        that.view.handleNavigationButtons(that.modelPager.hasNext(), that.modelPager.hasPrev());\n    });\n\n    goog.events.listen(that.view.get(that.view.domMappings.NEXT)[0], goog.events.EventType.CLICK,\n\t        this.nextAction, false, this);\n    goog.events.listen(that.view.get(that.view.domMappings.PREV)[0], goog.events.EventType.CLICK,\n\t        this.prevAction, false, this);\n};\n"
  },
  {
    "path": "tart/components/Carousel/Model.js",
    "content": "// Copyright 2012 Tart. All Rights Reserved.\n//\n// @author Firat Yalavuz firat.yalavuz@tart.com.tr\n\n/**\n * @fileoverview tart.components.Carousel.Model is a base class for all carousel Model's.\n */\n\n\ngoog.require('goog.events.EventTarget');\ngoog.require('tart.Carousel');\ngoog.require('tart.base.Model');\ngoog.require('tart.dataProxy.CircularLocal');\ngoog.provide('tart.components.Carousel.Model');\ngoog.provide('tart.components.Carousel.Model.EventTypes');\n\n/**\n * All component models should be inherited from goog.events.EventTarget\n * to publish events to controllers\n *\n * @extends {tart.base.Model}\n * @constructor\n */\ntart.components.Carousel.Model = function() {\n    goog.base(this);\n    /** @protected */\n    this.proxy = new tart.dataProxy.CircularLocal();\n};\ngoog.inherits(tart.components.Carousel.Model, tart.base.Model);\n\n\n/**\n *  Model's default offset value.\n */\ntart.components.Carousel.Model.prototype.offset = 0;\n\n\n/**\n * Model's default limit value.\n */\ntart.components.Carousel.Model.prototype.limit = 0;\n\n/**\n * WidgetModel's remoteModelClass's default value is  undefined.\n */\ntart.components.Carousel.Model.prototype.remoteModelClass = undefined;\n\n\n/**\n * WidgetModel's RemoteModelClass's default value is undefined.\n */\ntart.components.Carousel.Model.prototype.remoteModelClassParams = undefined;\n\n\n/**\n * event types enumaration\n * @enum {string}\n */\ntart.components.Carousel.Model.EventTypes = {\n    ITEMS_LOADED: 'loaded'\n};\n\n\n/**\n * Get carousel items\n * @param {boolean} dispatchEvent whether it dispatches an event.\n * @return {Array} modelItems is count of items..\n */\ntart.components.Carousel.Model.prototype.getItems = function(dispatchEvent) {\n    var that = this;\n    var modelItems;\n\n    this.load(function(items) {\n        if (dispatchEvent) {\n            var eventObject = {type: tart.components.Carousel.Model.EventTypes.ITEMS_LOADED,\n                visibleItems: items,\n                totalItemCount: that.getTotalItemCount()\n            };\n\n            that.dispatchEvent(eventObject);\n        }\n        modelItems = items;\n    });\n\n    return modelItems;\n};\n\n/**\n * @param {Function} callback load callback function.\n */\ntart.components.Carousel.Model.prototype.load = function(callback) {\n    var that = this;\n    var remoteModel;\n\n    var onProxyFetch = function(data) {\n        that.setItems(data);\n        callback.call(this, data);\n    };\n\n    var getremoteModelData = function() {\n        var data = remoteModel.getItems();\n        that.proxy.setData(data);\n        that.setTotalItemCount(data.length);\n        that.proxy.fetch(onProxyFetch);\n    };\n\n\n    that.proxy.setParams(this.params);\n\n    if (that.proxy.getData()) {\n        that.proxy.fetch(onProxyFetch);\n    }\n    else if (this.remoteModelClass) {\n        remoteModel = new this.remoteModelClass(this.remoteModelClassParams);\n        if (this.pagination) {\n            var remoteModelPager = new tart.base.plugin.Pager(remoteModel, this.pagination);\n            remoteModelPager.setOffset(this.offset);\n            remoteModelPager.setLimit(this.limit);\n        }\n\n        remoteModel.load(getremoteModelData);\n    }\n};\n"
  },
  {
    "path": "tart/components/Carousel/Template.js",
    "content": "// Copyright 2012 Tart. All Rights Reserved.\n//\n// @author Firat Yalavuz firat.yalavuz@tart.com.tr\n\n/**\n * @fileoverview tart.components.Carousel.Template is a base class for all carousel Template's.\n */\n\ngoog.provide('tart.components.Carousel.Template');\n\n\n\n/**\n * @constructor\n */\ntart.components.Carousel.Template = function() {\n    this.properties = {\n        CAROUSEL_WIDTH: this.carouselWidth\n    };\n\n    this.domMappings = {\n        NAVIGATION: '.navigation',\n        PREV: '.navigation.prev',\n        NEXT: '.navigation.next',\n        ITEMS: '.contents',\n        PAGER: '.pager',\n        PAGER_ITEMS: '.pagerItems',\n        PAGER_ITEM: 'span'\n    };\n};\n\n\n/**\n * Header\n *\n * @return {string} header markup.\n */\ntart.components.Carousel.Template.prototype.header = function() {\n    return '';\n};\n\ntart.components.Carousel.Template.prototype.carouselWidth = 780;\n\n/**\n * Footer\n *\n * @return {string} footer markup.\n */\ntart.components.Carousel.Template.prototype.footer = function() {\n    return '<div class=\"pager rounded\">' +\n\t\t\t\t'<div class=\"pagerItems\"></div>' +\n           '</div>';\n};\n\n\n/**\n * Base markup for carousel\n *\n * @return {string} base markup.\n */\ntart.components.Carousel.Template.prototype.base = function() {\n\treturn '<div class=\"carousel loading\">' +\n\t\t\t\tthis.header() +\n            \t'<span class=\"navigation next\" title=\"next\"></span>' +\n            \t'<span class=\"navigation prev\" title=\"previous\"></span>' +\n            \t'<div class=\"contentsWrapper\">' +\n               \t\t'<div class=\"contents\"></div>' +\n           \t\t'</div>' +\n           \t\tthis.footer() +\n\t\t\t'</div>';\n};\n\n\n/**\n * Markup for carousel group\n *\n * @param {Array.<*>} itemArray carousel items.\n * @return {(Node)} base markup.\n */\ntart.components.Carousel.Template.prototype.carouselItems = goog.abstractMethod;\n\n\n/**\n *\n * @param {number} pageNum is number of selected page.\n * @param {boolean} selected class.\n * @return {string} markup.\n */\ntart.components.Carousel.Template.prototype.pagerItem = function(pageNum, selected) {\n    var selectedClass = selected ? 'selected' : '';\n    return '<span class=\"' + selectedClass + '\" title=\"' + pageNum + ' \"></span>';\n};\n\n\n/**\n * @return {string}\n */\ntart.components.Carousel.Template.prototype.noResults = function() {\n\treturn '';\n};\n\n"
  },
  {
    "path": "tart/components/Carousel/View.js",
    "content": "// Copyright 2012 Tart. All Rights Reserved.\n//\n// @author Firat Yalavuz firat.yalavuz@tart.com.tr\n\n/**\n * @fileoverview tart.components.Carousel.View is a base class for all carousel View's.\n */\n\n\ngoog.require('tart.components.View');\n\ngoog.provide('tart.components.Carousel.View');\n\n\n\n/**\n * @extends {tart.components.View}\n * @constructor\n */\ntart.components.Carousel.View = function() {\n    goog.base(this);\n\n    this.template = new this.templateClass();\n\n    this.domMappings = this.template.domMappings;\n\n    this.pagerItemsCache = {};\n    this.activeItems = null;\n};\ngoog.inherits(tart.components.Carousel.View, tart.components.View);\n\n/**\n *\n */\ntart.components.Carousel.View.prototype.templateClass = tart.components.Carousel.Template;\n\n/**\n * Build carousel items from item array\n *\n * @param {Array.<Object>} itemArray carousel data array.\n */\ntart.components.Carousel.View.prototype.buildCarouselItems = function(itemArray) {\n    goog.dom.classlist.remove(this.getDOM(), 'loading');\n    var carouselItems = this.template.carouselItems(itemArray);\n\n    this.get(this.domMappings.ITEMS)[0].innerHTML = '';\n    goog.dom.appendChild(this.get(this.domMappings.ITEMS)[0], carouselItems);\n    this.itemsAppended(carouselItems);\n    this.activeItems = carouselItems;\n};\n\n\n/**\n * Render method which has to be overriden\n *\n * @return {string} markup.\n */\ntart.components.Carousel.View.prototype.render = function() {\n    return this.template.base();\n};\n\n\n/**\n * get all carousel items' DOM reference\n *\n * @return {Object} DOM refernce.\n * @protected\n */\ntart.components.Carousel.View.prototype.getAllCarouselItemsDomReference = function() {\n    var carouselItems = this.get(this.domMappings.ITEMS)[0];\n    return goog.dom.getChildren(carouselItems);\n};\n\n\n/**\n * Animate carousel with given rule\n *\n * @param {string} direction  'next' or 'previous' TODO: this should be enumarated.\n * @param {Array.<Object>} diff items to be inserted.\n * @param {number} moveCount count of move.\n */\ntart.components.Carousel.View.prototype.move = function(direction, diff, moveCount) {\n    var that = this;\n\n    if (diff.length > 0) {\n        var carouselItems = $(that.get(that.domMappings.ITEMS));\n\n        //prevent glitch on rapid movements\n        carouselItems.stop(true, true);\n\n        var marginLeft;\n\n        var moveWidth = this.template.properties.CAROUSEL_WIDTH;\n\n        var allCarouselItems = $(that.getAllCarouselItemsDomReference());\n\n        var markup = $(this.template.carouselItems(diff));\n        this.activeItems = markup;\n\n        for (var i = 0; i < markup.length; i++) {\n            for (var j = 0; j < allCarouselItems.length; j++) {\n                if (markup[i] === allCarouselItems[j])\n                    allCarouselItems = allCarouselItems.not(markup[i]);\n            }\n        }\n\n        if (direction == 'next') {\n            carouselItems.append(markup);\n            this.itemsAppended(markup);\n            marginLeft = '-=' + moveWidth + 'px';\n        } else {\n            carouselItems.prepend(markup);\n            this.itemsAppended(markup);\n            carouselItems.css('margin-left', (-1 * moveWidth) + 'px');\n\n            marginLeft = '+=' + moveWidth + 'px';\n\n        }\n\n        carouselItems.animate({ 'margin-left': marginLeft }, 500, '', function(){\n            allCarouselItems.detach();\n            carouselItems.css('margin-left', '0px');\n        });\n    }\n};\n\ntart.components.Carousel.View.prototype.itemsAppended = function(items) {\n\n};\n\n/**\n * Method to hide previous button.\n */\ntart.components.Carousel.View.prototype.hidePrev = function() {\n    goog.style.showElement(this.get(this.domMappings.PREV)[0], false);\n};\n\n\n/**\n *\n * @param {tart.base.plugin.Pager} pager to build pager.\n */\ntart.components.Carousel.View.prototype.buildPager = function(pager) {\n    var that = this;\n    var pagerElement = that.get(that.domMappings.PAGER)[0];\n\n    var totalPage = pager.getTotalPage();\n\n    var navigation = that.get(that.domMappings.NAVIGATION)[0];\n\n    if (totalPage > 1) { //show pager if only totalPage > 1\n        if (pagerElement.length > 0) {\n            var pagerItems = pagerElement.querySelectorAll(that.domMappings.PAGER_ITEMS)[0];\n\n            //for each pager create pager button and attach event\n            for (var i = 1; i <= totalPage; i++) {\n                (function(i) {\n                    var selected = (i == 1);\n                    var pagerItem = tart.dom.createElement(that.template.pagerItem(i, selected))[0];\n\n                    goog.events.listen(pagerItem, goog.events.EventType.CLICK, function(){\n                        pager.setCurrentPage(i);\n                    });\n\n                    goog.dom.appendChild(pagerItems, pagerItem);\n                    that.pagerItemsCache[i] = pagerItem;\n\n                })(i);\n            }\n\n            goog.style.showElement(pagerElement, true);\n        }\n\n        goog.style.showElement(navigation, true);\n\n        if (!pager.hasPrev()) that.hidePrev();\n\n\n    }\n    else {\n        //hide pager if totalPage < 2\n        pagerElement.hide();\n        navigation.hide();\n    }\n};\n\n\n/**\n *\n * @param {number} pageNum number of selected page.\n */\ntart.components.Carousel.View.prototype.setPageSelected = function(pageNum) {\n    var that = this;\n    var pager = that.get(that.domMappings.PAGER)[0];\n    var pagerItems = pager.querySelector(that.domMappings.PAGER_ITEMS).querySelectorAll(that.domMappings.PAGER_ITEM);\n    goog.array.forEach(pagerItems, function(pagerItem) {\n        goog.dom.classlist.remove(pagerItem, 'selected');\n    });\n\n    that.pagerItemsCache[pageNum] && goog.dom.classlist.add(that.pagerItemsCache[pageNum], 'selected');\n};\n\n\n/**\n *\n * @param {boolean} hasNext Whether there is a previous page.\n * @param {boolean} hasPrev Whether there is a next page.\n */\ntart.components.Carousel.View.prototype.handleNavigationButtons = function(hasNext, hasPrev) {\n    var pagerNext = this.get(this.domMappings.NEXT)[0];\n    var pagerPrev = this.get(this.domMappings.PREV)[0];\n    goog.style.showElement(pagerNext, true);\n    goog.style.showElement(pagerPrev, true);\n\n    if (!hasNext)     goog.style.showElement(pagerNext, false);\n    if (!hasPrev)     goog.style.showElement(pagerPrev, false);\n};\n\n\n/**\n * No results handler\n *\n */\ntart.components.Carousel.View.prototype.noResults = function() {\n    goog.dom.classlist.remove(this.getDOM(), 'loading');\n    var carouselText = this.template.noResults();\n    this.get(this.domMappings.ITEMS)[0].innerHTML = carouselText;\n    this.itemsAppended(carouselText);\n    this.activeItems = carouselText;\n};\n"
  },
  {
    "path": "tart/components/Carousel/Widget.js",
    "content": "// Copyright 2012 Tart. All Rights Reserved.\n//\n// @author Firat Yalavuz firat.yalavuz@tart.com.tr\n\n/**\n * @fileoverview tart.components.Carousel.Widget is a base for all carousel widgets.\n */\n\ngoog.provide('tart.components.Carousel.Widget');\n\ngoog.require('tart.components.Carousel.Controller');\ngoog.require('tart.components.Widget');\n\n\n/**\n * @constructor\n * @extends {tart.components.Widget}\n */\ntart.components.Carousel.Widget = function() {\n    this.controller = new this.controllerClass();\n    goog.base(this);\n    this.init();\n};\ngoog.inherits(tart.components.Carousel.Widget, tart.components.Widget);\n\n/**\n *\n */\ntart.components.Carousel.Widget.prototype.controllerClass = tart.components.Carousel.Controller;\n\ntart.components.Carousel.Widget.prototype.init = function() {\n    this.controller.model.getItems(true);\n};\n"
  },
  {
    "path": "tart/components/Controller.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview tart.components.Controller is a base class for all components Controller's.\n *\n * Example usage:\n *\n *      var ViewClass = function () {\n *          goog.base(this);\n *      };\n *      goog.inherits(ViewClass, tart.components.View);\n *\n *      ViewClass.prototype.render = function () {\n *          return \"<h1>Foo</h1>\";\n *      };\n *      var view = new ViewClass();\n *\n *      var ModelClass = function () {\n *          goog.base(this);\n *      };\n *      goog.inherits(ModelClass, tart.base.Model);\n *\n *\n *      var model = new ModelClass();\n *\n *      var ControllerClass = function () {\n *          goog.base(this);\n *      };\n *      goog.inherits(ControllerClass, tart.components.Controller);\n *\n *      var controller = new ControllerClass(model, view);\n *      var dom = controller.buildDOM();\n */\n\ngoog.require('tart.base.Model');\ngoog.require('tart.components.View');\n\ngoog.provide('tart.components.Controller');\n\n\n\n/**\n * Base controller\n *\n * @param {tart.base.Model=} opt_model Data model.\n * @param {tart.components.View=} opt_view View object.\n * @constructor\n */\ntart.components.Controller = function(opt_model, opt_view) {\n    this.model = opt_model || new tart.base.Model();\n    this.view = opt_view || new tart.components.View();\n};\n\n\n/**\n * Build DOM from view\n *\n * @return {Element} generated DOM of attached View object.\n */\ntart.components.Controller.prototype.buildDOM = function() {\n    var dom = this.view.render();\n    // TODO : render should always be string so we should remove string check.\n    if(goog.isString(dom))\n        dom = /** @type {Element} */(tart.dom.createElement(dom));\n    this.view.setDOM(/** @type {Element} */(dom));\n    return /** @type {Element} */ (dom);\n};\n\n\n/**\n * Get DOM generated by view and attached by controller\n *\n * @return {Element} DOM reference.\n */\ntart.components.Controller.prototype.getDOM = function() {\n    return this.view.getDOM();\n};\n"
  },
  {
    "path": "tart/components/RemoteModel.js",
    "content": "// Copyright 2012 Tart. All Rights Reserved.\n//\n// @author Firat Yalavuz firat.yalavuz@tart.com.tr\n\n/**\n * @fileoverview tart.components.RemoteModel RemoteModel which gets data from Xhr.\n */\n\ngoog.provide('tart.components.models.RemoteModel');\ngoog.require('tart.base.Model');\ngoog.require('tart.dataProxy.Xhr');\n\n\n/**\n * Remote Model\n *\n * @extends {tart.base.Model}\n * @constructor\n */\ntart.components.models.RemoteModel = function() {\n    goog.base(this);\n    this.params.set('method_', 'post');\n    this.params.set('url_', this.url);\n    this.totalCount = 0;\n    this.proxy = new this.proxyClass();\n};\ngoog.inherits(tart.components.models.RemoteModel, tart.base.Model);\n\n/**\n * RemoteModel's entity class. Default value is undefined.\n */\ntart.components.models.RemoteModel.prototype.entityClass = undefined;\n\ntart.components.models.RemoteModel.prototype.proxyClass = tart.dataProxy.Xhr;\n\n/**\n * RemoteModel's request url. Default value is undefined.\n */\ntart.components.models.RemoteModel.prototype.url = undefined;\n\n\n/**\n * Load data and map data to entity.\n * @param {Function=} opt_callback method to call after load.\n */\ntart.components.models.RemoteModel.prototype.load = function(opt_callback) {\n    var that = this;\n\n    that.proxy.setParams(this.params);\n    that.proxy.fetch(function(data) {\n        that.mapDataToEntities(data);\n        if (opt_callback) {\n            opt_callback.call(this, that.getItems());\n        }\n    });\n};\n\n\n/**\n * map data to entity class.\n * @param {Object} xhrData data returned from xhr request.\n * @protected\n */\ntart.components.models.RemoteModel.prototype.mapDataToEntities = function(xhrData) {\n\n    var items = [], collection = xhrData['data'];\n\n    for (var i = 0, l = collection.length; i < l; i++) {\n        items.push(new this.entityClass(collection[i]));\n    }\n\n    this.totalCount = items.length;\n\n    this.setItems(items);\n};\n"
  },
  {
    "path": "tart/components/ThumbnailedCarousel/Model.js",
    "content": "// Copyright 2012 Tart. All Rights Reserved.\n//\n// @author Firat Yalavuz firat.yalavuz@tart.com.tr\n\n\ngoog.require('tart.components.Carousel.Model');\ngoog.provide('tart.components.ThumbnailedCarousel.Model');\n\n\n/**\n * @extends {tart.components.Carousel.Model}\n * @constructor\n */\ntart.components.ThumbnailedCarousel.Model = function() {\n    goog.base(this);\n};\ngoog.inherits(tart.components.ThumbnailedCarousel.Model, tart.components.Carousel.Model);\n\n/**\n * @param {Array} activeItem Active carousel items.\n */\ntart.components.ThumbnailedCarousel.Model.prototype.setActiveItem = function(activeItem) {\n    this.activeItem = activeItem;\n    this.dispatchEvent({\n        type: this.EventTypes.ACTIVE_ITEM,\n        activeItem: activeItem\n    });\n};\n\ntart.components.ThumbnailedCarousel.Model.prototype.EventTypes = {\n    ACTIVE_ITEM: 'activeItem'\n};\n"
  },
  {
    "path": "tart/components/ThumbnailedCarousel/SpotController.js",
    "content": "// Copyright 2012 Tart. All Rights Reserved.\n//\n// @author Firat Yalavuz firat.yalavuz@tart.com.tr\n\n\ngoog.require('tart.CircularPagination');\ngoog.require('tart.components.Carousel.Controller');\ngoog.require('tart.components.ThumbnailedCarousel.Model');\ngoog.require('tart.components.ThumbnailedCarousel.ThumbnailsController');\ngoog.require('tart.components.ThumbnailedCarousel.ThumbnailsTemplate');\ngoog.require('tart.components.ThumbnailedCarousel.SpotView');\n\ngoog.provide('tart.components.ThumbnailedCarousel.SpotController');\n\n\n/**\n * @constructor\n * @extends {tart.components.Carousel.Controller}\n */\ntart.components.ThumbnailedCarousel.SpotController = function() {\n    this.pagination = new tart.CircularPagination();\n    goog.base(this);\n\n};\ngoog.inherits(tart.components.ThumbnailedCarousel.SpotController, tart.components.Carousel.Controller);\n\n/**\n * @override\n */\ntart.components.ThumbnailedCarousel.SpotController.prototype.paginationClass = tart.CircularPagination;\n\n/**\n * @override\n */\ntart.components.ThumbnailedCarousel.SpotController.prototype.itemCount = 1;\n\n/**\n * @override\n */\ntart.components.ThumbnailedCarousel.SpotController.prototype.viewClass = tart.components.ThumbnailedCarousel.SpotView;\n\n/**\n * @override\n */\ntart.components.ThumbnailedCarousel.SpotController.prototype.modelClass = tart.components.ThumbnailedCarousel.Model;\n\n/**\n *  Thumbnailed Carousel's thumbnails template class\n */\ntart.components.ThumbnailedCarousel.SpotController.prototype.thumbnailsTemplateClass =\n    tart.components.ThumbnailedCarousel.ThumbnailsTemplate;\n\n/**\n *  Thumbnailed Carousel's thumbnails controller class\n */\ntart.components.ThumbnailedCarousel.SpotController.prototype.thumbnailsControllerClass =\n    tart.components.ThumbnailedCarousel.ThumbnailsController;\n\n/**\n * @override\n */\ntart.components.ThumbnailedCarousel.SpotController.prototype.buildCarouselAction = function(visibleItems, totalItemCount) {\n    goog.base(this, 'buildCarouselAction', visibleItems, totalItemCount);\n    this.thumbnailsController = new this.thumbnailsControllerClass(this.model);\n    var $thumbnails = this.thumbnailsController.getDOM();\n    this.view.appendThumbnails($thumbnails);\n};\n\n/**\n * @override\n */\ntart.components.ThumbnailedCarousel.SpotController.prototype.bindEvents = function() {\n    goog.base(this, 'bindEvents');\n\n    var that = this;\n    goog.events.listen(this.modelPager, tart.Pagination.EventTypes.PAGE_CHANGED, function(e) {\n        that.model.setActiveItem(e.newValue);\n    });\n\n    goog.events.listen(this.model, this.model.EventTypes.ACTIVE_ITEM, function(e) {\n        that.modelPager.setCurrentPage(e.activeItem);\n    });\n};\n"
  },
  {
    "path": "tart/components/ThumbnailedCarousel/SpotTemplate.js",
    "content": "// Copyright 2012 Tart. All Rights Reserved.\n//\n// @author Firat Yalavuz firat.yalavuz@tart.com.tr\n\ngoog.require('tart.components.Carousel.Template');\ngoog.provide('tart.components.ThumbnailedCarousel.SpotTemplate');\n\n\n/**\n * @extends {tart.components.Carousel.Template}\n * @constructor\n */\ntart.components.ThumbnailedCarousel.SpotTemplate = function() {\n    goog.base(this);\n    this.domMappings.THUMBNAILS_CONTAINER = '.thumbs';\n};\ngoog.inherits(tart.components.ThumbnailedCarousel.SpotTemplate, tart.components.Carousel.Template);\n\n/**\n * Base function to create dom.\n *\n * @return {string} base markup of spot.\n */\ntart.components.ThumbnailedCarousel.SpotTemplate.prototype.base = function() {\n    var markup = '<div class=\"carousel loading thumbnailedCarousel\">' +\n        '<span class=\"navigation next\" title=\"ileri\"></span>' +\n        '<span class=\"navigation prev\" title=\"geri\"></span>' +\n        '<div class=\"contentsWrapper\">' +\n        '<div class=\"contents\"></div>' +\n        '</div>' +\n        '<div class=\"thumbs\"></div>';\n\n    return markup;\n};\n"
  },
  {
    "path": "tart/components/ThumbnailedCarousel/SpotView.js",
    "content": "// Copyright 2012 Tart. All Rights Reserved.\n//\n// @author Firat Yalavuz firat.yalavuz@tart.com.trr>\n\ngoog.require('tart.components.Carousel.View');\ngoog.require('tart.components.ThumbnailedCarousel.SpotTemplate');\n\ngoog.provide('tart.components.ThumbnailedCarousel.SpotView');\n\n\n/**\n * @extends {tart.components.Carousel.View}\n * @constructor\n */\ntart.components.ThumbnailedCarousel.SpotView = function() {\n    goog.base(this);\n};\ngoog.inherits(tart.components.ThumbnailedCarousel.SpotView, tart.components.Carousel.View);\n\ntart.components.ThumbnailedCarousel.SpotView.prototype.templateClass = tart.components.ThumbnailedCarousel.SpotTemplate;\n\n/**\n * @param {string|jQueryObject} $dom for append thumbnails to carousel.\n */\ntart.components.ThumbnailedCarousel.SpotView.prototype.appendThumbnails = function($dom) {\n    this.get(this.domMappings.THUMBNAILS_CONTAINER).append($dom);\n};\n"
  },
  {
    "path": "tart/components/ThumbnailedCarousel/ThumbnailsController.js",
    "content": "// Copyright 2012 Tart. All Rights Reserved.\n//\n// @author Firat Yalavuz firat.yalavuz@tart.com.tr\n\n\ngoog.require('tart.CircularPagination');\ngoog.require('tart.components.Carousel.Controller');\ngoog.require('tart.components.ThumbnailedCarousel.ThumbnailsView');\n\ngoog.provide('tart.components.ThumbnailedCarousel.ThumbnailsController');\n\n\n/**\n * @constructor\n * @extends {tart.components.Carousel.Controller}\n */\ntart.components.ThumbnailedCarousel.ThumbnailsController = function(model) {\n    this.pagination = new this.paginationClass();\n    this.model = model || new this.modelClass();\n    this.modelPager = new tart.base.plugin.Pager(this.model, new this.paginationClass());\n    this.modelPager.setOffset(0);\n    this.modelPager.setLimit(this.itemCount);\n    this.view = new this.viewClass();\n    this.buildDOM();\n    this.bindEvents();\n    var items = this.model.getItems(); // true = trigger load event after items loaded\n    this.buildCarouselAction(items, this.model.getTotalItemCount());\n};\ngoog.inherits(tart.components.ThumbnailedCarousel.ThumbnailsController, tart.components.Carousel.Controller);\n\n/**\n * @override\n */\ntart.components.ThumbnailedCarousel.ThumbnailsController.prototype.viewClass = tart.components.ThumbnailedCarousel.ThumbnailsView;\n\n/**\n * @override\n */\ntart.components.ThumbnailedCarousel.ThumbnailsController.prototype.bindEvents = function() {\n    goog.base(this, 'bindEvents');\n    var that = this;\n    goog.events.listen(that.model, this.model.EventTypes.ACTIVE_ITEM, function(e) {\n        that.modelPager.setCurrentPage(Math.ceil(e.activeItem / that.modelPager.pagination_.getItemPerPage()));\n        that.view.setActiveItem(e.activeItem);\n    });\n};\n\n/**\n *\n * @param visibleItems\n * @param totalItemCount\n */\ntart.components.ThumbnailedCarousel.ThumbnailsController.prototype.buildCarouselAction = function(visibleItems, totalItemCount) {\n    goog.base(this, 'buildCarouselAction', visibleItems, totalItemCount);\n\n    this.bindThumbnailEvents();\n    this.view.setActiveItem(1);\n};\n\ntart.components.ThumbnailedCarousel.ThumbnailsController.prototype.goToPageAction = function(p) {\n    goog.base(this, 'goToPageAction', p, null);\n\n    this.bindThumbnailEvents();\n};\n\ntart.components.ThumbnailedCarousel.ThumbnailsController.prototype.bindThumbnailEvents = function() {\n    var that = this;\n    var items = that.model.getItems();\n\n    goog.array.forEach(items, function(item, i) {\n        goog.events.removeAll(item.$thumbnail[0], goog.events.EventType.CLICK);\n        (function(item, i) {\n            goog.events.listen(item.$thumbnail[0], goog.events.EventType.CLICK, function(e) {\n                var offset = (that.modelPager.getCurrentPage() - 1) * that.modelPager.getLimit();\n                that.model.setActiveItem(offset + i);\n            });\n        })(item, i + 1);\n    });\n};\n\n\n"
  },
  {
    "path": "tart/components/ThumbnailedCarousel/ThumbnailsTemplate.js",
    "content": "// Copyright 2012 Tart. All Rights Reserved.\n//\n// @author Firat Yalavuz firat.yalavuz@tart.com.tr\n\ngoog.require('tart.components.Carousel.Template');\ngoog.provide('tart.components.ThumbnailedCarousel.ThumbnailsTemplate');\n\n\n/**\n * @extends {tart.components.Carousel.Template}\n * @constructor\n */\ntart.components.ThumbnailedCarousel.ThumbnailsTemplate = function() {\n    goog.base(this);\n};\ngoog.inherits(tart.components.ThumbnailedCarousel.ThumbnailsTemplate, tart.components.Carousel.Template);\n\n/**\n * @override\n */\ntart.components.ThumbnailedCarousel.ThumbnailsTemplate.prototype.footer = function() {\n    return '';\n}\n"
  },
  {
    "path": "tart/components/ThumbnailedCarousel/ThumbnailsView.js",
    "content": "// Copyright 2012 Tart. All Rights Reserved.\n//\n// @author Firat Yalavuz firat.yalavuz@tart.com.trr>\n\ngoog.require('tart.components.Carousel.View');\ngoog.require('tart.components.ThumbnailedCarousel.ThumbnailsTemplate');\n\ngoog.provide('tart.components.ThumbnailedCarousel.ThumbnailsView');\n\n\n/**\n * @extends {tart.components.Carousel.View}\n * @constructor\n */\ntart.components.ThumbnailedCarousel.ThumbnailsView = function() {\n    goog.base(this);\n};\ngoog.inherits(tart.components.ThumbnailedCarousel.ThumbnailsView, tart.components.Carousel.View);\n\ntart.components.ThumbnailedCarousel.ThumbnailsView.prototype.templateClass = tart.components.ThumbnailedCarousel.ThumbnailsTemplate;\n"
  },
  {
    "path": "tart/components/ThumbnailedCarousel/Widget.js",
    "content": "// Copyright 2012 Tart. All Rights Reserved.\n//\n// @author Firat Yalavuz firat.yalavuz@tart.com.tr\n\n\ngoog.require('tart.components.Carousel.Widget');\ngoog.require('tart.components.ThumbnailedCarousel.SpotController');\ngoog.provide('tart.components.ThumbnailedCarousel.Widget');\n\n\n\n/**\n * @extends {tart.components.Carousel.Widget}\n * @constructor\n */\ntart.components.ThumbnailedCarousel.Widget = function() {\n    goog.base(this);\n};\ngoog.inherits(tart.components.ThumbnailedCarousel.Widget, tart.components.Carousel.Widget);\n\ntart.components.ThumbnailedCarousel.Widget.prototype.controllerClass = tart.components.ThumbnailedCarousel.SpotController;\n"
  },
  {
    "path": "tart/components/View.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview tart.components.View is a base class for all components View's.\n *\n * Example usage:\n *\n *     SubViewClass = function() {\n *         goog.base(this);\n *\n *         this.domMappings = {\n *             HEADER: 'h1'\n *         };\n *     };\n *     goog.inherits(SubViewClass, tart.components.View);\n *\n *     SubViewClass.prototype.templates_header = function(text) {\n *         text = text || '';\n *         return '<h1>' + text + '</h1>';\n *     };\n *\n *     SubViewClass.prototype.render = function() {\n *         return this.templates_header();\n *     };\n *\n *     var subView = new SubViewClass();\n *\n *     var dummyDiv = tart.dom.createElement(subView.render());\n *\n *     subView.setDOM(dummyDiv);\n *     subView.get(subView.domMappings.HEADER);\n *\n *  Known issues:\n *  - Templates will be injected withing Templates object\n */\n\ngoog.provide('tart.components.View');\n\n\n\n/**\n * View class base\n * @constructor\n */\ntart.components.View = function() {\n    /** @protected */\n    this.domCache = {};\n};\n\n\n/** @type {Element} */\ntart.components.View.prototype.dom;\n\n\n/**\n * Render abstract method, which all subclasses should implement\n * @throws {Error}\n * @return {string}\n */\ntart.components.View.prototype.render = function() {\n    throw new Error('Not implemented yet');\n};\n\n\n/**\n * Sets base DOM tree for component\n * @param {Element} dom base DOM reference for component.\n */\ntart.components.View.prototype.setDOM = function(dom) {\n    this.dom = dom;\n};\n\n\n/**\n * get current DOM reference\n *\n * @return {Element}\n */\ntart.components.View.prototype.getDOM = function() {\n    return this.dom;\n};\n\n\n/**\n * Get item, which is indicated on domMappings node\n * Cache them to domCache and return item\n * Example of usage with an id as selector:\n * this.get(\"[id='elementId']\") or this.get(\"[id=elementId]\")\n *\n * @param {string} key Object key from domMappings node.\n * @return {{length: number}} found object after traverse.\n */\ntart.components.View.prototype.get = function(key) {\n    if (!this.dom) {\n        throw new Error('DOM not set yet');\n    }\n\n    this.domCache[key] = this.domCache[key] || this.dom.querySelectorAll(key);\n    return this.domCache[key];\n};\n\n\n/**\n * Clears the view's dom cache. This might come in handy where you find yourself with dangling HTMLElement's who are\n * not in DOM anymore but bugs you because they are in cache. This also helps with memory leaks; you should often clear\n * your cache. TODO: Make this default with a deconstructor for view\n */\ntart.components.View.prototype.clearCache = function() {\n    this.domCache = {};\n};\n"
  },
  {
    "path": "tart/components/Widget.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview tart.components.Widget is a base class for all components Widget's.\n */\n\ngoog.require('tart');\ngoog.provide('tart.components.Widget');\n\n/**\n * Base widget\n * @constructor\n */\ntart.components.Widget = function() {\n    /** @private */\n    this.componentId_ = tart.getUid();\n};\n\n/**\n * Renders the component in a given element or in its placeholder that should already be in the DOM.\n *\n * @param {Element=} rootEl If provided, the widget will render into this rootEl.\n *                              Otherwise, it will look for its placeholder in DOM.\n */\ntart.components.Widget.prototype.render = function (rootEl) {\n    rootEl = rootEl || goog.dom.getElement(this.componentId_);\n    rootEl.appendChild(this.controller.getDOM());\n};\n\n/**\n * Get placeholder template\n * @return {string} placeholder markup.\n */\ntart.components.Widget.prototype.getPlaceholder = function () {\n    return this.templates_placeholder();\n};\n\n/**\n * Component's placeholder template\n * @return {string} placeholder markup.\n */\ntart.components.Widget.prototype.templates_placeholder = function () {\n    return '<div class=\"widgetPlaceholder\" id=\"' + this.componentId_ + '\"></div>';\n};\n\n/**\n * Get component id\n * @return {Number} component id.\n */\ntart.components.Widget.prototype.getId = function () {\n    return this.componentId_;\n};\n\n"
  },
  {
    "path": "tart/components/spec/ComponentsSpec.js",
    "content": "goog.require('tart.components.Controller');\ngoog.require('tart.base.Model');\ngoog.require('tart.components.View');\n\ngoog.provide('tart.components.SpecRunner');\n\ndescribe('Component', function() {\n\n    var opt_model = new tart.base.Model();\n    var opt_view = new tart.components.View();\n\n    describe('ComponentController', function() {\n        describe('has model and view objects in it', function() {\n            it('should have model object', function() {\n                var controller = new tart.components.Controller(opt_model, opt_view);\n                expect(controller.model instanceof tart.base.Model).toBeTruthy();\n            });\n\n            it('should have view object', function() {\n                var controller = new tart.components.Controller(opt_model, opt_view);\n                expect(controller.view instanceof tart.components.View).toBeTruthy();\n            });\n        });\n\n        describe('will get components DOM with buildDOM method', function() {\n            /**\n             * @constructor\n             * @extends {tart.components.View}\n             */\n            var ViewClass = function() {\n                goog.base(this);\n            };\n            goog.inherits(ViewClass, tart.components.View);\n\n            /**\n             * @return {string} markup string .\n             */\n            ViewClass.prototype.render = function() {\n                return '<h1>Foo</h1>';\n            };\n\n            var view = new ViewClass();\n            var controller = new tart.components.Controller(opt_model, view);\n            var dom = controller.buildDOM();\n\n            expect(dom).toBeTruthy();\n        });\n    });\n\n\n    describe('Component Model', function() {\n        describe('is event driven', function() {\n            it('should  be inherited from goog.events.EventTarget', function() {\n                var model = new tart.base.Model();\n                expect(model instanceof goog.events.EventTarget).toBeTruthy();\n            });\n\n\n            it(\"should supply events to it's sub classes\", function() {\n\n                /**\n                 * @constructor\n                 * @extends {tart.base.Model}\n                 * */\n                var SubModelClass = function() {\n                    goog.base(this);\n                };\n                goog.inherits(SubModelClass, tart.base.Model);\n\n\n                SubModelClass.EventTypes = {\n                    SOMETHING_HAPPENED: 'foo'\n                };\n\n\n                var subModel = new SubModelClass();\n\n                var text;\n\n                goog.events.listen(subModel, SubModelClass.EventTypes.SOMETHING_HAPPENED, function(e) {\n                    text = 'something triggered from model';\n                });\n\n                subModel.dispatchEvent({type: SubModelClass.EventTypes.SOMETHING_HAPPENED });\n\n                expect(text).toEqual('something triggered from model');\n            });\n        });\n    });\n\n\n    describe('ComponentView', function() {\n        describe('is an abstract class which sub classes should implement thier own \"render\" method', function() {\n            it('should throw en exception when \"render\" method called from own instance', function() {\n                var view = new tart.components.View();\n                var fn = function() {\n                    view.render();\n                };\n\n                expect(fn).toThrow();\n            });\n\n            it('should render markup if sub class implemented its own \"render\" method', function() {\n\n                /**\n                 * @constructor\n                 * @extends {tart.components.View}\n                 */\n                var SubViewClass = function() {\n                    goog.base(this);\n                };\n                goog.inherits(SubViewClass, tart.components.View);\n\n                /**\n                 * @return {string} markup .\n                 */\n                SubViewClass.prototype.render = function() {\n                    return '<b>this is rendered</b';\n                };\n\n                var subView = new SubViewClass();\n                expect(subView.render()).toBeTruthy();\n            });\n        });\n\n\n        describe('supplies dom traverse with \"get\" method', function() {\n            var SubViewClass;\n\n            beforeEach(function() {\n                /**\n                 * @constructor\n                 * @extends {tart.components.View}\n                 */\n                SubViewClass = function() {\n                    goog.base(this);\n\n                    this.domMappings = {\n                        HEADER: 'h1'\n                    };\n                };\n                goog.inherits(SubViewClass, tart.components.View);\n\n                SubViewClass.prototype.templates_header = function(text) {\n                    text = text || '';\n                    return '<h1>' + text + '</h1>';\n                };\n\n                SubViewClass.prototype.render = function() {\n                    return this.templates_header();\n                };\n            });\n\n\n            it('should find related element on DOM', function() {\n                var subView = new SubViewClass();\n\n                //TODO: make it work with closure\n                var dummyDiv = $('<div>').append(subView.render());\n\n                subView.setDOM(dummyDiv);\n                expect(subView.get(subView.domMappings.HEADER)[0]).toBe(dummyDiv.find('h1')[0]);\n            });\n\n\n            it('should throw a \"DOM not set yet\" exception if DOM not set yet', function() {\n\n                var fn = function() {\n                    var subView = new SubViewClass();\n                    subView.get(subView.domMappings.HEADER);\n                };\n\n                expect(fn).toThrow('DOM not set yet');\n            });\n\n        });\n    });\n\n\n});\n\n\n/**\n * Run jasmine specs\n */\ntart.components.SpecRunner = function() {\n    jasmine.getEnv()['addReporter'](new jasmine.TrivialReporter());\n    jasmine.getEnv()['execute']();\n}();\n"
  },
  {
    "path": "tart/components/spec/SpecRunner.html",
    "content": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\n  \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n    <title>Jasmine Test Runner</title>\n    <link rel=\"stylesheet\" type=\"text/css\" href=\"../../../third_party/jasmine/lib/jasmine.css\">\n    <script type=\"text/javascript\" src=\"../../../third_party/jasmine/lib/jasmine.js\"></script>\n    <script type=\"text/javascript\" src=\"../../../third_party/jasmine/lib/jasmine-html.js\"></script>\n\n    <!-- include source files here... -->\n    <script type=\"text/javascript\" src=\"../../../third_party/jquery/jquery-1.5.2.js\"></script>\n    <script type=\"text/javascript\" src=\"../../../third_party/goog/goog/base.js\"></script>\n\n    <script type=\"text/javascript\">\n        goog.require(\"goog.events.EventTarget\");\n    </script>\n\n    <script type=\"text/javascript\" src=\"../../base/Model.js\"></script>\n    <script type=\"text/javascript\" src=\"../View.js\"></script>\n    <script type=\"text/javascript\" src=\"../Controller.js\"></script>\n\n</head>\n<body>\n    <script type=\"text/javascript\" src=\"ComponentsSpec.js\"></script>\n</body>\n</html>\n"
  },
  {
    "path": "tart/dataProxy/Abstract.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview tart.dataProxy.Abstract base abstract class for local and xhr data proxies.\n */\n\ngoog.provide('tart.dataProxy.Abstract');\n\ngoog.require('goog.structs.Map');\n\n/**\n * Base model to handle xhr requests\n *\n * @constructor\n */\ntart.dataProxy.Abstract = function() {\n    /** @protected **/\n    this.params = new goog.structs.Map();\n};\n\n\n/**\n * Set params as hash map.\n * @param {goog.structs.Map} params hash map to hold fetch params\n */\ntart.dataProxy.Abstract.prototype.setParams = function (params) {\n    this.params = new goog.structs.Map(params);\n};\n\n/**\n * Abstract method, which all inherited classes should implement\n * @param {Function} callback callback method after fetch.\n */\ntart.dataProxy.Abstract.prototype.fetch = function(callback) {\n    goog.abstractMethod();\n};\n"
  },
  {
    "path": "tart/dataProxy/CircularLocal.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview tart.dataProxy.CircularLocal XHR data proxy.\n */\n\ngoog.provide('tart.dataProxy.CircularLocal');\ngoog.require('tart.dataProxy.Local');\n\n\n\n/**\n *\n * Base model to handle xhr requests\n *\n * @extends {tart.dataProxy.Local}\n * @constructor\n */\ntart.dataProxy.CircularLocal = function() {\n    goog.base(this);\n};\ngoog.inherits(tart.dataProxy.CircularLocal, tart.dataProxy.Local);\n\n\n/**\n * Fetch data from xhr and call a function with returned data\n * @param {Function=} callback function to call with returned data.\n */\ntart.dataProxy.CircularLocal.prototype.fetch = function(callback) {\n    var fetchedData = this.getData();\n    var pagerParam = this.params.get('paginationParams');\n\n    if (!fetchedData || !pagerParam)\n        callback.call(this);\n\n    var offset = pagerParam.get('offset'),\n        limit = pagerParam.get('limit'),\n        length = fetchedData.length,\n        tmp = [],\n        pos;\n\n    if (limit > length) limit = length;\n\n    for (var i = offset, loopCount = offset + limit; i < loopCount; i++) {\n        pos = (i % length + length) % length;\n\n        tmp.push(fetchedData[pos]);\n    }\n\n    fetchedData = tmp;\n    \n    callback.call(this, fetchedData);\n};\n"
  },
  {
    "path": "tart/dataProxy/Local.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview tart.dataProxy.Local XHR data proxy.\n */\n\ngoog.provide('tart.dataProxy.Local');\n\ngoog.require('tart.dataProxy.Abstract');\ngoog.require('goog.array');\n\n/**\n * Base model to handle xhr requests\n *\n * @extends {tart.dataProxy.Abstract}\n * @constructor\n */\ntart.dataProxy.Local = function() {\n    goog.base(this);\n    /** @private **/\n    this.data_ = undefined;\n};\ngoog.inherits(tart.dataProxy.Local, tart.dataProxy.Abstract);\n\n/**\n * Fetch data from xhr and call a function with returned data\n * @param {Function=} callback function to call with returned data.\n */\ntart.dataProxy.Local.prototype.fetch = function(callback) {\n\n    var fetchedData = this.data_;\n\n    var pagerParam = this.params.get(\"paginationParams\");\n\n    if (pagerParam) {\n        var offset = pagerParam.get(\"offset\");\n        var limit = pagerParam.get(\"limit\");\n        var tmp = [];\n\n        for(var i = offset; i < offset + limit; i++) {\n            if (fetchedData && fetchedData[i]) {\n                tmp.push(fetchedData[i]);\n            }\n        }\n\n        fetchedData = tmp;\n    }\n\n    callback.call(this, fetchedData);\n};\n\ntart.dataProxy.Local.prototype.setData = function(data) {\n    this.data_ = data;\n};\n\ntart.dataProxy.Local.prototype.getData = function() {\n    return this.data_;\n};\n\n"
  },
  {
    "path": "tart/dataProxy/Xhr.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview tart.dataProxy.Xhr XHR data proxy.\n */\n\ngoog.provide('tart.dataProxy.Xhr');\n\ngoog.require('tart.XhrManager');\ngoog.require('tart.dataProxy.Abstract');\n\n\n\n/**\n * Base model to handle xhr requests\n *\n * @extends {tart.dataProxy.Abstract}\n * @constructor\n */\ntart.dataProxy.Xhr = function() {\n    goog.base(this);\n};\ngoog.inherits(tart.dataProxy.Xhr, tart.dataProxy.Abstract);\n\n\n/**\n * Fetch data from xhr and call a function with returned data\n * @param {?function(Object)} callback function to call with returned data.\n * @param {function(Object)=} opt_fail function to call when request failed.\n */\ntart.dataProxy.Xhr.prototype.fetch = function(callback, opt_fail) {\n    var url = this.params.get('url_');\n    this.params.remove('url_');\n    url = '' + url; //cast to string to make it type safe for XhrManager.get\n\n    var method = this.params.get('method_');\n    var methodFn;\n    this.params.remove('method_');\n\n    switch (method) {\n        case 'post' :\n            methodFn = tart.XhrManager.post;\n            break;\n        default:\n            methodFn = tart.XhrManager.get;\n    }\n\n    /**\n     * get plain objects from Maps from given plugins\n     */\n    var pluginParams = this.params.getKeys();\n\n    for (var i = 0, ii = pluginParams.length; i < ii; i++) {\n        var param = this.params.get(pluginParams[i]);\n        if (param && param.constructor == goog.structs.Map) {\n            this.params.set(pluginParams[i], param.toObject());\n        }\n        else {\n            this.params.set(pluginParams[i], param);\n        }\n    }\n\n    methodFn(url, this.params.toObject(), callback, opt_fail);\n};\n"
  },
  {
    "path": "tart/date/DateRange.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview This file provides utility functions and classes for dateranges.\n */\n\n\n\ngoog.require('goog.date.DateRange');\n\ngoog.provide('tart.date.DateRange');\n\n\n/**\n * @constructor\n * @extends {goog.date.DateRange}\n * @inheritDoc\n */\ntart.date.DateRange = function(startDate, endDate) {\n    goog.base(this, startDate, endDate);\n};\ngoog.inherits(tart.date.DateRange, goog.date.DateRange);\n\n\n/**\n * Returns the range that includes the thirty days that end today.\n * @param {goog.date.Date=} opt_today The date to consider today.\n *     Defaults to today.\n * @return {goog.date.DateRange} The range that includes the thirty days that end today.\n */\ntart.date.DateRange.last30Days = function(opt_today) {\n    var today = opt_today || new goog.date.Date();\n    var month = today.clone();\n    month.add(new goog.date.Interval(goog.date.Interval.DAYS, -30));\n    return new goog.date.DateRange(month, today);\n};\n"
  },
  {
    "path": "tart/date/date.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview This file provides utility functions and classes for dates.\n */\n\ngoog.require('goog.date.DateTime');\ngoog.require('goog.i18n.DateTimeFormat');\ngoog.require('goog.math');\ngoog.provide('tart.date');\ngoog.provide('tart.date.Date');\n\n\n\n/**\n * @constructor\n * @extends {goog.date.Date}\n */\ntart.date.Date = function() {\n    goog.base(this);\n};\ngoog.inherits(tart.date.Date, goog.date.Date);\n\n\n/**\n * Returns a random time.\n * @return {Date} Random time.\n */\ntart.date.randomTime = function() {\n    return new Date(goog.math.randomInt(2147483648000));\n};\n\n\n/**\n * Returns a random time between two given times.\n * @param {(goog.date.DateLike|goog.date.DateTime)} Date1 A boundary time.\n * @param {(goog.date.DateLike|goog.date.DateTime)} Date2 Another boundary time.\n * @return {Date} random time.\n */\ntart.date.randomTimeInBetween = function(Date1, Date2) {\n    var smaller = Date1, bigger = Date2;\n    if (Date1 > Date2) {\n        smaller = Date2;\n        bigger = Date1;\n    }\n    return new Date(goog.math.uniformRandom(smaller.getTime(), bigger.getTime()));\n};\n\n\n/**\n * Returns a random time between now and a given interval.\n * @param {goog.date.Interval} interval Any interval of any length. Can be both positive or negative.\n * @return {Date} Random time.\n */\ntart.date.randomTimeInInterval = function(interval) {\n    var now = new goog.date.DateTime(),\n        then = now.clone();\n    then.add(interval);\n\n    return tart.date.randomTimeInBetween(now, then);\n};\n\n\n(function() {\n    var date = new goog.date.DateTime();\n    var formatterCache = {};\n    var rvCache = {};\n    /**\n     * Formats milliseconds by a given pattern.\n     *\n     * Usage: tart.date.formatMilliseconds(1320676229977, 'd MMMM, EEEE') returns \"7 Kasım, Pazartesi\".\n     * If you want to format by a specific timeZone, pass timeZone difference as minute,\n     * e.g. for GMT+2 pass goog.i18n.TimeZone.createTimeZone(-120).\n     * For further information about patterns, please check out datetimeformat.js under goog/i18n.\n     *\n     * @param {!number} milliseconds Milliseconds that will be formatted.\n     * @param {!string} pattern Format pattern.\n     * @param {goog.i18n.TimeZone=} opt_timeZone Timezone that will be used when formatting.\n     * @return {string} Formatted date.\n     */\n    tart.date.formatMilliseconds = function(milliseconds, pattern, opt_timeZone) {\n        date.setTime(milliseconds);\n        var formatter = formatterCache[pattern];\n        if (!formatter) formatter = formatterCache[pattern] = new goog.i18n.DateTimeFormat(pattern);\n\n        var cacheKey = milliseconds + pattern + (opt_timeZone ? opt_timeZone.getTimeZoneId() : '');\n        var rv = rvCache[cacheKey];\n        if (!rv) rv = rvCache[cacheKey] = formatter.format(date, opt_timeZone);\n\n        return rv;\n    };\n})();\n\n\n/**\n * Get day from given date.\n *\n * @param {Date} date Date.\n * @return {Date} Day.\n */\ntart.date.getDay = function(date) {\n    var timestamp = date.getTime();\n    return new Date(tart.date.getDayTimestamp(timestamp));\n};\n\n\n/**\n * Get day timestamp from given timestamp.\n * Subtracts the modulo of a full day time from given timestamp.\n *\n * @param {number} timestamp Timestamp.\n * @return {number} Day.\n */\ntart.date.getDayTimestamp = function(timestamp) {\n    return timestamp - (timestamp % (1000 * 60 * 60 * 24));\n};\n"
  },
  {
    "path": "tart/deps.js",
    "content": "// This file was autogenerated by third_party/goog/closure/bin/build/depswriter.py.\n// Please do not edit.\ngoog.addDependency('../../../../tart/Builder.js', ['tart.Builder'], ['tart.Err'], false);\ngoog.addDependency('../../../../tart/Carousel/Carousel.js', ['tart.Carousel', 'tart.Carousel.EventTypes'], ['goog.debug.ErrorHandler', 'goog.events.EventHandler', 'goog.events.EventTarget'], false);\ngoog.addDependency('../../../../tart/Carousel/spec/CarouselSpec.js', ['tart.Carousel.SpecRunner'], ['tart.Carousel'], false);\ngoog.addDependency('../../../../tart/CircularCarousel/CircularCarousel.js', ['tart.CircularCarousel'], ['goog.events.EventTarget', 'tart.Carousel'], false);\ngoog.addDependency('../../../../tart/CircularCarousel/spec/CircularCarouselSpec.js', ['tart.CircularCarousel.SpecRunner'], ['tart.CircularCarousel'], false);\ngoog.addDependency('../../../../tart/Collection.js', ['tart.Collection'], ['goog.array', 'goog.pubsub.PubSub', 'tart.Err'], false);\ngoog.addDependency('../../../../tart/DropdownList/DropdownBuilder.js', ['tart.DropdownBuilder'], ['tart.Builder'], false);\ngoog.addDependency('../../../../tart/DropdownList/DropdownList.js', ['tart.DropdownList'], ['tart.Collection', 'tart.DropdownBuilder'], false);\ngoog.addDependency('../../../../tart/Err.js', ['tart.Err'], ['tart'], false);\ngoog.addDependency('../../../../tart/FormValidator/FormValidator.js', ['tart.FormValidator'], ['tart.Validation'], false);\ngoog.addDependency('../../../../tart/FormValidator/spec/FormValidatorSpec.js', ['tart.FormValidator.SpecRunner'], ['tart.FormValidator'], false);\ngoog.addDependency('../../../../tart/List.js', ['tart.List'], ['tart.Collection'], false);\ngoog.addDependency('../../../../tart/Pagination/CircularPagination.js', ['tart.CircularPagination'], ['tart.Pagination'], false);\ngoog.addDependency('../../../../tart/Pagination/Pagination.js', ['tart.Pagination'], ['goog.debug.ErrorHandler', 'goog.events.EventHandler', 'goog.events.EventTarget'], false);\ngoog.addDependency('../../../../tart/Pagination/spec/PaginationSpec.js', ['tart.Pagination.SpecRunner'], ['tart.Pagination'], false);\ngoog.addDependency('../../../../tart/Registry.js', ['tart.Registry'], ['goog.structs.Map'], false);\ngoog.addDependency('../../../../tart/StateMachine/State.js', ['tart.State'], [], false);\ngoog.addDependency('../../../../tart/StateMachine/StateMachine.js', ['tart.StateMachine'], ['goog.array', 'goog.pubsub.PubSub', 'tart.State'], false);\ngoog.addDependency('../../../../tart/Tabs/TabPanel.js', ['tart.TabPanel'], ['goog.pubsub.PubSub'], false);\ngoog.addDependency('../../../../tart/Tabs/Tabs.js', ['tart.Tabs'], ['goog.pubsub.PubSub', 'tart.TabPanel'], false);\ngoog.addDependency('../../../../tart/Validation/Validation.js', ['tart.Validation', 'tart.Validation.has', 'tart.Validation.is'], [], false);\ngoog.addDependency('../../../../tart/Validation/spec/ValidationSpec.js', ['tart.Validation.SpecRunner'], ['tart.Validation'], false);\ngoog.addDependency('../../../../tart/XhrManager.js', ['tart.XhrManager'], [], false);\ngoog.addDependency('../../../../tart/base/Model.js', ['tart.base.Model'], ['goog.debug.ErrorHandler', 'goog.events.EventHandler', 'goog.events.EventTarget', 'goog.structs.Map'], false);\ngoog.addDependency('../../../../tart/base/plugin/BasePlugin.js', ['tart.base.plugin.BasePlugin'], ['goog.debug.ErrorHandler', 'goog.events.EventHandler', 'goog.events.EventTarget', 'goog.structs.Map'], false);\ngoog.addDependency('../../../../tart/base/plugin/Filter.js', ['tart.base.plugin.Filter'], ['tart.base.plugin.BasePlugin'], false);\ngoog.addDependency('../../../../tart/base/plugin/Pager.js', ['tart.base.plugin.Pager'], ['tart.Pagination', 'tart.base.plugin.BasePlugin'], false);\ngoog.addDependency('../../../../tart/base/plugin/Sorter.js', ['tart.base.plugin.Sorter'], ['tart.base.plugin.BasePlugin'], false);\ngoog.addDependency('../../../../tart/components/Carousel/Controller.js', ['tart.components.Carousel.Controller'], ['goog.events.EventTarget', 'tart.Pagination', 'tart.base.plugin.Pager', 'tart.components.Carousel.Model', 'tart.components.Carousel.Template', 'tart.components.Carousel.View', 'tart.components.Controller'], false);\ngoog.addDependency('../../../../tart/components/Carousel/Model.js', ['tart.components.Carousel.Model', 'tart.components.Carousel.Model.EventTypes'], ['goog.events.EventTarget', 'tart.Carousel', 'tart.base.Model', 'tart.dataProxy.CircularLocal'], false);\ngoog.addDependency('../../../../tart/components/Carousel/Template.js', ['tart.components.Carousel.Template'], [], false);\ngoog.addDependency('../../../../tart/components/Carousel/View.js', ['tart.components.Carousel.View'], ['tart.components.View'], false);\ngoog.addDependency('../../../../tart/components/Carousel/Widget.js', ['tart.components.Carousel.Widget'], ['tart.components.Carousel.Controller', 'tart.components.Widget'], false);\ngoog.addDependency('../../../../tart/components/Controller.js', ['tart.components.Controller'], ['tart.base.Model', 'tart.components.View'], false);\ngoog.addDependency('../../../../tart/components/RemoteModel.js', ['tart.components.models.RemoteModel'], ['tart.base.Model', 'tart.dataProxy.Xhr'], false);\ngoog.addDependency('../../../../tart/components/ThumbnailedCarousel/Model.js', ['tart.components.ThumbnailedCarousel.Model'], ['tart.components.Carousel.Model'], false);\ngoog.addDependency('../../../../tart/components/ThumbnailedCarousel/SpotController.js', ['tart.components.ThumbnailedCarousel.SpotController'], ['tart.CircularPagination', 'tart.components.Carousel.Controller', 'tart.components.ThumbnailedCarousel.Model', 'tart.components.ThumbnailedCarousel.SpotView', 'tart.components.ThumbnailedCarousel.ThumbnailsController', 'tart.components.ThumbnailedCarousel.ThumbnailsTemplate'], false);\ngoog.addDependency('../../../../tart/components/ThumbnailedCarousel/SpotTemplate.js', ['tart.components.ThumbnailedCarousel.SpotTemplate'], ['tart.components.Carousel.Template'], false);\ngoog.addDependency('../../../../tart/components/ThumbnailedCarousel/SpotView.js', ['tart.components.ThumbnailedCarousel.SpotView'], ['tart.components.Carousel.View', 'tart.components.ThumbnailedCarousel.SpotTemplate'], false);\ngoog.addDependency('../../../../tart/components/ThumbnailedCarousel/ThumbnailsController.js', ['tart.components.ThumbnailedCarousel.ThumbnailsController'], ['tart.CircularPagination', 'tart.components.Carousel.Controller', 'tart.components.ThumbnailedCarousel.ThumbnailsView'], false);\ngoog.addDependency('../../../../tart/components/ThumbnailedCarousel/ThumbnailsTemplate.js', ['tart.components.ThumbnailedCarousel.ThumbnailsTemplate'], ['tart.components.Carousel.Template'], false);\ngoog.addDependency('../../../../tart/components/ThumbnailedCarousel/ThumbnailsView.js', ['tart.components.ThumbnailedCarousel.ThumbnailsView'], ['tart.components.Carousel.View', 'tart.components.ThumbnailedCarousel.ThumbnailsTemplate'], false);\ngoog.addDependency('../../../../tart/components/ThumbnailedCarousel/Widget.js', ['tart.components.ThumbnailedCarousel.Widget'], ['tart.components.Carousel.Widget', 'tart.components.ThumbnailedCarousel.SpotController'], false);\ngoog.addDependency('../../../../tart/components/View.js', ['tart.components.View'], [], false);\ngoog.addDependency('../../../../tart/components/Widget.js', ['tart.components.Widget'], ['tart'], false);\ngoog.addDependency('../../../../tart/components/spec/ComponentsSpec.js', ['tart.components.SpecRunner'], ['tart.base.Model', 'tart.components.Controller', 'tart.components.View'], false);\ngoog.addDependency('../../../../tart/dataProxy/Abstract.js', ['tart.dataProxy.Abstract'], ['goog.structs.Map'], false);\ngoog.addDependency('../../../../tart/dataProxy/CircularLocal.js', ['tart.dataProxy.CircularLocal'], ['tart.dataProxy.Local'], false);\ngoog.addDependency('../../../../tart/dataProxy/Local.js', ['tart.dataProxy.Local'], ['goog.array', 'tart.dataProxy.Abstract'], false);\ngoog.addDependency('../../../../tart/dataProxy/Xhr.js', ['tart.dataProxy.Xhr'], ['tart.XhrManager', 'tart.dataProxy.Abstract'], false);\ngoog.addDependency('../../../../tart/date/DateRange.js', ['tart.date.DateRange'], ['goog.date.DateRange'], false);\ngoog.addDependency('../../../../tart/date/date.js', ['tart.date', 'tart.date.Date'], ['goog.date.DateTime', 'goog.i18n.DateTimeFormat', 'goog.math'], false);\ngoog.addDependency('../../../../tart/dom/dom.js', ['tart.dom'], [], false);\ngoog.addDependency('../../../../tart/events.js', ['tart.events'], [], false);\ngoog.addDependency('../../../../tart/events/GestureHandler.js', ['tart.events.GestureHandler'], ['goog.dom', 'goog.events.EventTarget', 'goog.math.Coordinate'], false);\ngoog.addDependency('../../../../tart/events/HoverHandler.js', ['tart.events.HoverHandler'], ['goog.dom', 'goog.events.EventTarget'], false);\ngoog.addDependency('../../../../tart/locale/en.js', ['tart.locale.en'], [], false);\ngoog.addDependency('../../../../tart/locale/locale.js', ['tart.locale'], ['tart.locale.en', 'tart.locale.tr'], false);\ngoog.addDependency('../../../../tart/locale/tr.js', ['tart.locale.tr'], [], false);\ngoog.addDependency('../../../../tart/mock/jQuery/xhr.js', ['tart.mock.jQuery.xhr'], [], false);\ngoog.addDependency('../../../../tart/money/Currency.js', ['tart.Currency'], [], false);\ngoog.addDependency('../../../../tart/money/CurrencyTL.js', ['tart.CurrencyTL'], ['tart.Currency'], false);\ngoog.addDependency('../../../../tart/money/CurrencyUSD.js', ['tart.CurrencyUSD'], ['tart.Currency'], false);\ngoog.addDependency('../../../../tart/money/Money.js', ['tart.Money'], ['tart.CurrencyTL', 'tart.CurrencyUSD'], false);\ngoog.addDependency('../../../../tart/mvc/Action.js', ['tart.mvc.Action'], [], false);\ngoog.addDependency('../../../../tart/mvc/Application.js', ['tart.mvc.Application'], ['goog.History', 'goog.debug.ErrorHandler', 'goog.events', 'tart.dom', 'tart.mvc.Action', 'tart.mvc.Controller', 'tart.mvc.IApplication', 'tart.mvc.Layout', 'tart.mvc.Model', 'tart.mvc.Renderer', 'tart.mvc.uri.Route', 'tart.mvc.uri.Router'], false);\ngoog.addDependency('../../../../tart/mvc/Controller.js', ['tart.mvc.Controller'], [], false);\ngoog.addDependency('../../../../tart/mvc/IApplication.js', ['tart.mvc.IApplication'], [], false);\ngoog.addDependency('../../../../tart/mvc/Layout.js', ['tart.mvc.Layout'], ['tart.mvc.View'], false);\ngoog.addDependency('../../../../tart/mvc/MobileAction.js', ['tart.mvc.MobileAction'], [], false);\ngoog.addDependency('../../../../tart/mvc/MobileRenderer.js', ['tart.mvc.MobileRenderer'], ['tart.mvc.MobileAction', 'tart.mvc.Renderer'], false);\ngoog.addDependency('../../../../tart/mvc/Model.js', ['tart.mvc.Model'], [], false);\ngoog.addDependency('../../../../tart/mvc/Renderer.js', ['tart.mvc.Renderer'], ['tart.mvc.Action', 'tart.mvc.Layout', 'tart.mvc.View', 'tart.mvc.uri.Redirection'], false);\ngoog.addDependency('../../../../tart/mvc/View.js', ['tart.mvc.View'], [], false);\ngoog.addDependency('../../../../tart/mvc/mvc.js', ['tart.mvc'], ['tart.mvc.Application'], false);\ngoog.addDependency('../../../../tart/mvc/test/Bootstrapper.js', ['mvcapp.Bootstrapper'], ['mvcapp.Application'], false);\ngoog.addDependency('../../../../tart/mvc/test/application/controllers/GamesController.js', ['mvcapp.controllers.GamesController'], ['mvcapp.views.layouts.rare', 'mvcapp.views.scripts.games.index', 'mvcapp.views.scripts.games.list', 'tart.mvc.Controller'], false);\ngoog.addDependency('../../../../tart/mvc/test/application/controllers/IndexController.js', ['mvcapp.controllers.IndexController'], ['mvcapp.views.scripts.index.list', 'tart.mvc.Controller'], false);\ngoog.addDependency('../../../../tart/mvc/test/application/mvcapp.js', ['mvcapp.Application'], ['mvcapp.controllers.GamesController', 'mvcapp.controllers.IndexController', 'mvcapp.views.layouts.common', 'tart.mvc'], false);\ngoog.addDependency('../../../../tart/mvc/test/application/views/layouts/common.js', ['mvcapp.views.layouts.common'], [], false);\ngoog.addDependency('../../../../tart/mvc/test/application/views/layouts/rare.js', ['mvcapp.views.layouts.rare'], [], false);\ngoog.addDependency('../../../../tart/mvc/test/application/views/scripts/games/index.js', ['mvcapp.views.scripts.games.index'], [], false);\ngoog.addDependency('../../../../tart/mvc/test/application/views/scripts/games/list.js', ['mvcapp.views.scripts.games.list'], [], false);\ngoog.addDependency('../../../../tart/mvc/test/application/views/scripts/index/list.js', ['mvcapp.views.scripts.index.list'], [], false);\ngoog.addDependency('../../../../tart/mvc/uri/Redirection.js', ['tart.mvc.uri.Redirection'], [], false);\ngoog.addDependency('../../../../tart/mvc/uri/Request.js', ['tart.mvc.uri.Request'], ['goog.Uri'], false);\ngoog.addDependency('../../../../tart/mvc/uri/Route.js', ['tart.mvc.uri.Route'], ['tart.Err'], false);\ngoog.addDependency('../../../../tart/mvc/uri/Router.js', ['tart.mvc.uri.Router'], ['goog.array', 'goog.object', 'tart.mvc.uri.Redirection', 'tart.mvc.uri.Request'], false);\ngoog.addDependency('../../../../tart/storage/Storage.js', ['tart.storage.Storage'], ['goog.json'], false);\ngoog.addDependency('../../../../tart/string/string.js', ['tart.string'], [], false);\ngoog.addDependency('../../../../tart/tart.js', ['tart'], [], false);\ngoog.addDependency('../../../../tart/ui/Component.js', ['tart.ui.Component'], ['goog.events.EventTarget', 'tart', 'tart.dom'], false);\ngoog.addDependency('../../../../tart/ui/ComponentManager.js', ['tart.ui.ComponentManager'], ['goog.array', 'goog.events.EventType', 'tart.events', 'tart.events.GestureHandler', 'tart.events.HoverHandler'], false);\ngoog.addDependency('../../../../tart/ui/ComponentModel.js', ['tart.ui.ComponentModel'], ['goog.events.EventTarget'], false);\ngoog.addDependency('../../../../tart/ui/DlgComponent.js', ['tart.ui.DlgComponent'], ['goog.events.EventTarget', 'tart', 'tart.dom', 'tart.ui.ComponentManager'], false);\ngoog.addDependency('../../../../tart/ui/InfiniteScroll/InfiniteScrollComponent.js', ['tart.ui.InfiniteScrollComponent'], ['goog.async.Throttle', 'tart.ui.DlgComponent', 'tart.ui.InfiniteScrollComponentModel'], false);\ngoog.addDependency('../../../../tart/ui/InfiniteScroll/InfiniteScrollComponentModel.js', ['tart.ui.InfiniteScrollComponentModel'], ['tart.ui.ComponentModel'], false);\ngoog.addDependency('../../../../tart/ui/NavBar/NavBarComponent.js', ['tart.ui.NavBarComponent'], ['tart.ui.DlgComponent'], false);\ngoog.addDependency('../../../../tart/ui/PullToRefresh/P2RComponent.js', ['tart.ui.P2RComponent'], ['goog.async.Throttle', 'tart.ui.DlgComponent', 'tart.ui.P2RComponentModel'], false);\ngoog.addDependency('../../../../tart/ui/PullToRefresh/P2RComponentModel.js', ['tart.ui.P2RComponentModel'], ['tart.ui.ComponentModel'], false);\ngoog.addDependency('../../../../tart/ui/Sidebar/SidebarComponent.js', ['tart.ui.SidebarComponent'], ['tart.ui.DlgComponent'], false);\ngoog.addDependency('../../../../tart/ui/TabBar/TabBarView.js', ['tart.ui.TabBarView'], ['tart.ui.View'], false);\ngoog.addDependency('../../../../tart/ui/View.js', ['tart.ui.View'], ['tart.ui.DlgComponent', 'tart.ui.ViewManager'], false);\ngoog.addDependency('../../../../tart/ui/ViewManager.js', ['tart.ui.ViewManager'], ['goog.math'], false);\ngoog.addDependency('../../../../tart/ui/ViewModel.js', ['tart.ui.ViewModel'], ['tart.ui.ComponentModel'], false);\ngoog.addDependency('../../../../tart/ui/input/DateComponent.js', ['tart.ui.input.DateComponent'], ['goog.events.EventTarget', 'tart.ui.DlgComponent'], false);\ngoog.addDependency('../../../../tart/ui/input/RevealingPassword.js', ['tart.ui.input.RevealingPassword'], ['tart.ui.DlgComponent'], false);\ngoog.addDependency('../../../../tart/ui/tooltip/TooltipComponent.js', ['tart.ui.TooltipComponent'], ['goog.dom', 'goog.style', 'tart.ui.Component', 'tart.ui.TooltipComponentModel'], false);\ngoog.addDependency('../../../../tart/ui/tooltip/TooltipComponentModel.js', ['tart.ui.TooltipComponentModel'], ['tart.StateMachine', 'tart.ui.ComponentModel'], false);\n"
  },
  {
    "path": "tart/dom/dom.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview This file provides commonly used DOM functions.\n */\n\ngoog.provide('tart.dom');\n\n\n\n(function() {\n    var tempDiv = document.createElement('div');\n\n    /**\n     * Stripped down version of goog.dom.htmlToDocumentFragment. Its performance is fantastic across all browsers.\n     *\n     * This version won't work with <code><script></code> and <code><style></code> tags in IE.\n     * Also, it requires only one element in the top hieararchy, which basically means you have to combine\n     * your elements under one parent div, or you will only get the first element.\n     *\n     * @param {string} htmlString The HTML string to convert.\n     * @return {!Node} The resulting element.\n     */\n    tart.dom.createElement = function(htmlString) {\n        tempDiv.innerHTML = htmlString;\n        return /** @type {!Node} */ (tempDiv.removeChild(tempDiv.firstChild));\n    };\n})();\n"
  },
  {
    "path": "tart/events/GestureHandler.js",
    "content": "// Copyright 2012 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview GestureHandler adds the ability to capture gesture events on touch enabled devices.\n * It listens to 'touchstart', 'touchmove' and 'touchend' events and generates 'tap' or 'swipe' events with\n * inherent heuristics.\n *\n * Currently, the tap algorithm begins with a touchstart, checks for touchend. Any touchmove greater than 3px\n * cancels the tap event, and if a touchend is captured without a touchmove after a touchstart;\n * it's registered as a tap, and the GestureHandler dispatches a tap event on the touchend target.\n *\n * Swipe up, left, right and down gestures are also supported.\n *\n * Example usage:\n *\n *     goog.events.listen(document.body, tart.events.EventType.TAP, function() {\n *         console.log('tapped!');\n *     });\n *\n */\n\ngoog.provide('tart.events.GestureHandler');\ngoog.require('goog.dom');\ngoog.require('goog.events.EventTarget');\ngoog.require('goog.math.Coordinate');\n\n\n\n/**\n * Tracks and fires gestures on touch enabled devices.\n *\n * @constructor\n * @param {Element=} opt_el Provided, gesture handler will track gesture events on this element. The default\n *                          value is document.body; but an optional root element is inevitable for iframe's.\n */\ntart.events.GestureHandler = function(opt_el) {\n    this.el = opt_el || document.body;\n\n    goog.events.listen(this.el, goog.events.EventType.TOUCHSTART, this.onTouchstart, false, this);\n    goog.events.listen(this.el, goog.events.EventType.TOUCHMOVE, this.onTouchmove, false, this);\n    goog.events.listen(this.el, goog.events.EventType.TOUCHEND, this.onTouchend, false, this);\n};\ngoog.addSingletonGetter(tart.events.GestureHandler);\n\n\n/**\n * iOS 6.0(+?) requires the target element to be manually derived.\n * @type {?boolean}\n */\ntart.events.GestureHandler.prototype.deviceIsIOSWithBadTarget = navigator.userAgent.match(/iPhone/i) &&\n    (/OS ([6-9]|\\d{2})_\\d/).test(navigator.userAgent);\n\n\ntart.events.GestureHandler.prototype.onTouchstart = function(e) {\n    this.isInMotion = true;\n    this.canTap = true;\n    this.canSwipe = true;\n    this.touchStartTime = new Date().getTime();\n\n    var browserEvent = e.getBrowserEvent();\n    var changedTouch = browserEvent.changedTouches[0];\n\n    this.touches = [browserEvent.timeStamp, changedTouch.pageX, changedTouch.pageY];\n};\n\n\ntart.events.GestureHandler.prototype.onTouchmove = function(e) {\n    var touches = this.touches,\n        browserEvent = e.getBrowserEvent(),\n        changedTouch = browserEvent.changedTouches[0];\n\n    if (Math.abs(changedTouch.pageX - touches[1]) > 20 ||\n        Math.abs(changedTouch.pageY - touches[2]) > 20)\n        this.canTap = false;\n\n    if (this.canSwipe) {\n        touches.push(browserEvent.timeStamp, changedTouch.pageX, changedTouch.pageY);\n        if (+new Date() > touches[0] + 100) {\n            this.canSwipe = false;\n            return;\n        }\n\n        // Filter the touches\n        var date = browserEvent.timeStamp;\n        touches = goog.array.filter(touches, function(touch, index, arr) {\n            var relatedTimeStamp = arr[index - (index % 3)];\n            return relatedTimeStamp > date - 250;\n        });\n\n\n        if ((touches.length / 3) > 1) {\n            var firstTouch = new goog.math.Coordinate(touches[1], touches[2]);\n            var lastTouch = new goog.math.Coordinate(touches[touches.length - 2],\n                touches[touches.length - 1]);\n\n            // calculate distance. must be min 60px\n            var distance = goog.math.Coordinate.distance(firstTouch, lastTouch);\n            if (distance < 60) return;\n\n            // calculate angle.\n            var angle = goog.math.angle(firstTouch.x, firstTouch.y, lastTouch.x, lastTouch.y);\n\n            var eventType = tart.events.EventType.SWIPE_RIGHT;\n            if (angle > 45 && angle < 135) {\n                eventType = tart.events.EventType.SWIPE_DOWN;\n            }\n            else if (angle > 135 && angle < 225) {\n                eventType = tart.events.EventType.SWIPE_LEFT;\n            }\n            else if (angle > 225 && angle < 315) {\n                eventType = tart.events.EventType.SWIPE_UP;\n            }\n\n            var swipe = document.createEvent(\"Event\");\n            swipe.initEvent(eventType, true, true);\n            e.target.dispatchEvent(swipe);\n\n            this.canSwipe = false;\n        }\n    }\n};\n\n\ntart.events.GestureHandler.prototype.onTouchend = function(e) {\n    this.isInMotion = false;\n    if (this.canTap) {\n        var touches = this.touches,\n            browserEvent = e.getBrowserEvent(),\n            changedTouch = browserEvent.changedTouches[0];\n\n        if (Math.abs(changedTouch.pageX - touches[1]) > 20 ||\n            Math.abs(changedTouch.pageY - touches[2]) > 20) {\n            this.canTap = false;\n            return;\n        }\n\n        var tapTimeDiff = new Date().getTime() - this.touchStartTime;\n        var tap = document.createEvent(\"Event\");\n        var eventName = tapTimeDiff > 800 ? tart.events.EventType.LONG_TAP : tart.events.EventType.TAP;\n        tap.initEvent(eventName, true, true);\n\n        // Target element fix for iOS6+\n        var targetElement = e.target;\n        if (this.deviceIsIOSWithBadTarget)\n            targetElement = document.elementFromPoint(changedTouch.pageX - window.pageXOffset,\n                changedTouch.pageY - window.pageYOffset);\n\n        targetElement.dispatchEvent(tap);\n    }\n};\n"
  },
  {
    "path": "tart/events/HoverHandler.js",
    "content": "// Copyright 2012 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview Google Closure Library doesn't like mouseenter and mouseleave events, and provides no easy\n * way to listen to it. Therefore, HoverHandler provides a consistent behavior of mouseenter and leave actions.\n *\n * Example usage:\n *\n *     var handler = new tart.events.HoverHandler(elementToListen); // default is body.\n *     goog.events.listen(handler, tart.events.EventType.MOUSEENTER, function() {\n *         console.log(\"i'm on hover\");\n *     });\n *\n */\n\ngoog.provide('tart.events.HoverHandler');\ngoog.require('goog.dom');\ngoog.require('goog.events.EventTarget');\n\n\n\n/**\n * Tracks and fires mouseenter and mouseleave events on DOM elements.\n *\n * @constructor\n * @extends {goog.events.EventTarget}\n * @param {Element=} opt_el Optional element to bind mouseover and mouseout events to. Default is document.body.\n */\ntart.events.HoverHandler = function(opt_el) {\n    goog.base(this);\n\n    var target = opt_el || document.body;\n    goog.events.listen(target, [goog.events.EventType.MOUSEOVER, goog.events.EventType.MOUSEOUT], this);\n};\ngoog.inherits(tart.events.HoverHandler, goog.events.EventTarget);\n\n\n/**\n * This handles the underlying events and dispatches a new event.\n * @param {goog.events.BrowserEvent} e  The underlying browser event.\n */\ntart.events.HoverHandler.prototype.handleEvent = function(e) {\n    // fire mouseenter event\n    if (e.type == goog.events.EventType.MOUSEOVER) {\n        if (e.relatedTarget && !goog.dom.contains(e.target, e.relatedTarget)) {\n            var a = new goog.events.BrowserEvent(e.getBrowserEvent());\n            a.type = tart.events.EventType.MOUSEENTER;\n            this.dispatchEvent(a);\n        }\n    }\n\n    // fire mouseleave event\n    else if (e.type == goog.events.EventType.MOUSEOUT) {\n        if (e.relatedTarget && !goog.dom.contains(e.target, e.relatedTarget)) {\n            var a = new goog.events.BrowserEvent(e.getBrowserEvent());\n            a.type = tart.events.EventType.MOUSELEAVE;\n            this.dispatchEvent(a);\n        }\n    }\n};\n"
  },
  {
    "path": "tart/events.js",
    "content": "// Copyright (c) 2012 Tart New Media (http://www.tart.com.tr)\n// Tart Commercial License\n//\n// @author Sönmez Kartal <sonmez.kartal@tart.com.tr>\n\n/**\n * @fileoverview Event Manager.\n *\n * Provides browser event handling routines.\n *\n * This module extends goog.events for additional support.\n */\n\ngoog.provide('tart.events');\n\n\n/**\n * Constants for event names.\n *\n * @enum {string} Type definitions\n */\ntart.events.EventType = {\n    MOUSEENTER: 'mouseenter',\n    MOUSELEAVE: 'mouseleave',\n    TAP: 'tap',\n    LONG_TAP: 'longTap',\n    SWIPE_RIGHT: 'swipeRight',\n    SWIPE_UP: 'swipeUp',\n    SWIPE_LEFT: 'swipeLeft',\n    SWIPE_DOWN: 'swipeDown'\n};\n"
  },
  {
    "path": "tart/externs/jasmine.externs.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nvar it = {};\nvar runs = {};\nvar describe = {};\nvar waitsFor = {};\n\n\n/** @typedef {Object} */\nvar jasmineMatcher = {\n    toEqual: function() {},\n    toBeTruthy: function() {},\n    toBeFalsy: function() {},\n    toBe: function() {},\n    toThrow: function() {},\n    toBeGreaterThan: function() {}\n};\n\n\n/**\n * @return {jasmineMatcher}\n */\nvar expect = function(a) {};\nvar beforeEach = {};\n\nvar jasmine = {\n    'unimplementedMethod_': function() {},\n    'undefined': {},\n    'VERBOSE': {},\n    'DEFAULT_UPDATE_INTERVAL': {},\n    'DEFAULT_TIMEOUT_INTERVAL': {},\n    'getGlobal': function() {},\n    'bindOriginal_': function() {},\n    'setTimeout': function() {},\n    'clearTimeout': function() {},\n    'setInterval': function() {},\n    'clearInterval': function() {},\n    'MessageResult': function() {},\n    'ExpectationResult': function() {},\n    'getEnv': function() {},\n    'isArray_': function() {},\n    'isString_': function() {},\n    'isNumber_': function() {},\n    'isA_': function() {},\n    'pp': function() {},\n    'isDomNode': function() {},\n    'any': function() {},\n    'Spy': function() {},\n    'createSpy': function() {},\n    'isSpy': function() {},\n    'createSpyObj': function() {},\n    'log': function() {},\n    'XmlHttpRequest': function() {},\n    'util': {\n        'inherit': function() {},\n        'formatException': function() {},\n        'htmlEscape': function() {},\n        'argsToArray': function() {},\n        'extend': function() {}\n    },\n    'Env': function() {},\n    'Reporter': function() {},\n    'Block': function() {},\n    'JsApiReporter': function() {},\n    'Matchers': function() {},\n    'MultiReporter': function() {},\n    'NestedResults': function() {},\n    'PrettyPrinter': function() {},\n    'StringPrettyPrinter': function() {},\n    'Queue': function() {},\n    'Runner': function() {},\n    'Spec': function() {},\n    'Suite': function() {},\n    'WaitsBlock': function() {},\n    'WaitsForBlock': function() {},\n    'FakeTimer': function() {},\n    'Clock': {\n        'defaultFakeTimer': {\n            'timeoutsMade': {},\n            'scheduledFunctions': function() {},\n            'nowMillis': {},\n            'setTimeout': function() {},\n            'setInterval': function() {},\n            'clearTimeout': function() {},\n            'clearInterval': function() {},\n            'reset': function() {},\n            'tick': function() {},\n            'runFunctionsWithinRange': function() {},\n            'scheduleFunction': function() {}\n        },\n        'reset': function() {},\n        'tick': function() {},\n        'runFunctionsWithinRange': function() {},\n        'scheduleFunction': function() {},\n        'useMock': function() {},\n        'installMock': function() {},\n        'uninstallMock': function() {},\n        'real': {\n            'setTimeout': function() {},\n            'clearTimeout': function() {},\n            'setInterval': function() {},\n            'clearInterval': function() {}\n        },\n        'assertInstalled': function() {},\n        'isInstalled': function() {},\n        'installed': {\n            'setTimeout': function() {},\n            'clearTimeout': function() {},\n            'setInterval': function() {},\n            'clearInterval': function() {}\n        }\n    },\n    'version_': {\n        'major': {},\n        'minor': {},\n        'build': {},\n        'revision': {}\n    },\n    'TrivialReporter': function() {}\n};\n"
  },
  {
    "path": "tart/externs/jquery-1.4.4.externs.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n/*\n* Copyright 2010 The Closure Compiler Authors\n*\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n* you may not use this file except in compliance with the License.\n* You may obtain a copy of the License at\n*\n*     http://www.apache.org/licenses/LICENSE-2.0\n*\n* Unless required by applicable law or agreed to in writing, software\n* distributed under the License is distributed on an \"AS IS\" BASIS,\n* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n* See the License for the specific language governing permissions and\n* limitations under the License.\n*/\n\n/**\n* @fileoverview Externs for jQuery 1.4.4.\n* Note that some functions use different return types depending on the number\n* of parameters passed in. In these cases, you may need to annotate the type\n* of the result in your code, so the JSCompiler understands which type you're\n* expecting. For example:\n*\n*     var elt = /** @type {Element} * / (foo.get(0));\n*\n* @see http://api.jquery.com/\n* @externs\n*/\n\n\n/** @typedef {(Window|Document|Element|Array.<Element>|string|jQueryObject)} */\nvar jQuerySelector;\n\n\n/**\n * @param {(jQuerySelector|Element|Array|Object|string|function())=} arg1\n * @param {(Element|jQueryObject|Document|Object)=} arg2\n * @return {jQueryObject}\n */\nfunction $(arg1, arg2) {}\n\n\n/**\n * @param {(jQuerySelector|Element|Array|Object|string|function())=} arg1\n * @param {(Element|jQueryObject|Document|Object)=} arg2\n * @return {jQueryObject}\n */\nfunction jQuery(arg1, arg2) {}\n\n\n/**\n * @param {Object.<string,*>} settings\n * @return {XMLHttpRequest}\n */\njQuery.ajax = function(settings) {};\n\n\n/** @param {Object.<string,*>} options */\njQuery.ajaxSetup = function(options) {};\n\n\n/** @type {boolean} */\njQuery.boxModel;\n\n\n/** @type {Object.<string,*>} */\njQuery.browser;\n\n\n/** @type {string} */\njQuery.browser.version;\n\n\n/**\n * @param {Element} container\n * @param {Element} contained\n * @return {boolean}\n */\njQuery.contains = function(container, contained) {};\n\n\n/**\n * @param {Element} elem\n * @param {string=} key\n * @param {Object=} value\n * @return {(jQueryObject|Object)}\n */\njQuery.data = function(elem, key, value) {};\n\n\n/**\n * @param {Element} elem\n * @param {string=} queueName\n * @return {jQueryObject}\n */\njQuery.dequeue = function(elem, queueName) {};\n\n\n/**\n * @param {Object} collection\n * @param {function(number,*)} callback\n * @return {Object}\n */\njQuery.each = function(collection, callback) {};\n\n\n/** @param {string} message */\njQuery.error = function(message) {};\n\n\n\n/**\n * @constructor\n * @param {string} eventType\n */\njQuery.event = function(eventType) {};\n\n\n/** @type {Element} */\njQuery.event.prototype.currentTarget;\n\n\n/** @type {*} */\njQuery.event.prototype.data;\n\n\n/** @return {boolean} */\njQuery.event.prototype.isDefaultPrevented = function() {};\n\n\n/** @return {boolean} */\njQuery.event.prototype.isImmediatePropagationStopped = function() {};\n\n\n/** @return {boolean} */\njQuery.event.prototype.isPropagationStopped = function() {};\n\n\n/** @type {string} */\njQuery.event.prototype.namespace;\n\n\n/** @type {number} */\njQuery.event.prototype.pageX;\n\n\n/** @type {number} */\njQuery.event.prototype.pageY;\n\n\n/** @return {undefined} */\njQuery.event.prototype.preventDefault = function() {};\n\n\n/** @type {Element} */\njQuery.event.prototype.relatedTarget;\n\n\n/** @type {Object} */\njQuery.event.prototype.result;\n\n\n/** @return {undefined} */\njQuery.event.prototype.stopImmediatePropagation = function() {};\n\n\n/** @return {undefined} */\njQuery.event.prototype.stopPropagation = function() {};\n\n\n/** @type {Element} */\njQuery.event.prototype.target;\n\n\n/** @type {number} */\njQuery.event.prototype.timeStamp;\n\n\n/** @type {string} */\njQuery.event.prototype.type;\n\n\n/** @type {number} */\njQuery.event.prototype.which;\n\n\n/**\n * @param {(Object|boolean)=} arg1\n * @param {Object=} arg2\n * @param {Object=} arg3\n * @param {Object=} objectN\n * @return {Object}\n */\njQuery.extend = function(arg1, arg2, arg3, objectN) {};\n\njQuery.fx = {};\n\n\n/** @type {number} */\njQuery.fx.interval;\n\n\n/** @type {boolean} */\njQuery.fx.off;\n\n\n/**\n * @param {string} url\n * @param {(Object.<string,*>|string)=} data\n * @param {function(string,string,XMLHttpRequest)=} callback\n * @param {string=} dataType\n * @return {XMLHttpRequest}\n */\njQuery.get = function(url, data, callback, dataType) {};\n\n\n/**\n * @param {string} url\n * @param {Object.<string,*>=} data\n * @param {function(string,string,XMLHttpRequest)=} callback\n * @return {XMLHttpRequest}\n */\njQuery.getJSON = function(url, data, callback) {};\n\n\n/**\n * @param {string} url\n * @param {function(string,string)=} success\n * @return {XMLHttpRequest}\n */\njQuery.getScript = function(url, success) {};\n\n\n/** @param {string} code */\njQuery.globalEval = function(code) {};\n\n\n/**\n * @param {Array} arr\n * @param {function(*,number)} fnc\n * @param {boolean=} invert\n * @return {Array}\n */\njQuery.grep = function(arr, fnc, invert) {};\n\n\n/**\n * @param {*} value\n * @param {Array} arr\n * @return {number}\n */\njQuery.inArray = function(value, arr) {};\n\n\n/**\n * @param {Object} obj\n * @return {boolean}\n * @nosideeffects\n */\njQuery.isArray = function(obj) {};\n\n\n/**\n * @param {Object} obj\n * @return {boolean}\n * @nosideeffects\n */\njQuery.isEmptyObject = function(obj) {};\n\n\n/**\n * @param {Object} obj\n * @return {boolean}\n * @nosideeffects\n */\njQuery.isFunction = function(obj) {};\n\n\n/**\n * @param {Object} obj\n * @return {boolean}\n * @nosideeffects\n */\njQuery.isPlainObject = function(obj) {};\n\n\n/**\n * @param {Object} obj\n * @return {boolean}\n * @nosideeffects\n */\njQuery.isWindow = function(obj) {};\n\n\n/**\n * @param {Element} node\n * @return {boolean}\n * @nosideeffects\n */\njQuery.isXMLDoc = function(node) {};\n\n\n/**\n * @param {Object} obj\n * @return {Array}\n */\njQuery.makeArray = function(obj) {};\n\n\n/**\n * @param {Array} arr\n * @param {function(*,number)} callback\n * @return {Array}\n */\njQuery.map = function(arr, callback) {};\n\n\n/**\n * @param {Array} first\n * @param {Array} second\n * @return {Array}\n */\njQuery.merge = function(first, second) {};\n\n\n/**\n * @param {boolean=} removeAll\n * @return {Object}\n */\njQuery.noConflict = function(removeAll) {};\n\n\n/**\n * @return {function()}\n * @nosideeffects\n */\njQuery.noop = function() {};\n\n\n/**\n * @param {(Array|Object)} obj\n * @param {boolean=} traditional\n * @return {string}\n */\njQuery.param = function(obj, traditional) {};\n\n\n/**\n * @param {string} json\n * @return {Object}\n */\njQuery.parseJSON = function(json) {};\n\n\n/**\n * @param {string} url\n * @param {(Object.<string,*>|string)=} data\n * @param {function(string,string,XMLHttpRequest)=} success\n * @param {string=} dataType\n * @return {XMLHttpRequest}\n */\njQuery.post = function(url, data, success, dataType) {};\n\n\n/**\n * @param {(function()|Object)} arg1\n * @param {(Object|string)} arg2\n * @return {function()}\n */\njQuery.proxy = function(arg1, arg2) {};\n\n\n/**\n * @param {Element} elem\n * @param {string=} queueName\n * @param {(Array|function())=} arg3\n * @return {(Array|jQueryObject)}\n */\njQuery.queue = function(elem, queueName, arg3) {};\n\n\n/**\n * @param {Element} elem\n * @param {string=} name\n * @return {jQueryObject}\n */\njQuery.removeData = function(elem, name) {};\n\n\n/** @type {Object} */\njQuery.support;\n\n\n/**\n * @param {string} str\n * @return {string}\n * @nosideeffects\n */\njQuery.trim = function(str) {};\n\n\n/**\n * @param {Object} obj\n * @return {string}\n * @nosideeffects\n */\njQuery.type = function(obj) {};\n\n\n/**\n * @param {Array} arr\n * @return {Array}\n */\njQuery.unique = function(arr) {};\n\n\n\n/**\n * @constructor\n * @private\n */\nfunction jQueryObject() { }\n\n\n/**\n * @param {(jQuerySelector|Array.<Element>|string)} arg1\n * @param {Element=} context\n * @return {jQueryObject}\n */\njQueryObject.prototype.add = function(arg1, context) {};\n\n\n/**\n * @param {(string|function(number,string))} arg1\n * @return {jQueryObject}\n */\njQueryObject.prototype.addClass = function(arg1) {};\n\n\n/**\n * @param {(string|Element|jQueryObject|function(number))} arg1\n * @return {jQueryObject}\n */\njQueryObject.prototype.after = function(arg1) {};\n\n\n/**\n * @param {function(jQuery.event,XMLHttpRequest,Object.<string, *>)} handler\n * @return {jQueryObject}\n */\njQueryObject.prototype.ajaxComplete = function(handler) {};\n\n\n/**\n * @param {function(jQuery.event,XMLHttpRequest,Object.<string, *>,*)} handler\n * @return {jQueryObject}\n */\njQueryObject.prototype.ajaxError = function(handler) {};\n\n\n/**\n * @param {function(jQuery.event,XMLHttpRequest,Object.<string, *>)} handler\n * @return {jQueryObject}\n */\njQueryObject.prototype.ajaxSend = function(handler) {};\n\n\n/**\n * @param {function()} handler\n * @return {jQueryObject}\n */\njQueryObject.prototype.ajaxStart = function(handler) {};\n\n\n/**\n * @param {function()} handler\n * @return {jQueryObject}\n */\njQueryObject.prototype.ajaxStop = function(handler) {};\n\n\n/**\n * @param {function(jQuery.event,XMLHttpRequest,Object.<string, *>)} handler\n * @return {jQueryObject}\n */\njQueryObject.prototype.ajaxSuccess = function(handler) {};\n\n\n/** @return {jQueryObject} */\njQueryObject.prototype.andSelf = function() {};\n\n\n/**\n * @param {Object.<string,*>} properties\n * @param {(string|number|Object.<string,*>)=} arg2\n * @param {string=} easing\n * @param {function()=} callback\n * @return {jQueryObject}\n */\njQueryObject.prototype.animate = function(properties, arg2, easing, callback) {};\n\n\n/**\n * @param {(string|Element|Array|jQueryObject|function(number,string))=} arg1\n * @return {jQueryObject}\n */\njQueryObject.prototype.append = function(arg1) {};\n\n\n/**\n * @param {(jQuerySelector|Element|jQueryObject)} target\n * @return {jQueryObject}\n */\njQueryObject.prototype.appendTo = function(target) {};\n\n\n/**\n * @param {(string|Object.<string,*>)} arg1\n * @param {(string|number|function(number,string))=} arg2\n * @return {(string|jQueryObject)}\n */\njQueryObject.prototype.attr = function(arg1, arg2) {};\n\n\n/**\n * @param {(string|Element|jQueryObject|function())} arg1\n * @return {jQueryObject}\n */\njQueryObject.prototype.before = function(arg1) {};\n\n\n/**\n * @param {(string|Object)} arg1\n * @param {Object=} eventData\n * @param {(function(jQuery.event)|boolean)=} arg3\n * @return {jQueryObject}\n */\njQueryObject.prototype.bind = function(arg1, eventData, arg3) {};\n\n\n/**\n * @param {(function(jQuery.event)|Object)=} arg1\n * @param {function(jQuery.event)=} handler\n * @return {jQueryObject}\n */\njQueryObject.prototype.blur = function(arg1, handler) {};\n\n\n/**\n * @param {(function(jQuery.event)|Object)=} arg1\n * @param {function(jQuery.event)=} handler\n * @return {jQueryObject}\n */\njQueryObject.prototype.change = function(arg1, handler) {};\n\n\n/**\n * @param {jQuerySelector=} selector\n * @return {jQueryObject}\n */\njQueryObject.prototype.children = function(selector) {};\n\n\n/**\n * @param {string=} queueName\n * @return {jQueryObject}\n */\njQueryObject.prototype.clearQueue = function(queueName) {};\n\n\n/**\n * @param {(function(jQuery.event)|Object)=} arg1\n * @param {function(jQuery.event)=} handler\n * @return {jQueryObject}\n */\njQueryObject.prototype.click = function(arg1, handler) {};\n\n\n/**\n * @param {boolean=} withDataAndEvents\n * @return {jQueryObject}\n */\njQueryObject.prototype.clone = function(withDataAndEvents) {};\n\n\n/**\n * @param {(jQuerySelector|Array)} arg1\n * @param {Element=} context\n * @return {(jQueryObject|Array)}\n */\njQueryObject.prototype.closest = function(arg1, context) {};\n\n\n/** @return {jQueryObject} */\njQueryObject.prototype.contents = function() {};\n\n\n/** @type {Element} */\njQueryObject.prototype.context;\n\n\n/**\n * @param {(string|Object.<string,*>)} arg1\n * @param {(string|number|function(number,*))=} arg2\n * @return {(string|jQueryObject)}\n */\njQueryObject.prototype.css = function(arg1, arg2) {};\n\n\n/**\n * @param {(string|Object)=} arg1\n * @param {(*)=} value\n * @return {(jQueryObject|Object)}\n */\njQueryObject.prototype.data = function(arg1, value) {};\n\n\n/**\n * @param {(function(jQuery.event)|Object)=} arg1\n * @param {function(jQuery.event)=} handler\n * @return {jQueryObject}\n */\njQueryObject.prototype.dblclick = function(arg1, handler) {};\n\n\n/**\n * @param {number} duration\n * @param {string=} queueName\n * @return {jQueryObject}\n */\njQueryObject.prototype.delay = function(duration, queueName) {};\n\n\n/**\n * @param {string} selector\n * @param {string} eventType\n * @param {(function()|Object)} arg3\n * @param {function()=} handler\n * @return {jQueryObject}\n */\njQueryObject.prototype.delegate = function(selector, eventType, arg3, handler) {};\n\n\n/**\n * @param {string=} queueName\n * @return {jQueryObject}\n */\njQueryObject.prototype.dequeue = function(queueName) {};\n\n\n/**\n * @param {jQuerySelector=} selector\n * @return {jQueryObject}\n */\njQueryObject.prototype.detach = function(selector) {};\n\n\n/**\n * @param {string=} eventType\n * @param {string=} handler\n * @return {jQueryObject}\n */\njQueryObject.prototype.die = function(eventType, handler) {};\n\n\n/**\n * @param {function(number,Element)} fnc\n * @return {jQueryObject}\n */\njQueryObject.prototype.each = function(fnc) {};\n\n\n/** @return {jQueryObject} */\njQueryObject.prototype.empty = function() {};\n\n\n/** @return {jQueryObject} */\njQueryObject.prototype.end = function() {};\n\n\n/**\n * @param {number} arg1\n * @return {jQueryObject}\n */\njQueryObject.prototype.eq = function(arg1) {};\n\n\n/**\n * @param {(function(jQuery.event)|Object)=} arg1\n * @param {function(jQuery.event)=} handler\n * @return {jQueryObject}\n */\njQueryObject.prototype.error = function(arg1, handler) {};\n\n\n/**\n * @param {(string|number)=} duration\n * @param {(function()|string)=} arg2\n * @param {function()=} callback\n * @return {jQueryObject}\n */\njQueryObject.prototype.fadeIn = function(duration, arg2, callback) {};\n\n\n/**\n * @param {(string|number)=} duration\n * @param {(function()|string)=} arg2\n * @param {function()=} callback\n * @return {jQueryObject}\n */\njQueryObject.prototype.fadeOut = function(duration, arg2, callback) {};\n\n\n/**\n * @param {(string|number)} duration\n * @param {number} opacity\n * @param {(function()|string)=} arg3\n * @param {function()=} callback\n * @return {jQueryObject}\n */\njQueryObject.prototype.fadeTo = function(duration, opacity, arg3, callback) {};\n\n\n/**\n * @param {(string|number)=} duration\n * @param {string=} easing\n * @param {function()=} callback\n * @return {jQueryObject}\n */\njQueryObject.prototype.fadeToggle = function(duration, easing, callback) {};\n\n\n/**\n * @param {(jQuerySelector|function(number)|Element|Object)} arg1\n * @return {jQueryObject}\n */\njQueryObject.prototype.filter = function(arg1) {};\n\n\n/**\n * @param {jQuerySelector} selector\n * @return {jQueryObject}\n */\njQueryObject.prototype.find = function(selector) {};\n\n\n/** @return {jQueryObject} */\njQueryObject.prototype.first = function() {};\n\n\n/**\n * @param {(function(jQuery.event)|Object)=} arg1\n * @param {function(jQuery.event)=} handler\n * @return {jQueryObject}\n */\njQueryObject.prototype.focus = function(arg1, handler) {};\n\n\n/**\n * @param {(function(jQuery.event)|Object)=} arg1\n * @param {function(jQuery.event)=} handler\n * @return {jQueryObject}\n */\njQueryObject.prototype.focusin = function(arg1, handler) {};\n\n\n/**\n * @param {(function(jQuery.event)|Object)=} arg1\n * @param {function(jQuery.event)=} handler\n * @return {jQueryObject}\n */\njQueryObject.prototype.focusout = function(arg1, handler) {};\n\n\n/**\n * @param {number=} index\n * @return {(Element|Array)}\n * @nosideeffects\n */\njQueryObject.prototype.get = function(index) {};\n\n\n/**\n * @param {(string|Element)} arg1\n * @return {jQueryObject}\n */\njQueryObject.prototype.has = function(arg1) {};\n\n\n/**\n * @param {string} className\n * @return {boolean}\n */\njQueryObject.prototype.hasClass = function(className) {};\n\n\n/**\n * @param {(jQueryObject|string|number|function(number,number))=} arg1\n * @return {(number|jQueryObject)}\n * @nosideeffects\n */\njQueryObject.prototype.height = function(arg1) {};\n\n\n/**\n * @param {(string|number)=} duration\n * @param {(function()|string)=} arg2\n * @param {function()=} callback\n * @return {jQueryObject}\n */\njQueryObject.prototype.hide = function(duration, arg2, callback) {};\n\n\n/**\n * @param {function(jQuery.event)} arg1\n * @param {function(jQuery.event)=} handlerOut\n * @return {jQueryObject}\n */\njQueryObject.prototype.hover = function(arg1, handlerOut) {};\n\n\n/**\n * @param {(jQueryObject|number|string|function(number,string))=} arg1\n * @return {(string|jQueryObject)}\n */\njQueryObject.prototype.html = function(arg1) {};\n\n\n/**\n * @param {(jQuerySelector|Element|jQueryObject)=} arg1\n * @return {number}\n */\njQueryObject.prototype.index = function(arg1) {};\n\n\n/**\n * @return {number}\n * @nosideeffects\n */\njQueryObject.prototype.innerHeight = function() {};\n\n\n/**\n * @return {number}\n * @nosideeffects\n */\njQueryObject.prototype.innerWidth = function() {};\n\n\n/**\n * @param {(jQuerySelector|Element|jQueryObject)} target\n * @return {jQueryObject}\n */\njQueryObject.prototype.insertAfter = function(target) {};\n\n\n/**\n * @param {(jQuerySelector|Element|jQueryObject)} target\n * @return {jQueryObject}\n */\njQueryObject.prototype.insertBefore = function(target) {};\n\n\n/**\n * @param {jQuerySelector} selector\n * @return {boolean}\n * @nosideeffects\n */\njQueryObject.prototype.is = function(selector) {};\n\n\n/**\n * @param {(function(jQuery.event)|Object)=} arg1\n * @param {function(jQuery.event)=} handler\n * @return {jQueryObject}\n */\njQueryObject.prototype.keydown = function(arg1, handler) {};\n\n\n/**\n * @param {(function(jQuery.event)|Object)=} arg1\n * @param {function(jQuery.event)=} handler\n * @return {jQueryObject}\n */\njQueryObject.prototype.keypress = function(arg1, handler) {};\n\n\n/**\n * @param {(function(jQuery.event)|Object)=} arg1\n * @param {function(jQuery.event)=} handler\n * @return {jQueryObject}\n */\njQueryObject.prototype.keyup = function(arg1, handler) {};\n\n\n/** @return {jQueryObject} */\njQueryObject.prototype.last = function() {};\n\n\n/** @type {number} */\njQueryObject.prototype.length;\n\n\n/**\n * @param {string} eventType\n * @param {(function()|Object)} arg2\n * @param {function()=} handler\n * @return {jQueryObject}\n */\njQueryObject.prototype.live = function(eventType, arg2, handler) {};\n\n\n/**\n * @param {(function(jQuery.event)|Object|string)=} arg1\n * @param {(function(jQuery.event)|Object.<string,*>|string)=} arg2\n * @param {function(string,string,XMLHttpRequest)=} complete\n * @return {jQueryObject}\n */\njQueryObject.prototype.load = function(arg1, arg2, complete) {};\n\n\n/**\n * @param {function(number,Element)} callback\n * @return {jQueryObject}\n */\njQueryObject.prototype.map = function(callback) {};\n\n\n/**\n * @param {(function(jQuery.event)|Object)=} arg1\n * @param {function(jQuery.event)=} handler\n * @return {jQueryObject}\n */\njQueryObject.prototype.mousedown = function(arg1, handler) {};\n\n\n/**\n * @param {(function(jQuery.event)|Object)=} arg1\n * @param {function(jQuery.event)=} handler\n * @return {jQueryObject}\n */\njQueryObject.prototype.mouseenter = function(arg1, handler) {};\n\n\n/**\n * @param {(function(jQuery.event)|Object)=} arg1\n * @param {function(jQuery.event)=} handler\n * @return {jQueryObject}\n */\njQueryObject.prototype.mouseleave = function(arg1, handler) {};\n\n\n/**\n * @param {(function(jQuery.event)|Object)=} arg1\n * @param {function(jQuery.event)=} handler\n * @return {jQueryObject}\n */\njQueryObject.prototype.mousemove = function(arg1, handler) {};\n\n\n/**\n * @param {(function(jQuery.event)|Object)=} arg1\n * @param {function(jQuery.event)=} handler\n * @return {jQueryObject}\n */\njQueryObject.prototype.mouseout = function(arg1, handler) {};\n\n\n/**\n * @param {(function(jQuery.event)|Object)=} arg1\n * @param {function(jQuery.event)=} handler\n * @return {jQueryObject}\n */\njQueryObject.prototype.mouseover = function(arg1, handler) {};\n\n\n/**\n * @param {(function(jQuery.event)|Object)=} arg1\n * @param {function(jQuery.event)=} handler\n * @return {jQueryObject}\n */\njQueryObject.prototype.mouseup = function(arg1, handler) {};\n\n\n/**\n * @param {jQuerySelector=} selector\n * @return {jQueryObject}\n */\njQueryObject.prototype.next = function(selector) {};\n\n\n/**\n * @param {string=} selector\n * @return {jQueryObject}\n */\njQueryObject.prototype.nextAll = function(selector) {};\n\n\n/**\n * @param {jQuerySelector=} selector\n * @return {jQueryObject}\n */\njQueryObject.prototype.nextUntil = function(selector) {};\n\n\n/**\n * @param {(jQuerySelector|Array.<Element>|function(number))} arg1\n * @return {jQueryObject}\n */\njQueryObject.prototype.not = function(arg1) {};\n\n\n/**\n * @param {(Object|function(number,{top:number,left:number}))=} arg1\n * @return {(Object|jQueryObject)}\n * @nosideeffects\n */\njQueryObject.prototype.offset = function(arg1) {};\n\n\n/** @return {jQueryObject} */\njQueryObject.prototype.offsetParent = function() {};\n\n\n/**\n * @param {string} eventType\n * @param {Object=} eventData\n * @param {function(jQuery.event)=} handler\n * @return {jQueryObject}\n */\njQueryObject.prototype.one = function(eventType, eventData, handler) {};\n\n\n/**\n * @param {boolean=} includeMargin\n * @return {number}\n * @nosideeffects\n */\njQueryObject.prototype.outerHeight = function(includeMargin) {};\n\n\n/**\n * @param {boolean=} includeMargin\n * @return {number}\n * @nosideeffects\n */\njQueryObject.prototype.outerWidth = function(includeMargin) {};\n\n\n/**\n * @param {jQuerySelector=} selector\n * @return {jQueryObject}\n */\njQueryObject.prototype.parent = function(selector) {};\n\n\n/**\n * @param {jQuerySelector=} selector\n * @return {jQueryObject}\n */\njQueryObject.prototype.parents = function(selector) {};\n\n\n/**\n * @param {jQuerySelector=} selector\n * @return {jQueryObject}\n */\njQueryObject.prototype.parentsUntil = function(selector) {};\n\n\n/**\n * @return {Object}\n * @nosideeffects\n */\njQueryObject.prototype.position = function() {};\n\n\n/**\n * @param {(string|Element|jQueryObject|function(number,string))} arg1\n * @return {jQueryObject}\n */\njQueryObject.prototype.prepend = function(arg1) {};\n\n\n/**\n * @param {(jQuerySelector|Element|jQueryObject)} target\n * @return {jQueryObject}\n */\njQueryObject.prototype.prependTo = function(target) {};\n\n\n/**\n * @param {jQuerySelector=} selector\n * @return {jQueryObject}\n */\njQueryObject.prototype.prev = function(selector) {};\n\n\n/**\n * @param {jQuerySelector=} selector\n * @return {jQueryObject}\n */\njQueryObject.prototype.prevAll = function(selector) {};\n\n\n/**\n * @param {jQuerySelector=} selector\n * @return {jQueryObject}\n */\njQueryObject.prototype.prevUntil = function(selector) {};\n\n\n/**\n * @param {Array} elements\n * @param {string=} name\n * @param {Array=} args\n * @return {jQueryObject}\n */\njQueryObject.prototype.pushStack = function(elements, name, args) {};\n\n\n/**\n * @param {string=} queueName\n * @param {(Array|function(function()))=} arg2\n * @return {(Array|jQueryObject)}\n */\njQueryObject.prototype.queue = function(queueName, arg2) {};\n\n\n/**\n * @param {function()} handler\n * @return {jQueryObject}\n */\njQueryObject.prototype.ready = function(handler) {};\n\n\n/**\n * @param {string=} selector\n * @return {jQueryObject}\n */\njQueryObject.prototype.remove = function(selector) {};\n\n\n/**\n * @param {string} attributeName\n * @return {jQueryObject}\n */\njQueryObject.prototype.removeAttr = function(attributeName) {};\n\n\n/**\n * @param {(string|function(number,string))=} arg1\n * @return {jQueryObject}\n */\njQueryObject.prototype.removeClass = function(arg1) {};\n\n\n/**\n * @param {string=} name\n * @return {jQueryObject}\n */\njQueryObject.prototype.removeData = function(name) {};\n\n\n/**\n * @param {jQuerySelector} target\n * @return {jQueryObject}\n */\njQueryObject.prototype.replaceAll = function(target) {};\n\n\n/**\n * @param {(string|Element|jQueryObject|function())} arg1\n * @return {jQueryObject}\n */\njQueryObject.prototype.replaceWith = function(arg1) {};\n\n\n/**\n * @param {(function(jQuery.event)|Object)=} arg1\n * @param {function(jQuery.event)=} handler\n * @return {jQueryObject}\n */\njQueryObject.prototype.resize = function(arg1, handler) {};\n\n\n/**\n * @param {(function(jQuery.event)|Object)=} arg1\n * @param {function(jQuery.event)=} handler\n * @return {jQueryObject}\n */\njQueryObject.prototype.scroll = function(arg1, handler) {};\n\n\n/**\n * @param {number=} value\n * @return {(number|jQueryObject)}\n */\njQueryObject.prototype.scrollLeft = function(value) {};\n\n\n/**\n * @param {number=} value\n * @return {(number|jQueryObject)}\n */\njQueryObject.prototype.scrollTop = function(value) {};\n\n\n/**\n * @param {(function(jQuery.event)|Object)=} arg1\n * @param {function(jQuery.event)=} handler\n * @return {jQueryObject}\n */\njQueryObject.prototype.select = function(arg1, handler) {};\n\n\n/** @type {string} */\njQueryObject.prototype.selector;\n\n\n/** @return {string} */\njQueryObject.prototype.serialize = function() {};\n\n\n/** @return {Array} */\njQueryObject.prototype.serializeArray = function() {};\n\n\n/**\n * @param {(string|number)=} duration\n * @param {(function()|string)=} arg2\n * @param {function()=} callback\n * @return {jQueryObject}\n */\njQueryObject.prototype.show = function(duration, arg2, callback) {};\n\n\n/**\n * @param {jQuerySelector=} selector\n * @return {jQueryObject}\n */\njQueryObject.prototype.siblings = function(selector) {};\n\n\n/** @return {number} */\njQueryObject.prototype.size = function() {};\n\n\n/**\n * @param {number} start\n * @param {number=} end\n * @return {jQueryObject}\n */\njQueryObject.prototype.slice = function(start, end) {};\n\n\n/**\n * @param {(function()|string|number)=} duration\n * @param {(function()|string)=} arg2\n * @param {function()=} callback\n * @return {jQueryObject}\n */\njQueryObject.prototype.slideDown = function(duration, arg2, callback) {};\n\n\n/**\n * @param {(string|number)=} duration\n * @param {(function()|string)=} arg2\n * @param {function()=} callback\n * @return {jQueryObject}\n */\njQueryObject.prototype.slideToggle = function(duration, arg2, callback) {};\n\n\n/**\n * @param {(function()|string|number)=} duration\n * @param {(function()|string)=} arg2\n * @param {function()=} callback\n * @return {jQueryObject}\n */\njQueryObject.prototype.slideUp = function(duration, arg2, callback) {};\n\n\n/**\n * @param {boolean=} clearQueue\n * @param {boolean=} jumpToEnd\n * @return {jQueryObject}\n */\njQueryObject.prototype.stop = function(clearQueue, jumpToEnd) {};\n\n\n/**\n * @param {(function(jQuery.event)|Object)=} arg1\n * @param {function(jQuery.event)=} handler\n * @return {jQueryObject}\n */\njQueryObject.prototype.submit = function(arg1, handler) {};\n\n\n/**\n * @param {(string|function(number,string))=} arg1\n * @return {(string|jQueryObject)}\n */\njQueryObject.prototype.text = function(arg1) {};\n\n\n/** @return {Array} */\njQueryObject.prototype.toArray = function() {};\n\n\n/**\n * @param {(function(jQuery.event)|string|number|boolean)=} arg1\n * @param {(function(jQuery.event)|string)=} arg2\n * @param {function(jQuery.event)=} arg3\n * @return {jQueryObject}\n */\njQueryObject.prototype.toggle = function(arg1, arg2, arg3) {};\n\n\n/**\n * @param {(string|function(number,string))} arg1\n * @param {boolean=} flag\n * @return {jQueryObject}\n */\njQueryObject.prototype.toggleClass = function(arg1, flag) {};\n\n\n/**\n * @param {(string|jQuery.event)} arg1\n * @param {Array=} extraParameters\n * @return {jQueryObject}\n */\njQueryObject.prototype.trigger = function(arg1, extraParameters) {};\n\n\n/**\n * @param {string} eventType\n * @param {Array} extraParameters\n * @return {Object}\n */\njQueryObject.prototype.triggerHandler = function(eventType, extraParameters) {};\n\n\n/**\n * @param {(string|Object)=} arg1\n * @param {(function(jQuery.event)|boolean)=} arg2\n * @return {jQueryObject}\n */\njQueryObject.prototype.unbind = function(arg1, arg2) {};\n\n\n/**\n * @param {string=} selector\n * @param {string=} eventType\n * @param {function()=} handler\n * @return {jQueryObject}\n */\njQueryObject.prototype.undelegate = function(selector, eventType, handler) {};\n\n\n/**\n * @param {(function(jQuery.event)|Object)=} arg1\n * @param {function(jQuery.event)=} handler\n * @return {jQueryObject}\n */\njQueryObject.prototype.unload = function(arg1, handler) {};\n\n\n/** @return {jQueryObject} */\njQueryObject.prototype.unwrap = function() {};\n\n\n/**\n * @param {(string|number|function(number,*))=} arg1\n * @return {(string|Array|jQueryObject)}\n */\njQueryObject.prototype.val = function(arg1) {};\n\n\n/**\n * @param {(string|number|function(number,number))=} arg1\n * @return {(number|jQueryObject)}\n * @nosideeffects\n */\njQueryObject.prototype.width = function(arg1) {};\n\n\n/**\n * @param {(string|jQuerySelector|Element|jQueryObject|function())} arg1\n * @return {jQueryObject}\n */\njQueryObject.prototype.wrap = function(arg1) {};\n\n\n/**\n * @param {(string|jQuerySelector|Element|jQueryObject)} wrappingElement\n * @return {jQueryObject}\n */\njQueryObject.prototype.wrapAll = function(wrappingElement) {};\n\n\n/**\n * @param {(string|function())} arg1\n * @return {jQueryObject}\n */\njQueryObject.prototype.wrapInner = function(arg1) {};\n\n/* for jquery.json-2.2.js */\njQuery.toJSON = function(o) {};\njQuery.evalJSON = function(src) {};\njQuery.secureEvalJSON = function(src) {};\njQuery.quoteString = function(string) {};\n\n\n/* for jquery.bt.js */\njQuery.bt = function(content, options) {};\njQuery.btPosition = function() {};\njQuery.btOuterWidth = function(margin) {};\njQuery.btOn = function() {};\njQuery.btOff = function() {};\n\n\n/* for jquery-dotnet_String_formatting-1.0.0.js */\njQuery.format = function(text) {};\n\n\n\njQuery.ajaxTransport = function(a, b) {};\njQuery.ajaxPrefilter = function(a) {};\n"
  },
  {
    "path": "tart/externs/tart.externs.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nvar console;\n\n\n/** @param {...*} var_args */\nconsole.log = function(var_args) {};\nconsole.time = function(name) {};\nconsole.timeEnd = function(name) {};\nconsole.trace = function() {};\n\n\n/** @param {...*} var_args */\nconsole.dir = function(var_args) {};\n\nvar localStorage = {};\n"
  },
  {
    "path": "tart/locale/en.js",
    "content": "// Copyright 2014 Startup Kitchen. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\ngoog.provide('tart.locale.en');\n\n\n\ntart.locale['en'] = {\n    '_name': 'English'\n};\n"
  },
  {
    "path": "tart/locale/locale.js",
    "content": "// Copyright 2014 Startup Kitchen. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\ngoog.provide('tart.locale');\ngoog.require('tart.locale.en');\ngoog.require('tart.locale.tr');\n\n\n/**\n * The default language\n *\n * @type {string}\n * @private\n */\ntart.locale.defaultLang_ = 'tr';\n\n\n/**\n * Change the active dictionary\n *\n * @param {string} lang Language code.\n */\ntart.locale.setLanguage = function(lang) {\n    tart.locale.dictionary_ = tart.locale[lang];\n};\n\n\n/**\n * Return translation of the given text\n *\n * Look for a translation from goog.require()'d scripts. Replace the variables inside the translation.\n * Return the same text if no translation found.\n *\n * Pass in variables as integers inside curly brackets. {0} will be replaced by first argument and so on.\n *\n * @param  {string}    text        Text to be translated.\n * @param  {...*}      variables   Translation arguments.\n * @return {string}    Localized string.\n * @see    {goog.LOCALE}\n */\ntart.locale.getLocalizedString = function(text, variables) {\n    if (!tart.locale.dictionary_)\n        tart.locale.dictionary_ = tart.locale[tart.locale.defaultLang_];\n\n    var translation = tart.locale.dictionary_[text] || text;\n    var args = goog.array.slice(arguments, 1);\n\n    return translation.replace(/{(\\d+)}/g, function(match, number) {\n        return typeof args[number] != 'undefined' ? args[number] : match;\n    });\n};\n\n\n// Set a global function for convenience.\nwindow['__'] = tart.locale.getLocalizedString;\n"
  },
  {
    "path": "tart/locale/tr.js",
    "content": "// Copyright 2014 Startup Kitchen. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\ngoog.provide('tart.locale.tr');\n\n\n\ntart.locale['tr'] = {\n    '_name': 'Türkçe'\n};\n"
  },
  {
    "path": "tart/mock/index.html",
    "content": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\n  \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n  <title>Jasmine Test Runner</title>\n  <script type=\"text/javascript\" src=\"http://code.jquery.com/jquery-1.6.1.js\"></script>\n  <script type=\"text/javascript\" src=\"../../third_party/goog/goog/base.js\"></script>\n  <script type=\"text/javascript\" src=\"jQuery/xhr.js\"></script>\n\n</head>\n<body>\n\n<script type=\"text/javascript\">\n\ntart.mock.jQuery.xhr = function (request) {\n    var url = request.url;\n    var data = request.data;\n\n    if (url == \"foo.html\") {\n        return {\"deneme\" : \"foo\"};\n    }\n};\n\njQuery.post(\"foo.html\", {xxx : \"yyy\"}, function (response) {\n    console.log(response);\n},'json');\n\n\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "tart/mock/jQuery/xhr.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\ngoog.provide('tart.mock.jQuery.xhr');\n\njQuery.ajaxSetup({\n    'converters': {\n        'mockup text': function(requestOptions) {\n            return tart.mock.jQuery.xhr(requestOptions);\n        },\n        'mockup json': function(requestOptions) {\n            return tart.mock.jQuery.xhr(requestOptions);\n        },\n        'mockup xml': function(requestOptions) {\n            return tart.mock.jQuery.xhr(requestOptions);\n        }\n    }\n});\n\n\njQuery.ajaxTransport('mockup', function(options) {\n    return {\n        'send': function(headers, callback) {\n            setTimeout(function () {\n                callback(200, 'OK', {\n                    'mockup': options\n                });\n            }, 1);\n        }\n    };\n});\n\n// Switch to mockup\njQuery.ajaxSetup({\n    'mock': true\n});\n\n\njQuery.ajaxPrefilter(function(options) {\n    if (options['mock']) {\n        var finalDataType = options['dataTypes']['pop']();\n        options['dataTypes'] = [finalDataType === '*' ? 'text' : finalDataType];\n        return 'mockup';\n    }\n});\n"
  },
  {
    "path": "tart/money/Currency.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\ngoog.provide('tart.Currency');\n\n\n\n/**\n * Tart Currency class for defining prefix, suffix, separator of tart.Money object.\n * @constructor\n */\ntart.Currency = function() {};\n\n\n/**\n * Prefix Value of Currency.\n */\ntart.Currency.prototype.prefix = '';\n\n\n/**\n * Suffix Value of Currency.\n */\ntart.Currency.prototype.suffix = '';\n\n\n/**\n * Separator Value of Currency.\n */\ntart.Currency.prototype.separator = '';\n\n\n/**\n * Converts Money to currency type.\n * @param {tart.Money} money Retrieves money object from tart.Money.\n * @return {string} Returns Money with currency type.\n */\ntart.Currency.prototype.convert = function(money) {\n    var prefix = '';\n    var suffix = '';\n\n    //Adds space after prefix.\n    if (this.prefix) {\n        prefix = this.prefix + ' ';\n    }\n\n    //Adds space before suffix.\n    if (this.suffix) {\n        suffix = ' ' + this.suffix;\n    }\n\n    return prefix + money.getCapital() + this.separator + money.getFraction() + suffix;\n};\n\n\n/**\n * Gets Currency Type. Like TL, USD etc.\n * @return {string} Returns currency Type.\n */\ntart.Currency.prototype.getType = function() {\n    return this.prefix || this.suffix;\n};\n"
  },
  {
    "path": "tart/money/CurrencyTL.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\ngoog.provide('tart.CurrencyTL');\ngoog.require('tart.Currency');\n\n\n\n/**\n * TL Currency Type of Money.\n * @constructor\n * @extends {tart.Currency}\n */\ntart.CurrencyTL = function() {\n    goog.base(this);\n};\ngoog.inherits(tart.CurrencyTL, tart.Currency);\n\n\n/**\n * Prefix Value of Currency.\n */\ntart.CurrencyTL.prototype.prefix = '';\n\n\n/**\n * Suffix Value of Currency.\n */\ntart.CurrencyTL.prototype.suffix = 'TL';\n\n\n/**\n * Separator Value of Currency.\n */\ntart.CurrencyTL.prototype.separator = ',';\n"
  },
  {
    "path": "tart/money/CurrencyUSD.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\ngoog.provide('tart.CurrencyUSD');\ngoog.require('tart.Currency');\n\n\n\n/**\n * USD Currency Type of Money.\n * @constructor\n * @extends {tart.Currency}\n */\ntart.CurrencyUSD = function() {\n    goog.base(this);\n};\ngoog.inherits(tart.CurrencyUSD, tart.Currency);\n\n\n/**\n * Prefix Value of Currency.\n */\ntart.CurrencyUSD.prototype.prefix = '$';\n\n\n/**\n * Suffix Value of Currency.\n */\ntart.CurrencyUSD.prototype.suffix = '';\n\n\n/**\n * Separator Value of Currency.\n */\ntart.CurrencyUSD.prototype.separator = '.';\n"
  },
  {
    "path": "tart/money/Money.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n//\n// HELP\n// -----------------------------\n// var currency = new tart.CurrencyUSD(); //You can add other currencies as a new file to tart/money/CurrencyNAME.js.\n// var money = new tart.Money(12.500, currency); //Default value is tart.CurrencyTL (leave blank 2nd param).\n//\n// money.toCurrency(); //Gets Full Currency Like USD 12.50\n// money.getCapital(); //Gets Only Capital Of Money Like 12\n// money.getFraction(); //Gets Only Fraction Of Money Line 50\n// money.toArray(); //Gets As Array Like [12, 50]\n// money.getCurrency().getType(); //Gets Type Of Money Like USD\n\ngoog.provide('tart.Money');\n\ngoog.require('tart.CurrencyTL');\ngoog.require('tart.CurrencyUSD');\n\n\n\n/**\n * Tart Money Class for defining money type.\n * @constructor\n * @param {number} amount Retrieves Amount for convert to currency.\n * @param {tart.Currency=} currency Currency type.\n */\ntart.Money = function(amount, currency) {\n    /** @private */\n    this.amount_ = amount;\n    this.currency_ = currency || new tart.CurrencyTL();\n};\n\n\n/**\n * Converts Money and Currency to Array.\n * @return {Array} Returns capital and fraction as array.\n */\ntart.Money.prototype.toArray = function() {\n    return [this.getCapital(), this.getFraction()];\n};\n\n\n/**\n * Gets Capital of money.\n * @return {string} Returns capital of money.\n */\ntart.Money.prototype.getCapital = function() {\n    return parseInt(this.amount_, 10).toString();\n};\n\n\n/**\n * @return {string} Returns fraction of money.\n */\ntart.Money.prototype.getFraction = function() {\n    //JavaScript math calculation fix for floating point arithmetic\n    //http://stackoverflow.com/questions/588004/is-javascripts-math-broken/588053#588053\n    var mathFix = ((this.amount_).toFixed(2) - this.getCapital()).toFixed(2);\n\n    var result = mathFix.substr(2,2);\n\n    if (result.length == 1) {\n        result = '0' + result;\n    }\n\n    return result;\n};\n\n\n/**\n * Gets amount of Money.\n * @return {number} Returns full amount of money.\n */\ntart.Money.prototype.getAmount = function() {\n    return this.amount_;\n};\n\n\n/**\n * Gets Value of Money.\n * @return {number} Returns full amount of money.\n */\ntart.Money.prototype.valueOf = function() {\n    return this.getAmount();\n};\n\n\n/**\n * Gets object of currency.\n * @return {Object} Returns object of tart.Currency.\n */\ntart.Money.prototype.getCurrency = function() {\n    return this.currency_;\n};\n\n\n/**\n * Gets tart.Currency.convert Method.\n * @return {string} Returns converted currency.\n */\ntart.Money.prototype.toCurrency = function() {\n    return this.currency_.convert(this);\n};\n"
  },
  {
    "path": "tart/mvc/Action.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\ngoog.provide('tart.mvc.Action');\n\n\n\n/**\n * @constructor\n * @param {Object} params Params.\n * @param {tart.mvc.LayoutTemplate} layout Layout.\n * @param {tart.mvc.View} view View.\n * @param {tart.mvc.Controller} controller Controller.\n */\ntart.mvc.Action = function(params, layout, view, controller) {\n    this.params = params;\n    this.view = view;\n    this.layout_ = layout;\n    this.controller = controller;\n};\n\n\n/**\n *\n * @param {tart.mvc.LayoutTemplate} layout Layout.\n */\ntart.mvc.Action.prototype.setLayout = function(layout) {\n    this.layout_ = layout;\n};\n\n\n/** @nosideeffects */\ntart.mvc.Action.prototype.params;\n\n\n/** @nosideeffects */\ntart.mvc.Action.prototype.layout;\n\n\n/** @nosideeffects */\ntart.mvc.Action.prototype.view;\n\n\n/**\n * @return {tart.mvc.LayoutTemplate} The layout template (whether custom or default) that belongs to the action.\n */\ntart.mvc.Action.prototype.getLayout = function() {\n    return this.layout_;\n};\n\n\n/**\n * Deconstructor method of this action. Developers should override this property in an action function like;\n *\n * this.deconstructor = function() {}\n *\n * and should deallocate the memory they have used in the action. This is also helpful for resolving issues that arise\n * because of tartMVC's statefullness; such as removed but dangling DOM nodes, etc.\n */\ntart.mvc.Action.prototype.deconstructor = null;\n\n\n/**\n * @return {tart.mvc.ViewTemplate} The view script that belongs to the action.\n */\ntart.mvc.Action.prototype.getViewScript = function() {\n    if (!this.viewScript_)\n        throw new tart.Err('No view script set for the action', 'tartMVC Action Exception');\n\n    return this.viewScript_;\n};\n\n\n/**\n * Sets the action's view script.\n * @param {tart.mvc.ViewTemplate} viewScript view script.\n */\ntart.mvc.Action.prototype.setViewScript = function(viewScript) {\n    this.viewScript_ = viewScript;\n};\n"
  },
  {
    "path": "tart/mvc/Application.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview This class implements the base application. The users of tart.mvc should extend this class\n * in order to create their own MVC application.\n */\n\ngoog.require('goog.History');\ngoog.require('goog.debug.ErrorHandler');\ngoog.require('goog.events');\ngoog.require('tart.dom');\ngoog.require('tart.mvc.Action');\ngoog.require('tart.mvc.Controller');\ngoog.require('tart.mvc.IApplication');\ngoog.require('tart.mvc.Layout');\ngoog.require('tart.mvc.Model');\ngoog.require('tart.mvc.Renderer');\ngoog.require('tart.mvc.uri.Route');\ngoog.require('tart.mvc.uri.Router');\ngoog.provide('tart.mvc.Application');\n\n\n\n/**\n * Base application class for tart.mvc.\n * @constructor\n * @implements {tart.mvc.IApplication}\n * @param {HTMLElement=} dom Optional DOM element to render the application in.\n */\ntart.mvc.Application = function(dom) {\n    var uri = new goog.Uri(window.location),\n        uriString = uri.toString(),\n        uriPath = uri.getPath(),\n        myPath = '';\n\n    this.id = tart.getUid();\n\n    if (dom)\n        this.dom = dom;\n    else {\n        this.dom = /** @type {Element} */(tart.dom.createElement(this.template_container()));\n        goog.dom.appendChild(document.body, this.dom);\n    }\n\n    if (goog.string.startsWith(uriPath, this.basePath)) {\n        myPath = uriPath.substr(this.basePath.length - 1);\n        if (myPath.length > 1 && !goog.string.endsWith(myPath, '/')) {\n            myPath = myPath + '/';\n        }\n        uri.setPath(myPath);\n    }\n\n    if (myPath.length > 1 &&\n        (!uri.hasFragment() || uriString.indexOf(myPath) < uriString.indexOf(uri.getFragment())))\n        window.location = this.basePath + '#!' + myPath;\n    else {\n        if (!this.defaultRoute)\n            throw new tart.Err('No default route is set.', 'tartMVC Application Exception');\n\n        var historyCallback, that = this;\n        var hiddenInput = /** @type {HTMLInputElement} */(tart.dom.createElement('input'));\n\n        /** @private */\n        this.history_ = new goog.History(false, undefined, hiddenInput);\n        this.initRouting();\n\n        /**\n         * every time the URI changes, this.router_ routes the request to the appropriate controller/action.\n         */\n        goog.events.listen(this.history_, goog.history.EventType.NAVIGATE, this.onNavigate, false, this);\n\n        this.history_.setEnabled(true);\n    }\n};\n\n\n/**\n * @protected\n */\ntart.mvc.Application.prototype.onNavigate = function() {\n    this.getRouter().route();\n};\n\n\n/**\n * @return {tart.mvc.Renderer} The renderer instance. This method creates a single renderer instance if it's not\n * already been created.\n */\ntart.mvc.Application.prototype.getRenderer = function() {\n    if (!this.renderer_)\n        this.renderer_ = new tart.mvc.Renderer(this.defaultLayout, this.dom);\n\n    return this.renderer_;\n};\n\n\n/**\n * @return {string} Container template for the application. Developers may override this method for their own likes;\n * or not use it at all if they provide a dom object to this class's constructor.\n */\ntart.mvc.Application.prototype.template_container = function() {\n    return '<div id=\"' + this.id + '\"></div>';\n};\n\n\n/**\n * @return {tart.mvc.uri.Router} The router of the application.\n */\ntart.mvc.Application.prototype.getRouter = function() {\n    if (!this.router_)\n        this.router_ = new tart.mvc.uri.Router(this.basePath,\n                                                   this.defaultRoute,\n                                                   this.getRenderer(),\n                                                   this.redirectionType);\n\n    return this.router_;\n};\n\n\n/**\n * Users of tartMVC should implement this method. It should include all the routing jobs (adding routes to the router)\n */\ntart.mvc.Application.prototype.initRouting = goog.abstractMethod;\n\n\n/**\n * The base path for the application. If your application will run in the root domain (such as http://www.foo.com)\n * your application doesn't need to override this property. On the other hand, if it will run in a subdirectory\n * (such as http://www.foo.com/bar/) you need to override and set this property to the subdirectory (such as '/bar/').\n * @type {string}\n * @protected\n */\ntart.mvc.Application.prototype.basePath = '/';\n\n\n/**\n * The default route fallback, which will be used if there are no matching routes found for a given url.\n * @type {tart.mvc.uri.Route}\n * @protected\n */\ntart.mvc.Application.prototype.defaultRoute = null;\n\n\n/**\n * The default layout view of the application.\n * @protected\n * @type {tart.mvc.LayoutTemplate}\n */\ntart.mvc.Application.prototype.defaultLayout = function() {\n};\n\n\n/**\n * The default redirection type for an MVC application.\n * @type {tart.mvc.uri.Router.RedirectionType}\n * @protected\n */\ntart.mvc.Application.prototype.redirectionType = tart.mvc.uri.Router.RedirectionType.CLASSICAL;\n"
  },
  {
    "path": "tart/mvc/Controller.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\ngoog.provide('tart.mvc.Controller');\n\n\n\n/**\n * @constructor\n */\ntart.mvc.Controller = function() { };\n"
  },
  {
    "path": "tart/mvc/IApplication.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview This file combines the requirements of tart.mvc in a single requirement called tart.mvc so that\n * projects that use the tart.mvc need only require tart.mvc. It also implements the base application. The users of\n * tart.mvc should implement this tart.mvc.IApplication class.\n */\n\ngoog.provide('tart.mvc.IApplication');\n\n\n\n/**\n * Base application class for tart.mvc.\n * @interface\n */\ntart.mvc.IApplication = function() {};\n\n\n/**\n * The base path for the application. If your application will run in the root domain (such as http://www.foo.com)\n * your application doesn't need to override this property. On the other hand, if it will run in a subdirectory\n * (such as http://www.foo.com/bar/) you need to override and set this property to the subdirectory (such as '/bar/').\n */\ntart.mvc.IApplication.prototype.basePath;\n\n\n/**\n * Default scheme for the application. Each application should implement a default controller and an action as these\n * will be called when there are no matching controller / actions.\n */\ntart.mvc.IApplication.prototype.defaultRoute;\n"
  },
  {
    "path": "tart/mvc/Layout.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview The instances of this class will hold the root HTML markups for the MVC application.\n */\ngoog.provide('tart.mvc.Layout');\ngoog.require('tart.mvc.View');\n\n\n\n/**\n * Layout class.\n * @constructor\n * @param {tart.mvc.View} view View instance that will be rendered in this layout.\n */\ntart.mvc.Layout = function(view) {\n    this.view = view;\n};\n\n\n/**\n * Sets the content of the layout. This will generally be the output of a view script associated with an action.\n * @param {string} content Output of a view script.\n */\ntart.mvc.Layout.prototype.setContent = function(content) {\n    this.content_ = content;\n};\n\n\n/**\n * @return {string} Current content of the layout.\n */\ntart.mvc.Layout.prototype.getContent = function() {\n    return this.content_;\n};\n\n\n/**\n * Renders the layout.\n */\ntart.mvc.Layout.prototype.render = function(body) {\n    if (this.resetLayout == true) {\n        body.innerHTML = this.markup;\n        this.resetLayout = false;\n        goog.typeOf(this.onRender) == 'function' && this.onRender();\n    }\n    else\n        this.getContentArea(body).innerHTML = this.getContent();\n};\n\n\n/**\n * If resetLayout is true, the layout will be redrawn upon next action call whatever the circumstance.\n */\ntart.mvc.Layout.prototype.resetLayout = false;\n\n\n/** @nosideeffects */\ntart.mvc.Layout.prototype.body;\n\n\n/** @nosideeffects */\ntart.mvc.Layout.prototype.contentArea;\n\n\n/** @nosideeffects */\ntart.mvc.Layout.prototype.view;\n\n\n/**\n * Default markup of a layout.\n */\ntart.mvc.Layout.prototype.markup = '';\n\n\n/**\n * Default content of a layout.\n * @private\n */\ntart.mvc.Layout.prototype.content_ = '';\n\n\n/**\n * Returns the content are element where the content will be placed.\n * @param {Element} body\n * @return {Element} The main element the contents will reside in.\n */\ntart.mvc.Layout.prototype.getContentArea = function(body) {\n    if (!this.contentArea) {\n        this.contentArea = body.querySelector('[id=\"content\"]');\n        if (!this.contentArea) {\n            this.contentArea = body;\n        }\n    }\n\n    return this.contentArea;\n};\n\n\n/**\n * @nosideeffects\n */\ntart.mvc.Layout.prototype.onRender;\n\n\n/**\n * Deconstructor method of this layout. Developers should override this property in an action function like;\n *\n * this.deconstructor = function() {}\n *\n * and should deallocate the memory they have used in this layout. This is also helpful for resolving issues that arise\n * because of tartMVC's statefullness; such as removed but dangling DOM nodes, etc.\n */\ntart.mvc.Layout.prototype.deconstructor = null;\n"
  },
  {
    "path": "tart/mvc/MobileAction.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\ngoog.provide('tart.mvc.MobileAction');\n\n\n\n/**\n * @constructor\n * @param {Object} params Params.\n * @param {tart.mvc.LayoutTemplate} layout Layout.\n * @param {tart.mvc.View} view View.\n * @param {tart.mvc.Controller} controller Controller.\n * @extends {tart.mvc.Action}\n */\ntart.mvc.MobileAction = function(params, layout, view, controller) {\n    goog.base(this, params, layout, view, controller);\n    this.refresh = true;\n};\ngoog.inherits(tart.mvc.MobileAction, tart.mvc.Action);\n"
  },
  {
    "path": "tart/mvc/MobileRenderer.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\ngoog.provide('tart.mvc.MobileRenderer');\n\ngoog.require('tart.mvc.MobileAction');\ngoog.require('tart.mvc.Renderer');\n\n\n\n/**\n * @constructor\n * @extends {tart.mvc.Renderer}\n * @param {tart.mvc.LayoutTemplate} layout The default layout of the application. This layout will be used when an\n * action chooses not to set its own layout.\n * @param {Element} dom DOM element this renderer will render the application in.\n */\ntart.mvc.MobileRenderer = function(layout, dom) {\n    goog.base(this, layout, dom);\n};\ngoog.inherits(tart.mvc.MobileRenderer, tart.mvc.Renderer);\n\n\n/**\n * Renders the final view; executing the action and putting the resulting view script in a related layout.\n * @param {tart.mvc.uri.Router} router Application's router.\n */\ntart.mvc.MobileRenderer.prototype.render = function(router) {\n    var oldLayout = this.currentLayout,\n        oldLayoutContext = this.currentLayoutContext,\n        oldViewScript = this.currentViewScript,\n        oldAction = this.currentAction,\n        viewMarkup,\n        layout,\n        view = new tart.mvc.View(),\n        controller = new (router.getController())(),\n        action = this.currentAction = new tart.mvc.MobileAction(router.getParams(), this.defaultLayout, view,\n            controller);\n\n    // if there is an action already executed and it has a deconstructor, call it.\n    if (oldAction)\n        goog.typeOf(oldAction.deconstructor) == 'function' && oldAction.deconstructor();\n\n    if (this.currentLayout && this.currentLayout.beforeViewRender)\n        goog.typeOf(this.currentLayout.beforeViewRender) == 'function' &&\n        this.currentLayout.beforeViewRender.call(layout);\n\n    // execute the action\n    var actionResult = router.getAction().call(action);\n\n    if (actionResult instanceof tart.mvc.uri.Redirection) {\n        return;\n    }\n\n\n\n    this.currentViewScript = action.view;\n    // generate the view markup\n    viewMarkup = action.getViewScript().call(action.view);\n    if (viewMarkup instanceof tart.mvc.uri.Redirection) {\n        return;\n    }\n    // instantiate the layout, set its content and then markup.\n    layout = new tart.mvc.Layout(action.view);\n    layout.setContent(viewMarkup);\n\n    this.currentLayout = action.getLayout();\n\n    // have to reset the layout if the action's layout is different than the previous one\n    if (this.currentLayout != oldLayout) {\n        layout.resetLayout = true;\n\n        // if there is a layout already rendered and it has a deconstructor, call it.\n        if (oldLayoutContext)\n            goog.typeOf(oldLayout.deconstructor) == 'function' && oldLayout.deconstructor.call(oldLayoutContext);\n\n        this.currentLayout.call(layout);\n    }\n\n    var isSameView = oldAction && oldAction.getViewScript() == action.getViewScript();\n\n\n    // if there is an action already executed and it has a deconstructor, call it.\n    if ((!isSameView || (isSameView && action.refresh != false)) && oldViewScript)\n        goog.typeOf(oldViewScript.deconstructor) == 'function' && oldViewScript.deconstructor();\n\n    if (!isSameView || (isSameView && action.refresh != false) || !oldViewScript)\n        layout.render(this.dom_);\n\n\n\n\n    // call respective render callback functions; if there are any. These let the developers\n    // watch out for rendering events.\n    goog.typeOf(action.view.onRender) == 'function' && action.view.onRender();\n    if (this.currentLayout.onViewRender)\n        goog.typeOf(this.currentLayout.onViewRender) == 'function' && this.currentLayout.onViewRender.call(layout);\n\n    this.currentLayoutContext = layout;\n};\n"
  },
  {
    "path": "tart/mvc/Model.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\ngoog.provide('tart.mvc.Model');\n\n\n\n/**\n * @constructor\n */\ntart.mvc.Model = function() { };\n"
  },
  {
    "path": "tart/mvc/README.md",
    "content": "# tart.mvc\nTart MVC framework is a classical web MVC framework for Javascript. The framework is based upon Google Closure Library so it plays very well with Google Closure Compiler.\n\n# Idea\nTart MVC framework is a micro-framework in that it only provides core MVC functionality without infringing any implementation details, which means, as a developer, you are free to choose your own way of development; therefore there are no such convenient methods as Model.find, etc. The library's main concern is performance, so every care is taken for performance to be bulletproof."
  },
  {
    "path": "tart/mvc/Renderer.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\ngoog.provide('tart.mvc.Renderer');\ngoog.require('tart.mvc.Action');\ngoog.require('tart.mvc.Layout');\ngoog.require('tart.mvc.View');\ngoog.require('tart.mvc.uri.Redirection');\n\n\n\n/**\n * @constructor\n * @param {tart.mvc.LayoutTemplate} layout The default layout of the application. This layout will be used when an\n * action chooses not to set its own layout.\n * @param {Element} dom DOM element this renderer will render the application in.\n */\ntart.mvc.Renderer = function(layout, dom) {\n    this.defaultLayout = layout;\n    this.dom_ = dom;\n};\n\n\n/**\n * Renders the final view; executing the action and putting the resulting view script in a related layout.\n * @param {tart.mvc.uri.Router} router Application's router.\n */\ntart.mvc.Renderer.prototype.render = function(router) {\n    var oldLayout = this.currentLayout,\n        oldLayoutContext = this.currentLayoutContext,\n        oldViewScript = this.currentViewScript,\n        oldAction = this.currentAction,\n        viewMarkup,\n        layout,\n        view = new tart.mvc.View(),\n        controller = new (router.getController())(),\n        action = this.currentAction = new tart.mvc.Action(router.getParams(), this.defaultLayout, view, controller);\n\n    // if there is an action already executed and it has a deconstructor, call it.\n    if (oldAction)\n        goog.typeOf(oldAction.deconstructor) == 'function' && oldAction.deconstructor();\n\n    // execute the action\n    var actionResult = router.getAction().call(action);\n\n    if (actionResult instanceof tart.mvc.uri.Redirection) {\n        return;\n    }\n\n    // if there is a view script already rendered and it has a deconstructor, call it.\n    if (oldViewScript)\n        goog.typeOf(oldViewScript.deconstructor) == 'function' && oldViewScript.deconstructor();\n\n    this.currentViewScript = action.view;\n    // generate the view markup\n    viewMarkup = action.getViewScript().call(action.view);\n    if (viewMarkup instanceof tart.mvc.uri.Redirection) {\n        return;\n    }\n    // instantiate the layout, set its content and then markup.\n    layout = new tart.mvc.Layout(action.view);\n    layout.setContent(viewMarkup);\n\n    this.currentLayout = action.getLayout();\n\n    // have to reset the layout if the action's layout is different than the previous one\n    if (this.currentLayout != oldLayout) {\n        layout.resetLayout = true;\n\n        // if there is a layout already rendered and it has a deconstructor, call it.\n        if (oldLayoutContext)\n            goog.typeOf(oldLayout.deconstructor) == 'function' && oldLayout.deconstructor.call(oldLayoutContext);\n\n        this.currentLayout.call(layout);\n    }\n\n    layout.render(this.dom_);\n\n    // call respective render callback functions; if there are any. These let the developers\n    // watch out for rendering events.\n    goog.typeOf(action.view.onRender) == 'function' && action.view.onRender();\n    if (this.currentLayout.onViewRender)\n        goog.typeOf(this.currentLayout.onViewRender) == 'function' && this.currentLayout.onViewRender.call(layout);\n\n    this.currentLayoutContext = layout;\n};\n"
  },
  {
    "path": "tart/mvc/View.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview The View class.\n */\ngoog.provide('tart.mvc.View');\n\n\n\n/**\n * @constructor\n */\ntart.mvc.View = function() {\n};\n\n\n/**\n * Deconstructor method of this view. Developers should override this property in an action function like;\n *\n * this.deconstructor = function() {}\n *\n * and should deallocate the memory they have used in this view. This is also helpful for resolving issues that arise\n * because of tartMVC's statefullness; such as removed but dangling DOM nodes, etc.\n */\ntart.mvc.View.prototype.deconstructor = null;\n"
  },
  {
    "path": "tart/mvc/mvc.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview This file provides a single namespace to include tart.mvc in your application. It also sets the\n * basic needs such as type definitions.\n */\n\ngoog.require('tart.mvc.Application');\ngoog.provide('tart.mvc');\n\n\n/** @typedef {function(this:tart.mvc.Layout)} */\ntart.mvc.LayoutTemplate;\n\n\n/** @typedef {function(new:tart.mvc.Controller)} */\ntart.mvc.ControllerTemplate;\n\n\n/** @typedef {function(this:tart.mvc.Action)} */\ntart.mvc.ActionTemplate;\n\n\n/** @typedef {function(this:tart.mvc.View)} */\ntart.mvc.ViewTemplate;\n"
  },
  {
    "path": "tart/mvc/spec/SpecRunner.html",
    "content": "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\"\n  \"http://www.w3.org/TR/html4/loose.dtd\">\n<html>\n<head>\n  <title>Jasmine Test Runner</title>\n  <link rel=\"stylesheet\" type=\"text/css\" href=\"../../../third_party/jasmine/lib/jasmine.css\">\n  <script type=\"text/javascript\" src=\"../../../third_party/jasmine/lib/jasmine.js\"></script>\n  <script type=\"text/javascript\" src=\"../../../third_party/jasmine/lib/jasmine-html.js\"></script>\n\n  <!-- include source files here... -->\n  <script type=\"text/javascript\" src=\"../../../third_party/jquery/jquery-1.5.2.js\"></script>\n  <script type=\"text/javascript\" src=\"../../../third_party/goog/goog/base.js\"></script>\n  <script type=\"text/javascript\" src=\"../../deps.js\"></script>\n\n  <!-- include spec files here... -->\n  <script type=\"text/javascript\">\n      goog.require('tart.mvc');\n  </script>\n  <script type=\"text/javascript\" src=\"mvcSpec.js\"></script>\n\n</head>\n<body>\n\n<script type=\"text/javascript\">\n  jasmine.getEnv().addReporter(new jasmine.TrivialReporter());\n  jasmine.getEnv().execute();\n</script>\n\n</body>\n</html>\n"
  },
  {
    "path": "tart/mvc/spec/mvcSpec.js",
    "content": "describe('MVC', function() {\n    var app = new tart.mvc.Application(),\n        basePath = '/',\n        defaultRoute = new tart.mvc.uri.Route({\n            name: 'default',\n            format: '/',\n            controller: tart.mvc.Controller,\n            action: function() {\n                return 'action1';\n            }\n        });\n\n    describe('MVC Application', function() {\n        it('should instantiate', function() {\n            expect(app instanceof tart.mvc.Application).toBeTruthy();\n        });\n    });\n\n    describe('URI Router', function() {\n        var router;\n        var controller1, controller2, action1, action2, action3, action4, route1, route2, route3;\n        controller1 = tart.mvc.Controller;\n        action1 = function() {\n            return 'action1';\n        };\n        action2 = function() {\n            return 'action2';\n        };\n        action3 = function() {\n            return 'action3';\n        };\n        action4 = function() {\n            return 'action4';\n        };\n\n        beforeEach(function() {\n            router = new tart.mvc.uri.Router(basePath, defaultRoute);\n            router.setBasePath('/');\n            route1 = new tart.mvc.uri.Route({\n                name: 'controller1',\n                format: 'controller1/action1',\n                controller: controller1,\n                action: action1\n            });\n            route2 = new tart.mvc.uri.Route({\n                name: 'controller1.2',\n                format: 'controller1/action2',\n                controller: controller1,\n                action: action2\n            });\n\n            route3 = new tart.mvc.uri.Route({\n                name: 'controller2',\n                format: 'controller1/action2/*',\n                controller: controller2,\n                action: action3\n            });\n        });\n\n        it('should set a default basePath', function() {\n            router.setBasePath('');\n            expect(router.getBasePath()).toEqual('/');\n        });\n\n        it('should set a basePath', function() {\n            router.setBasePath('/test');\n            expect(router.getBasePath()).toEqual('/test');\n        });\n\n        it('should resolve the default route if no appropriate route is found', function() {\n            router.route('/test');\n\n            expect(router.getCurrentRoute()).toEqual(defaultRoute);\n        });\n        describe('Route logic', function() {\n\n            beforeEach(function() {\n                router = new tart.mvc.uri.Router('/', defaultRoute);\n            });\n\n            it('should add a new route', function() {\n                router.addRoute(route1);\n                expect(router.getRoutes().length).toEqual(1);\n            });\n\n            it('should add more routes', function() {\n                router.addRoute(route1);\n                router.addRoute(route2);\n                expect(router.getRoutes().length).toEqual(2);\n            });\n\n            it('should set the controller of the route', function() {\n                router.addRoute(route1);\n                router.addRoute(route2);\n                router.route('/#!/controller1/action1/');\n                expect(router.getController()).toEqual(controller1);\n            });\n\n            it('should set the action of the route too', function() {\n                router.addRoute(route1);\n                router.addRoute(route2);\n                router.route('/#!/controller1/action1/');\n                expect(router.getAction()).toEqual(action1);\n            });\n\n            it('should set some params too', function() {\n                router.addRoute(route1);\n                router.addRoute(route2);\n                router.addRoute(route3);\n                router.route('/#!/controller1/action2/key1/value1/key2/value2/');\n                expect(router.getParams()).toEqual({ 'key1': 'value1', 'key2': 'value2' });\n            });\n\n        });\n    });\n\n    describe('Request', function() {\n\n    });\n});\n"
  },
  {
    "path": "tart/mvc/test/Bootstrapper.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\ngoog.provide('mvcapp.Bootstrapper');\ngoog.require('mvcapp.Application');\n\n\n\n/**\n * Bootstrapper of the example application.\n * @constructor\n */\nmvcapp.Bootstrapper = function() {\n    new mvcapp.Application();\n};\n\ngoog.exportSymbol('mvcapp.Bootstrapper', mvcapp.Bootstrapper);\n"
  },
  {
    "path": "tart/mvc/test/application/controllers/GamesController.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\ngoog.provide('mvcapp.controllers.GamesController');\ngoog.require('mvcapp.views.layouts.rare');\ngoog.require('mvcapp.views.scripts.games.index');\ngoog.require('mvcapp.views.scripts.games.list');\ngoog.require('tart.mvc.Controller');\n\n\n\n/**\n * @constructor\n * @extends {tart.mvc.Controller}\n */\nmvcapp.controllers.GamesController = function() {\n    goog.base(this);\n};\ngoog.inherits(mvcapp.controllers.GamesController, tart.mvc.Controller);\n\n\n/**\n * @this {tart.mvc.Action}\n * @return {tart.mvc.uri.Redirection} This action redirects to 'home anything' route.\n */\nmvcapp.controllers.GamesController.indexAction = function() {\n    this.setViewScript(mvcapp.views.scripts.games.index);\n    this.setLayout(mvcapp.views.layouts.rare);\n    console.log('games index');\n    this.view.p1 = this.params['p1'];\n    this.view.p2 = this.params['p2'];\n    this.view.a = this.params['a'];\n    this.view.b = this.params['b'];\n\n    if (this.view.p1 == 'a')\n        return mvcapp.router.redirectToRoute('home anything', {'p1': 'pe1', 'p2': 'pe2', 'c': 'd'});\n    return null;\n};\n\n\n/**\n * @this {tart.mvc.Action}\n */\nmvcapp.controllers.GamesController.listAction = function() {\n    this.setViewScript(mvcapp.views.scripts.games.list);\n    this.view.vp1 = this.params['param1'];\n    this.view.vp2 = this.params['param2'];\n    console.log('games list');\n};\n\n\n/**\n * @this {tart.mvc.Action}\n */\nmvcapp.controllers.GamesController.showAction = function() {\n    this.setViewScript(mvcapp.views.scripts.games.index);\n    console.log('games show');\n};\n"
  },
  {
    "path": "tart/mvc/test/application/controllers/IndexController.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\ngoog.provide('mvcapp.controllers.IndexController');\ngoog.require('mvcapp.views.scripts.index.list');\ngoog.require('tart.mvc.Controller');\n\n\n\n/**\n * @constructor\n * @extends {tart.mvc.Controller}\n */\nmvcapp.controllers.IndexController = function() {\n    goog.base(this);\n};\ngoog.inherits(mvcapp.controllers.IndexController, tart.mvc.Controller);\n\n\n/**\n * @this {tart.mvc.Action}\n */\nmvcapp.controllers.IndexController.indexAction = function() {\n    console.log('Index');\n    console.log(this);\n};\n\n\n/**\n * @this {tart.mvc.Action}\n */\nmvcapp.controllers.IndexController.listAction = function() {\n    this.setViewScript(mvcapp.views.scripts.index.list);\n    console.log('list');\n    this.view.id = 'id: 3';\n    console.log(this);\n\n};\n\n\n/**\n * @this {tart.mvc.Action}\n */\nmvcapp.controllers.IndexController.showAction = function() {\n    console.log('show');\n};\n"
  },
  {
    "path": "tart/mvc/test/application/mvcapp.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\ngoog.require('mvcapp.controllers.GamesController');\ngoog.require('mvcapp.controllers.IndexController');\ngoog.require('mvcapp.views.layouts.common');\ngoog.require('tart.mvc');\ngoog.provide('mvcapp.Application');\n\n\n\n/**\n * @constructor\n * @extends {tart.mvc.Application}\n */\nmvcapp.Application = function() {\n    mvcapp.app = this;\n    this.defaultRoute = new tart.mvc.uri.Route({\n        name: 'default',\n        format: '',\n        controller: mvcapp.controllers.IndexController,\n        action: mvcapp.controllers.IndexController.listAction\n    });\n    goog.base(this);\n};\ngoog.inherits(mvcapp.Application, tart.mvc.Application);\n\n\n/**\n * @inheritDoc\n */\nmvcapp.Application.prototype.basePath = '/tart/mvc/test/';\n\n\n/**\n * @inheritDoc\n */\nmvcapp.Application.prototype.defaultLayout = mvcapp.views.layouts.common;\n\n\n/**\n * @inheritDoc\n */\nmvcapp.Application.prototype.initRouting = function() {\n    var router = this.getRouter();\n    mvcapp.router = router;\n    router.addRoute(new tart.mvc.uri.Route({\n        name: 'homeshow',\n        format: 'home/show/',\n        controller: mvcapp.controllers.GamesController,\n        action: mvcapp.controllers.GamesController.showAction\n    }));\n    router.addRoute(new tart.mvc.uri.Route({\n        name: 'homeList',\n        format: 'home/list/:param1/:param2/',\n        controller: mvcapp.controllers.GamesController,\n        action: mvcapp.controllers.GamesController.listAction\n    }));\n    router.addRoute(new tart.mvc.uri.Route({\n        name: 'homeList',\n        format: 'home/list/',\n        controller: mvcapp.controllers.GamesController,\n        action: mvcapp.controllers.GamesController.listAction\n    }));\n    router.addRoute(new tart.mvc.uri.Route({\n        name: 'home anything',\n        format: 'home/list/:p1/:p2/*',\n        controller: mvcapp.controllers.GamesController,\n        action: mvcapp.controllers.GamesController.indexAction\n    }));\n};\n"
  },
  {
    "path": "tart/mvc/test/application/views/layouts/common.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\ngoog.provide('mvcapp.views.layouts.common');\n\n\n/**\n * @this {tart.mvc.Layout}\n */\nmvcapp.views.layouts.common = function() {\n    this.markup = '<div id=\"header\">header</div>' +\n        '<div id=\"content\">' +\n        this.getContent() +\n        '</div>' +\n        '<div id=\"footer\">footer</div>';\n};\n"
  },
  {
    "path": "tart/mvc/test/application/views/layouts/rare.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\ngoog.provide('mvcapp.views.layouts.rare');\n\n\n/**\n * @this {tart.mvc.Layout}\n */\nmvcapp.views.layouts.rare = function() {\n    this.onRender = function() {\n        console && console.log('rare layout render callback');\n    };\n    this.markup = '<div id=\"header\">rare header</div>' +\n                  this.view.layoutName +\n                  '<div id=\"content\">' +\n                  this.getContent() +\n                  '</div>' +\n                  '<div id=\"footer\">rare footer</div>';\n};\n"
  },
  {
    "path": "tart/mvc/test/application/views/scripts/games/index.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\ngoog.provide('mvcapp.views.scripts.games.index');\n\n\n/**\n * @this {tart.mvc.View}\n * @return {string} Output.\n */\nmvcapp.views.scripts.games.index = function() {\n    this.layoutName = 'layoutname: games index';\n    var ps = [this.p1, this.p2, this.a, this.b];\n    if (this.p1 == 'b')\n        return mvcapp.router.redirectToRoute('home anything', {'p1': 'pe3', 'p2': 'pe2', 'c': 'd'});\n\n    this.onRender = function() {\n        console && console.log('games index view script render callback');\n    }\n\n    return 'games index content ' + ps.join(' ') + ' will be here';\n};\n"
  },
  {
    "path": "tart/mvc/test/application/views/scripts/games/list.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\ngoog.provide('mvcapp.views.scripts.games.list');\n\n\n/**\n * @this {tart.mvc.View}\n * @return {string} Output.\n */\nmvcapp.views.scripts.games.list = function() {\n    return 'list vp1: ' + this.vp1 + ', vp2: ' + this.vp2;\n};\n"
  },
  {
    "path": "tart/mvc/test/application/views/scripts/index/list.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\ngoog.provide('mvcapp.views.scripts.index.list');\n\n\n/**\n * @this {tart.mvc.View}\n * @return {string} Output.\n */\nmvcapp.views.scripts.index.list = function() {\n    return 'list' + this.id;\n};\n"
  },
  {
    "path": "tart/mvc/test/index.html",
    "content": "<!DOCTYPE html>\n<html>\n<head>\n    <title></title>\n    <script type=\"text/javascript\" src=\"../../../third_party/jquery/jquery-1.5.2.js\"></script>\n    <!--<script type=\"text/javascript\" src=\"../../../third_party/goog/closure/goog/base.js\"></script>-->\n    <!--<script type=\"text/javascript\" src=\"../../deps.js\"></script>-->\n    <!--<script type=\"text/javascript\" src=\"Bootstrapper.js\"></script>-->\n    <script type=\"text/javascript\" src=\"../../../compiled/compiled.js\"></script>\n</head>\n<body>\n<script type=\"text/javascript\">\n    mvcapp.Bootstrapper();\n</script>\n</body>\n</html>\n"
  },
  {
    "path": "tart/mvc/uri/Redirection.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview This is a special return value that is used to identify a redirection. If a redirection is in place\n * the tart.mvc.Router returns an instance of this class, so that the redirector won't resume after the redirection\n * takes place.\n */\n\ngoog.provide('tart.mvc.uri.Redirection');\n\n\n\n/**\n * Special return value for a redirection in tart.mvc.Router.\n * @constructor\n */\ntart.mvc.uri.Redirection = function() {\n};\n"
  },
  {
    "path": "tart/mvc/uri/Request.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\ngoog.provide('tart.mvc.uri.Request');\ngoog.require('goog.Uri');\n\n\n\n/**\n * Represents a request made to the application, storing its controller, action and parameters.\n * @constructor\n * @param {Location|string} uriString uri to be routed. This can either be a string of the uri or a Location such as\n *                                    window.location.\n * @param {tart.mvc.uri.Router} router uri router.\n */\ntart.mvc.uri.Request = function(uriString, router) {\n    var basePath = router.getBasePath(),\n        uri = new goog.Uri(uriString),\n        requestPath;\n\n    var fragment = uri.getFragment();\n    //@TODO We should implement pushing extra parameters to the request parameters, as supporting both \n    //\"url?key=value\" and \"url/key/value\"\n    var parameters = fragment.split('?');\n    if (parameters.length > 0) {\n        fragment = parameters[0];\n        this.customQuery = parameters[1];\n    }\n\n    if (uri.hasFragment() && !goog.string.endsWith(basePath, '#!/'))\n        basePath = basePath + '#!/';\n\n    requestPath = uri.getPath() + (uri.hasFragment() ? '#' + fragment : '');\n\n    if (goog.string.startsWith(requestPath, basePath))\n        this.path = requestPath.substr(basePath.length);\n    else\n        throw new tart.Err('Request cannot be handled by application.', 'Request Error');\n\n    if (!goog.string.endsWith(this.path, '/'))\n        this.path += '/';\n\n    this.fragments = this.path.split('/');\n    this.fragments = goog.array.filter(this.fragments, function(el) {\n        return (el != '');\n    });\n};\n\n\n/**\n * @type {?string} Custom query field of Request object. This field holds extra parameter which followed by \"?\".\n */\ntart.mvc.uri.Request.prototype.customQuery = null;\n\n"
  },
  {
    "path": "tart/mvc/uri/Route.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\ngoog.provide('tart.mvc.uri.Route');\ngoog.require('tart.Err');\n\n\n\n/**\n * Represents a request made to the application, storing its controller, action and parameters.\n * @constructor\n * @param {tart.mvc.uri.routeTemplate} template uri route template object.\n */\ntart.mvc.uri.Route = function(template) {\n    this.name = template.name;\n    this.controller = template.controller;\n    this.action = template.action;\n    this.setFormat(template.format);\n};\n\n\n/**\n * Parses a route's human readable format into hard-core RegExp.\n * @param {string} format Route's format.\n */\ntart.mvc.uri.Route.prototype.setFormat = function(format) {\n    this.templateFormat = format;\n    var fields, wildchars;\n    wildchars = format.match(/\\*/g);\n    if (wildchars && wildchars.length > 1)\n        throw new tart.Err('Route cannot contain more than one wildchar.', 'Routing Error');\n\n    if (goog.string.endsWith(format, '/') == false)\n        format += '/';\n\n    format = '^' + format + '$';\n\n    format = format.replace(/\\*/g, '(.*?)');\n    fields = format.match(/((:\\w+)|\\(\\.\\*\\?\\))/g);\n\n    if (fields) {\n        this.params = [];\n        format = format.replace(/(:\\w+)/g, '([^?#\\/]+)');\n        for (var i = 0, l = fields.length; i < l; i++) {\n            this.params.push(fields[i].substr(1));\n        }\n    }\n    format = format.replace(/\\//g, '\\\\/');\n    this.format = new RegExp(format);\n\n};\n\n\n/** @typedef\n * {{\n *  name: string,\n *  format: string,\n *  controller: function(new:tart.mvc.Controller),\n *  action: function(this:tart.mvc.Action)\n * }}\n * **/\ntart.mvc.uri.routeTemplate;\n"
  },
  {
    "path": "tart/mvc/uri/Router.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview URI Router class that takes a given URI and resolves the necessary controller / action.\n */\n\ngoog.provide('tart.mvc.uri.Router');\ngoog.require('goog.array');\ngoog.require('goog.object');\ngoog.require('tart.mvc.uri.Redirection');\ngoog.require('tart.mvc.uri.Request');\n\n\n\n/**\n * Router class that is responsible for routing the incoming request to appropriate controller and actions\n * with appropriate parameters.\n * The application routes are added to the Router instance and every time the URI\n * changes, it routes the request to the appropriate controller/action.\n * @param {string} basePath The URI to parse.\n * @param {tart.mvc.uri.Route} defaultRoute Default URI route that is used as fallback when no appropriate\n * controller/action is found.\n * @param {tart.mvc.Renderer} renderer Renderer instance to actually execute the routing and draw the layout and view.\n * @param {tart.mvc.uri.Router.RedirectionType=} redirectionType How the redirection will affect the url. By default, all\n * redirections change the url.\n * @constructor\n */\ntart.mvc.uri.Router = function(basePath, defaultRoute, renderer, redirectionType) {\n    this.setBasePath(basePath);\n\n    /**\n     * @type {Array.<tart.mvc.uri.Route>}\n     * @private\n     */\n    this.routes_ = [];\n    this.defaultRoute = defaultRoute;\n    this.addRoute(this.defaultRoute);\n    this.renderer_ = renderer;\n    this.redirectionType = redirectionType || tart.mvc.uri.Router.RedirectionType.CLASSICAL;\n};\n\n\n/**\n * Constant values for redirection types.\n * CLASSICAL makes all redirections with the url changing and reflecting the new path.\n * SILENT_ALL makes all redirections without the url changing.\n * SILENT_ONLY_DEFAULT makes only the error redirections silent. All the other ones are CLASSICAL.\n *\n * @enum\n */\ntart.mvc.uri.Router.RedirectionType = {\n    CLASSICAL: 0,\n    SILENT_ALL: 1,\n    SILENT_ONLY_DEFAULT: 2,\n    SILENT: 3\n};\n\n\n/**\n * Responsible for routing the incoming request to appropriate controller and actions with appropriate parameters.\n * The application routes are added to the uri.Router instance.\n * @param {string=} uri The URI to parse.\n */\ntart.mvc.uri.Router.prototype.route = function(uri) {\n    var route;\n\n    try {\n        this.request = new tart.mvc.uri.Request(uri || window.location, this);\n        route = this.resolve_(this.request);\n    }\n    catch (e) {\n        this.redirectToRoute(this.getDefaultRoute());\n        return;\n    }\n\n    this.setCurrentRoute_(route);\n    this.process_(this.request);\n    this.renderer_.render(this);\n};\n\n\n/**\n * Redirects to a given route with given parameters.\n *\n * @param {tart.mvc.uri.Route|string} route The name of the route the redirection will be made to.\n * This method will first search for the given route and may throw a tart.Err if the requested route is undefined.\n * @param {Object.<string, *>=} params The object that contains parameters to be sent to the route. Make sure that\n * the parameters fully match the route's requirements, otherwise a tart.Err may be thrown.\n * @param {tart.mvc.uri.Router.RedirectionType=} redirectionType How the redirection will affect the url.\n * @return {tart.mvc.uri.Redirection} Explicitly make known that this is a redirection, so that the redirector stops\n * execution after this action.\n */\ntart.mvc.uri.Router.prototype.redirectToRoute = function(route, params, redirectionType) {\n    var url,\n        validParams,\n        customParamArray = [],\n        routeContainsCustomParams,\n        requestParams = {},\n        paramsLength,\n        routeParams,\n        silentRedirect = false;\n\n    if (params && goog.typeOf(params) == 'object')\n        requestParams = params;\n\n    paramsLength = goog.object.getCount(requestParams);\n\n    if (route instanceof tart.mvc.uri.Route)\n        route = route.name;\n    try {\n        route = this.getRoute(route);\n    }\n    catch (e) {\n        throw e;\n    }\n\n    if (( redirectionType && redirectionType != tart.mvc.uri.Router.RedirectionType.CLASSICAL) ||\n        redirectionType == tart.mvc.uri.Router.RedirectionType.SILENT ||\n        this.redirectionType == tart.mvc.uri.Router.RedirectionType.SILENT_ALL ||\n        (this.redirectionType == tart.mvc.uri.Router.RedirectionType.SILENT_ONLY_DEFAULT &&\n             route == this.getDefaultRoute())) {\n        silentRedirect = true;\n    }\n\n    // we'll construct the url in this variable and we start with the given template of a route.\n    url = route.templateFormat;\n    routeContainsCustomParams = url.indexOf('*') > -1;\n\n    // find required parameters with \":paramName\" notation.\n    routeParams = url.match(/:\\w+/g);\n\n    if (routeParams) {\n        // validParams is true whenever each and every one of those required parameters are present in params array.\n        validParams = goog.array.every(routeParams, function(routeParam) {\n            return routeParam.substr(1) in requestParams;\n        });\n\n        // check number of parameters match.\n        if (!routeContainsCustomParams && paramsLength != routeParams.length ||\n                routeContainsCustomParams && paramsLength <= routeParams.length)\n            validParams = false;\n\n        // if parameters do not match the route's requirements; throw an error.\n        if (!validParams)\n            throw new tart.Err('Given parameters do not match the required parameters of the route', 'Routing Error');\n\n        // replace route parameters with their equivalents in params object.\n        goog.array.forEach(routeParams, function(routeParam) {\n            routeParam = routeParam.substr(1);\n            url = url.replace(':' + routeParam, requestParams[routeParam]);\n            delete requestParams[routeParam];\n        });\n\n        // convert all remaining custom parameters to an array for easier addition to url.\n        if (routeContainsCustomParams)\n            for (var key in requestParams)\n                customParamArray.push(key, requestParams[key]);\n    }\n\n    // construct the final url by replacing custom parameter placeholder with custom parameters\n    url = this.getBasePath() + '#!/' + url.replace('*', customParamArray.join('/'));\n\n    if (silentRedirect)\n        // route the request but don't change the url.\n        this.route(url);\n    else // set the url. Since the application listens url changes; it will trigger the correct redirection\n        window.location = url;\n\n    // since this is a redirection; return a proof that it really is; so that a renderer knows a redirection took place\n    // and doesn't go on executing the previous action / view scripts' remaining tasks.\n\n    if (!this.redirectionReturnValue)\n        this.redirectionReturnValue = new tart.mvc.uri.Redirection();\n\n    return this.redirectionReturnValue;\n};\n\n\n/**\n * Redirects to a given controller and action with given parameters. This method is a convenience method for\n * redirectToRoute in that one may use without hard-coding the name of the route. Keep in mind that there still\n * needs to be an actual route that will resolve to the given controller and action.\n *\n * @param {tart.mvc.ControllerTemplate} controller The controller child class that the redirection will resolve to.\n * @param {tart.mvc.ActionTemplate} action The action that the redirection will reeolve to.\n * @param {Object.<string, *>=} params The object that contains parameters to be sent to the route. Make sure that\n * the parameters fully match the route's requirements, otherwise a tart.Err may be thrown.\n * @param {tart.mvc.uri.Router.RedirectionType=} redirectionType How the redirection will affect the url.\n * @return {tart.mvc.uri.Redirection} Explicitly make known that this is a redirection, so that the redirector stops\n * execution after this action.\n */\ntart.mvc.uri.Router.prototype.redirectToAction = function(controller, action, params, redirectionType) {\n    var route = goog.array.find(this.getRoutes(), function(route) {\n        return route.controller = controller && route.action == action;\n    });\n\n    return this.redirectToRoute(route.name, params, redirectionType);\n};\n\n\n/**\n * Set base path\n *\n * @param {string} path uri base path.\n */\ntart.mvc.uri.Router.prototype.setBasePath = function(path) {\n    this.basePath = path || '/';\n};\n\n\n/**\n * Return uri base path\n *\n * @return {string} uri base path.\n */\ntart.mvc.uri.Router.prototype.getBasePath = function() {\n    return this.basePath;\n};\n\n\n/**\n * Resolves routes.\n * If the request matches any route, this function resolves it. Or else, it will throw a tart.Err.\n * @private\n * @param {tart.mvc.uri.Request} request Request to look for a route match.\n * @return {?tart.mvc.uri.Route} Resolved route that holds the details of handling the request. Note that this\n * function never returns null; this is a Google Closure Compiler fix.\n */\ntart.mvc.uri.Router.prototype.resolve_ = function(request) {\n    var response, route, responseValue, responseArray, that = this;\n\n    // Find a matching route in our routes list\n    route = goog.array.find(this.routes_, function(/** tart.mvc.uri.Route */ route) {\n        if (response = request.path.match(route.format)) { // response holds the parameters if the format matches\n            var fragments = [];\n\n            for (var i = 0; i < response.length - 1; i++) {\n                responseValue = response[i + 1]; // the first item will be the full uri so skip it.\n                responseArray = responseValue.split('/');\n                /*\n                 if the parameter contains a slash, this means a wildchar was used; so we have to turn each of them\n                 into real parameters.\n                 */\n                if (responseArray.length > 1) {\n                    that.fixOddParams_(responseArray); // there can be an odd number of parameters so let's fix them\n                    fragments = fragments.concat(responseArray);\n                }\n                else\n                    /*\n                 no slashes, this is a valid parameter, so we should add it (responseValue)\n                 with its respective owner that was given as :name (route.params[i])\n                 */\n                    fragments.push(route.params[i], responseValue);\n            }\n            request.params = fragments;\n            return true;\n        }\n        return false;\n    });\n    if (!route)\n        throw new tart.Err('The request cannot be resolved to a route.', 'Routing Error');\n\n    if (route instanceof tart.mvc.uri.Route) // workaround for casting goog.array.find return type to route.\n        return route;\n    return null;\n};\n\n\n/**\n * This function sets the current route and the related controllers, actions and parameters.\n * @private\n * @param {tart.mvc.uri.Request} request Request to be processed.\n */\ntart.mvc.uri.Router.prototype.process_ = function(request) {\n    var route = this.getCurrentRoute();\n    this.setController_(route.controller);\n    this.setAction_(route.action);\n    this.setParams_(request.params);\n    this.setCustomQuery_(request.customQuery);\n};\n\n\n/**\n * Sets a URL route as the current route.\n * @param {tart.mvc.uri.Route} route Route to set as the current one.\n * @private\n */\ntart.mvc.uri.Router.prototype.setCurrentRoute_ = function(route) {\n    this.currentRoute_ = route;\n};\n\n\n/**\n * @return {tart.mvc.uri.Route} the active URI route.\n */\ntart.mvc.uri.Router.prototype.getCurrentRoute = function() {\n    return this.currentRoute_;\n};\n\n/**\n * Sets custom query parameter.\n * @param {?string} customQuery Retrieved key and parameter pair from uri followed by ? to set as customQuery.\n * @private\n */\ntart.mvc.uri.Router.prototype.setCustomQuery_ = function(customQuery) {\n    this.customQuery_ = customQuery;\n};\n\n\n/**\n * Returns custom query parameter.\n * @return {?string} customQuery Retrieved key and parameter pair from uri.\n */\ntart.mvc.uri.Router.prototype.getCustomQuery = function() {\n    return this.customQuery_;\n};\n\n\n/**\n * Sets the current controller required by the request. If there are no such controllers, default controller is set.\n * @private\n * @param {tart.mvc.ControllerTemplate} controller Controller present on the route.\n */\ntart.mvc.uri.Router.prototype.setController_ = function(controller) {\n    this.controller_ = controller;\n};\n\n\n/**\n * Sets the current action required by the request. If there are no such actions, default action is set.\n * @private\n * @param {tart.mvc.ActionTemplate} action Action present on the route.\n */\ntart.mvc.uri.Router.prototype.setAction_ = function(action) {\n    this.action_ = action;\n};\n\n\n/**\n * Sets the parameters. Notice that if there are odd number of parameters, an empty value is added to the end of\n * the array for convenient operation of sending only the keys (where values are unimportant to the backend)\n * @private\n * @param {Array.<string>} paramsArray Array of parameters.\n */\ntart.mvc.uri.Router.prototype.setParams_ = function(paramsArray) {\n    var params = {};\n\n    if (this.getCurrentRoute() == this.getDefaultRoute()) {\n        this.params_ = {};\n        return;\n    }\n\n    if (paramsArray && paramsArray.length > 0) {\n        this.fixOddParams_(paramsArray);\n        params = goog.object.create(paramsArray);\n    }\n\n    this.params_ = params;\n};\n\n\n/**\n * This little function fixes parameters in case there are odd number of elements so that it's impossible to construct\n * a valid key value pair. It adds an empty item at the end; making the last item a key with empty value. This is\n * quite handy when you only want the key present and no value is necessary.\n * @param {Array} params Request parameters.\n * @private\n */\ntart.mvc.uri.Router.prototype.fixOddParams_ = function(params) {\n    if (params.length % 2 == 1)\n        params.push(true);\n};\n\n\n/**\n * Returns the active controller.\n * @return {(function (new:tart.mvc.Controller))} Active controller.\n */\ntart.mvc.uri.Router.prototype.getController = function() {\n    return this.controller_;\n};\n\n\n/**\n * Returns the active action.\n * @return {Function} Active action.\n */\ntart.mvc.uri.Router.prototype.getAction = function() {\n    return this.action_;\n};\n\n\n/**\n * @return {Object} The active parameters.\n */\ntart.mvc.uri.Router.prototype.getParams = function() {\n    return this.params_;\n};\n\n\n/**\n * Adds a route to the router.\n * @param {tart.mvc.uri.Route} route Route to be added.\n */\ntart.mvc.uri.Router.prototype.addRoute = function(route) {\n    this.routes_.push(route);\n};\n\n\n/**\n * @return {Array.<tart.mvc.uri.Route>} The array of routes in this router.\n */\ntart.mvc.uri.Router.prototype.getRoutes = function() {\n    return this.routes_;\n};\n\n\n/**\n * Returns a route with a given name. If no matching route is found, this method throws a tart.Err.\n * @param {string} name Route name to look up.\n * @return {?tart.mvc.uri.Route} Route with the given name. Note that this function never returns null; this is a\n * Google Closure Compiler fix.\n */\ntart.mvc.uri.Router.prototype.getRoute = function(name) {\n    var route = goog.array.find(this.getRoutes(), function(route) {\n        return route.name == name;\n    });\n    if (!route)\n        throw new tart.Err('Route name \"' + name + '\" cannot be found', 'Routing Error');\n\n    if (route instanceof tart.mvc.uri.Route) // workaround for casting goog.array.find return type to route.\n        return route;\n    return null;\n};\n\n\n/**\n * Returns the default route associated with this router.\n * @return {tart.mvc.uri.Route} Default route.\n */\ntart.mvc.uri.Router.prototype.getDefaultRoute = function() {\n    return this.defaultRoute;\n};\n"
  },
  {
    "path": "tart/storage/Storage.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview This file provides localStorage extensions that are essential to Tart. Basically, the localStorage\n * only allows you to store strings. tart.storage.Storage can store any type of object via serialization.\n *\n * Example usage:\n *\n *     var storage = new tart.storage.Storage();\n *     storage.set('foo', {bar: 'baz'});\n *     storage.get('foo');\n *     // you can still iterate through localStorage as before with for .. in;\n *     for (var key in localStorage) {\n *         var object = storage.get(key);\n *         //do something with the object\n *     }\n */\n\n\ngoog.provide('tart.storage.Storage');\ngoog.require('goog.json');\n\n\n\n/**\n* Basic local storage class that adds object storage abilities to the standard html5 localStorage by\n* serializing objects.\n* @constructor\n*/\ntart.storage.Storage = function() {\n};\n\n\n/**\n* Sets a key value pair to the local storage.\n* @param {string} key Key of the pair to be stored.\n* @param {*} value Value of the pair to be stored. The value will be stored serialized.\n*/\ntart.storage.Storage.prototype.set = function(key, value) {\n    var val;\n    try {\n        val = JSON.stringify(value);\n    }\n    catch (e) {\n        val = goog.json.serialize(value);\n    }\n\n    localStorage.setItem(key, val);\n};\n\n\n/**\n* Fetches an item from the storage.\n* @param {string} key Key of the value to be fetched from the storage.\n* @return {*} Value of the item.\n*/\ntart.storage.Storage.prototype.get = function(key) {\n    var rv = null,\n        val = localStorage.getItem(key);\n\n    try {\n        rv = JSON.parse(val);\n    }\n    catch (e) {\n        rv = goog.json.parse(val);\n    }\n\n    return rv;\n};\n\n\n/**\n * Remove value from storage.\n *\n * @param {string} key Key of the associated pair.\n */\ntart.storage.Storage.prototype.remove = function(key) {\n    localStorage.removeItem(key);\n};\n\n\n/**\n * Clear all values from storage.\n */\ntart.storage.Storage.prototype.clear = function() {\n    localStorage.clear();\n};\n\n\n/**\n * Get the number of stored key-value pairs.\n * @return {number} Number of stored elements\n */\ntart.storage.Storage.prototype.getCount = function() {\n    return localStorage.length;\n};\n"
  },
  {
    "path": "tart/string/string.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview Provides utility functions for string operations.\n */\n\ngoog.provide('tart.string');\n\n(function() {\n    var loremIpsum = 'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris nisi tortor, porta ac lobortis vel, euismod sit amet turpis. Vivamus tempus turpis velit. Phasellus tincidunt tellus vitae lorem placerat rutrum. Quisque varius purus non nibh molestie eget lacinia neque tristique. Cras nec felis nec lorem egestas egestas quis ut quam. Praesent aliquam bibendum tellus, non pulvinar ante blandit vel. Sed quis mollis nibh. Praesent sagittis, nunc ac dapibus mattis, mi est rhoncus risus, nec volutpat tellus urna at lectus. Sed est enim, vulputate sed consequat sed, rutrum sed tellus. Suspendisse lacinia sapien at libero auctor id condimentum dui lobortis. Curabitur auctor posuere elementum. Cras vestibulum urna eu lectus vestibulum rhoncus. Suspendisse mattis eleifend ullamcorper. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nunc et nisi ut sapien placerat commodo. In convallis sem orci, convallis auctor orci. Suspendisse sed urna dolor. Suspendisse id dui ante, ac lobortis turpis. Maecenas tristique posuere lacus in venenatis. Aliquam cursus fermentum dui vestibulum adipiscing. Duis dui ipsum, tempor et gravida eu, varius id diam. Integer volutpat est eu nunc mollis quis accumsan tellus ultricies. Vestibulum fermentum luctus lacus quis rhoncus. Donec eleifend rutrum urna eget lobortis. Sed vitae erat erat, vel adipiscing mauris. Aenean malesuada posuere auctor. Donec in semper nulla. Vivamus venenatis enim ut purus tempor eu posuere mauris ullamcorper. Proin semper felis sit amet urna auctor at hendrerit magna commodo. Maecenas dictum mi nec odio luctus suscipit. Sed mattis, leo sed feugiat pulvinar, quam risus adipiscing mi, vitae pretium erat metus ac risus. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Fusce vel velit quis arcu venenatis elementum quis vitae libero. Maecenas rutrum, erat et porta hendrerit, felis eros scelerisque erat, in venenatis lacus est in leo. Fusce ac ante quis ipsum interdum interdum non ac quam. Sed nulla quam, gravida quis dapibus vel, pharetra ac elit. Curabitur sed metus eu enim eleifend hendrerit id id lacus. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Duis feugiat diam nec lorem tempus aliquet. Mauris imperdiet, mauris sit amet viverra dignissim, augue elit pellentesque sapien, eget blandit turpis nunc sed est. Praesent lacinia sapien in mi molestie sit amet posuere lacus vehicula. Aliquam quam ligula, aliquam id dictum vel, vehicula sed ipsum. Aliquam vestibulum eros id erat mattis imperdiet. In pretium, ante sed rhoncus tincidunt, mauris felis porttitor felis, sed tempor elit libero eu arcu. Phasellus molestie, ligula sit amet placerat tincidunt, tortor elit tristique arcu, eu eleifend massa nisi ut leo. Nulla sagittis erat eget nulla cursus tristique. Mauris turpis arcu, rhoncus nec hendrerit a, tincidunt in lorem. Praesent dapibus mauris nec risus vestibulum feugiat. Vestibulum ac sem leo. Quisque sodales rutrum purus a egestas. Duis placerat, ante et viverra molestie, augue neque faucibus tortor, sit amet pellentesque ante nulla vel ante';\n    var loremIpsumArray = loremIpsum.split('. ');\n    tart.string.loremIpsum = function() {\n        var random = Math.round(Math.random() * loremIpsumArray.length);\n        return loremIpsumArray[random] + '.';\n    }\n})();\n\n\n/**\n * This function helps to decode url parameters back to a javascript object.\n *\n * For example, a%5Bb%5D%5B%5D=1&a%5Bb%5D%5B%5D=2 is deparam'med to\n * { a: { b: [\"1\", \"2\"] } }\n *\n * This function is a modified form of an answer by Jacky Li to the question in\n * http://stackoverflow.com/questions/1131630/javascript-jquery-param-inverse-function\n *\n * This version would fail on a param like [=]=20.\n *\n * @param {string} query Query string to deparam.\n * @return {Object} Deparameterized string.\n */\ntart.string.deparam = function(query) {\n    var setValue = function(root, path, value) {\n        if (path.length > 1) {\n            var dir = path.shift();\n            if (typeof root[dir] == 'undefined') {\n                root[dir] = (path[0] == '' || parseInt(path[0], 10) == path[0]) ? [] : {};\n            }\n\n            arguments.callee(root[dir], path, value);\n        } else {\n            if (root instanceof Array) {\n                root.push(value);\n            } else {\n                root[path] = value;\n            }\n        }\n    };\n    var nvp = query.split('&');\n    var data = {};\n    for (var i = 0; i < nvp.length; i++) {\n        var equalsIndex = nvp[i].lastIndexOf('=');\n        var pair = [nvp[i].substr(0, equalsIndex), nvp[i].substr(equalsIndex + 1)];\n\n        //var pair = nvp[i].split('=');\n        var name = decodeURIComponent(pair[0]);\n        var value = decodeURIComponent(pair[1]);\n\n        var path = name.match(/(^[^\\[]+)(\\[.*\\]$)?/);\n        var first = path[1];\n        if (path[2]) {\n            //case of 'array[level1]' || 'array[level1][level2]'\n            path = path[2].match(/(?=\\[(.*)\\]$)/)[1].split('][');\n        } else {\n            //case of 'name'\n            path = [];\n        }\n        path.unshift(first);\n\n        setValue(data, path, value);\n    }\n    return data;\n};\n"
  },
  {
    "path": "tart/tart.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview tartJS base.\n */\ngoog.provide('tart');\n\n\n\n/** @typedef {Object} */\ntart.JSON;\n\n(function() {\n    var counter = Math.floor(Math.random() * 2147483648);\n    tart.getUid = function() {\n        return (counter++).toString(36);\n    }\n})();\n\n\n/**\n * @typedef {{method, headers, url, data}}\n */\ntart.XhrOptions;\n\n\n/**\n * @typedef {function(boolean=, Object=, number=)}\n */\ntart.XhrCallback;\n\n\n/**\n * Makes XHR requests with given options. This is\n *\n * @param {tart.XhrOptions|string} options Options for this method. This can also be a simple string denoting the URL.\n * @param {tart.XhrCallback=} opt_callback Callback to execute when the request ends.\n *                                                          It will be invoked with errors, data and status code.\n * @param {Object=} opt_context The context of the callback to be applied.\n */\ntart.xhr = function(options, opt_callback, opt_context) {\n    var req = new XMLHttpRequest(),\n        opts = options;\n\n    if (typeof options == 'string')\n        opts = {\n            url: options\n        };\n\n    opts.method = opts.method || 'GET';\n    opts.headers = opts.headers || {};\n\n    if ((opts.method == 'PUT' || opts.method == 'POST') &&\n        !opts.headers['Content-Type'] &&\n        typeof opts.data == 'object')\n        opts.headers['Content-Type'] = 'application/json';\n\n    req.open(opts.method, opts.url, true);\n\n    Object.keys(opts.headers).forEach(function(key) {\n        req.setRequestHeader(key, opts.headers[key]);\n    });\n\n    req.onreadystatechange = function(e) {\n        if (req.readyState != 4) return;\n\n        var data,\n            err = false;\n\n        if ([200, 304].indexOf(req.status) == -1)\n            err = true;\n\n        try {\n            data = JSON.parse(e.target.response);\n        } catch (ex) {\n            data = e.target.response;\n        }\n\n        opt_callback && opt_callback.call(opt_context || goog.global, err, /** @type {Object} */(data), req.status);\n    };\n    req.withCredentials = true;\n    req.send(JSON.stringify(opts.data));\n};\n"
  },
  {
    "path": "tart/ui/Component.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview This class offers a component architecture for projects that include highly interactive user\n * interfaces. Unlike tart.Component which features a classical MVC role seperation - with 5 or 6 classes, which is\n * also a heavy implementation - tart.ui.Component uses 3 classes and joins the roles of the Template, View and\n * Controller into one Component class.\n *\n * The other roles help responsibility seperation that is necessary enough for a UI component.\n *\n * The Component class is useful for event management; it listens to DOM events, map these to related functions in the\n * model and vice versa.\n *\n * The model is responsible for all the states of the component and the business logic.\n * The component shouldn't keep state and should be as dummy as possible; any state change on the model is dispatched\n * via an event to the Component class to update itself. This decoupled architecture makes it possible that business\n * critical unit tests of the component can run fully functionally without a DOM. The model may also be responsible for\n * dealing with the data in any way (remote requests, other events to other modules in the system, etc).\n *\n * Finally, the third, optional class is a value class, which is like a POJO. It keeps all the related data in an\n * instance. This allows one to exchange data in the application with very lightweight data objects - make it through a\n * constructor class and you get to keep object oriented design.\n *\n * So, the data the component displays or deals with resides in a value class. The model keeps its state and business\n * logic, and the Component class makes the representation.\n */\n\ngoog.provide('tart.ui.Component');\ngoog.require('goog.events.EventTarget');\ngoog.require('tart');\ngoog.require('tart.dom');\n\n\n\n/**\n * The component class useful for building small and single responsible UI components.\n * @constructor\n * @extends {goog.events.EventTarget}\n */\ntart.ui.Component = function() {\n    this.id = tart.getUid();\n    this.element = /** @type {Element} */(tart.dom.createElement(this.templates_base()));\n\n    this.createElements();\n    this.bindModelEvents();\n    this.bindDomEvents();\n};\ngoog.inherits(tart.ui.Component, goog.events.EventTarget);\n\n\n/**\n * Returns the dom element attached with the Component instance.\n * @return {Element} Returns the root DOM element.\n */\ntart.ui.Component.prototype.getElement = function() {\n    return this.element;\n};\n\n\n/**\n * Listens to the model's events. This method should be overriden by the implementer, and should keep the model's event\n * listeners.\n * @protected\n */\ntart.ui.Component.prototype.bindModelEvents = function() {\n\n};\n\n\n/**\n * Listens to DOM events. This method should be overriden by the implementer, and should keep the component's DOM\n * event bindings.\n * @protected\n */\ntart.ui.Component.prototype.bindDomEvents = function() {\n\n};\n\n\n/**\n * Creates the necessary DOM elements and appends them to the root element. This method should be overriden by the\n * implementer.\n */\ntart.ui.Component.prototype.createElements = function() {\n\n};\n\n\n/**\n * Template of the root element. This method can be overridden if necessary. Other templates should be named with the\n * templates_ prefix as necessary.\n * @return {string} Root element's tempalte.\n */\ntart.ui.Component.prototype.templates_base = function() {\n    return '<div id=\"' + this.id + '\"></div>';\n};\n"
  },
  {
    "path": "tart/ui/ComponentManager.js",
    "content": "// Copyright (c) 2009-2012 Techinox Information Technologies (http://www.techinox.com)\n// Techinox Commercial License\n//\n// @author Armagan Amcalar <armagan.amcalar@tart.com.tr>\n\n\ngoog.provide('tart.ui.ComponentManager');\ngoog.require('tart.events');\ngoog.require('goog.array');\ngoog.require('goog.events.EventType');\ngoog.require('tart.events.HoverHandler');\ngoog.require('tart.events.GestureHandler');\n\n/**\n * @fileoverview Registry for tart.ui.DlgComponent. Manages DOM event interactions for these components.\n */\n\n\n/**\n *\n * @constructor\n */\ntart.ui.ComponentManager = function() {\n    /** @type {Object.<string, tart.ui.DlgComponent>} */\n    this.components = {};\n    this.gestureHandler = tart.events.GestureHandler.getInstance();\n    this.hoverHandler = new tart.events.HoverHandler();\n\n    goog.events.listen(document.body, tart.ui.ComponentManager.eventTypes, this);\n    goog.events.listen(this.hoverHandler, [tart.events.EventType.MOUSEENTER, tart.events.EventType.MOUSELEAVE], this);\n};\ngoog.addSingletonGetter(tart.ui.ComponentManager);\n\n\n/**\n * Returns parent components (if available) of a given DOM node.\n *\n *\n * @param {Node} child DOM node that will be used for finding parent components.\n * @return {Array.<tart.ui.DlgComponent>} Parent components.\n */\ntart.ui.ComponentManager.prototype.getParentComponents = function(child) {\n    var node = child, cmps = [], cmp, ids;\n\n    if (ids = node.getAttribute && node.getAttribute('data-cmp')) {\n        ids.split(',').forEach(function(id) {\n            if (id) cmps.push(this.components[id]);\n        }, this);\n\n        return cmps;\n    }\n\n    ids = [];\n\n    do {\n        if (cmp = this.components[node.id]) {\n            cmps.push(cmp);\n            ids.push(node.id);\n        }\n    } while (node = node.parentNode);\n\n    child.setAttribute('data-cmp', ids.join(','));\n    return cmps;\n};\n\n\n/**\n * Keeps event types.\n * @type {Array.<goog.events.EventType>}\n */\ntart.ui.ComponentManager.eventTypes = [\n    goog.events.EventType.CLICK,\n    goog.events.EventType.MOUSEOVER,\n    goog.events.EventType.MOUSEOUT,\n    goog.events.EventType.MOUSEMOVE,\n    goog.events.EventType.MOUSEDOWN,\n    goog.events.EventType.MOUSEUP,\n    tart.events.EventType.MOUSEENTER,\n    tart.events.EventType.MOUSELEAVE,\n    tart.events.EventType.TAP,\n    tart.events.EventType.LONG_TAP,\n    tart.events.EventType.SWIPE_LEFT,\n    tart.events.EventType.SWIPE_RIGHT,\n    tart.events.EventType.SWIPE_UP,\n    tart.events.EventType.SWIPE_DOWN,\n    goog.events.EventType.SCROLL,\n    goog.events.EventType.KEYUP,\n    goog.events.EventType.KEYPRESS,\n    goog.events.EventType.FOCUSIN,\n    goog.events.EventType.FOCUSOUT,\n    goog.events.EventType.TOUCHSTART,\n    goog.events.EventType.TOUCHMOVE,\n    goog.events.EventType.TOUCHEND\n];\n\n\n/**\n * @param {goog.events.BrowserEvent} e Browser event to be executed.\n */\ntart.ui.ComponentManager.prototype.handleEvent = function (e) {\n    var cmps = this.getParentComponents(e.target),\n        broken = false;\n\n    do {\n        if (broken) break;\n\n        if (e.type == tart.events.EventType.MOUSEENTER || e.type == tart.events.EventType.MOUSELEAVE) {\n            if (e.relatedTarget && !goog.dom.contains(e.target, e.relatedTarget)) {\n                broken = this.callHandlers_(cmps, e);\n            }\n        }\n        else {\n            broken = this.callHandlers_(cmps, e);\n        }\n    } while (e.target = e.target.parentNode);\n};\n\n\n/**\n * Given a list of components, checks whether any component would respond to the given event and if so, executes the\n * event handler defined in the component.\n *\n * @private\n *\n * @param {Array.<tart.ui.DlgComponent>} cmps Array of components to look for handlers about the event's target.\n * @param {goog.events.BrowserEvent} e Browser event that will be executed for the target.\n */\ntart.ui.ComponentManager.prototype.callHandlers_ = function(cmps, e) {\n    var broken = false;\n\n    for (var i = 0; i < cmps.length; i++) {\n        var cmp = cmps[i];\n        var handlers = cmp && cmp.events && cmp.events[e.type];\n\n        if (!handlers) continue;\n\n        var selectors = goog.object.getKeys(handlers);\n\n        if (this.callHandler_(cmp, e, handlers, selectors) === false) {\n            broken = true;\n            break;\n        }\n    }\n\n    return broken;\n};\n\n\n/**\n * @private\n *\n * @param cmp\n * @param e\n * @param handlers\n * @param selectors\n * @return {boolean}\n */\ntart.ui.ComponentManager.prototype.callHandler_ = function(cmp, e, handlers, selectors){\n    var rv = true;\n    goog.array.forEach(selectors, function(selector) {\n        // event's target equals to handler's selector\n        if (this.matchesSelector(e.target, selector)) {\n            rv = handlers[selector].call(cmp, e);\n        }\n    }, this);\n    return rv;\n};\n\n\n\n\n/**\n *\n * @param el\n * @param selector\n * @return {*}\n */\ntart.ui.ComponentManager.prototype.matchesSelector = function(el, selector) {\n    return goog.array.indexOf(document.querySelectorAll(selector), el) >= 0;\n};\n\n\n/**\n * Set given component.\n * @param {tart.ui.DlgComponent} cmp Component which will be set to components.\n */\ntart.ui.ComponentManager.prototype.set = function(cmp) {\n    this.components[cmp.getId()] = cmp;\n};\n\n\n/**\n * Removes given component.\n * @param {tart.ui.DlgComponent} cmp Component which will be removed from components.\n */\ntart.ui.ComponentManager.prototype.remove = function(cmp) {\n    delete this.components[cmp.getId()];\n};\n"
  },
  {
    "path": "tart/ui/ComponentModel.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview This class offers a base class for model implementations. It makes no enforcements as how to shape\n * your model, it's just a basic container. Subclasses of this class should accept either a JS object or a value class\n * instance.\n *\n * See tart.ui.Component for details on the model's responsibilities.\n */\n\ngoog.provide('tart.ui.ComponentModel');\ngoog.require('goog.events.EventTarget');\n\n\n\n/**\n * @constructor\n * @extends {goog.events.EventTarget}\n */\ntart.ui.ComponentModel = function() {\n    goog.base(this);\n};\ngoog.inherits(tart.ui.ComponentModel, goog.events.EventTarget);\n\n"
  },
  {
    "path": "tart/ui/DlgComponent.js",
    "content": "// Copyright 2011 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview Delegated Component class offers a component architecture that is an improved version of\n * tart.ui.Component. Like tart.ui.Component, it carries Controller, View and Template in classical MVC role separation.\n *\n * Now, this class is not listening to any of dom events itself. Additionally, it uses ComponentManager\n * which keeps components and controls user interactions of these components.  For this\n * reason templates of all components have to include a unique id attribute.\n */\n\ngoog.provide('tart.ui.DlgComponent');\ngoog.require('tart.ui.ComponentManager');\ngoog.require('goog.events.EventTarget');\ngoog.require('tart');\ngoog.require('tart.dom');\n\n\n/**\n * Base class for all tuttur components.\n * @extends {goog.events.EventTarget}\n * @constructor\n */\ntart.ui.DlgComponent = function() {\n    goog.base(this);\n    this.id = tart.getUid();\n\n    tart.ui.ComponentManager.getInstance().set(this);\n    this.bindModelEvents();\n};\ngoog.inherits(tart.ui.DlgComponent, goog.events.EventTarget);\n\n\n/**\n * Returns the dom element attached with the Component instance.\n * @return {?Element}\n */\ntart.ui.DlgComponent.prototype.getElement = function() {\n    var rv = this.element;\n    if (!rv) rv = this.element = goog.dom.getElement(this.id);\n    return rv;\n};\n\n\n/**\n * Returns base template of component\n * @return {string}\n */\ntart.ui.DlgComponent.prototype.getPlaceholder = function() {\n    return this.templates_base();\n};\n\n\n/**\n * Listens to the model's events. This method should be overriden by the implementer, and should keep the model's event\n * listeners.\n * @protected\n */\ntart.ui.DlgComponent.prototype.bindModelEvents = function() {\n\n};\n\n\n/**\n * Returns children of component's element\n * @param {string} selector Expression which is searching in component element. This is kind of $ for selecting\n * dom element.\n * @return {{length: number}}\n */\ntart.ui.DlgComponent.prototype.getChild = function (selector) {\n    var rv = null, el = this.getElement();\n\n    if (el)\n        rv = el.querySelectorAll(selector);\n\n    if (rv.length == 0)\n        rv = null;\n\n    return rv;\n};\n\n\n/**\n * This method should be called after the DlgComponent is inserted into the document. Any work (rendering child\n * components, updating DOM, etc.) should be done in this method.\n *\n * @param {Element=} opt_base Optional element to render this item into.\n * @param {number=} opt_index Place to render element in base element's children list.\n */\ntart.ui.DlgComponent.prototype.render = function(opt_base, opt_index) {\n    if (opt_base) {\n        this.element = tart.dom.createElement(this.getPlaceholder());\n        opt_base.insertBefore(this.element, opt_base.childNodes[opt_index] || null);\n    }\n};\n\n\n/**\n * Returns the id of this component.\n * @return {string} The id of this component.\n */\ntart.ui.DlgComponent.prototype.getId = function() {\n    return this.id;\n}\n\n\n/**\n * Template of the root element. This method can be overridden if necessary. Other templates should be named with the\n * templates_ prefix as necessary. Also this template carries related component's id.\n * @return {string}\n */\ntart.ui.DlgComponent.prototype.templates_base = function() {\n    return '<div id=\"' + this.id + '\"></div>';\n};\n\n\n/**\n * @override\n */\ntart.ui.DlgComponent.prototype.disposeInternal = function() {\n    tart.ui.ComponentManager.getInstance().remove(this);\n    this.element = null;\n    this.id = null;\n};\n"
  },
  {
    "path": "tart/ui/InfiniteScroll/InfiniteScrollComponent.js",
    "content": "// Copyright 2014 Startup Kitchen. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\ngoog.provide('tart.ui.InfiniteScrollComponent');\ngoog.require('goog.async.Throttle');\ngoog.require('tart.ui.InfiniteScrollComponentModel');\ngoog.require('tart.ui.DlgComponent');\n\n\n\n/**\n * InfiniteScrollComponent is a small component which checks the scroll position of a given DOM element, and if it's in\n * an appropriate position, fires a LOAD event for the parent component to act upon. When the parent component is\n * done loading new items, it should reset this InfiniteScrollComponent with the reset() method.\n *\n * @constructor\n * @extends {tart.ui.DlgComponent}\n *\n * @param {Element=} opt_el Optional element to track its scroll.\n */\ntart.ui.InfiniteScrollComponent = function(opt_el) {\n    this.model = new tart.ui.InfiniteScrollComponentModel();\n    this.model.setParentEventTarget(this);\n    goog.base(this);\n\n    this.EventType = this.model.EventType;\n    this.throttle = new goog.async.Throttle(this.checkShouldLoadMore_, 100, this);\n\n    if (opt_el) this.register(opt_el);\n};\ngoog.inherits(tart.ui.InfiniteScrollComponent, tart.ui.DlgComponent);\n\n\n/**\n * Message to show when no more items are available to load.\n *\n * @type {string}\n */\ntart.ui.InfiniteScrollComponent.prototype.endOfListText = '';\n\n\n/**\n * @override\n */\ntart.ui.InfiniteScrollComponent.prototype.render = function(opt_base, opt_index) {\n    goog.base(this, 'render', opt_base, opt_index);\n\n    if (!this.el) this.register(this.getElement().parentNode);\n};\n\n\n/**\n * Resets the component state to default. This should be used to signal the end of loading so that this component\n * can again check for loading.\n */\ntart.ui.InfiniteScrollComponent.prototype.reset = function() {\n    this.model.reset();\n};\n\n\n/**\n * Registers an element to track its scroll. This can be used for lazily introducing an element to track.\n *\n * @param {Node} el Element to track.\n */\ntart.ui.InfiniteScrollComponent.prototype.register = function(el) {\n    this.reset();\n\n    this.el = el;\n\n    goog.events.unlistenByKey(this.scrollListener);\n    this.scrollListener = goog.events.listen(el, goog.events.EventType.SCROLL, this.onScroll_, false, this);\n};\n\n\n/**\n * Scroll event handler for infinite scroll. Fires the throttle to check for the correct load more position.\n *\n * @private\n */\ntart.ui.InfiniteScrollComponent.prototype.onScroll_ = function() {\n    this.throttle.fire();\n};\n\n\n/**\n * If in an appropriate state, checks if the scroll position is right and if so triggers a load more event.\n *\n * @private\n */\ntart.ui.InfiniteScrollComponent.prototype.checkShouldLoadMore_ = function() {\n    this.model.triggerShouldCheckState();\n    if (!this.model.shouldCheck()) return;\n\n    var el = this.el;\n    if (!el) return;\n\n    if (el.scrollHeight > el.offsetHeight && // the element can actually scroll\n        el.scrollTop > el.scrollHeight - el.offsetHeight - 400) // and we're in a good position to load more\n        this.model.load();\n};\n\n\n/**\n * Shows spinner during load.\n */\ntart.ui.InfiniteScrollComponent.prototype.showSpinner = function() {\n    this.getElement().classList.add('spinner');\n    this.getElement().innerText = '';\n    this.reset();\n};\n\n\n/**\n * Shows end of list message if no more items are available.\n */\ntart.ui.InfiniteScrollComponent.prototype.showEndOfList = function() {\n    this.getElement().innerText = this.endOfListText;\n    this.getElement().classList.remove('spinner');\n};\n\n\n/**\n * @override\n */\ntart.ui.InfiniteScrollComponent.prototype.templates_base = function() {\n    return '<div id=\"' + this.getId() + '\" class=\"inf-scroll\"></div>';\n};\n\n\n/**\n * @override\n */\ntart.ui.InfiniteScrollComponent.prototype.disposeInternal = function() {\n    this.model.dispose();\n    this.throttle.dispose();\n    goog.events.unlistenByKey(this.scrollListener);\n\n    goog.dom.removeNode(this.getElement());\n    goog.base(this, 'disposeInternal');\n};\n"
  },
  {
    "path": "tart/ui/InfiniteScroll/InfiniteScrollComponentModel.js",
    "content": "// Copyright 2014 Startup Kitchen. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\ngoog.provide('tart.ui.InfiniteScrollComponentModel');\ngoog.require('tart.ui.ComponentModel');\n\n\n\n/**\n * Model for the load more component. Manages loading states to prevent\n * performance problems like double actions.\n *\n * @constructor\n * @extends {tart.ui.ComponentModel}\n */\ntart.ui.InfiniteScrollComponentModel = function() {\n    this.reset();\n};\ngoog.inherits(tart.ui.InfiniteScrollComponentModel, tart.ui.ComponentModel);\n\n\n/**\n * Resets the component state to default state.\n */\ntart.ui.InfiniteScrollComponentModel.prototype.reset = function() {\n    this.state_ = this.State.DEFAULT;\n};\n\n\n/**\n * If the component is not in LOADING state, it should check to see if it\n * should load. This method will be triggered on every scroll event.\n */\ntart.ui.InfiniteScrollComponentModel.prototype.triggerShouldCheckState = function() {\n    if (this.state_ != this.State.LOADING)\n        this.state_ = this.State.SHOULD_CHECK;\n};\n\n\n/**\n * Informs the caller if this model is in an appropriate state for checking\n * the right (scroll) position.\n *\n * @return {boolean} Whether the component should check for the right\n *                   (scroll) position.\n */\ntart.ui.InfiniteScrollComponentModel.prototype.shouldCheck = function() {\n    return this.state_ == this.State.SHOULD_CHECK;\n};\n\n\n/**\n * Dispatches a load event to inform the parent component that it's at the end\n * of a scroll and should load more items.\n */\ntart.ui.InfiniteScrollComponentModel.prototype.load = function() {\n    if (!this.shouldCheck()) return;\n\n    this.state_ = this.State.LOADING;\n\n    this.dispatchEvent(this.EventType.SHOULD_LOAD);\n};\n\n\n/**\n * Load more states.\n *\n * @enum {string}\n */\ntart.ui.InfiniteScrollComponentModel.prototype.State = {\n    DEFAULT: 'default',\n    SHOULD_CHECK: 'shouldCheck',\n    LOADING: 'loading'\n};\n\n\n/**\n * Event types for this model.\n *\n * @enum {string}\n */\ntart.ui.InfiniteScrollComponentModel.prototype.EventType = {\n    SHOULD_LOAD: 'load'\n};\n"
  },
  {
    "path": "tart/ui/InfiniteScroll/infinite-scroll.css",
    "content": ".inf-scroll {\n    display: block;\n    height: 140px;\n    width: 100%;\n    color: rgba(0, 0, 0, 0.48);\n    text-shadow: 0px 0px 1px rgba(0, 0, 0, 0.17);\n    line-height: 140px;\n    font-size: 40px;\n    text-align: center;\n}\n\n.inf-scroll.spinner {\n    position: relative;\n    top: 0;\n    left: 0;\n    height: 96px;\n    width: 100%;\n    background: url(data:image/gif;base64,R0lGODlhIAAgAKUAAAQCBISChMTCxERCROTi5KSipGRmZCQmJJSSlNTS1PTy9LSytHR2dDQ2NIyKjMzKzOzq7GxubJyanNza3Pz6/Ly6vBwaHExOTKyqrDQyNHx+fDw+PISGhMTGxOTm5GxqbCwqLJSWlNTW1PT29LS2tHx6fDw6PIyOjMzOzOzu7HRydJyenNze3Pz+/Ly+vBweHFRWVKyurP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQICQAAACwAAAAAIAAgAAAG/kCZcEgkKiIqRXHJbAo7l8vDSRWiIgWiIDodljad6rBgMCSGUOnQlck4xEJCWdMSbgcoIeWSabDgQmQGFXZcQittHIBCRwZJMltqECYZG0pOIgsQRBVlWSgfEWcabRhEIiUuRBwaAQsjQi0lHxh1Qy0ODTC2KQwWFgdEMRrEDh11LB5NBGcUEge/FipFEyfEAQgEYg8b0Q2qSxQCrAGbVSIvwCEUVAoxJIAlKuZitvVNIwQs+vrKiy4LAgYkkQKDhBASDkqIsUhGBgAQI2bAgBBhQoaLHkaEmCEfPxbJGgKMsYAkwSb2qqSkQgHFGTgJULBz0mICiQUkLrW7SYLFhUohHgCWFJBCTAqhC1zQsyKwZ50UOosoKNqCxc2AeYZclRkLoIiULRIktdWyJKEhHhJEnRDwjAcBSmWgCPhniIIE/vDxZOchoDIKexuKXVCXgF8hbBe8hONuLNCS5lpUeBeVitgY9PouyOvh5uIqnbM+3kwEBYmlDWX0xZy6CgUXAmaKCQIAIfkECAkAAAAsAAAAACAAIACFBAIEhIKExMLEREJE5OLkpKakJCYkZGZk1NLU9PL0lJKUVFJUtLa0FBIUNDY0jIqMzMrM7Ors3Nrc/Pr8DA4MTE5MtLK0NDI0fH58nJqcXFpcvL68BAYEhIaExMbEREZE5ObkrKqsLCosbGps1NbU9Pb0VFZUvLq8HBocPD48jI6MzM7M7O7s3N7c/P78nJ6c////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABv5AmHBIJCYCnVJxyWwKV4cDwkkVkjoWIlRKVJkg1aEFg5EMt1Ohp1LJhIURssIlhETTkwOb8BaOMR5Pd0IhFR9ufTAlHUgJMGgwEQsVGo5OBAIsRB5kWQgBASQwCmxZQxIdgUMvGRkeSjATCgEndEMuGRUjtiwdFxcDRBsKrS8kdAQRTQSiEwUDvxcBRS0FrQohylUrCxciFxWqRS4rrC+aVRIOFykFE1QlG+JVDx3oYbb4TRMgEf392voIOMHgBMENCTZYWMhQQCIYH1BInPhBIcOFGx5GnNgAxQd+IEKGvPdGAIOTDDYwsLQkXxWXVCasSBNmxIGATFxIYGBhZZYYEhwAUFDxbgkIixY2kGwiQASApwYYFFnBkEELOixYFkmgaYIKCk8BHCDC08KKoi4UHiPiAkFKWxEOPG1ABAQCrRIWTgEhYIMyqhZaEEFwQKqTEjwZvAOxEESshYofIlgoGAaBxkLyWqAZJgFGW4wtOIbh4sRCrVQAj4YRenXoFX1AMIA9pLUWBjgfssasO+aGDUXDBAEAIfkECAkAAAAsAAAAACAAIACFBAIEhIKExMLETE5M5OLkbGpsJCIkpKak1NLU9PL0XF5cFBIUlJKUdHZ0NDI0tLa0zMrMVFZU7OrsLCos3Nrc/Pr8nJqcDA4MdHJ0tLK0ZGZkHBocfH58BAYEjIqMxMbEVFJU5ObkbG5sJCYkrKqs1NbU9Pb0ZGJklJaUfHp8PD48vL68zM7MXFpc7O7sLC4s3N7c/P78nJ6cHB4c////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABv5AmnBIJJpQFlNxyWwKSxwOxUkVwmQCYimQmg5lIkR1KLBYYEOodMg6aUhjocuCIsWeXK8ppdGE4kJlKGI0JSlrNA99cIA0JjIWMkpqUy4iJxgJVCEImkMISFkUKChoMgUnK0QEKBBEDxkZCBVCMSQyH3dDthoBugkoAwMtRCyxGQ8wdyGeSyFoFRkRwgMMRSErxyvNTiUF1CeuSxUUsA/cTTDCIBm0TiYshGMoDOhOumP4RRUhEv39EhrRgCBghYCCHxJkOxYrS6MIDiK+iKhgIUNVjRQ4mBjRgQJ+IUKGdCEQwooPAj6ctFcLkD4qFeIBStEg4L1yyFgWoTBjw5QIC+6uWVxBsgoEFRuSqsDI5liyOy50lnBlwsKIDQs2YHgVi4W7GNlK6IshosMLdy4aJB1BhBM3CrHEhCgY8AQAACi0NGDKxIQ5WiFi/QlxAcCCooAQxEJDg4BgIQEAABDRKEGsFboCZ/hDo8IMAB1KADK2eYhmzjQySKYcJ8QDFm0fD1Fw4YHAa7JvO6mwYkXQKkEAACH5BAgJAAAALAAAAAAgACAAhQQCBISChMTCxERCROTi5KSipCQmJNTS1GRmZPTy9LSytJSSlDQ2NHx+fIyKjMzKzOzq7KyqrNza3GxubPz6/Ly6vBwaHExOTDQyNJyanDw+PISGhMTGxOTm5KSmpCwqLNTW1GxqbPT29LS2tJSWlDw6PIyOjMzOzOzu7KyurNze3HRydPz+/Ly+vBweHFRSVP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAb+QJhwSCSKUilKcclsClWZjMpJFXZGB6IkQyIQUxtJdXhQKDpDqHQICjRGY2EiNWqxnlwvjGJqBCBxQmUKYjBQXUICDQ0KgUIiIwojShIkawkbDQ4iVB0HCUQqZicwHUhoKYsPRAQeWUORCgdKMCwtCiB3QywVAQu6CQUICCtEJ2YpFSp3KKBMEF68E8MIBUUdt2YtKGMSDdQNr0UsEpEjzp0hCBMVtE0iJ+JVHgXoVbpj+EUUHRD9/YAcnXjAgeCDBwmymTEjwBGMCRciSpyQjQ6dho4gXhggcQU/fyADBhp48IEAhE30UVHphEK8QA4CcHNCzpy9JioYYNDgwR2MEWzIBMykcuAFhqMXOBQ5ZmbEMhjNmkggRcGDhqMYAhCJdYKWLVz6WDRwMYAWig06Nfz8pMVMlhFHW8BYYcFCBi0bML4zpyQCAACNOhiw8GFonEFTYPgFLGRB3QaO5iiwI2RxIxgiGFhwUWhMmRQiLcN6HOgKqSEp/l4WEsKAXIdfVMOuAuEDA8NUggAAIfkECAkAAAAsAAAAACAAIACFBAIEhIKExMLEREJE5OLkpKKkZGJkJCYklJKU1NLU9PL0VFJUtLK0FBIUdHJ0jIqMzMrMTEpM7OrsNDY0nJqc3Nrc/Pr8DA4MrKqsbGpsXFpcvL68BAYEhIaExMbEREZE5ObkpKakZGZkNDI0lJaU1NbU9Pb0VFZUtLa0HBocfH58jI6MzM7MTE5M7O7sPD48nJ6c3N7c/P78////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABv7AmXBIJFo2AktxyWwKQQwGyEl9ohJEqJS4gRGqw0R0+hwPYxSKACxURDey8nYmC6VdbCErGhMSzDMsFCQeeUIWKAwoSlpTJjAUBSZUIAkKRDFRLDMSGxt4G4MlRBIMFUSJDAlKdBsMJXFDMh4UGLEmDCoqHUR7USgxcS6XTC4SdB4dugEYRSCub3hVBAgqASoIp0sWFYkoxJTXAR6sTSYsWGxR4FWxYO5FFiAS8/PHhiUJ6OgJJtBRUdYYCiCioAgDIgL8A7jB0IwOCBEW7CAPhEWL0vLk45fAUhN4VEA6sYAuDwkE7JbI6KYoJRMCC1qcYFAuy79PYEqIaBEhgo6ITb0AAovjQduSGFgsMDjBswUCVJpYWTjAwQE8GQ9eLIilAAFPDVk8DlkBAICIGQIGfCikYsSIZmdIQKAi4QKAC8cYpEjRUMKLES9cUhFRdoUQFCkaNJwBw+0DQwnKHmCll++hFiMm9GFDGACDIYgtC9ngOA+DCwaI6FVMRMULgQ5B710c24mEDx8yVgkCACH5BAgJAAAALAAAAAAgACAAhQQCBISChMTCxExOTOTi5KSipGxqbCQiJNTS1PTy9FxeXLSytBQSFJSWlHR2dDQyNAwKDMzKzFRWVOzq7Nza3Pz6/Ly6vIyKjKyqrHRydCwqLGRmZJyenAQGBMTGxFRSVOTm5KSmpGxubCQmJNTW1PT29GRiZLS2tBwaHJyanHx+fDw+PAwODMzOzFxaXOzu7Nze3Pz+/Ly+vIyOjP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAb+QJpwSCRWZIJKcclsCkGLBchJfZ4QRKiU2DpNqkNEdPocDydRLJiWiMpi5S0tZokm1sJWFCYkmGkUUS14QhUnCydKWlMlh4lUIAh3QzCCNBMyMi80egt8Qy8CBESHCwhKczILJHBDMWJvhQINKRxcUYgwcC+TSwmbrxwptDJFIKpum1UTGLQNGKNLFRSOvU4TKbUIrU0lLWpgHjIleNxV5kYgE+rqX4QwJBQk8SRHuLgChDQNKioB/SpSILtXjFAKgP4CVgDBsKEyPDDkSSRBjgk6JxebgDCRAU+IAtakXYAAoAMFMCAMbBBhAVWRBQcAyNTgAQwMFSY2bFABToiOApkAWDRQEuHTEgInK1jIkHNDASIkAYhwV2HFARXmYqQYYKBVggI6Ow7BIKJnAxQoHNDw4MLFoBkDBiwgQiBEzyUvRqAYsUnGgwf5XnwY4CJkFQdoUwjx+6AghriK8ZBAuwIV44IVTMSNBgYxihNDGOcT4gEynhMjxC7+W1DIDAkR9BURLbvKCxcKHlYJAgAh+QQICQAAACwAAAAAIAAgAIUEAgSEgoTEwsREQkTk4uSkpqQkIiRkZmTU0tT08vQ0MjS0trSUkpR8enzMyszs6uysrqwsKixsbmzc2tz8+vw8OjycmpwcGhxMTky8vryEhoTExsTk5uSsqqwkJiRsamzU1tT09vQ0NjS8uryUlpR8fnzMzszs7uy0srQsLix0cnTc3tz8/vw8PjycnpwcHhxUUlT///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG/sCYcEgkUjICSnHJbAo5KBTHSX0uEESolGhaPKpDRHT6REG+ZRQWHEtAFhlWmswaRRNsoRg1mQsnZiB5QiELKAtKWlMUhohUHAh4QytRJjEPGRknMSZRK0QJCGRChmpKMSwZKCByQyxicUIUnYdcURAjK3InkksJmywrpRBrQxyqUZpgJ8goGaNELBONvU4JUQsTrU0hJsVVCCanYNtV5UQnpVHOgzEcBCvwBAQhEQD3+CLtEBYWJP4WIKTAl28fwH4kzphZyG6QvBXxVowrcs5JxSYPVJTIY6jaEgokPFx48anKgwAlNGy4OELEhZctLFUhwKBEiQAM+hCR8PKCiQcXShCUXPIuBoUNGmyWQEFE5IUGm4xiqMCgHIsOH0q0unZTA5EFDQQNKaBAgVcTEiRgcXHgQAYiD1ZROdFCQYtNAjBgcBDjxIcDKjxW0VC2gJANevnGWNC2w6AJIhRgOJV3r6wGbaFRIaxgw5DKijk1zpOhRQAioIlY+PCtXQzEA2S6tiYhcJ4gACH5BAgJAAAALAAAAAAgACAAhQQCBISChMTCxERCROTi5KSipCQmJGRiZJSSlNTS1PTy9LSytBQSFDQ2NHRydFRSVAwKDIyKjMzKzOzq7GxqbJyanNza3Pz6/Ly6vKyqrDQyNDw+PFxaXAQGBISGhMTGxExOTOTm5CwqLGRmZJSWlNTW1PT29LS2tBwaHDw6PHx+fFRWVAwODIyOjMzOzOzu7GxubJyenNze3Pz+/Ly+vKyurP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAb+QJtwSCReaIJLcclsCkOLRchJfZ4SRKiU6DpNqsNEdPpc1L7lBRZsU9ROtFmaPMNEFWyheGGZCy1mJXlCJicLJ0paUxeGiFQLFIJDgAsuNhM0NC82LlEyRAoJZEIQAAAwmzYzNFdyQzNicUIXnYdEHKYADCRKL3hMCpszMoZma0M1BrkiH2AvNFELNKNEJhGlHZJUClEnFq5NIQcOeQkuSmzgVepELxjvJ+8Cg5chE/b2FwMo/P0g9NCimRGwjwE/g/8GBXxzSBOGE3AgNht0r2K+JuycZGzyIkCEPAIEmKByIUYKDSkIOKtAIkaCjQJAaJi54piTEBkq6MzwiYiOipkaNmSQU4IakXuqXMQgoZMGkZMNPPy6MOJBDHUzTgTgNUsA0xhEaHjoKWQBCBAIbJQIEKBPDRUqJLQTQJbJixUgHuBxMeIAFgUBVEQYOYjE2QVCJIwYsUYA3BODZDwAccCViwOMZ7UIjAaMYRByhfD1O6TE4zwfHqQdojjzkAwe+tDjQoH07G1sCYMJAgAh+QQICQAAACwAAAAAIAAgAIUEAgSMjozMysxEQkSsrqzk5uRkYmQkJiScnpzc2ty8vrz09vR0cnQUEhRUUlTU0tS0trTs7uxsamw0MjSkpqRcWlwMDgyUlpTk4uTExsT8/vx8enwcGhwEBgTMzsxMTky0srTs6uxkZmQsKiykoqTc3tzEwsT8+vxUVlTU1tS8urz08vRsbmw8OjysqqxcXlycmpx8fnwcHhz///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG/sCZcEgknhSmU3HJbAoLIFDBSRWCLAYiVEr0QELVoQgAgAy3U2Eo+ggLH+SDcgYlgGcaFQGycgvHAAFPUWkJUR5+ahYAFmBoMwsQIBBzTSobKUQBZCIzIQoKETMeUSVEKw9pQgccHBuiMycHHQwaRBoPIAq2saSTRBKtHAckShkJTSuiGiWSIARtRBAtwgOIVREKUbqqRAsXBw0yyFUrURAJvE0hLDF+KR6VVerzySZI9yYCiZ4FIf7+TqCYQLDgC34mtkUhYGJgQYIHE2nbs0dXhHugMii45uefx4BN6FER6SRCABh+HsSjcoKAgw8OuiU7V4LkDAEiPuiUQI7KladtCu4MCaDzQwUQSkoILRJhCjNnIDjOePnhQp9YMSS4oKchA4ytQk6QIqCCiIALGIioEGGAxIwEFy6YMnEBRqYhKzwsXbKChQgWfVLEiIFsBQIYCOSFISFCRNkZggkL8QADRoZEGBpv4BWZ3AkKdWEtbhzt7QbJQkpUvuzGAwu3Qx4M7jlDAYK0/Ih0zl1lQeUFfoIAACH5BAgJAAAALAAAAAAgACAAhQQCBISChMTCxERCROTi5KSipGRmZCQmJNTS1PTy9LSytJSSlHR2dDQ2NIyKjMzKzOzq7KyqrGxubNza3Pz6/Ly6vBwaHExOTCwuLJyanHx+fDw+PISGhMTGxOTm5KSmpGxqbNTW1PT29LS2tHx6fDw6PIyOjMzOzOzu7KyurHRydNze3Pz+/Ly+vBweHFRWVDQyNJyenP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAb+QJlwSCRCYA1UcclsClMAgMJJFY4OKmIkOh2eRpDqkGGxtIZb6dCjUCDEwlC5RBGmu6xKOwEXki0ZQh9cQhMpIyd9QhAHFgdKdzIiIwojdU4CHCtEGWUMMiMYGGcnbZtDCQgeRCVIDkoyFCUuASxELAgjLbaxpZVEGjDCGxG2J6dLCUosK5RtiUQtF8IwL29VKC1tCi2rSxQxG0jITgltIxO8TSgaJn0IJ5di6lX0RAkPHfn5130QHv8CUgBxoaDBLIoEbGuTQgBBgwUR9tF26BA3fPoEPBDQD05AgADlFbHnhGSTBDEivItHhcIICQZAeKOSgNKIFSYRkDDAMwCJuSYQtLVpEYZIDJ4GVFSwRaBosmXNtkETAoJnBD6xTHBYegsBN14USqWoQOTEBwJEOgTQMIVAihSrfJFLNZOJCA4aOPBZkSHDJpeVRIpRoCGAACF8F6CVMaFNxyoQNGhYcImvXyF5DmEdLHnCEMvIPFB67CQEhy6F+pL74lTRZ9WuxYiIkEJEnyAAIfkECAkAAAAsAAAAACAAIACFBAIEhIKExMLEREJE5OLkpKakZGJkJCIklJKU1NLUVFJU9PL0tLa0NDI0FBIUfH58jIqMzMrMTEpM7OrsrK6sbGpsnJqc3NrcXFpc/Pr8PDo8DA4MvL68BAYEhIaExMbEREZE5ObkrKqsZGZkLC4slJaU1NbUVFZU9Pb0vLq8NDY0HBocjI6MzM7MTE5M7O7stLK0bG5snJ6c3N7cXF5c/P78PD48////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABv7Am3BIJL5AkldxyWwKGatVykkVCmwBIiw6HdI2jOow0GgIhgzHijOkAAAxsfCiIikyzyj7hjq8TXJCHmUFQltSgm9xgTcvNg02SlCIIRsAG0pOESUERAVlHjccAzYfNwZvJUQLCSFECi4uFgtCKAoqCDVENTEdJHg3GS0wMGFDLBLJGAx4LZ1MJhE3NTMMxBQJRREjLhIuFYBVLxzEMByuSxkiJxIKz1QLxAwXuk4vLDKBLQkogfVi/4qw2kfwAqMbE0IkXJjhwYiHECEcJFcOBgUBASA+NCCREUUK1hhwYJWgZIIWBhktVKgQ2JKAVGA6WUChi5iTLplk+ODhQZiATPDkzZB5wwSCB0gRvLNH0dyEIhSQBvAQQdcEoAKVULNGAUa2IR4CPIDRL5gICx8C1kggsp6wkERMwHg6JEEJC2cmcBDwdBiMGataUUEhw4KMfiGIucogL6cYARZKfE0MA90FYl/lvIgsol5iCnRrpABJS46Au4CFUEZ3I4S1zFVmyDgzZDWRFgzoHqxtUffuJhn2OnYSBAAh+QQICQAAACwAAAAAIAAgAIUEAgSMjozMysxEQkS0srTk5uRkYmQkJiScnpz09vR0cnQUEhTU1tRUUlS8vryUlpTs7uxsamw0MjSkpqRcWlwMDgzU0tS8urz8/vx8enwcGhzc3tzExsQEBgSUkpTMzsxMTky0trTs6uxkZmQsKiykoqT8+vzc2txUVlTEwsScmpz08vRsbmw8OjysqqxcXlx8fnwcHhz///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG/kCZcEgkrlCvVXHJbAodEknKSRVyUB4iVEpkHRzV4QMEEgy3YGFIo8mEhZsGyIARXqJTmanFZryFHmQEdlFpD2wwf0IrcihKaDIiBwskEFQWEwVEBGRZVygfMixsCEQWESFEESMjLkp6Bg0IdUMmMDEDJkIiIx0AC0QIIwYjCg51DJpMJ6EmAQsA0QZFFhnDIzAbYRwk0QAHg0smISwjEcqXvhUBuk4rJS5/qyJ/tGH2RQknDPv82ooiCgQcaMIDjIMIVSiSkYKAw4cOHiBMuNDBQ4j6TmjU+O9PwAIgQeIjMtJJySYJUnD4Y+FDuyYYPiBQoeIVlRUOQ2w4ucEFic0HLtA5gWDRoQN6WlQ8UIHAQh0INoussIRhQ4iHoYbMVJEigRAMFhngw2AhxDEhJj7kJLIhhaUhJxxakFEgxVEZagl0lLHiA9Im4wiE0FXAoSYTOV++yXtCSGECyuISmPsHJ4GzdA1/veAw6iXNjkFnnvynQIisoSET+RDi78LUQl8zMeGg658gADs=) no-repeat center;\n}\n"
  },
  {
    "path": "tart/ui/NavBar/NavBarComponent.js",
    "content": "// Copyright 2014 Startup Kitchen. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\ngoog.provide('tart.ui.NavBarComponent');\ngoog.require('tart.ui.DlgComponent');\n\n\n\n/**\n * Includes back button for back navigation.\n *\n * @constructor\n * @extends {tart.ui.DlgComponent}\n *\n * @param {tart.ui.NavBarComponent.NavBarOptions=} opt_config Config parameters to\n *        include things like title.\n */\ntart.ui.NavBarComponent = function(opt_config) {\n    goog.base(this);\n\n    this.config = opt_config || {};\n\n    this.hasBackButton = this.config.hasBackButton || this.hasBackButton;\n    this.hasMenuButton = this.config.hasMenuButton || this.hasMenuButton;\n};\ngoog.inherits(tart.ui.NavBarComponent, tart.ui.DlgComponent);\n\n\n/**\n* @typedef {{hasBackButton: (boolean|undefined), hasMenuButton: (boolean|undefined), title: string}}\n*/\ntart.ui.NavBarComponent.NavBarOptions;\n\n\n/**\n * Defines whether the back button is visible.\n * @type {boolean}\n */\ntart.ui.NavBarComponent.prototype.hasBackButton = false;\n\n\n/**\n * @override\n */\ntart.ui.NavBarComponent.prototype.templates_base = function() {\n    var backButton = '',\n        menuButton = '';\n\n    if (this.hasBackButton) backButton = '<back-button style=\"display: block\"><i class=\"icon-back\"></i></back-button>';\n    if (this.hasMenuButton) menuButton = '<menu-button><i class=\"icon-navigation\"></i></menu-button>';\n\n    return '<nav-bar id=\"' + this.getId() + '\">' +\n            backButton +\n            menuButton +\n            (this.config.title || '') +\n        '</nav-bar>';\n};\n\n\n/**\n * Back button tap event handler.\n */\ntart.ui.NavBarComponent.prototype.onBackButtonTap = function() {\n    this.vm.push();\n};\n\n\n/**\n * Menu button tap event handler. Delegates event handling to subclasses via menuButtonHandler method.\n * @return {undefined} Returns executing menuButtonHandler if available.\n */\ntart.ui.NavBarComponent.prototype.onMenuButtonTap = function() {\n    if (this.menuButtonHandler) return this.menuButtonHandler();\n\n    this.vm.toggleSidebar();\n};\n\n\n/**\n * @enum {string} Dom mapping.\n */\ntart.ui.NavBarComponent.prototype.mappings = {\n    BACK_BUTTON: 'back-button',\n    MENU_BUTTON: 'menu-button'\n};\n\n\n(function() {\n    this.events = {};\n    var tap = this.events[tart.events.EventType.TAP] = {};\n\n    tap[this.mappings.BACK_BUTTON] = this.onBackButtonTap;\n    tap[this.mappings.MENU_BUTTON] = this.onMenuButtonTap;\n}).call(tart.ui.NavBarComponent.prototype);\n"
  },
  {
    "path": "tart/ui/NavBar/nav-bar.css",
    "content": "nav-bar, back-button, logo, share {\n    display: block;\n    position: absolute;\n}\n\nnav-bar {\n    height: 90px;\n    width: 100%;\n    left: 0;\n    top: 0;\n    z-index: 9999;\n    background: rgba(0,0,0,0.8);\n    -webkit-transform: translate3d(0,0,99999px)\n}\n\nlogo {\n    left: 50%;\n    margin-left: -39px;\n    height: 100px;\n    font-size: 78px;\n    padding-top: 3px;\n    display: block;\n    position: absolute;\n    text-shadow: 0 0 5px rgba(0, 0, 0, 0.14);\n}\n\nmenu-button {\n    right: 0px;\n    height: 90px;\n    font-size: 50px;\n    padding-top: 5px;\n    display: block;\n    position: absolute;\n    text-shadow: 0 0 5px rgba(0,0,0,.14);\n    width:100px;\n}\n\nback-button {\n    height: 90px;\n    width: 110px;\n    font-size: 36px;\n    padding: 3px 36px;\n    text-align: left;\n    display: none;\n}\n"
  },
  {
    "path": "tart/ui/PullToRefresh/P2RComponent.js",
    "content": "// Copyright 2014 Startup Kitchen. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\ngoog.provide('tart.ui.P2RComponent');\ngoog.require('goog.async.Throttle');\ngoog.require('tart.ui.P2RComponentModel');\ngoog.require('tart.ui.DlgComponent');\n\n\n\n/**\n * P2RComponent is a small component which checks the scroll position of a given DOM element, and if it's in\n * an appropriate position, fires a REFRESH event for the parent component to act upon. When the parent component is\n * done with refreshing, it should reset this P2RComponent with the reset() method.\n *\n * @constructor\n * @extends {tart.ui.DlgComponent}\n *\n * @param {Element=} opt_el Optional element to track its scroll.\n */\ntart.ui.P2RComponent = function(opt_el) {\n    this.model = new tart.ui.P2RComponentModel();\n    this.model.setParentEventTarget(this);\n    goog.base(this);\n\n    this.EventType = this.model.EventType;\n\n    if (opt_el) this.register(opt_el);\n};\ngoog.inherits(tart.ui.P2RComponent, tart.ui.DlgComponent);\n\n\n/**\n * Threshold value for the release action. Releases after this threshold will trigger a refresh.\n *\n * @type {number}\n */\ntart.ui.P2RComponent.prototype.threshold = 135;\n\n\n/**\n * Height of this component. This setting is used to offset the scroll view while refreshing.\n *\n * @type {number}\n */\ntart.ui.P2RComponent.prototype.height = 96;\n\n\n/**\n * Start position of the arrow. This is adjusted for a spring-like effect.\n *\n * @type {number}\n */\ntart.ui.P2RComponent.prototype.arrowOffset = -40;\n\n\n/**\n * @override\n */\ntart.ui.P2RComponent.prototype.bindModelEvents = function() {\n    goog.events.listen(this.model, this.model.EventType.SHOULD_REFRESH, this.onShouldRefresh,\n        false, this);\n};\n\n\n/**\n * Triggered when the components decides a refresh action. This method should be overridden\n * to, for example, display a spinner animation during refresh.\n */\ntart.ui.P2RComponent.prototype.onShouldRefresh = function() {\n    this.el.style.webkitTransform = 'translateY(' + this.height + 'px)';\n    this.el.style.webkitTransition = '300ms ease-out';\n\n    this.getChild(this.mappings.SPINNER)[0].style.visibility = 'visible';\n    this.getChild(this.mappings.ARROW)[0].style.visibility = 'hidden';\n};\n\n\n/**\n * @override\n */\ntart.ui.P2RComponent.prototype.render = function(opt_base, opt_index) {\n    goog.base(this, 'render', opt_base, opt_index);\n\n    this.rendered = true;\n\n    if (!this.el) this.register(this.getElement().parentNode);\n};\n\n\n/**\n * Resets the component state to default. This should be used to signal the end of refreshing so that this component\n * can again check for pull to refresh.\n */\ntart.ui.P2RComponent.prototype.reset = function() {\n    if (this.el) this.el.style.webkitTransform = 'translateY(0)';\n\n    var spinner = this.getChild(this.mappings.SPINNER);\n    var arrow = this.getChild(this.mappings.ARROW);\n\n    if (spinner) spinner[0].style.visibility = 'hidden';\n\n    setTimeout(function() {\n        if (arrow) arrow[0].style.visibility = 'visible';\n    }, 500);\n\n    this.model.reset();\n};\n\n\n/**\n * Registers an element to track its scroll. This can be used for lazily introducing an element to track.\n *\n * @param {Node} el Element to track.\n */\ntart.ui.P2RComponent.prototype.register = function(el) {\n    this.reset();\n\n    this.el = el;\n\n    goog.events.unlistenByKey(this.scrollListener);\n    goog.events.unlistenByKey(this.releaseListener);\n\n    this.scrollListener = goog.events.listen(el, goog.events.EventType.SCROLL, this.onScroll, false, this);\n    this.releaseListener = goog.events.listen(document.body, goog.events.EventType.TOUCHEND,\n        this.onRelease_, false, this);\n};\n\n\n/**\n * Scroll event handler for pull to refresh.\n *\n * @param {goog.events.BrowserEvent} e Scroll event object.\n */\ntart.ui.P2RComponent.prototype.onScroll = function(e) {\n    this.checkShouldRefresh(e);\n\n    var rot = 0,\n        scroll = -e.target.scrollTop,\n        pos = this.arrowOffset + Math.pow(scroll, 0.75),\n        rotationThreshold = this.threshold - 60;\n\n    if (scroll >= rotationThreshold)\n        rot = Math.min(180, (scroll - rotationThreshold) * 3);\n\n    this.getChild(this.mappings.ARROW)[0].style.webkitTransform = 'translateY(' + pos + 'px) rotate(' + rot + 'deg)';\n};\n\n\n/**\n * Fires when the user lifts her finger to finish the scroll.\n * If the user scrolled enough, inform the model to refresh\n *\n * @private\n */\ntart.ui.P2RComponent.prototype.onRelease_ = function() {\n    if (this.el.scrollTop < -this.threshold)\n        this.model.refresh();\n};\n\n\n/**\n * If in an appropriate state, checks if the scroll position is right and if so triggers a refresh event.\n *\n * @param {goog.events.BrowserEvent} e Scroll event object.\n */\ntart.ui.P2RComponent.prototype.checkShouldRefresh = function(e) {\n    this.model.triggerShouldCheckState();\n};\n\n\n/**\n * @override\n */\ntart.ui.P2RComponent.prototype.templates_base = function() {\n    return '<div id=\"' + this.getId() + '\" class=\"pull-to-refresh\">' +\n            '<div class=\"pull-to-refresh-arrow\"></div>' +\n            '<div class=\"pull-to-refresh-spinner\"></div>' +\n        '</div>';\n};\n\n\n/**\n * @override\n */\ntart.ui.P2RComponent.prototype.disposeInternal = function() {\n    this.model.dispose();\n    goog.events.unlistenByKey(this.scrollListener);\n\n    goog.dom.removeNode(this.getElement());\n    goog.base(this, 'disposeInternal');\n};\n\n\n/**\n * @enum {string}\n */\ntart.ui.P2RComponent.prototype.mappings = {\n    ARROW: '.pull-to-refresh-arrow',\n    SPINNER: '.pull-to-refresh-spinner'\n};\n"
  },
  {
    "path": "tart/ui/PullToRefresh/P2RComponentModel.js",
    "content": "// Copyright 2014 Startup Kitchen. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\ngoog.provide('tart.ui.P2RComponentModel');\ngoog.require('tart.ui.ComponentModel');\n\n\n\n/**\n * Model for the pull to refresh component. Manages refreshing states to prevent\n * performance problems like double actions.\n *\n * @constructor\n * @extends {tart.ui.ComponentModel}\n */\ntart.ui.P2RComponentModel = function() {\n    this.reset();\n};\ngoog.inherits(tart.ui.P2RComponentModel, tart.ui.ComponentModel);\n\n\n/**\n * Resets the component state to default state.\n */\ntart.ui.P2RComponentModel.prototype.reset = function() {\n    this.state_ = this.State.DEFAULT;\n};\n\n\n/**\n * If the component is not in REFRESHING state, it should check to see if it\n * should refresh. This method will be triggered on every scroll event.\n */\ntart.ui.P2RComponentModel.prototype.triggerShouldCheckState = function() {\n    if (this.state_ != this.State.REFRESHING)\n        this.state_ = this.State.SHOULD_CHECK;\n};\n\n\n/**\n * Informs the caller if this model is in an appropriate state for checking\n * the right (scroll) position.\n *\n * @return {boolean} Whether the component should check for the right\n *                   (scroll) position.\n */\ntart.ui.P2RComponentModel.prototype.shouldCheck = function() {\n    return this.state_ == this.State.SHOULD_CHECK;\n};\n\n\n/**\n * Dispatches a refresh event to inform the parent component that it's at the appropriate\n * position for refresh.\n */\ntart.ui.P2RComponentModel.prototype.refresh = function() {\n    if (!this.shouldCheck()) return;\n\n    this.state_ = this.State.REFRESHING;\n\n    this.dispatchEvent(this.EventType.SHOULD_REFRESH);\n};\n\n\n/**\n * Pull to refresh states.\n *\n * @enum {string}\n */\ntart.ui.P2RComponentModel.prototype.State = {\n    DEFAULT: 'default',\n    SHOULD_CHECK: 'shouldCheck',\n    REFRESHING: 'refreshing'\n};\n\n\n/**\n * Event types for this model.\n *\n * @enum {string}\n */\ntart.ui.P2RComponentModel.prototype.EventType = {\n    SHOULD_REFRESH: 'refresh'\n};\n"
  },
  {
    "path": "tart/ui/PullToRefresh/pull-to-refresh.css",
    "content": ".pull-to-refresh {\n    position: absolute;\n    top: 0px;\n    display: block;\n    height: 140px;\n    width: 100%;\n    font-size: 30px;\n    color: #50B075;\n    -webkit-transform-origin: 50% 100%;\n    text-align: center;\n}\n\n.pull-to-refresh-spinner {\n    position: absolute;\n    top: 0;\n    left: 0;\n    height: 96px;\n    width: 100%;\n    background: url(data:image/gif;base64,R0lGODlhIAAgAKUAAAQCBISChMTCxERCROTi5KSipGRmZCQmJJSSlNTS1PTy9LSytHR2dDQ2NIyKjMzKzOzq7GxubJyanNza3Pz6/Ly6vBwaHExOTKyqrDQyNHx+fDw+PISGhMTGxOTm5GxqbCwqLJSWlNTW1PT29LS2tHx6fDw6PIyOjMzOzOzu7HRydJyenNze3Pz+/Ly+vBweHFRWVKyurP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQICQAAACwAAAAAIAAgAAAG/kCZcEgkKiIqRXHJbAo7l8vDSRWiIgWiIDodljad6rBgMCSGUOnQlck4xEJCWdMSbgcoIeWSabDgQmQGFXZcQittHIBCRwZJMltqECYZG0pOIgsQRBVlWSgfEWcabRhEIiUuRBwaAQsjQi0lHxh1Qy0ODTC2KQwWFgdEMRrEDh11LB5NBGcUEge/FipFEyfEAQgEYg8b0Q2qSxQCrAGbVSIvwCEUVAoxJIAlKuZitvVNIwQs+vrKiy4LAgYkkQKDhBASDkqIsUhGBgAQI2bAgBBhQoaLHkaEmCEfPxbJGgKMsYAkwSb2qqSkQgHFGTgJULBz0mICiQUkLrW7SYLFhUohHgCWFJBCTAqhC1zQsyKwZ50UOosoKNqCxc2AeYZclRkLoIiULRIktdWyJKEhHhJEnRDwjAcBSmWgCPhniIIE/vDxZOchoDIKexuKXVCXgF8hbBe8hONuLNCS5lpUeBeVitgY9PouyOvh5uIqnbM+3kwEBYmlDWX0xZy6CgUXAmaKCQIAIfkECAkAAAAsAAAAACAAIACFBAIEhIKExMLEREJE5OLkpKakJCYkZGZk1NLU9PL0lJKUVFJUtLa0FBIUNDY0jIqMzMrM7Ors3Nrc/Pr8DA4MTE5MtLK0NDI0fH58nJqcXFpcvL68BAYEhIaExMbEREZE5ObkrKqsLCosbGps1NbU9Pb0VFZUvLq8HBocPD48jI6MzM7M7O7s3N7c/P78nJ6c////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABv5AmHBIJCYCnVJxyWwKV4cDwkkVkjoWIlRKVJkg1aEFg5EMt1Ohp1LJhIURssIlhETTkwOb8BaOMR5Pd0IhFR9ufTAlHUgJMGgwEQsVGo5OBAIsRB5kWQgBASQwCmxZQxIdgUMvGRkeSjATCgEndEMuGRUjtiwdFxcDRBsKrS8kdAQRTQSiEwUDvxcBRS0FrQohylUrCxciFxWqRS4rrC+aVRIOFykFE1QlG+JVDx3oYbb4TRMgEf392voIOMHgBMENCTZYWMhQQCIYH1BInPhBIcOFGx5GnNgAxQd+IEKGvPdGAIOTDDYwsLQkXxWXVCasSBNmxIGATFxIYGBhZZYYEhwAUFDxbgkIixY2kGwiQASApwYYFFnBkEELOixYFkmgaYIKCk8BHCDC08KKoi4UHiPiAkFKWxEOPG1ABAQCrRIWTgEhYIMyqhZaEEFwQKqTEjwZvAOxEESshYofIlgoGAaBxkLyWqAZJgFGW4wtOIbh4sRCrVQAj4YRenXoFX1AMIA9pLUWBjgfssasO+aGDUXDBAEAIfkECAkAAAAsAAAAACAAIACFBAIEhIKExMLETE5M5OLkbGpsJCIkpKak1NLU9PL0XF5cFBIUlJKUdHZ0NDI0tLa0zMrMVFZU7OrsLCos3Nrc/Pr8nJqcDA4MdHJ0tLK0ZGZkHBocfH58BAYEjIqMxMbEVFJU5ObkbG5sJCYkrKqs1NbU9Pb0ZGJklJaUfHp8PD48vL68zM7MXFpc7O7sLC4s3N7c/P78nJ6cHB4c////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABv5AmnBIJJpQFlNxyWwKSxwOxUkVwmQCYimQmg5lIkR1KLBYYEOodMg6aUhjocuCIsWeXK8ppdGE4kJlKGI0JSlrNA99cIA0JjIWMkpqUy4iJxgJVCEImkMISFkUKChoMgUnK0QEKBBEDxkZCBVCMSQyH3dDthoBugkoAwMtRCyxGQ8wdyGeSyFoFRkRwgMMRSErxyvNTiUF1CeuSxUUsA/cTTDCIBm0TiYshGMoDOhOumP4RRUhEv39EhrRgCBghYCCHxJkOxYrS6MIDiK+iKhgIUNVjRQ4mBjRgQJ+IUKGdCEQwooPAj6ctFcLkD4qFeIBStEg4L1yyFgWoTBjw5QIC+6uWVxBsgoEFRuSqsDI5liyOy50lnBlwsKIDQs2YHgVi4W7GNlK6IshosMLdy4aJB1BhBM3CrHEhCgY8AQAACi0NGDKxIQ5WiFi/QlxAcCCooAQxEJDg4BgIQEAABDRKEGsFboCZ/hDo8IMAB1KADK2eYhmzjQySKYcJ8QDFm0fD1Fw4YHAa7JvO6mwYkXQKkEAACH5BAgJAAAALAAAAAAgACAAhQQCBISChMTCxERCROTi5KSipCQmJNTS1GRmZPTy9LSytJSSlDQ2NHx+fIyKjMzKzOzq7KyqrNza3GxubPz6/Ly6vBwaHExOTDQyNJyanDw+PISGhMTGxOTm5KSmpCwqLNTW1GxqbPT29LS2tJSWlDw6PIyOjMzOzOzu7KyurNze3HRydPz+/Ly+vBweHFRSVP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAb+QJhwSCSKUilKcclsClWZjMpJFXZGB6IkQyIQUxtJdXhQKDpDqHQICjRGY2EiNWqxnlwvjGJqBCBxQmUKYjBQXUICDQ0KgUIiIwojShIkawkbDQ4iVB0HCUQqZicwHUhoKYsPRAQeWUORCgdKMCwtCiB3QywVAQu6CQUICCtEJ2YpFSp3KKBMEF68E8MIBUUdt2YtKGMSDdQNr0UsEpEjzp0hCBMVtE0iJ+JVHgXoVbpj+EUUHRD9/YAcnXjAgeCDBwmymTEjwBGMCRciSpyQjQ6dho4gXhggcQU/fyADBhp48IEAhE30UVHphEK8QA4CcHNCzpy9JioYYNDgwR2MEWzIBMykcuAFhqMXOBQ5ZmbEMhjNmkggRcGDhqMYAhCJdYKWLVz6WDRwMYAWig06Nfz8pMVMlhFHW8BYYcFCBi0bML4zpyQCAACNOhiw8GFonEFTYPgFLGRB3QaO5iiwI2RxIxgiGFhwUWhMmRQiLcN6HOgKqSEp/l4WEsKAXIdfVMOuAuEDA8NUggAAIfkECAkAAAAsAAAAACAAIACFBAIEhIKExMLEREJE5OLkpKKkZGJkJCYklJKU1NLU9PL0VFJUtLK0FBIUdHJ0jIqMzMrMTEpM7OrsNDY0nJqc3Nrc/Pr8DA4MrKqsbGpsXFpcvL68BAYEhIaExMbEREZE5ObkpKakZGZkNDI0lJaU1NbU9Pb0VFZUtLa0HBocfH58jI6MzM7MTE5M7O7sPD48nJ6c3N7c/P78////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABv7AmXBIJFo2AktxyWwKQQwGyEl9ohJEqJS4gRGqw0R0+hwPYxSKACxURDey8nYmC6VdbCErGhMSzDMsFCQeeUIWKAwoSlpTJjAUBSZUIAkKRDFRLDMSGxt4G4MlRBIMFUSJDAlKdBsMJXFDMh4UGLEmDCoqHUR7USgxcS6XTC4SdB4dugEYRSCub3hVBAgqASoIp0sWFYkoxJTXAR6sTSYsWGxR4FWxYO5FFiAS8/PHhiUJ6OgJJtBRUdYYCiCioAgDIgL8A7jB0IwOCBEW7CAPhEWL0vLk45fAUhN4VEA6sYAuDwkE7JbI6KYoJRMCC1qcYFAuy79PYEqIaBEhgo6ITb0AAovjQduSGFgsMDjBswUCVJpYWTjAwQE8GQ9eLIilAAFPDVk8DlkBAICIGQIGfCikYsSIZmdIQKAi4QKAC8cYpEjRUMKLES9cUhFRdoUQFCkaNJwBw+0DQwnKHmCll++hFiMm9GFDGACDIYgtC9ngOA+DCwaI6FVMRMULgQ5B710c24mEDx8yVgkCACH5BAgJAAAALAAAAAAgACAAhQQCBISChMTCxExOTOTi5KSipGxqbCQiJNTS1PTy9FxeXLSytBQSFJSWlHR2dDQyNAwKDMzKzFRWVOzq7Nza3Pz6/Ly6vIyKjKyqrHRydCwqLGRmZJyenAQGBMTGxFRSVOTm5KSmpGxubCQmJNTW1PT29GRiZLS2tBwaHJyanHx+fDw+PAwODMzOzFxaXOzu7Nze3Pz+/Ly+vIyOjP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAb+QJpwSCRWZIJKcclsCkGLBchJfZ4QRKiU2DpNqkNEdPocDydRLJiWiMpi5S0tZokm1sJWFCYkmGkUUS14QhUnCydKWlMlh4lUIAh3QzCCNBMyMi80egt8Qy8CBESHCwhKczILJHBDMWJvhQINKRxcUYgwcC+TSwmbrxwptDJFIKpum1UTGLQNGKNLFRSOvU4TKbUIrU0lLWpgHjIleNxV5kYgE+rqX4QwJBQk8SRHuLgChDQNKioB/SpSILtXjFAKgP4CVgDBsKEyPDDkSSRBjgk6JxebgDCRAU+IAtakXYAAoAMFMCAMbBBhAVWRBQcAyNTgAQwMFSY2bFABToiOApkAWDRQEuHTEgInK1jIkHNDASIkAYhwV2HFARXmYqQYYKBVggI6Ow7BIKJnAxQoHNDw4MLFoBkDBiwgQiBEzyUvRqAYsUnGgwf5XnwY4CJkFQdoUwjx+6AghriK8ZBAuwIV44IVTMSNBgYxihNDGOcT4gEynhMjxC7+W1DIDAkR9BURLbvKCxcKHlYJAgAh+QQICQAAACwAAAAAIAAgAIUEAgSEgoTEwsREQkTk4uSkpqQkIiRkZmTU0tT08vQ0MjS0trSUkpR8enzMyszs6uysrqwsKixsbmzc2tz8+vw8OjycmpwcGhxMTky8vryEhoTExsTk5uSsqqwkJiRsamzU1tT09vQ0NjS8uryUlpR8fnzMzszs7uy0srQsLix0cnTc3tz8/vw8PjycnpwcHhxUUlT///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG/sCYcEgkUjICSnHJbAo5KBTHSX0uEESolGhaPKpDRHT6REG+ZRQWHEtAFhlWmswaRRNsoRg1mQsnZiB5QiELKAtKWlMUhohUHAh4QytRJjEPGRknMSZRK0QJCGRChmpKMSwZKCByQyxicUIUnYdcURAjK3InkksJmywrpRBrQxyqUZpgJ8goGaNELBONvU4JUQsTrU0hJsVVCCanYNtV5UQnpVHOgzEcBCvwBAQhEQD3+CLtEBYWJP4WIKTAl28fwH4kzphZyG6QvBXxVowrcs5JxSYPVJTIY6jaEgokPFx48anKgwAlNGy4OELEhZctLFUhwKBEiQAM+hCR8PKCiQcXShCUXPIuBoUNGmyWQEFE5IUGm4xiqMCgHIsOH0q0unZTA5EFDQQNKaBAgVcTEiRgcXHgQAYiD1ZROdFCQYtNAjBgcBDjxIcDKjxW0VC2gJANevnGWNC2w6AJIhRgOJV3r6wGbaFRIaxgw5DKijk1zpOhRQAioIlY+PCtXQzEA2S6tiYhcJ4gACH5BAgJAAAALAAAAAAgACAAhQQCBISChMTCxERCROTi5KSipCQmJGRiZJSSlNTS1PTy9LSytBQSFDQ2NHRydFRSVAwKDIyKjMzKzOzq7GxqbJyanNza3Pz6/Ly6vKyqrDQyNDw+PFxaXAQGBISGhMTGxExOTOTm5CwqLGRmZJSWlNTW1PT29LS2tBwaHDw6PHx+fFRWVAwODIyOjMzOzOzu7GxubJyenNze3Pz+/Ly+vKyurP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAb+QJtwSCReaIJLcclsCkOLRchJfZ4SRKiU6DpNqsNEdPpc1L7lBRZsU9ROtFmaPMNEFWyheGGZCy1mJXlCJicLJ0paUxeGiFQLFIJDgAsuNhM0NC82LlEyRAoJZEIQAAAwmzYzNFdyQzNicUIXnYdEHKYADCRKL3hMCpszMoZma0M1BrkiH2AvNFELNKNEJhGlHZJUClEnFq5NIQcOeQkuSmzgVepELxjvJ+8Cg5chE/b2FwMo/P0g9NCimRGwjwE/g/8GBXxzSBOGE3AgNht0r2K+JuycZGzyIkCEPAIEmKByIUYKDSkIOKtAIkaCjQJAaJi54piTEBkq6MzwiYiOipkaNmSQU4IakXuqXMQgoZMGkZMNPPy6MOJBDHUzTgTgNUsA0xhEaHjoKWQBCBAIbJQIEKBPDRUqJLQTQJbJixUgHuBxMeIAFgUBVEQYOYjE2QVCJIwYsUYA3BODZDwAccCViwOMZ7UIjAaMYRByhfD1O6TE4zwfHqQdojjzkAwe+tDjQoH07G1sCYMJAgAh+QQICQAAACwAAAAAIAAgAIUEAgSMjozMysxEQkSsrqzk5uRkYmQkJiScnpzc2ty8vrz09vR0cnQUEhRUUlTU0tS0trTs7uxsamw0MjSkpqRcWlwMDgyUlpTk4uTExsT8/vx8enwcGhwEBgTMzsxMTky0srTs6uxkZmQsKiykoqTc3tzEwsT8+vxUVlTU1tS8urz08vRsbmw8OjysqqxcXlycmpx8fnwcHhz///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG/sCZcEgknhSmU3HJbAoLIFDBSRWCLAYiVEr0QELVoQgAgAy3U2Eo+ggLH+SDcgYlgGcaFQGycgvHAAFPUWkJUR5+ahYAFmBoMwsQIBBzTSobKUQBZCIzIQoKETMeUSVEKw9pQgccHBuiMycHHQwaRBoPIAq2saSTRBKtHAckShkJTSuiGiWSIARtRBAtwgOIVREKUbqqRAsXBw0yyFUrURAJvE0hLDF+KR6VVerzySZI9yYCiZ4FIf7+TqCYQLDgC34mtkUhYGJgQYIHE2nbs0dXhHugMii45uefx4BN6FER6SRCABh+HsSjcoKAgw8OuiU7V4LkDAEiPuiUQI7KladtCu4MCaDzQwUQSkoILRJhCjNnIDjOePnhQp9YMSS4oKchA4ytQk6QIqCCiIALGIioEGGAxIwEFy6YMnEBRqYhKzwsXbKChQgWfVLEiIFsBQIYCOSFISFCRNkZggkL8QADRoZEGBpv4BWZ3AkKdWEtbhzt7QbJQkpUvuzGAwu3Qx4M7jlDAYK0/Ih0zl1lQeUFfoIAACH5BAgJAAAALAAAAAAgACAAhQQCBISChMTCxERCROTi5KSipGRmZCQmJNTS1PTy9LSytJSSlHR2dDQ2NIyKjMzKzOzq7KyqrGxubNza3Pz6/Ly6vBwaHExOTCwuLJyanHx+fDw+PISGhMTGxOTm5KSmpGxqbNTW1PT29LS2tHx6fDw6PIyOjMzOzOzu7KyurHRydNze3Pz+/Ly+vBweHFRWVDQyNJyenP///wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAb+QJlwSCRCYA1UcclsClMAgMJJFY4OKmIkOh2eRpDqkGGxtIZb6dCjUCDEwlC5RBGmu6xKOwEXki0ZQh9cQhMpIyd9QhAHFgdKdzIiIwojdU4CHCtEGWUMMiMYGGcnbZtDCQgeRCVIDkoyFCUuASxELAgjLbaxpZVEGjDCGxG2J6dLCUosK5RtiUQtF8IwL29VKC1tCi2rSxQxG0jITgltIxO8TSgaJn0IJ5di6lX0RAkPHfn5130QHv8CUgBxoaDBLIoEbGuTQgBBgwUR9tF26BA3fPoEPBDQD05AgADlFbHnhGSTBDEivItHhcIICQZAeKOSgNKIFSYRkDDAMwCJuSYQtLVpEYZIDJ4GVFSwRaBosmXNtkETAoJnBD6xTHBYegsBN14USqWoQOTEBwJEOgTQMIVAihSrfJFLNZOJCA4aOPBZkSHDJpeVRIpRoCGAACF8F6CVMaFNxyoQNGhYcImvXyF5DmEdLHnCEMvIPFB67CQEhy6F+pL74lTRZ9WuxYiIkEJEnyAAIfkECAkAAAAsAAAAACAAIACFBAIEhIKExMLEREJE5OLkpKakZGJkJCIklJKU1NLUVFJU9PL0tLa0NDI0FBIUfH58jIqMzMrMTEpM7OrsrK6sbGpsnJqc3NrcXFpc/Pr8PDo8DA4MvL68BAYEhIaExMbEREZE5ObkrKqsZGZkLC4slJaU1NbUVFZU9Pb0vLq8NDY0HBocjI6MzM7MTE5M7O7stLK0bG5snJ6c3N7cXF5c/P78PD48////AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABv7Am3BIJL5AkldxyWwKGatVykkVCmwBIiw6HdI2jOow0GgIhgzHijOkAAAxsfCiIikyzyj7hjq8TXJCHmUFQltSgm9xgTcvNg02SlCIIRsAG0pOESUERAVlHjccAzYfNwZvJUQLCSFECi4uFgtCKAoqCDVENTEdJHg3GS0wMGFDLBLJGAx4LZ1MJhE3NTMMxBQJRREjLhIuFYBVLxzEMByuSxkiJxIKz1QLxAwXuk4vLDKBLQkogfVi/4qw2kfwAqMbE0IkXJjhwYiHECEcJFcOBgUBASA+NCCREUUK1hhwYJWgZIIWBhktVKgQ2JKAVGA6WUChi5iTLplk+ODhQZiATPDkzZB5wwSCB0gRvLNH0dyEIhSQBvAQQdcEoAKVULNGAUa2IR4CPIDRL5gICx8C1kggsp6wkERMwHg6JEEJC2cmcBDwdBiMGataUUEhw4KMfiGIucogL6cYARZKfE0MA90FYl/lvIgsol5iCnRrpABJS46Au4CFUEZ3I4S1zFVmyDgzZDWRFgzoHqxtUffuJhn2OnYSBAAh+QQICQAAACwAAAAAIAAgAIUEAgSMjozMysxEQkS0srTk5uRkYmQkJiScnpz09vR0cnQUEhTU1tRUUlS8vryUlpTs7uxsamw0MjSkpqRcWlwMDgzU0tS8urz8/vx8enwcGhzc3tzExsQEBgSUkpTMzsxMTky0trTs6uxkZmQsKiykoqT8+vzc2txUVlTEwsScmpz08vRsbmw8OjysqqxcXlx8fnwcHhz///8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAG/kCZcEgkrlCvVXHJbAodEknKSRVyUB4iVEpkHRzV4QMEEgy3YGFIo8mEhZsGyIARXqJTmanFZryFHmQEdlFpD2wwf0IrcihKaDIiBwskEFQWEwVEBGRZVygfMixsCEQWESFEESMjLkp6Bg0IdUMmMDEDJkIiIx0AC0QIIwYjCg51DJpMJ6EmAQsA0QZFFhnDIzAbYRwk0QAHg0smISwjEcqXvhUBuk4rJS5/qyJ/tGH2RQknDPv82ooiCgQcaMIDjIMIVSiSkYKAw4cOHiBMuNDBQ4j6TmjU+O9PwAIgQeIjMtJJySYJUnD4Y+FDuyYYPiBQoeIVlRUOQ2w4ucEFic0HLtA5gWDRoQN6WlQ8UIHAQh0INoussIRhQ4iHoYbMVJEigRAMFhngw2AhxDEhJj7kJLIhhaUhJxxakFEgxVEZagl0lLHiA9Im4wiE0FXAoSYTOV++yXtCSGECyuISmPsHJ4GzdA1/veAw6iXNjkFnnvynQIisoSET+RDi78LUQl8zMeGg658gADs=) no-repeat center;\n    visibility: hidden;\n}\n\n.pull-to-refresh-arrow {\n    display: inline-block;\n}\n"
  },
  {
    "path": "tart/ui/Sidebar/SidebarComponent.js",
    "content": "// Copyright 2014 Startup Kitchen. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\ngoog.provide('tart.ui.SidebarComponent');\ngoog.require('tart.ui.DlgComponent');\n\n\n\n/**\n * @constructor\n * @extends {tart.ui.DlgComponent}\n */\ntart.ui.SidebarComponent = function() {\n    goog.base(this);\n};\ngoog.inherits(tart.ui.SidebarComponent, tart.ui.DlgComponent);\n\n\n/**\n * Dispatches a switch view event to listeners and toggles the sidebar of the view manager that\n * is responsible for this sidebar.\n *\n * @param {goog.events.BrowserEvent} e Tap event.\n */\ntart.ui.SidebarComponent.prototype.onSidebarItemTap = function(e) {\n    var view = e.target.getAttribute('data-view');\n    if (!view) return;\n\n    this.dispatchEvent({\n        type: tart.ui.SidebarComponent.EventType.SWITCH_VIEW,\n        view: view\n    });\n\n    this.vm.toggleSidebar();\n};\n\n\n/**\n * @return {string} Returns the template base.\n */\ntart.ui.SidebarComponent.prototype.templates_base = function() {\n    return '<sidebar-view class=\"view\" id=\"' + this.id + '\">' +\n            '<sidebar-items>' + this.template_items() + '</sidebar-items>' +\n        '</sidebar-view>';\n};\n\n\n/**\n * @return {string} Returns the items for the sidebar.\n */\ntart.ui.SidebarComponent.prototype.template_items = function() {\n    return '';\n};\n\n\n/**\n * @enum {string} Sidebar events.\n */\ntart.ui.SidebarComponent.EventType = {\n    SWITCH_VIEW: 'switchView'\n};\n\n\n/**\n * @enum {string} Dom mapping.\n */\ntart.ui.SidebarComponent.prototype.mappings = {\n    ITEM: 'sidebar-item'\n};\n\n\n(function(proto) {\n    proto.events = {};\n    var tap = proto.events[tart.events.EventType.TAP] = {};\n\n    tap[proto.mappings.ITEM] = proto.onSidebarItemTap;\n})(tart.ui.SidebarComponent.prototype);\n"
  },
  {
    "path": "tart/ui/Sidebar/sidebar.css",
    "content": "sidebar-view {\n    background: #eee;\n    position: absolute;\n    -webkit-transition-duration: 0s;\n    display: block;\n    height: 100%;\n    top: 0;\n    width: 100%;\n    padding-left: 20%;\n}\n\nsidebar-items {\n    display: block;\n    height: 100%;\n    width: 100%;\n    left: 0;\n    padding-left: 60px;\n}\n\nsidebar-item {\n    display: block;\n    font-size: 80px;\n    font-weight: 100;\n    top: 0;\n    padding: 40px 20px;\n    border-bottom:1px solid #aaa;\n}\n\nsidebar-item i {\n    left: 45px;\n    top: 5px;\n    font-size: 59px;\n    position: absolute;\n}\n\nsidebar-item:active {\n    background-color: #ccc;\n}\n\nsidebar-label {\n    display: block;\n    font-size: 45px;\n    color: black;\n}\n"
  },
  {
    "path": "tart/ui/TabBar/TabBarView.js",
    "content": "// Copyright 2014 Startup Kitchen. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\ngoog.provide('tart.ui.TabBarView');\ngoog.require('tart.ui.View');\n\n\n\n/**\n * @constructor\n * @extends {tart.ui.View}\n */\ntart.ui.TabBarView = function() {\n    goog.base(this);\n};\ngoog.inherits(tart.ui.TabBarView, tart.ui.View);\n\n\n/**\n * @override\n */\ntart.ui.TabBarView.prototype.onAfterRender = function() {\n    this.vm = new tart.ui.ViewManager(this.getElement());\n};\n\n\n/**\n * @param {goog.events.BrowserEvent} e Item touch event handler.\n */\ntart.ui.TabBarView.prototype.onItemTap = function(e) {\n    var activeItem = this.getChild(this.mappings.ACTIVE)[0];\n    if (activeItem && activeItem == e.target) return;\n\n    var itemIndex = [].indexOf.call(this.getChild(this.mappings.ITEMS)[0].childNodes, e.target);\n\n    this.activateItem(itemIndex);\n};\n\n\n/**\n * Adds active class to item.\n * @param {number} index Index of the item to be active.\n */\ntart.ui.TabBarView.prototype.activateItem = function(index) {\n    if (index == -1) return;\n\n    this.deactivateActiveItem();\n    var item = this.getChild(this.mappings.ITEM)[index];\n    goog.dom.classlist.add(item, 'active');\n\n    if (this.views && this.views[index])\n        this.vm.setCurrentView(this.views[index], true);\n};\n\n\n/**\n * Activates a tab bar item with a given name. If an item for the given the name isn't found, does nothing.\n *\n * @param {string} name Name for the tab bar item.\n */\ntart.ui.TabBarView.prototype.activateItemByName = function(name) {\n    var child = this.getChild(this.mappings.ITEM + '[data-view=' + name + ']')[0];\n    if (!child) return;\n\n    var itemIndex = [].indexOf.call(this.getChild(this.mappings.ITEMS)[0].childNodes, child);\n\n    this.activateItem(itemIndex);\n};\n\n\n/**\n * Removes active class of active item.\n */\ntart.ui.TabBarView.prototype.deactivateActiveItem = function() {\n    var activeItem = this.getChild(this.mappings.ACTIVE);\n    if (activeItem && activeItem.length)\n        goog.dom.classlist.remove(activeItem[0], 'active');\n};\n\n\n/**\n * @return {string} Base template of NavigationBar component.\n */\ntart.ui.TabBarView.prototype.templates_content = function() {\n    return '<tab-bar id=\"' + this.id + '\">' +\n            '<tab-items>' +\n            this.templates_items() +\n            '</tab-items>' +\n        '</tab-bar>';\n};\n\n\n/**\n * @return {string} Template for tab bar items.\n */\ntart.ui.TabBarView.prototype.templates_items = function() {\n    return '';\n};\n\n\n/**\n * @enum {string} Dom mappings.\n */\ntart.ui.TabBarView.prototype.mappings = {\n    ITEM: 'tab-item',\n    ITEMS: 'tab-items',\n    ACTIVE: '.active'\n};\n\n\n(function() {\n    this.events = {};\n    var tap = this.events[goog.events.EventType.TOUCHEND] = {};\n    tap[this.mappings.ITEM] = this.onItemTap;\n}).call(tart.ui.TabBarView.prototype);\n"
  },
  {
    "path": "tart/ui/TabBar/tabbar.css",
    "content": "tab-bar {\n    position: absolute;\n    bottom: 0;\n    height: 120px;\n    width: 100%;\n    text-align: center;\n    line-height: 120px;\n    background: rgba(0,0,0,0.9);\n    background: white;\n    -webkit-transform: translate3d(0,0,1000px);\n    border-top: 1px solid #ccc;\n    z-index: 1;\n}\n\ntab-items {\n    display: block;\n    width: 100%;\n    height: 100%;\n}\n\ntab-item {\n    display: inline-block;\n    text-align: center;\n    width: 50%;\n}\n\ntab-item:first-child,\ntab-item:nth-child(2) {\n    border-right: 1px solid #ccc;\n}\n\ntab-item.active {\n    background: #eee;\n}\n"
  },
  {
    "path": "tart/ui/View.js",
    "content": "// Copyright 2014 Startup Kitchen. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\ngoog.provide('tart.ui.View');\ngoog.require('tart.ui.DlgComponent');\ngoog.require('tart.ui.ViewManager');\n\n\n\n/**\n * The default view class for all views. Handles default overrides for tart.ui.DlgComponent such as rendering\n * to body by default.\n *\n * @constructor\n * @extends {tart.ui.DlgComponent}\n */\ntart.ui.View = function() {\n    goog.base(this);\n};\ngoog.inherits(tart.ui.View, tart.ui.DlgComponent);\n\n\n/**\n * View index in z-axis. This should be used as the z value for initial translate3d style declaration.\n *\n * @type {number}\n */\ntart.ui.View.prototype.index = 0;\n\n\n/**\n * Determines whether the view should support back gestures to go back in history or not.\n *\n * @type {boolean}\n */\ntart.ui.View.prototype.supportsBackGesture = true;\n\n\n/**\n * True if the view allows sidebar access. This lets the view manager orchestrate touch gestures for the sidebar menu.\n * Default is false.\n *\n * @type {boolean}\n */\ntart.ui.View.prototype.hasSidebar = false;\n\n\n/**\n * Defines CSS class names for the view.\n *\n * @type {string}\n */\ntart.ui.View.prototype.className = '';\n\n\n/**\n * @type {number} Gives the device width.\n */\ntart.ui.View.WIDTH = parseInt(window.getComputedStyle(document.body, null).width, 10);\n\n\n/**\n * Overridden to make document.body the default parent element. This method also saves if a view is already rendered.\n * Original opt_index parameter is also overridden with the view index. In this case, this view will always be appended\n * to the body.\n *\n * @override\n *\n * @param {(Element|number)=} opt_rootEl Root element to render this view in.\n * @param {number=} opt_index The index of this view in z-axis.\n */\ntart.ui.View.prototype.render = function(opt_rootEl, opt_index) {\n    this.onBeforeRender();\n    this.rendered = true;\n    if (goog.isNumber(opt_rootEl)) {\n        opt_index = opt_rootEl;\n        opt_rootEl = document.body;\n    }\n\n    if (goog.isDef(opt_index)) this.index = opt_index;\n    goog.base(this, 'render', opt_rootEl || document.body);\n    this.onAfterRender();\n};\n\n\n/**\n * Method called before a render process. Called automatically before each render. Subclasses should override\n * this method for tasks that should be done right before the View enters the document.\n */\ntart.ui.View.prototype.onBeforeRender = function() {};\n\n\n/**\n * Method called after a render process. Called automatically after each render. Subclasses should override\n * this method for tasks that should be done when the View is in document.\n */\ntart.ui.View.prototype.onAfterRender = function() {};\n\n\n/**\n * Returns the HTML markup for the initial state.\n *\n * @return {string} The template for the view.\n */\ntart.ui.View.prototype.getTemplate = function() {\n    return this.templates_base();\n};\n\n\n/**\n * Method called when the View is being activated by a ViewManager. Subclasses should override this method for tasks\n * that should be done when the View is in viewport, such as updating information, etc.\n */\ntart.ui.View.prototype.activate = function() {};\n\n\n/**\n * Overriden to include 'view' as a class name.\n *\n * @override\n */\ntart.ui.View.prototype.templates_base = function() {\n    return '<view id=\"' + this.id + '\"' +\n        'class=\"' + this.className + '\"' +\n        'style=\"-webkit-transform: translate3d(100%, 0, ' + this.index + 'px)\">' +\n        this.templates_content() +\n        '</view>';\n};\n\n\n/**\n * Empty content template. Subclasses should override this method and implement necessary markup here.\n *\n * @return {string} Content markup for the view.\n */\ntart.ui.View.prototype.templates_content = function() {\n    return '';\n};\n\n\n/**\n * @override\n */\ntart.ui.View.prototype.disposeInternal = function() {\n    var element = this.element;\n    goog.base(this, 'disposeInternal');\n\n    goog.dom.removeNode(element);\n};\n"
  },
  {
    "path": "tart/ui/ViewManager.js",
    "content": "// Copyright 2014 Startup Kitchen. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\ngoog.provide('tart.ui.ViewManager');\ngoog.require('goog.math');\n\n\n\n/**\n * This class handles view transitions and view history in a consistent manner. Should be used by views who would like\n * to contain other views. Also, each application should have at least one ViewManager.\n *\n * @constructor\n *\n * @param {Element=} opt_rootEl Root element for this view manager.\n */\ntart.ui.ViewManager = function(opt_rootEl) {\n    this.history = [];\n    this.lastTouches = [];\n    this.state = tart.ui.ViewManager.State.DEFAULT;\n    this.rootEl = opt_rootEl || document.body;\n\n    this.initTouchEvents_();\n};\n\n\n/**\n * 3d transform Z position for the uppermost view. Used to set the right view on top.\n * @type {number}\n */\ntart.ui.ViewManager.prototype.topIndex = 1;\n\n\n/**\n *\n * @param {tart.ui.View} view View to pull into view.\n * @param {boolean=} opt_canGoBack Whether this view keeps history so that one can go back to the previous view.\n */\ntart.ui.ViewManager.prototype.pull = function(view, opt_canGoBack) {\n    if (!view.rendered) view.render(this.rootEl, this.topIndex += 2);\n\n    var currentView = this.currentView;\n\n    if (opt_canGoBack) {\n        this.history.push(currentView);\n        goog.events.listenOnce(currentView.getElement(), 'webkitTransitionEnd', function() {\n            currentView.getElement().style.webkitTransitionDuration = 0;\n            currentView.getElement().style.webkitTransform = 'translate3d(-100%,-100%,0)';\n        });\n    }\n    else {\n        var history = this.history.slice(0);\n        this.history = [];\n\n        setTimeout(function() {\n            currentView.dispose();\n\n            // Dispose all views in history.\n            history.forEach(function(historicView) {\n                historicView.dispose();\n            });\n        }, 1000);\n    }\n\n    setTimeout(function() {\n        currentView.getElement().style.webkitTransitionDuration = '0.35s';\n        view.getElement().style.webkitTransform = 'translate3d(0, 0, ' + view.index + 'px)';\n        currentView.getElement().style.webkitTransform = 'translate3d(-30%, 0, ' + currentView.index + 'px)';\n        view.getElement().style['boxShadow'] = '0 0 24px black';\n    }, 50);\n\n    this.currentView = view;\n\n    this.state = tart.ui.ViewManager.State.DEFAULT;\n};\n\n\n/**\n * Returns true if there is one or more views in history,\n * returns false otherwise.\n *\n * @return {boolean} Whether the view manager can push current view.\n */\ntart.ui.ViewManager.prototype.canGoBack = function() {\n    return this.history && this.history.length > 0;\n};\n\n\n/**\n * Switches to the previous view if there's one.\n */\ntart.ui.ViewManager.prototype.push = function() {\n    var lastView = this.history.pop(),\n        currentView = this.currentView;\n\n    if (!lastView) return;\n\n    window.requestAnimationFrame(function() {\n        lastView.getElement().style.webkitTransitionDuration = 0;\n        lastView.getElement().style.webkitTransform = 'translate3d(-30%,0,0)';\n        window.requestAnimationFrame(function() {\n            lastView.getElement().style.webkitTransitionDuration = '0.35s';\n            currentView.getElement().style.webkitTransitionDuration = '0.35s';\n\n            lastView.getElement().style.webkitTransform = 'translate3d(0, 0, ' + lastView.index + 'px)';\n            currentView.getElement().style.webkitTransform = 'translate3d(100%, 0, ' + currentView.index + 'px)';\n            currentView.getElement().style['boxShadow'] = '0 0 0 black';\n        });\n    });\n\n    this.currentView = lastView;\n    lastView.activate && lastView.activate();\n\n    setTimeout(function() {\n        currentView.dispose();\n    }, 1000);\n\n    this.state = tart.ui.ViewManager.State.DEFAULT;\n};\n\n\n/**\n * Makes a given view the foremost view without animations and with disposing previous views in history.\n *\n * @param {tart.ui.View} view The view to set as the foremost view.\n * @param {boolean=} opt_noDispose Whether to dispose the current view.\n */\ntart.ui.ViewManager.prototype.setCurrentView = function(view, opt_noDispose) {\n    if (!view.rendered) view.render(this.rootEl, this.topIndex += 2);\n\n    var currentView = this.currentView;\n\n    if (!opt_noDispose) {\n        setTimeout(function() {\n            currentView && currentView.dispose();\n        }, 1000);\n    } else if (currentView) {\n        currentView.getElement().style.webkitTransitionDuration = '0s';\n        currentView.getElement().style.webkitTransform = 'translate3d(100%, 0, ' + currentView.index + 'px)';\n    }\n\n    view.index = this.topIndex += 2;\n    this.currentView = view;\n    this.currentView.activate && this.currentView.activate();\n\n\n    // Dispose all views in history.\n    this.history.forEach(function(historicView) {\n        historicView.dispose();\n    });\n\n    this.history = [];\n\n    var translation = 'translate3d(0, 0, ' + view.index + 'px)';\n    view.getElement().style.webkitTransitionDuration = '0s';\n\n    if (this.state == tart.ui.ViewManager.State.SIDEBAR_OPEN) {\n        translation = 'translate3d(' + (128 - tart.ui.View.WIDTH) + 'px, 0, ' + view.index + 'px)';\n\n        view.getElement().style.webkitTransform = translation;\n        this.toggleSidebar_(false);\n\n        return;\n    }\n\n    view.getElement().style.webkitTransform = translation;\n    //view.getElement().style.zIndex = view.index;\n\n    this.state = tart.ui.ViewManager.State.DEFAULT;\n};\n\n\n/**\n * Toggles the sidebar on or off according to its current state. This is to be used for a menu button, for example.\n */\ntart.ui.ViewManager.prototype.toggleSidebar = function() {\n    this.toggleSidebar_(this.state == tart.ui.ViewManager.State.DEFAULT);\n};\n\n\n/**\n * Initializes touch event handlers for all touch end and touch move events ocurring on the root element.\n *\n * @protected\n */\ntart.ui.ViewManager.prototype.initTouchEvents_ = function() {\n    goog.events.listen(this.rootEl, goog.events.EventType.TOUCHMOVE, this.onTouchMove_, false, this);\n    goog.events.listen(this.rootEl, goog.events.EventType.TOUCHEND, this.onTouchEnd_, false, this);\n};\n\n\n/**\n * Handles touch move events and decides how the view transitions should occur.\n *\n * @protected\n * @param {goog.events.Event} e Touch move event.\n */\ntart.ui.ViewManager.prototype.onTouchMove_ = function(e) {\n    var clientX = e.getBrowserEvent().changedTouches[0].clientX;\n    clearTimeout(this.hideSidebarTimeout);\n\n    if (this.state == tart.ui.ViewManager.State.DEFAULT || this.state == tart.ui.ViewManager.State.SIDEBAR_OPEN)\n        this.firstX = clientX;\n\n    if (this.state == tart.ui.ViewManager.State.DEFAULT) {\n        this.lastTouches = [];\n\n        this.state = tart.ui.ViewManager.State.STARTED_GESTURE;\n    }\n\n    if (this.state == tart.ui.ViewManager.State.STARTED_GESTURE) {\n        if (clientX <= 50) {\n            if (this.history.length && this.currentView.supportsBackGesture)\n                this.state = tart.ui.ViewManager.State.GOING_TO_BACK_VIEW;\n        }\n        else if (this.currentView.hasSidebar) {\n            this.lastTouches.push(this.firstX - clientX);\n\n            if (this.lastTouches.length == 4) this.lastTouches.shift();\n\n            if (this.lastTouches[2] - this.lastTouches[0] > 40)\n                this.state = tart.ui.ViewManager.State.OPENING_SIDEBAR;\n        }\n    }\n\n    if (this.state == tart.ui.ViewManager.State.SIDEBAR_OPEN)\n        this.state = tart.ui.ViewManager.State.CLOSING_SIDEBAR;\n\n    switch (this.state) {\n        case tart.ui.ViewManager.State.GOING_TO_BACK_VIEW:\n            this.backGestureTouchMove_(e);\n            break;\n        case tart.ui.ViewManager.State.CLOSING_SIDEBAR:\n            this.closeSidebarTouchMove_(e);\n            break;\n        case tart.ui.ViewManager.State.OPENING_SIDEBAR:\n            this.openSidebarTouchMove_(e);\n            break;\n    }\n};\n\n\n/**\n * Handles touch end events and decides how the view transitions should follow.\n *\n * @protected\n * @param {goog.events.Event} e Touch end event.\n */\ntart.ui.ViewManager.prototype.onTouchEnd_ = function(e) {\n    var state;\n\n    switch (this.state) {\n        case tart.ui.ViewManager.State.GOING_TO_BACK_VIEW:\n            this.backGestureTouchEnd_(e);\n            break;\n        case tart.ui.ViewManager.State.OPENING_SIDEBAR:\n            state = true;\n            if (this.lastTouches[2] - this.lastTouches[0] < 3)\n                state = false;\n\n            this.toggleSidebar_(state);\n            break;\n        case tart.ui.ViewManager.State.CLOSING_SIDEBAR:\n            state = true;\n            if (this.lastTouches[2] - this.lastTouches[0] < -3)\n                state = false;\n\n            this.toggleSidebar_(state);\n            break;\n        case tart.ui.ViewManager.State.SIDEBAR_OPEN:\n            if (tart.events.GestureHandler.getInstance().canTap) return;\n            this.toggleSidebar_(false);\n            break;\n        default:\n            this.state = tart.ui.ViewManager.State.DEFAULT;\n    }\n};\n\n\n/**\n * Handles touch end event when they occur in a back gesture.\n *\n * @protected\n * @param {goog.events.Event} e Touch end event.\n */\ntart.ui.ViewManager.prototype.backGestureTouchEnd_ = function(e) {\n    if (!this.firstX) return;\n\n    var that = this,\n        history = this.history,\n        lastView = history[history.length - 1],\n        currentView = this.currentView,\n        clientX = e.getBrowserEvent().changedTouches[0].clientX,\n        duration = goog.math.lerp(0.15, 0.35, (tart.ui.View.WIDTH - clientX) / tart.ui.View.WIDTH);\n\n    window.requestAnimationFrame(function() {\n        currentView.getElement().style.webkitTransitionDuration = duration + 's';\n        lastView.getElement().style.webkitTransitionDuration = duration + 's';\n\n        var currentViewX = '100%',\n            lastViewX = '0';\n\n        if (clientX < (tart.ui.View.WIDTH / 2)) {\n            currentViewX = '0';\n            lastViewX = '-30%';\n\n            goog.events.listenOnce(lastView.getElement(), 'webkitTransitionEnd', function() {\n                lastView.getElement().style.webkitTransitionDuration = 0;\n                lastView.getElement().style.webkitTransform = 'translate3d(-100%,-100%,0)';\n            });\n        } else {\n            history.pop();\n            that.currentView = lastView;\n\n            lastView.activate && lastView.activate();\n\n            setTimeout(function() {\n                currentView.dispose();\n            }, 1000);\n        }\n\n        currentView.getElement().style.webkitTransform = 'translate3d(' + currentViewX + ', 0, ' +\n            currentView.index + 'px)';\n        lastView.getElement().style.webkitTransform = 'translate3d(' + lastViewX + ', 0, ' +\n            (currentView.index - 1) + 'px)';\n        currentView.getElement().style['boxShadow'] = '0px 0 0px black';\n    });\n\n    this.state = tart.ui.ViewManager.State.DEFAULT;\n};\n\n\n/**\n * Handle touch move events when they occur in a back gesture.\n *\n * @protected\n * @param {goog.events.Event} e Touch end event.\n */\ntart.ui.ViewManager.prototype.backGestureTouchMove_ = function(e) {\n    if (!this.history.length) return;\n\n    /* Google Chrome will fire a touchcancel event about 200 milliseconds\n     after touchstart if it thinks the user is panning/scrolling and you\n     do not call event.preventDefault(). */\n    e.preventDefault();\n    var clientX = e.getBrowserEvent().changedTouches[0].clientX;\n\n    var lastView = this.history[this.history.length - 1];\n    var currentView = this.currentView;\n    var currentViewDiff = clientX - this.firstX;\n    var viewWidth = tart.ui.View.WIDTH;\n    var lastViewDiff = Math.floor(goog.math.lerp(-viewWidth * 0.3, 0, currentViewDiff / (viewWidth - this.firstX)));\n    var boxShadow = Math.floor(goog.math.lerp(1, 0, currentViewDiff / (viewWidth - this.firstX)) * 5) / 5;\n    if (currentViewDiff < 0) return;\n\n    window.requestAnimationFrame(function() {\n        currentView.getElement().style.webkitTransitionDuration = '0s';\n        lastView.getElement().style.webkitTransitionDuration = '0s';\n        currentView.getElement().style.webkitTransform = 'translate3d(' + currentViewDiff + 'px, 0, ' +\n            currentView.index + 'px)';\n        lastView.getElement().style.webkitTransform = 'translate3d(' + lastViewDiff + 'px, 0, ' +\n            (currentView.index - 1) + 'px)';\n\n        currentView.getElement().style['boxShadow'] = '0px 0 24px rgba(0, 0, 0, ' + boxShadow + ')';\n    });\n};\n\n\n/**\n * Close sidebar touch move functionality.\n *\n * @protected\n * @param {goog.events.Event} e X coordinate difference.\n */\ntart.ui.ViewManager.prototype.closeSidebarTouchMove_ = function(e) {\n    var clientX = e.getBrowserEvent().changedTouches[0].clientX;\n\n    this.lastTouches.push(this.firstX - clientX);\n\n    if (this.lastTouches.length == 4) this.lastTouches.shift();\n\n    /* Google Chrome will fire a touchcancel event about 200 milliseconds\n     after touchstart if it thinks the user is panning/scrolling and you\n     do not call event.preventDefault(). */\n    e.preventDefault();\n\n    var currentView = this.currentView;\n    var viewWidth = tart.ui.View.WIDTH;\n    var currentViewDiff = clientX - this.firstX - viewWidth * 4 / 5;\n    window.requestAnimationFrame(function() {\n        currentView.getElement().style.webkitTransitionDuration = '0s';\n        currentView.getElement().style.webkitTransform = 'translate3d(' +\n            currentViewDiff + 'px, 0, ' + currentView.index + 'px)';\n    });\n};\n\n\n/**\n * Toggles the sidebar on or off according to a given state.\n *\n * @protected\n * @param {boolean} state Whether to open or close the sidebar.\n */\ntart.ui.ViewManager.prototype.toggleSidebar_ = function(state) {\n    var that = this,\n        currentView = this.currentView,\n        sidebar = document.querySelector('sidebar-view');\n\n    setTimeout(function() {\n        currentView.getElement().style.webkitTransitionDuration = '0.35s';\n\n        var currentViewX = (128 - tart.ui.View.WIDTH) + 'px',\n            sidebarX = '0',\n            sidebarZ = currentView.index - 1 + 'px';\n\n        if (!state) {\n            currentViewX = '0';\n            sidebarX = '100%';\n            sidebarZ = 0;\n            that.hideSidebarTimeout = setTimeout(function() {\n                if (that.state == tart.ui.ViewManager.State.DEFAULT)\n                    sidebar.style.webkitTransform = 'translate3d(' + sidebarX + ', 0, ' + sidebarZ + ')';\n            }, 1000);\n        } else {\n            sidebar.style.webkitTransform = 'translate3d(' + sidebarX + ', 0, ' + sidebarZ + ')';\n        }\n        currentView.getElement().style.webkitTransform = 'translate3d(' + currentViewX + ', 0, ' +\n            currentView.index + 'px)';\n    }, 10);\n\n    if (state)\n        this.state = tart.ui.ViewManager.State.SIDEBAR_OPEN;\n    else\n        this.state = tart.ui.ViewManager.State.DEFAULT;\n};\n\n\n/**\n * Close sidebar touch move functionality.\n *\n * @protected\n * @param {goog.events.Event} e X coordinate difference.\n */\ntart.ui.ViewManager.prototype.openSidebarTouchMove_ = function(e) {\n    if (tart.events.GestureHandler.getInstance().canTap) return;\n\n    var clientX = e.getBrowserEvent().changedTouches[0].clientX;\n    this.lastTouches.push(this.firstX - clientX);\n\n    if (this.lastTouches.length == 4) this.lastTouches.shift();\n\n    /* Google Chrome will fire a touchcancel event about 200 milliseconds\n     after touchstart if it thinks the user is panning/scrolling and you\n     do not call event.preventDefault(). */\n    e.preventDefault();\n\n    var sidebar = document.querySelector('sidebar-view');\n    var currentView = this.currentView;\n    var currentViewDiff = clientX - this.firstX;\n\n    if (currentViewDiff >= 0) return;\n    this.state = tart.ui.ViewManager.State.OPENING_SIDEBAR;\n\n    window.requestAnimationFrame(function() {\n        sidebar.style.webkitTransform = 'translate3d(0, 0, ' + (currentView.index - 1) + 'px)';\n        sidebar.style.webkitTransitionDuration = '0s';\n\n        currentView.getElement().style.webkitTransitionDuration = '0s';\n        currentView.getElement().style.webkitTransform = 'translate3d(' +\n            currentViewDiff + 'px, 0, ' + currentView.index + 'px)';\n    });\n};\n\n\n/**\n * View manager states.\n *\n * @enum {string}\n */\ntart.ui.ViewManager.State = {\n    DEFAULT: 'default',\n    STARTED_GESTURE: 'started',\n    CLOSING_SIDEBAR: 'closingSidebar',\n    OPENING_SIDEBAR: 'openingSidebar',\n    SIDEBAR_OPEN: 'sidebarOpen',\n    GOING_TO_BACK_VIEW: 'going'\n};\n\n\nwindow.requestAnimationFrame = (function() {\n    return  window.requestAnimationFrame ||\n        window.webkitRequestAnimationFrame ||\n        window.mozRequestAnimationFrame ||\n        function(callback){\n            window.setTimeout(callback, 1000 / 60);\n        };\n})();\n"
  },
  {
    "path": "tart/ui/ViewModel.js",
    "content": "// Copyright 2014 Startup Kitchen. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\ngoog.provide('tart.ui.ViewModel');\ngoog.require('tart.ui.ComponentModel');\n\n\n\n/**\n * Base view model for tart.ui.View instances.\n *\n * @constructor\n * @extends {tart.ui.ComponentModel}\n */\ntart.ui.ViewModel = function() {\n    goog.base(this);\n};\ngoog.inherits(tart.ui.ViewModel, tart.ui.ComponentModel);\n"
  },
  {
    "path": "tart/ui/input/DateComponent.js",
    "content": "// Copyright 2012 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n\n\n/**\n * @fileoverview This component displays the date entered in a predefined date format and returns that date's value in\n * milliseconds format when asked. If the entered value is not suitable, getDateTime function returns 'NaN' value.\n */\n\ngoog.provide('tart.ui.input.DateComponent');\ngoog.require('goog.events.EventTarget');\ngoog.require('tart.ui.DlgComponent');\n\n\n\n/**\n * Date component.\n * @extends {tart.ui.DlgComponent}\n * @constructor\n */\ntart.ui.input.DateComponent = function() {\n    goog.base(this);\n};\ngoog.inherits(tart.ui.input.DateComponent, tart.ui.DlgComponent);\n\n\n/**\n * Returns the date in Date format.\n * @return {Date} date in Date format.\n */\ntart.ui.input.DateComponent.prototype.getDateTime = function() {\n    var dateInputArea = this.getChild(this.mappings.INPUT)[0];\n    var dateInput = dateInputArea.value;\n    var formattedDateString = dateInput.slice(3, 5) + '/' + dateInput.slice(0, 2) + '/' +\n    dateInput.slice(5, dateInput.length);\n    return new Date(formattedDateString);\n};\n\n\n/**\n * Reformats the text entered, in order to display it in a visual style adjusted with predefined style.\n *\n * @param {goog.events.BrowserEvent} e keyPress Event.\n */\ntart.ui.input.DateComponent.prototype.onKeyPress = function(e) {\n    var dateInputArea = this.getChild(this.mappings.INPUT)[0];\n    var textToChange = dateInputArea.value;\n    textToChange = textToChange.replace(/^(\\d{1,1}\\/)/, '0$1');\n    textToChange = textToChange.replace(/(\\/)(\\d{1,1})(\\/)/, '$10$2');\n    textToChange = textToChange.replace(/[^\\d]/g, '');\n    textToChange = textToChange.replace(/^(\\d{0,2})(\\d{0,2})(\\d{0,4})(\\d{0,})/g, '$1/$2/$3');\n    textToChange = textToChange.replace(/\\/{0,}$/, '');\n    dateInputArea.value = textToChange;\n};\n\n\n/**\n * Cleans the text area if no text entrance was made.\n */\ntart.ui.input.DateComponent.prototype.onFocusIn = function() {\n    var dateInputArea = this.getChild(this.mappings.INPUT)[0];\n    if (dateInputArea.value == 'GG/AA/YYYY')\n        dateInputArea.value = '';\n};\n\n\n/**\n * Dispatches an event after focusOut action which carries the date in milliseconds.\n */\ntart.ui.input.DateComponent.prototype.onFocusOut = function() {\n    var dateInputArea = this.getChild(this.mappings.INPUT)[0];\n    if (dateInputArea.value == '')\n        this.resetInputArea();\n};\n\n\n/**\n * Resets the text area, date string and formatted date string parameters.\n */\ntart.ui.input.DateComponent.prototype.resetInputArea = function() {\n    var dateInputArea = this.getChild(this.mappings.INPUT)[0];\n    dateInputArea.value = 'GG/AA/YYYY';\n};\n\n\n/**\n * Constructs the base template\n * @return {string} base template.\n */\ntart.ui.input.DateComponent.prototype.templates_base = function() {\n    return '<span id=\"' + this.id + '\">' +\n        '<input name=\"dateInput\" type=\"text\" class=\"textForm numberOnly dateInput dateInputArea\" minlength=\"1\" ' +\n        'maxlength=\"10\" value=\"GG/AA/YYYY\"/>' +\n        '</span>';\n};\n\n\n/**\n * DateComponent domMappings.\n * @enum {string}\n */\ntart.ui.input.DateComponent.prototype.mappings = {\n    INPUT: '.dateInput'\n};\n\n\n(function() {\n    var proto = tart.ui.input.DateComponent.prototype;\n    proto.events = {};\n    var focusIn = proto.events[goog.events.EventType.FOCUSIN] = {};\n    focusIn[proto.mappings.INPUT] = proto.onFocusIn;\n    var focusOut = proto.events[goog.events.EventType.FOCUSOUT] = {};\n    focusOut[proto.mappings.INPUT] = proto.onFocusOut;\n    var keyup = proto.events[goog.events.EventType.KEYUP] = {};\n    keyup[proto.mappings.INPUT] = proto.onKeyPress;\n})();\n\n"
  },
  {
    "path": "tart/ui/input/RevealingPassword.js",
    "content": "// Copyright 2012 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n\n\n/**\n * @fileoverview This component handles the password entrance and display mode toggling of password string.\n * It takes an optional value defining the minimum length requirement of the password string. If the minimum length\n * requirement is not being meet, it returns an empty string. The display toggler works like a switch for displaying\n * mode. When the value of related variable 'displayPassword' is equal to false, the input area conceals the string\n * entered and displays '*'\n * chars instead. Otherwise, the password string is being displayed as it is.\n */\n\n\n\ngoog.provide('tart.ui.input.RevealingPassword');\ngoog.require('tart.ui.DlgComponent');\n\n\n\n/**\n * @constructor\n * @extends {tart.ui.DlgComponent}\n * @param {{minLength: number}=} opt_options\n */\ntart.ui.input.RevealingPassword = function(opt_options) {\n    goog.base(this);\n\n    this.displayPassword = false;\n    this.minLength = opt_options && opt_options.minLength || 6;\n};\ngoog.inherits(tart.ui.input.RevealingPassword, tart.ui.DlgComponent);\n\n\n/**\n * Returns the password as a string if it meets the requirements, otherwise, it returns an empty string.\n * @return {string} returning value.\n */\ntart.ui.input.RevealingPassword.prototype.getPassword = function() {\n    var passwordArea = this.getChild(this.mappings.INPUT)[0];\n    if (passwordArea.value.length >= this.minLength)\n        return passwordArea.value;\n    else\n        return '';\n};\n\n\n/**\n * Toggles the input area's displaying mode in order to conceal or reveal the text entered.\n *\n */\ntart.ui.input.RevealingPassword.prototype.toggleDisplay = function() {\n    this.displayPassword = !this.displayPassword;\n    var passwordArea = this.getChild(this.mappings.INPUT)[0];\n    if (this.displayPassword)\n        passwordArea.type = 'text';\n    else\n        passwordArea.type = 'password';\n    passwordArea.focus();\n};\n\n\n/**\n * Constructs the base template.\n * @return {string} base template.\n */\ntart.ui.input.RevealingPassword.prototype.templates_base = function() {\n    return '<span id=\"' + this.id + '\" class=\"revealingPassword\">' +\n                '<input name=\"passwordInput\" type=\"password\" class=\"textForm passwordInput passwordInputArea\" ' +\n                'minlength=\"6\" value=\"\"/>' +\n                '<span class=\"visibilityToggler\"></span>' +\n           '</span>';\n};\n\n\n/**\n * Resets the password text area.\n */\ntart.ui.input.RevealingPassword.prototype.resetInputArea = function() {\n    var passwordArea = this.getChild(this.mappings.INPUT)[0];\n    passwordArea.value = '';\n};\n\n\n/**\n * RevealingPassword domMappings.\n * @enum {string}\n */\ntart.ui.input.RevealingPassword.prototype.mappings = {\n    INPUT: '.passwordInput',\n    TOGGLER: '.visibilityToggler'\n};\n\n\n(function() {\n    var proto = tart.ui.input.RevealingPassword.prototype;\n    proto.events = {};\n    var toggleVisibility = proto.events[goog.events.EventType.CLICK] = {};\n    toggleVisibility[proto.mappings.TOGGLER] = proto.toggleDisplay;\n})();\n"
  },
  {
    "path": "tart/ui/tooltip/TooltipComponent.js",
    "content": "// Copyright 2012 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview\n */\n\ngoog.provide('tart.ui.TooltipComponent');\ngoog.require('goog.dom');\ngoog.require('goog.style');\ngoog.require('tart.ui.Component');\ngoog.require('tart.ui.TooltipComponentModel');\n\n\n\n/**\n * @constructor\n * @extends {tart.ui.Component}\n */\ntart.ui.TooltipComponent = function(refElement, options) {\n    this.element = goog.dom.getElement(this.id);\n    this.refElement = refElement;\n    this.model = new this.modelClass(options);\n    if (!this.element) {\n        this.element = /** @type {Element} */(tart.dom.createElement(this.templates_base()));\n        this.element.style.display = 'none';\n        document.body.appendChild(this.element);\n    }\n\n    this.contentArea = goog.dom.getElementsByClass('content', this.element)[0];\n    this.wrapper = goog.dom.getElementsByClass('wrapper', this.element)[0];\n    this.cap = goog.dom.getElementsByClass('cap', this.element)[0];\n\n\n    this.bindModelEvents();\n    this.bindDomEvents();\n};\ngoog.inherits(tart.ui.TooltipComponent, tart.ui.Component);\n\ntart.ui.TooltipComponent.prototype.modelClass = tart.ui.TooltipComponentModel;\n\ntart.ui.TooltipComponent.prototype.id = 'tartTooltip';\ntart.ui.TooltipComponent.prototype.cssClass = 'tartTooltip';\n\n\n/** @param {Element} refElement Reference element. */\ntart.ui.TooltipComponent.prototype.setRefElement = function(refElement) {\n    this.unbindDomEvents();\n    this.refElement = refElement;\n    this.bindDomEvents();\n};\n\n\n/** @override */\ntart.ui.TooltipComponent.prototype.bindDomEvents = function() {\n    switch (this.model.options.type) {\n        case tart.ui.TooltipComponentModel.Type.CLICK:\n            goog.events.listen(this.refElement, goog.events.EventType.CLICK, this.onClick, false, this);\n            break;\n\n        case tart.ui.TooltipComponentModel.Type.HOVER:\n        default:\n            goog.events.listen(this.refElement, [goog.events.EventType.MOUSEOVER, goog.events.EventType.MOUSEOUT],\n                this.onHover, false, this);\n            goog.events.listen(this.element, goog.events.EventType.MOUSEOUT, this.onBoxMouseout, false, this);\n    }\n};\n\ntart.ui.TooltipComponent.prototype.onClick = function(e) {\n    this.model.handleEvent(e.type);\n    e.stopPropagation();\n    this.bodyListen = goog.events.listen(document.body, goog.events.EventType.CLICK, function(e) {\n        if (goog.dom.contains(this.element, e.target))\n            return;\n        goog.events.unlistenByKey(this.bodyListen);\n        this.model.handleEvent(tart.ui.TooltipComponentModel.SMEventType.BODY_CLICK);\n    }, false, this);\n};\n\ntart.ui.TooltipComponent.prototype.onHover = function(e) {\n    if (e.type == goog.events.EventType.MOUSEOUT &&\n        ((e.relatedTarget && goog.dom.contains(this.element, e.relatedTarget)) ||\n        e.relatedTarget == this.element) || e.relatedTarget == null || goog.dom.contains(this.refElement, e.relatedTarget))\n        return;\n    this.model.handleEvent(e.type);\n\n};\n\ntart.ui.TooltipComponent.prototype.onBoxMouseout = function(e) {\n    if (goog.dom.contains(this.element, e.relatedTarget)) {\n        return false;\n    }\n    if (e.relatedTarget != this.refElement)\n        this.model.handleEvent(e.type);\n};\n\n\n/** Unbind DOM event listeners of reference element. */\ntart.ui.TooltipComponent.prototype.unbindDomEvents = function() {\n    var clickListeners = goog.events.getListeners(this.refElement, goog.events.EventType.CLICK, false),\n        mouseOverListeners = goog.events.getListeners(this.refElement, goog.events.EventType.MOUSEOVER, false),\n        mouseOutListeners = goog.events.getListeners(this.refElement, goog.events.EventType.MOUSEOUT, false),\n        listeners = goog.array.concat(clickListeners, mouseOverListeners, mouseOutListeners);\n\n    goog.array.forEach(listeners, function(listener) {\n        goog.events.unlistenByKey(listener);\n    });\n};\n\n\n/** @override */\ntart.ui.TooltipComponent.prototype.bindModelEvents = function() {\n    goog.events.listen(this.model, tart.ui.TooltipComponentModel.EventType.SHOW, this.onShow, undefined, this);\n    goog.events.listen(this.model, tart.ui.TooltipComponentModel.EventType.INIT, this.onInit, undefined, this);\n    goog.events.listen(this.model, tart.ui.TooltipComponentModel.EventType.CLICK_WAIT, this.onWait, undefined,\n        this);\n};\n\n\ntart.ui.TooltipComponent.prototype.onWait = function() {\n    if (this.element.tooltip != this && this.element.tooltip) {\n        this.element.tooltip.reset();\n    }\n    this.element.tooltip = this;\n};\n\n\ntart.ui.TooltipComponent.prototype.onShow = function() {\n    this.contentArea.innerHTML = (this.templates_loading());\n    document.body.appendChild(this.element);\n    this.element.style.display = 'inline-block';\n    this.position();\n\n    this.windowResizeListener = goog.events.listen(window, goog.events.EventType.RESIZE, function(e) {\n        this.position();\n    }, false, this);\n    this.windowScrollListener = goog.events.listen(window, goog.events.EventType.SCROLL, function(e) {\n        this.position();\n    }, false, this);\n};\n\ntart.ui.TooltipComponent.prototype.reset = function() {\n    this.model.reset(); // sends to onInit\n};\n\ntart.ui.TooltipComponent.prototype.onInit = function() {\n    this.element.style.display = 'none';\n    goog.events.unlistenByKey(this.windowResizeListener);\n    goog.events.unlistenByKey(this.windowScrollListener);\n};\n\n\n/**\n * This function returns the base of the tooltip as a string.\n * @return {string}\n */\ntart.ui.TooltipComponent.prototype.templates_base = function() {\n    return '<div id=\"' + this.id + '\" class=\"' + this.cssClass + '\">' +\n        '<div class=\"wrapper\">' +\n        '<div class=\"content\"></div>' +\n        '<div class=\"cap\"></div>' +\n        '</div>' +\n        '</div>';\n};\n\n\n/**\n * This function returns the content area of the tooltip as a string.\n * @return {string}\n */\ntart.ui.TooltipComponent.prototype.templates_loading = function() {\n    return '<div class=\"loadContainer\"><div class=\"loading\"></div></div>';\n};\n\n\n/**\n * This function takes a string or an element to append into the content area of the tooltip.\n * @param content {string | Element}\n */\ntart.ui.TooltipComponent.prototype.setContent = function(content) {\n    if (typeof content == 'string') {\n        this.contentArea.innerHTML = content;\n    }\n    else {\n        this.contentArea.innerHTML = '';\n        this.contentArea.appendChild(content);\n    }\n\n    this.position();\n};\n\n\n/**\n * This method takes a reference element and uses its offSet and size values along with tooltip element's size values\n * to calculate the right position to display the tooltip. If the toolTip can be shown on the top of the reference\n * element, it positions the tooltip with the distance calculated by this.model's tipOffset and boxOffset values. If it\n * is not to possible to display on top, than it looks for the suitable area to display tooltip. The possible matches\n * are 'right', 'left', 'bottom' and as a default match 'top'.\n *\n **/\ntart.ui.TooltipComponent.prototype.position = function() {\n    var refElementOffset = goog.style.getPageOffset(this.refElement);\n    var refElementSize = goog.style.getSize(this.refElement);\n    var myElementSize = goog.style.getSize(this.element);\n    var myWrapperSize = goog.style.getSize(this.wrapper);\n    var myWindowSize = goog.dom.getViewportSize();\n    var winScrollTop = document.body.scrollTop || window.document.documentElement.scrollTop;\n    var winScrollLeft = document.body.scrollLeft || window.document.documentElement.scrollLeft;\n    var coordinate;\n    var handlerFn;\n\n    var topDown = true;\n    var horizontalShift = 0;\n    var verticalShift = 0;\n    var verticalTipCapShift = 0;\n    var horizontalTipCapShift = 0;\n\n    if (refElementSize.width < this.model.offsetThreshold) {\n        this.model.tipOffset = refElementSize.width / 2;\n    }\n\n    if ((refElementOffset.x < winScrollLeft) &&\n        (refElementOffset.x + refElementSize.width - winScrollLeft < 2 * this.model.tipOffset)) {\n        topDown = false;\n        this.model.options.direction = tart.ui.TooltipComponentModel.Direction.RIGHT;\n        horizontalTipCapShift = -8;\n    }\n\n    if (myWindowSize.width + winScrollLeft - refElementOffset.x < 2 * this.model.tipOffset) {\n        topDown = false;\n        this.model.options.direction = tart.ui.TooltipComponentModel.Direction.LEFT;\n        horizontalTipCapShift = myWrapperSize.width;\n    }\n\n    if (topDown) {\n        if (refElementOffset.x < winScrollLeft) {\n            horizontalShift = winScrollLeft - refElementOffset.x;\n        }\n\n        if (horizontalShift == 0) {\n            if (myWrapperSize.width + (refElementOffset.x - winScrollLeft) > myWindowSize.width &&\n                this.model.options.direction != tart.ui.TooltipComponentModel.Direction.TOP_LEFT) {\n                horizontalShift = horizontalShift +\n                    (myWindowSize.width - myWrapperSize.width - refElementOffset.x + winScrollLeft);\n            }\n        }\n\n        if (refElementOffset.y - winScrollTop >= myElementSize.height + this.model.tipOffset + this.model.boxOffset) {\n            if (this.model.options.direction != tart.ui.TooltipComponentModel.Direction.TOP_LEFT) {\n                this.model.options.direction = tart.ui.TooltipComponentModel.Direction.TOP;\n            }\n            verticalTipCapShift = myWrapperSize.height;\n        }\n        else {\n            this.model.options.direction = tart.ui.TooltipComponentModel.Direction.BOTTOM;\n            verticalTipCapShift = -16;\n        }\n\n        if (this.model.options.direction == tart.ui.TooltipComponentModel.Direction.TOP_LEFT) {\n            horizontalTipCapShift = myWrapperSize.width - 36;\n        } else {\n            horizontalTipCapShift = (horizontalShift >= 0) ? this.model.tipOffset :\n                (-horizontalShift >= myWrapperSize.width - this.model.tipOffset) ?\n                -horizontalShift : this.model.tipOffset - horizontalShift;\n        }\n\n        verticalShift = 0;\n    }\n    else {\n        if (myWindowSize.height + winScrollTop - refElementOffset.y - myElementSize.height < 0) {\n            verticalShift = myWindowSize.height + winScrollTop - refElementOffset.y - myElementSize.height;\n        }\n        if (refElementOffset.y <= winScrollTop) {\n            verticalShift = winScrollTop - refElementOffset.y;\n        }\n\n        if (verticalShift >= 0) {\n            verticalTipCapShift = this.model.tipOffset;\n        }\n        else {\n            verticalTipCapShift = (this.model.tipOffset - verticalShift >= myElementSize.height - this.model.tipOffset) ?\n                myElementSize.height - this.model.tipOffset : this.model.tipOffset - verticalShift;\n        }\n\n        if (this.model.tipOffset >= myElementSize.height / 2) {\n            verticalTipCapShift = myElementSize.height / 2 - 1;\n        }\n    }\n\n    this.wrapper.appendChild(this.cap);\n    goog.dom.classlist.remove(this.element, 'right', 'left', 'top', 'bottom', 'topLeft');\n    goog.dom.classlist.add(this.element, this.model.options.direction);\n    this.cap.style.top = verticalTipCapShift + 'px';\n    this.cap.style.left = horizontalTipCapShift + 'px';\n\n    switch (this.model.options.direction) {\n        case tart.ui.TooltipComponentModel.Direction.LEFT:\n            handlerFn = this.positionLeft;\n            break;\n        case tart.ui.TooltipComponentModel.Direction.RIGHT:\n            handlerFn = this.positionRight;\n            break;\n        case tart.ui.TooltipComponentModel.Direction.BOTTOM:\n            handlerFn = this.positionBottom;\n            break;\n        case tart.ui.TooltipComponentModel.Direction.TOP:\n            handlerFn = this.positionTop;\n            break;\n        case tart.ui.TooltipComponentModel.Direction.TOP_LEFT:\n            handlerFn = this.positionTopLeft;\n            break;\n        default:\n            handlerFn = this.positionTop;\n            break;\n    }\n\n    coordinate = handlerFn.call(this, refElementOffset, refElementSize, myElementSize);\n    this.element.style.top = coordinate.y + verticalShift + 'px';\n    this.element.style.left = coordinate.x + horizontalShift + 'px';\n};\n\n\n/**\n * @protected\n *\n * @param refElementOffset {goog.math.Coordinate}\n * @param refElementSize {goog.math.Size}\n * @param myElementSize {goog.math.Size}\n * @return {goog.math.Coordinate}\n */\ntart.ui.TooltipComponent.prototype.positionLeft = function(refElementOffset, refElementSize, myElementSize) {\n    var y = refElementOffset.y - 16;\n    var x = refElementOffset.x - (myElementSize.width);\n\n    return new goog.math.Coordinate(x, y);\n};\n\n\n/**\n * @protected\n *\n * @param refElementOffset {goog.math.Coordinate}\n * @param refElementSize {goog.math.Size}\n * @param myElementSize {goog.math.Size}\n * @return {goog.math.Coordinate}\n */\ntart.ui.TooltipComponent.prototype.positionTop = function(refElementOffset, refElementSize, myElementSize) {\n    var y = refElementOffset.y - (myElementSize.height);\n    var x = refElementOffset.x - 16;\n\n    return new goog.math.Coordinate(x, y);\n};\n\n\n/**\n * @protected\n *\n * @param refElementOffset {goog.math.Coordinate}\n * @param refElementSize {goog.math.Size}\n * @param myElementSize {goog.math.Size}\n * @return {goog.math.Coordinate}\n */\ntart.ui.TooltipComponent.prototype.positionTopLeft = function(refElementOffset, refElementSize, myElementSize) {\n    var y = refElementOffset.y - (myElementSize.height);\n    var x = refElementOffset.x - (myElementSize.width) + 80;\n\n    return new goog.math.Coordinate(x, y);\n};\n\n\n/**\n * @protected\n *\n * @param refElementOffset {goog.math.Coordinate}\n * @param refElementSize {goog.math.Size}\n * @param myElementSize {goog.math.Size}\n * @return {goog.math.Coordinate}\n */\ntart.ui.TooltipComponent.prototype.positionBottom = function(refElementOffset, refElementSize, myElementSize) {\n    var y = refElementOffset.y + refElementSize.height;\n    var x = refElementOffset.x - 16;\n\n    return new goog.math.Coordinate(x, y);\n};\n\n\n/**\n * @protected\n *\n * @param refElementOffset {goog.math.Coordinate}\n * @param refElementSize {goog.math.Size}\n * @param myElementSize {goog.math.Size}\n * @return {goog.math.Coordinate}\n */\ntart.ui.TooltipComponent.prototype.positionRight = function(refElementOffset, refElementSize, myElementSize) {\n    var y = refElementOffset.y - 16;\n    var x = refElementOffset.x + refElementSize.width;\n\n    return new goog.math.Coordinate(x, y);\n};\n"
  },
  {
    "path": "tart/ui/tooltip/TooltipComponentModel.js",
    "content": "// Copyright 2012 Tart. All Rights Reserved.\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n//      http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS-IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\n/**\n * @fileoverview\n */\n\ngoog.provide('tart.ui.TooltipComponentModel');\ngoog.require('tart.ui.ComponentModel');\ngoog.require('tart.StateMachine');\n\n\n\n/**\n * @constructor\n * @extends {tart.ui.ComponentModel}\n */\ntart.ui.TooltipComponentModel = function(options) {\n    options = options || {};\n    this.options = {};\n    this.options.timeout = options.timeout || this.timeout;\n    this.options.type = options.type || this.type;\n    this.options.direction = options.direction || this.direction;\n    this.initStateMachine();\n};\ngoog.inherits(tart.ui.TooltipComponentModel, tart.ui.ComponentModel);\n\n\n/**\n * How long it should take the tooltip to appear for a given event type, in milliseconds.\n * Timeout 0 is instant activation.\n *\n * @type {number}\n */\ntart.ui.TooltipComponentModel.prototype.timeout = 0;\n\n\n/**\n * Actions to trigger this tooltip. It can be triggered on click or on hover. Default is hover.\n *\n * @enum {string}\n */\ntart.ui.TooltipComponentModel.Type = {\n    CLICK: 'click',\n    HOVER: 'hover'\n};\n\n\n/**\n * Tooltip is triggered on hover by default.\n *\n * @type {tart.ui.TooltipComponentModel.Type}\n */\ntart.ui.TooltipComponentModel.prototype.type = tart.ui.TooltipComponentModel.Type.HOVER;\n\n\n/**\n * How many pixels away the tip should be with respect to the reference element. For top and bottom directions, this\n * is horizontal. For left and right this is vertical. Element (box) positioning is fluid, but this distance should\n * always be kept.\n *\n * @type {number}\n */\ntart.ui.TooltipComponentModel.prototype.tipOffset = 20;\n\n\n/**\n * How many pixels away the box (element) should be positioned with respect to the reference element.\n *\n * @type {number}\n */\ntart.ui.TooltipComponentModel.prototype.boxOffset = 3;\n\n\n/**\n * If the size of the reference element is greater than this threshold, the tip should be placed at a distance of\n * tipOffset. Else, the tip should point to the center of the reference element.\n *\n * @type {number}\n */\ntart.ui.TooltipComponentModel.prototype.offsetThreshold = 30;\n\n\n/**\n * Events that this model dispatches at corresponding states\n *\n * @enum {string}\n */\ntart.ui.TooltipComponentModel.EventType = {\n    INIT: 'init',\n    SHOW: 'show',\n    CLICK_WAIT: 'clickWait',\n    HOVER_WAIT: 'hoverWait'\n};\n\n\n/**\n * Transition events for the internal state machine\n * @enum {string}\n */\ntart.ui.TooltipComponentModel.SMEventType = {\n    TIMEOUT: 'timeout',\n    BODY_CLICK: 'bodyClick',\n    MOUSEOVER: goog.events.EventType.MOUSEOVER,\n    MOUSEOUT: goog.events.EventType.MOUSEOUT,\n    CLICK: goog.events.EventType.CLICK\n};\n\n\n/**\n * Direction this tooltip will be shown regarding the reference element.\n * @enum {string}\n */\ntart.ui.TooltipComponentModel.Direction = {\n    TOP: 'top',\n    BOTTOM: 'bottom',\n    LEFT: 'left',\n    RIGHT: 'right',\n    TOP_LEFT: 'topLeft'\n};\n\ntart.ui.TooltipComponentModel.prototype.direction = tart.ui.TooltipComponentModel.Direction.TOP;\n\n\n/**\n * @protected\n */\ntart.ui.TooltipComponentModel.prototype.initStateMachine = function() {\n    var that = this;\n    this.mEvents = tart.ui.TooltipComponentModel.EventType;\n\n    /** @protected */\n    this.stateMachine = new tart.StateMachine();\n    this.stateMachine.smEvents = tart.ui.TooltipComponentModel.SMEventType;\n\n    this.timeoutHandler = false;\n\n    this.stateMachine.createStates = function() {\n        var sm = this;\n\n        var INIT = new tart.State(function() {\n            clearTimeout(that.timeoutHandler);\n            that.dispatchEvent({\n                type: that.mEvents.INIT\n            });\n        });\n        var CLICK_WAIT = new tart.State(function() {\n            that.dispatchEvent({\n                type: that.mEvents.CLICK_WAIT\n            });\n            that.timeoutHandler = setTimeout(function() {\n                sm.publish(sm.smEvents.TIMEOUT);\n            }, that.options.timeout);\n        });\n        var SHOW = new tart.State(function() {\n            clearTimeout(that.timeoutHandler);\n            that.dispatchEvent({\n                type: that.mEvents.SHOW\n            });\n        });\n        var HOVER_WAIT = new tart.State(function() {\n            that.dispatchEvent({\n                type: that.mEvents.HOVER_WAIT\n            });\n            that.timeoutHandler = setTimeout(function() {\n                sm.publish(sm.smEvents.TIMEOUT);\n            }, that.options.timeout);\n        });\n\n        switch (that.options.type) {\n            case tart.ui.TooltipComponentModel.Type.CLICK:\n                INIT.transitions[this.smEvents.CLICK] = CLICK_WAIT;\n                CLICK_WAIT.transitions[this.smEvents.BODY_CLICK] = INIT;\n                CLICK_WAIT.transitions[this.smEvents.TIMEOUT] = SHOW;\n                SHOW.transitions[this.smEvents.BODY_CLICK] = INIT;\n                SHOW.transitions[this.smEvents.CLICK] = INIT;\n\n                break;\n\n            case tart.ui.TooltipComponentModel.Type.HOVER:\n            default:\n                INIT.transitions[this.smEvents.MOUSEOVER] = HOVER_WAIT;\n                HOVER_WAIT.transitions[this.smEvents.MOUSEOUT] = INIT;\n                HOVER_WAIT.transitions[this.smEvents.TIMEOUT] = SHOW;\n                SHOW.transitions[this.smEvents.MOUSEOUT] = INIT;\n        }\n\n        this.addState(INIT);\n        this.addState(CLICK_WAIT);\n        this.addState(SHOW);\n        this.addState(HOVER_WAIT);\n        return INIT;\n    }\n\n    this.stateMachine.startMachine();\n};\n\n\n/**\n * @param {string} type\n */\ntart.ui.TooltipComponentModel.prototype.handleEvent = function(type) {\n    this.stateMachine.publish(type);\n};\n\n\ntart.ui.TooltipComponentModel.prototype.reset = function() {\n    this.stateMachine.reset();\n};\n"
  },
  {
    "path": "third_party/jquery/jquery-1.5.2.js",
    "content": "/*!\n * jQuery JavaScript Library v1.5.2\n * http://jquery.com/\n *\n * Copyright 2011, John Resig\n * Dual licensed under the MIT or GPL Version 2 licenses.\n * http://jquery.org/license\n *\n * Includes Sizzle.js\n * http://sizzlejs.com/\n * Copyright 2011, The Dojo Foundation\n * Released under the MIT, BSD, and GPL Licenses.\n *\n * Date: Thu Mar 31 15:28:23 2011 -0400\n */\n(function( window, undefined ) {\n\n// Use the correct document accordingly with window argument (sandbox)\n    var document = window.document;\n    var jQuery = (function() {\n\n// Define a local copy of jQuery\n        var jQuery = function( selector, context ) {\n                // The jQuery object is actually just the init constructor 'enhanced'\n                return new jQuery.fn.init( selector, context, rootjQuery );\n            },\n\n        // Map over jQuery in case of overwrite\n            _jQuery = window.jQuery,\n\n        // Map over the $ in case of overwrite\n            _$ = window.$,\n\n        // A central reference to the root jQuery(document)\n            rootjQuery,\n\n        // A simple way to check for HTML strings or ID strings\n        // (both of which we optimize for)\n            quickExpr = /^(?:[^<]*(<[\\w\\W]+>)[^>]*$|#([\\w\\-]+)$)/,\n\n        // Check if a string has a non-whitespace character in it\n            rnotwhite = /\\S/,\n\n        // Used for trimming whitespace\n            trimLeft = /^\\s+/,\n            trimRight = /\\s+$/,\n\n        // Check for digits\n            rdigit = /\\d/,\n\n        // Match a standalone tag\n            rsingleTag = /^<(\\w+)\\s*\\/?>(?:<\\/\\1>)?$/,\n\n        // JSON RegExp\n            rvalidchars = /^[\\],:{}\\s]*$/,\n            rvalidescape = /\\\\(?:[\"\\\\\\/bfnrt]|u[0-9a-fA-F]{4})/g,\n            rvalidtokens = /\"[^\"\\\\\\n\\r]*\"|true|false|null|-?\\d+(?:\\.\\d*)?(?:[eE][+\\-]?\\d+)?/g,\n            rvalidbraces = /(?:^|:|,)(?:\\s*\\[)+/g,\n\n        // Useragent RegExp\n            rwebkit = /(webkit)[ \\/]([\\w.]+)/,\n            ropera = /(opera)(?:.*version)?[ \\/]([\\w.]+)/,\n            rmsie = /(msie) ([\\w.]+)/,\n            rmozilla = /(mozilla)(?:.*? rv:([\\w.]+))?/,\n\n        // Keep a UserAgent string for use with jQuery.browser\n            userAgent = navigator.userAgent,\n\n        // For matching the engine and version of the browser\n            browserMatch,\n\n        // The deferred used on DOM ready\n            readyList,\n\n        // The ready event handler\n            DOMContentLoaded,\n\n        // Save a reference to some core methods\n            toString = Object.prototype.toString,\n            hasOwn = Object.prototype.hasOwnProperty,\n            push = Array.prototype.push,\n            slice = Array.prototype.slice,\n            trim = String.prototype.trim,\n            indexOf = Array.prototype.indexOf,\n\n        // [[Class]] -> type pairs\n            class2type = {};\n\n        jQuery.fn = jQuery.prototype = {\n            constructor: jQuery,\n            init: function( selector, context, rootjQuery ) {\n                var match, elem, ret, doc;\n\n                // Handle $(\"\"), $(null), or $(undefined)\n                if ( !selector ) {\n                    return this;\n                }\n\n                // Handle $(DOMElement)\n                if ( selector.nodeType ) {\n                    this.context = this[0] = selector;\n                    this.length = 1;\n                    return this;\n                }\n\n                // The body element only exists once, optimize finding it\n                if ( selector === \"body\" && !context && document.body ) {\n                    this.context = document;\n                    this[0] = document.body;\n                    this.selector = \"body\";\n                    this.length = 1;\n                    return this;\n                }\n\n                // Handle HTML strings\n                if ( typeof selector === \"string\" ) {\n                    // Are we dealing with HTML string or an ID?\n                    match = quickExpr.exec( selector );\n\n                    // Verify a match, and that no context was specified for #id\n                    if ( match && (match[1] || !context) ) {\n\n                        // HANDLE: $(html) -> $(array)\n                        if ( match[1] ) {\n                            context = context instanceof jQuery ? context[0] : context;\n                            doc = (context ? context.ownerDocument || context : document);\n\n                            // If a single string is passed in and it's a single tag\n                            // just do a createElement and skip the rest\n                            ret = rsingleTag.exec( selector );\n\n                            if ( ret ) {\n                                if ( jQuery.isPlainObject( context ) ) {\n                                    selector = [ document.createElement( ret[1] ) ];\n                                    jQuery.fn.attr.call( selector, context, true );\n\n                                } else {\n                                    selector = [ doc.createElement( ret[1] ) ];\n                                }\n\n                            } else {\n                                ret = jQuery.buildFragment( [ match[1] ], [ doc ] );\n                                selector = (ret.cacheable ? jQuery.clone(ret.fragment) : ret.fragment).childNodes;\n                            }\n\n                            return jQuery.merge( this, selector );\n\n                            // HANDLE: $(\"#id\")\n                        } else {\n                            elem = document.getElementById( match[2] );\n\n                            // Check parentNode to catch when Blackberry 4.6 returns\n                            // nodes that are no longer in the document #6963\n                            if ( elem && elem.parentNode ) {\n                                // Handle the case where IE and Opera return items\n                                // by name instead of ID\n                                if ( elem.id !== match[2] ) {\n                                    return rootjQuery.find( selector );\n                                }\n\n                                // Otherwise, we inject the element directly into the jQuery object\n                                this.length = 1;\n                                this[0] = elem;\n                            }\n\n                            this.context = document;\n                            this.selector = selector;\n                            return this;\n                        }\n\n                        // HANDLE: $(expr, $(...))\n                    } else if ( !context || context.jquery ) {\n                        return (context || rootjQuery).find( selector );\n\n                        // HANDLE: $(expr, context)\n                        // (which is just equivalent to: $(context).find(expr)\n                    } else {\n                        return $( context ).find( selector );\n                    }\n\n                    // HANDLE: $(function)\n                    // Shortcut for document ready\n                } else if ( jQuery.isFunction( selector ) ) {\n                    return rootjQuery.ready( selector );\n                }\n\n                if (selector.selector !== undefined) {\n                    this.selector = selector.selector;\n                    this.context = selector.context;\n                }\n\n                return jQuery.makeArray( selector, this );\n            },\n\n            // Start with an empty selector\n            selector: \"\",\n\n            // The current version of jQuery being used\n            jquery: \"1.5.2\",\n\n            // The default length of a jQuery object is 0\n            length: 0,\n\n            // The number of elements contained in the matched element set\n            size: function() {\n                return this.length;\n            },\n\n            toArray: function() {\n                return slice.call( this, 0 );\n            },\n\n            // Get the Nth element in the matched element set OR\n            // Get the whole matched element set as a clean array\n            get: function( num ) {\n                return num == null ?\n\n                    // Return a 'clean' array\n                    this.toArray() :\n\n                    // Return just the object\n                    ( num < 0 ? this[ this.length + num ] : this[ num ] );\n            },\n\n            // Take an array of elements and push it onto the stack\n            // (returning the new matched element set)\n            pushStack: function( elems, name, selector ) {\n                // Build a new jQuery matched element set\n                var ret = $();\n\n                if ( jQuery.isArray( elems ) ) {\n                    push.apply( ret, elems );\n\n                } else {\n                    jQuery.merge( ret, elems );\n                }\n\n                // Add the old object onto the stack (as a reference)\n                ret.prevObject = this;\n\n                ret.context = this.context;\n\n                if ( name === \"find\" ) {\n                    ret.selector = this.selector + (this.selector ? \" \" : \"\") + selector;\n                } else if ( name ) {\n                    ret.selector = this.selector + \".\" + name + \"(\" + selector + \")\";\n                }\n\n                // Return the newly-formed element set\n                return ret;\n            },\n\n            // Execute a callback for every element in the matched set.\n            // (You can seed the arguments with an array of args, but this is\n            // only used internally.)\n            each: function( callback, args ) {\n                return jQuery.each( this, callback, args );\n            },\n\n            ready: function( fn ) {\n                // Attach the listeners\n                jQuery.bindReady();\n\n                // Add the callback\n                readyList.done( fn );\n\n                return this;\n            },\n\n            eq: function( i ) {\n                return i === -1 ?\n                    this.slice( i ) :\n                    this.slice( i, +i + 1 );\n            },\n\n            first: function() {\n                return this.eq( 0 );\n            },\n\n            last: function() {\n                return this.eq( -1 );\n            },\n\n            slice: function() {\n                return this.pushStack( slice.apply( this, arguments ),\n                    \"slice\", slice.call(arguments).join(\",\") );\n            },\n\n            map: function( callback ) {\n                return this.pushStack( jQuery.map(this, function( elem, i ) {\n                    return callback.call( elem, i, elem );\n                }));\n            },\n\n            end: function() {\n                return this.prevObject || this.constructor(null);\n            },\n\n            // For internal use only.\n            // Behaves like an Array's method, not like a jQuery method.\n            push: push,\n            sort: [].sort,\n            splice: [].splice\n        };\n\n// Give the init function the jQuery prototype for later instantiation\n        jQuery.fn.init.prototype = jQuery.fn;\n\n        jQuery.extend = jQuery.fn.extend = function() {\n            var options, name, src, copy, copyIsArray, clone,\n                target = arguments[0] || {},\n                i = 1,\n                length = arguments.length,\n                deep = false;\n\n            // Handle a deep copy situation\n            if ( typeof target === \"boolean\" ) {\n                deep = target;\n                target = arguments[1] || {};\n                // skip the boolean and the target\n                i = 2;\n            }\n\n            // Handle case when target is a string or something (possible in deep copy)\n            if ( typeof target !== \"object\" && !jQuery.isFunction(target) ) {\n                target = {};\n            }\n\n            // extend jQuery itself if only one argument is passed\n            if ( length === i ) {\n                target = this;\n                --i;\n            }\n\n            for ( ; i < length; i++ ) {\n                // Only deal with non-null/undefined values\n                if ( (options = arguments[ i ]) != null ) {\n                    // Extend the base object\n                    for ( name in options ) {\n                        src = target[ name ];\n                        copy = options[ name ];\n\n                        // Prevent never-ending loop\n                        if ( target === copy ) {\n                            continue;\n                        }\n\n                        // Recurse if we're merging plain objects or arrays\n                        if ( deep && copy && ( jQuery.isPlainObject(copy) || (copyIsArray = jQuery.isArray(copy)) ) ) {\n                            if ( copyIsArray ) {\n                                copyIsArray = false;\n                                clone = src && jQuery.isArray(src) ? src : [];\n\n                            } else {\n                                clone = src && jQuery.isPlainObject(src) ? src : {};\n                            }\n\n                            // Never move original objects, clone them\n                            target[ name ] = jQuery.extend( deep, clone, copy );\n\n                            // Don't bring in undefined values\n                        } else if ( copy !== undefined ) {\n                            target[ name ] = copy;\n                        }\n                    }\n                }\n            }\n\n            // Return the modified object\n            return target;\n        };\n\n        jQuery.extend({\n            noConflict: function( deep ) {\n                window.$ = _$;\n\n                if ( deep ) {\n                    window.jQuery = _jQuery;\n                }\n\n                return jQuery;\n            },\n\n            // Is the DOM ready to be used? Set to true once it occurs.\n            isReady: false,\n\n            // A counter to track how many items to wait for before\n            // the ready event fires. See #6781\n            readyWait: 1,\n\n            // Handle when the DOM is ready\n            ready: function( wait ) {\n                // A third-party is pushing the ready event forwards\n                if ( wait === true ) {\n                    jQuery.readyWait--;\n                }\n\n                // Make sure that the DOM is not already loaded\n                if ( !jQuery.readyWait || (wait !== true && !jQuery.isReady) ) {\n                    // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).\n                    if ( !document.body ) {\n                        return setTimeout( jQuery.ready, 1 );\n                    }\n\n                    // Remember that the DOM is ready\n                    jQuery.isReady = true;\n\n                    // If a normal DOM Ready event fired, decrement, and wait if need be\n                    if ( wait !== true && --jQuery.readyWait > 0 ) {\n                        return;\n                    }\n\n                    // If there are functions bound, to execute\n                    readyList.resolveWith( document, [ jQuery ] );\n\n                    // Trigger any bound ready events\n                    if ( jQuery.fn.trigger ) {\n                        jQuery( document ).trigger( \"ready\" ).unbind( \"ready\" );\n                    }\n                }\n            },\n\n            bindReady: function() {\n                if ( readyList ) {\n                    return;\n                }\n\n                readyList = jQuery._Deferred();\n\n                // Catch cases where $(document).ready() is called after the\n                // browser event has already occurred.\n                if ( document.readyState === \"complete\" ) {\n                    // Handle it asynchronously to allow scripts the opportunity to delay ready\n                    return setTimeout( jQuery.ready, 1 );\n                }\n\n                // Mozilla, Opera and webkit nightlies currently support this event\n                if ( document.addEventListener ) {\n                    // Use the handy event callback\n                    document.addEventListener( \"DOMContentLoaded\", DOMContentLoaded, false );\n\n                    // A fallback to window.onload, that will always work\n                    window.addEventListener( \"load\", jQuery.ready, false );\n\n                    // If IE event model is used\n                } else if ( document.attachEvent ) {\n                    // ensure firing before onload,\n                    // maybe late but safe also for iframes\n                    document.attachEvent(\"onreadystatechange\", DOMContentLoaded);\n\n                    // A fallback to window.onload, that will always work\n                    window.attachEvent( \"onload\", jQuery.ready );\n\n                    // If IE and not a frame\n                    // continually check to see if the document is ready\n                    var toplevel = false;\n\n                    try {\n                        toplevel = window.frameElement == null;\n                    } catch(e) {}\n\n                    if ( document.documentElement.doScroll && toplevel ) {\n                        doScrollCheck();\n                    }\n                }\n            },\n\n            // See test/unit/core.js for details concerning isFunction.\n            // Since version 1.3, DOM methods and functions like alert\n            // aren't supported. They return false on IE (#2968).\n            isFunction: function( obj ) {\n                return jQuery.type(obj) === \"function\";\n            },\n\n            isArray: Array.isArray || function( obj ) {\n                return jQuery.type(obj) === \"array\";\n            },\n\n            // A crude way of determining if an object is a window\n            isWindow: function( obj ) {\n                return obj && typeof obj === \"object\" && \"setInterval\" in obj;\n            },\n\n            isNaN: function( obj ) {\n                return obj == null || !rdigit.test( obj ) || isNaN( obj );\n            },\n\n            type: function( obj ) {\n                return obj == null ?\n                    String( obj ) :\n                    class2type[ toString.call(obj) ] || \"object\";\n            },\n\n            isPlainObject: function( obj ) {\n                // Must be an Object.\n                // Because of IE, we also have to check the presence of the constructor property.\n                // Make sure that DOM nodes and window objects don't pass through, as well\n                if ( !obj || jQuery.type(obj) !== \"object\" || obj.nodeType || jQuery.isWindow( obj ) ) {\n                    return false;\n                }\n\n                // Not own constructor property must be Object\n                if ( obj.constructor &&\n                    !hasOwn.call(obj, \"constructor\") &&\n                    !hasOwn.call(obj.constructor.prototype, \"isPrototypeOf\") ) {\n                    return false;\n                }\n\n                // Own properties are enumerated firstly, so to speed up,\n                // if last one is own, then all properties are own.\n\n                var key;\n                for ( key in obj ) {}\n\n                return key === undefined || hasOwn.call( obj, key );\n            },\n\n            isEmptyObject: function( obj ) {\n                for ( var name in obj ) {\n                    return false;\n                }\n                return true;\n            },\n\n            error: function( msg ) {\n                throw msg;\n            },\n\n            parseJSON: function( data ) {\n                if ( typeof data !== \"string\" || !data ) {\n                    return null;\n                }\n\n                // Make sure leading/trailing whitespace is removed (IE can't handle it)\n                data = jQuery.trim( data );\n\n                // Make sure the incoming data is actual JSON\n                // Logic borrowed from http://json.org/json2.js\n                if ( rvalidchars.test(data.replace(rvalidescape, \"@\")\n                    .replace(rvalidtokens, \"]\")\n                    .replace(rvalidbraces, \"\")) ) {\n\n                    // Try to use the native JSON parser first\n                    return window.JSON && window.JSON.parse ?\n                        window.JSON.parse( data ) :\n                        (new Function(\"return \" + data))();\n\n                } else {\n                    jQuery.error( \"Invalid JSON: \" + data );\n                }\n            },\n\n            // Cross-browser xml parsing\n            // (xml & tmp used internally)\n            parseXML: function( data , xml , tmp ) {\n\n                if ( window.DOMParser ) { // Standard\n                    tmp = new DOMParser();\n                    xml = tmp.parseFromString( data , \"text/xml\" );\n                } else { // IE\n                    xml = new ActiveXObject( \"Microsoft.XMLDOM\" );\n                    xml.async = \"false\";\n                    xml.loadXML( data );\n                }\n\n                tmp = xml.documentElement;\n\n                if ( ! tmp || ! tmp.nodeName || tmp.nodeName === \"parsererror\" ) {\n                    jQuery.error( \"Invalid XML: \" + data );\n                }\n\n                return xml;\n            },\n\n            noop: function() {},\n\n            // Evalulates a script in a global context\n            globalEval: function( data ) {\n                if ( data && rnotwhite.test(data) ) {\n                    // Inspired by code by Andrea Giammarchi\n                    // http://webreflection.blogspot.com/2007/08/global-scope-evaluation-and-dom.html\n                    var head = document.head || document.getElementsByTagName( \"head\" )[0] || document.documentElement,\n                        script = document.createElement( \"script\" );\n\n                    if ( jQuery.support.scriptEval() ) {\n                        script.appendChild( document.createTextNode( data ) );\n                    } else {\n                        script.text = data;\n                    }\n\n                    // Use insertBefore instead of appendChild to circumvent an IE6 bug.\n                    // This arises when a base node is used (#2709).\n                    head.insertBefore( script, head.firstChild );\n                    head.removeChild( script );\n                }\n            },\n\n            nodeName: function( elem, name ) {\n                return elem.nodeName && elem.nodeName.toUpperCase() === name.toUpperCase();\n            },\n\n            // args is for internal usage only\n            each: function( object, callback, args ) {\n                var name, i = 0,\n                    length = object.length,\n                    isObj = length === undefined || jQuery.isFunction(object);\n\n                if ( args ) {\n                    if ( isObj ) {\n                        for ( name in object ) {\n                            if ( callback.apply( object[ name ], args ) === false ) {\n                                break;\n                            }\n                        }\n                    } else {\n                        for ( ; i < length; ) {\n                            if ( callback.apply( object[ i++ ], args ) === false ) {\n                                break;\n                            }\n                        }\n                    }\n\n                    // A special, fast, case for the most common use of each\n                } else {\n                    if ( isObj ) {\n                        for ( name in object ) {\n                            if ( callback.call( object[ name ], name, object[ name ] ) === false ) {\n                                break;\n                            }\n                        }\n                    } else {\n                        for ( var value = object[0];\n                              i < length && callback.call( value, i, value ) !== false; value = object[++i] ) {}\n                    }\n                }\n\n                return object;\n            },\n\n            // Use native String.trim function wherever possible\n            trim: trim ?\n                function( text ) {\n                    return text == null ?\n                        \"\" :\n                        trim.call( text );\n                } :\n\n                // Otherwise use our own trimming functionality\n                function( text ) {\n                    return text == null ?\n                        \"\" :\n                        text.toString().replace( trimLeft, \"\" ).replace( trimRight, \"\" );\n                },\n\n            // results is for internal usage only\n            makeArray: function( array, results ) {\n                var ret = results || [];\n\n                if ( array != null ) {\n                    // The window, strings (and functions) also have 'length'\n                    // The extra typeof function check is to prevent crashes\n                    // in Safari 2 (See: #3039)\n                    // Tweaked logic slightly to handle Blackberry 4.7 RegExp issues #6930\n                    var type = jQuery.type(array);\n\n                    if ( array.length == null || type === \"string\" || type === \"function\" || type === \"regexp\" || jQuery.isWindow( array ) ) {\n                        push.call( ret, array );\n                    } else {\n                        jQuery.merge( ret, array );\n                    }\n                }\n\n                return ret;\n            },\n\n            inArray: function( elem, array ) {\n                if ( array.indexOf ) {\n                    return array.indexOf( elem );\n                }\n\n                for ( var i = 0, length = array.length; i < length; i++ ) {\n                    if ( array[ i ] === elem ) {\n                        return i;\n                    }\n                }\n\n                return -1;\n            },\n\n            merge: function( first, second ) {\n                var i = first.length,\n                    j = 0;\n\n                if ( typeof second.length === \"number\" ) {\n                    for ( var l = second.length; j < l; j++ ) {\n                        first[ i++ ] = second[ j ];\n                    }\n\n                } else {\n                    while ( second[j] !== undefined ) {\n                        first[ i++ ] = second[ j++ ];\n                    }\n                }\n\n                first.length = i;\n\n                return first;\n            },\n\n            grep: function( elems, callback, inv ) {\n                var ret = [], retVal;\n                inv = !!inv;\n\n                // Go through the array, only saving the items\n                // that pass the validator function\n                for ( var i = 0, length = elems.length; i < length; i++ ) {\n                    retVal = !!callback( elems[ i ], i );\n                    if ( inv !== retVal ) {\n                        ret.push( elems[ i ] );\n                    }\n                }\n\n                return ret;\n            },\n\n            // arg is for internal usage only\n            map: function( elems, callback, arg ) {\n                var ret = [], value;\n\n                // Go through the array, translating each of the items to their\n                // new value (or values).\n                for ( var i = 0, length = elems.length; i < length; i++ ) {\n                    value = callback( elems[ i ], i, arg );\n\n                    if ( value != null ) {\n                        ret[ ret.length ] = value;\n                    }\n                }\n\n                // Flatten any nested arrays\n                return ret.concat.apply( [], ret );\n            },\n\n            // A global GUID counter for objects\n            guid: 1,\n\n            proxy: function( fn, proxy, thisObject ) {\n                if ( arguments.length === 2 ) {\n                    if ( typeof proxy === \"string\" ) {\n                        thisObject = fn;\n                        fn = thisObject[ proxy ];\n                        proxy = undefined;\n\n                    } else if ( proxy && !jQuery.isFunction( proxy ) ) {\n                        thisObject = proxy;\n                        proxy = undefined;\n                    }\n                }\n\n                if ( !proxy && fn ) {\n                    proxy = function() {\n                        return fn.apply( thisObject || this, arguments );\n                    };\n                }\n\n                // Set the guid of unique handler to the same of original handler, so it can be removed\n                if ( fn ) {\n                    proxy.guid = fn.guid = fn.guid || proxy.guid || jQuery.guid++;\n                }\n\n                // So proxy can be declared as an argument\n                return proxy;\n            },\n\n            // Mutifunctional method to get and set values to a collection\n            // The value/s can be optionally by executed if its a function\n            access: function( elems, key, value, exec, fn, pass ) {\n                var length = elems.length;\n\n                // Setting many attributes\n                if ( typeof key === \"object\" ) {\n                    for ( var k in key ) {\n                        jQuery.access( elems, k, key[k], exec, fn, value );\n                    }\n                    return elems;\n                }\n\n                // Setting one attribute\n                if ( value !== undefined ) {\n                    // Optionally, function values get executed if exec is true\n                    exec = !pass && exec && jQuery.isFunction(value);\n\n                    for ( var i = 0; i < length; i++ ) {\n                        fn( elems[i], key, exec ? value.call( elems[i], i, fn( elems[i], key ) ) : value, pass );\n                    }\n\n                    return elems;\n                }\n\n                // Getting an attribute\n                return length ? fn( elems[0], key ) : undefined;\n            },\n\n            now: function() {\n                return (new Date()).getTime();\n            },\n\n            // Use of jQuery.browser is frowned upon.\n            // More details: http://docs.jquery.com/Utilities/jQuery.browser\n            uaMatch: function( ua ) {\n                ua = ua.toLowerCase();\n\n                var match = rwebkit.exec( ua ) ||\n                    ropera.exec( ua ) ||\n                    rmsie.exec( ua ) ||\n                    ua.indexOf(\"compatible\") < 0 && rmozilla.exec( ua ) ||\n                    [];\n\n                return { browser: match[1] || \"\", version: match[2] || \"0\" };\n            },\n\n            sub: function() {\n                function jQuerySubclass( selector, context ) {\n                    return new jQuerySubclass.fn.init( selector, context );\n                }\n                jQuery.extend( true, jQuerySubclass, this );\n                jQuerySubclass.superclass = this;\n                jQuerySubclass.fn = jQuerySubclass.prototype = this();\n                jQuerySubclass.fn.constructor = jQuerySubclass;\n                jQuerySubclass.subclass = this.subclass;\n                jQuerySubclass.fn.init = function init( selector, context ) {\n                    if ( context && context instanceof jQuery && !(context instanceof jQuerySubclass) ) {\n                        context = jQuerySubclass(context);\n                    }\n\n                    return jQuery.fn.init.call( this, selector, context, rootjQuerySubclass );\n                };\n                jQuerySubclass.fn.init.prototype = jQuerySubclass.fn;\n                var rootjQuerySubclass = jQuerySubclass(document);\n                return jQuerySubclass;\n            },\n\n            browser: {}\n        });\n\n// Populate the class2type map\n        jQuery.each(\"Boolean Number String Function Array Date RegExp Object\".split(\" \"), function(i, name) {\n            class2type[ \"[object \" + name + \"]\" ] = name.toLowerCase();\n        });\n\n        browserMatch = jQuery.uaMatch( userAgent );\n        if ( browserMatch.browser ) {\n            jQuery.browser[ browserMatch.browser ] = true;\n            jQuery.browser.version = browserMatch.version;\n        }\n\n// Deprecated, use jQuery.browser.webkit instead\n        if ( jQuery.browser.webkit ) {\n            jQuery.browser.safari = true;\n        }\n\n        if ( indexOf ) {\n            jQuery.inArray = function( elem, array ) {\n                return indexOf.call( array, elem );\n            };\n        }\n\n// IE doesn't match non-breaking spaces with \\s\n        if ( rnotwhite.test( \"\\xA0\" ) ) {\n            trimLeft = /^[\\s\\xA0]+/;\n            trimRight = /[\\s\\xA0]+$/;\n        }\n\n// All jQuery objects should point back to these\n        rootjQuery = jQuery(document);\n\n// Cleanup functions for the document ready method\n        if ( document.addEventListener ) {\n            DOMContentLoaded = function() {\n                document.removeEventListener( \"DOMContentLoaded\", DOMContentLoaded, false );\n                jQuery.ready();\n            };\n\n        } else if ( document.attachEvent ) {\n            DOMContentLoaded = function() {\n                // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).\n                if ( document.readyState === \"complete\" ) {\n                    document.detachEvent( \"onreadystatechange\", DOMContentLoaded );\n                    jQuery.ready();\n                }\n            };\n        }\n\n// The DOM ready check for Internet Explorer\n        function doScrollCheck() {\n            if ( jQuery.isReady ) {\n                return;\n            }\n\n            try {\n                // If IE is used, use the trick by Diego Perini\n                // http://javascript.nwbox.com/IEContentLoaded/\n                document.documentElement.doScroll(\"left\");\n            } catch(e) {\n                setTimeout( doScrollCheck, 1 );\n                return;\n            }\n\n            // and execute any waiting functions\n            jQuery.ready();\n        }\n\n// Expose jQuery to the global object\n        return jQuery;\n\n    })();\n\n\n    var // Promise methods\n        promiseMethods = \"then done fail isResolved isRejected promise\".split( \" \" ),\n    // Static reference to slice\n        sliceDeferred = [].slice;\n\n    jQuery.extend({\n        // Create a simple deferred (one callbacks list)\n        _Deferred: function() {\n            var // callbacks list\n                callbacks = [],\n            // stored [ context , args ]\n                fired,\n            // to avoid firing when already doing so\n                firing,\n            // flag to know if the deferred has been cancelled\n                cancelled,\n            // the deferred itself\n                deferred  = {\n\n                    // done( f1, f2, ...)\n                    done: function() {\n                        if ( !cancelled ) {\n                            var args = arguments,\n                                i,\n                                length,\n                                elem,\n                                type,\n                                _fired;\n                            if ( fired ) {\n                                _fired = fired;\n                                fired = 0;\n                            }\n                            for ( i = 0, length = args.length; i < length; i++ ) {\n                                elem = args[ i ];\n                                type = jQuery.type( elem );\n                                if ( type === \"array\" ) {\n                                    deferred.done.apply( deferred, elem );\n                                } else if ( type === \"function\" ) {\n                                    callbacks.push( elem );\n                                }\n                            }\n                            if ( _fired ) {\n                                deferred.resolveWith( _fired[ 0 ], _fired[ 1 ] );\n                            }\n                        }\n                        return this;\n                    },\n\n                    // resolve with given context and args\n                    resolveWith: function( context, args ) {\n                        if ( !cancelled && !fired && !firing ) {\n                            // make sure args are available (#8421)\n                            args = args || [];\n                            firing = 1;\n                            try {\n                                while( callbacks[ 0 ] ) {\n                                    callbacks.shift().apply( context, args );\n                                }\n                            }\n                            finally {\n                                fired = [ context, args ];\n                                firing = 0;\n                            }\n                        }\n                        return this;\n                    },\n\n                    // resolve with this as context and given arguments\n                    resolve: function() {\n                        deferred.resolveWith( this, arguments );\n                        return this;\n                    },\n\n                    // Has this deferred been resolved?\n                    isResolved: function() {\n                        return !!( firing || fired );\n                    },\n\n                    // Cancel\n                    cancel: function() {\n                        cancelled = 1;\n                        callbacks = [];\n                        return this;\n                    }\n                };\n\n            return deferred;\n        },\n\n        // Full fledged deferred (two callbacks list)\n        Deferred: function( func ) {\n            var deferred = jQuery._Deferred(),\n                failDeferred = jQuery._Deferred(),\n                promise;\n            // Add errorDeferred methods, then and promise\n            jQuery.extend( deferred, {\n                then: function( doneCallbacks, failCallbacks ) {\n                    deferred.done( doneCallbacks ).fail( failCallbacks );\n                    return this;\n                },\n                fail: failDeferred.done,\n                rejectWith: failDeferred.resolveWith,\n                reject: failDeferred.resolve,\n                isRejected: failDeferred.isResolved,\n                // Get a promise for this deferred\n                // If obj is provided, the promise aspect is added to the object\n                promise: function( obj ) {\n                    if ( obj == null ) {\n                        if ( promise ) {\n                            return promise;\n                        }\n                        promise = obj = {};\n                    }\n                    var i = promiseMethods.length;\n                    while( i-- ) {\n                        obj[ promiseMethods[i] ] = deferred[ promiseMethods[i] ];\n                    }\n                    return obj;\n                }\n            } );\n            // Make sure only one callback list will be used\n            deferred.done( failDeferred.cancel ).fail( deferred.cancel );\n            // Unexpose cancel\n            delete deferred.cancel;\n            // Call given func if any\n            if ( func ) {\n                func.call( deferred, deferred );\n            }\n            return deferred;\n        },\n\n        // Deferred helper\n        when: function( firstParam ) {\n            var args = arguments,\n                i = 0,\n                length = args.length,\n                count = length,\n                deferred = length <= 1 && firstParam && jQuery.isFunction( firstParam.promise ) ?\n                    firstParam :\n                    jQuery.Deferred();\n            function resolveFunc( i ) {\n                return function( value ) {\n                    args[ i ] = arguments.length > 1 ? sliceDeferred.call( arguments, 0 ) : value;\n                    if ( !( --count ) ) {\n                        // Strange bug in FF4:\n                        // Values changed onto the arguments object sometimes end up as undefined values\n                        // outside the $.when method. Cloning the object into a fresh array solves the issue\n                        deferred.resolveWith( deferred, sliceDeferred.call( args, 0 ) );\n                    }\n                };\n            }\n            if ( length > 1 ) {\n                for( ; i < length; i++ ) {\n                    if ( args[ i ] && jQuery.isFunction( args[ i ].promise ) ) {\n                        args[ i ].promise().then( resolveFunc(i), deferred.reject );\n                    } else {\n                        --count;\n                    }\n                }\n                if ( !count ) {\n                    deferred.resolveWith( deferred, args );\n                }\n            } else if ( deferred !== firstParam ) {\n                deferred.resolveWith( deferred, length ? [ firstParam ] : [] );\n            }\n            return deferred.promise();\n        }\n    });\n\n\n\n\n    (function() {\n\n        jQuery.support = {};\n\n        var div = document.createElement(\"div\");\n\n        div.style.display = \"none\";\n        div.innerHTML = \"   <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>\";\n\n        var all = div.getElementsByTagName(\"*\"),\n            a = div.getElementsByTagName(\"a\")[0],\n            select = document.createElement(\"select\"),\n            opt = select.appendChild( document.createElement(\"option\") ),\n            input = div.getElementsByTagName(\"input\")[0];\n\n        // Can't get basic test support\n        if ( !all || !all.length || !a ) {\n            return;\n        }\n\n        jQuery.support = {\n            // IE strips leading whitespace when .innerHTML is used\n            leadingWhitespace: div.firstChild.nodeType === 3,\n\n            // Make sure that tbody elements aren't automatically inserted\n            // IE will insert them into empty tables\n            tbody: !div.getElementsByTagName(\"tbody\").length,\n\n            // Make sure that link elements get serialized correctly by innerHTML\n            // This requires a wrapper element in IE\n            htmlSerialize: !!div.getElementsByTagName(\"link\").length,\n\n            // Get the style information from getAttribute\n            // (IE uses .cssText insted)\n            style: /red/.test( a.getAttribute(\"style\") ),\n\n            // Make sure that URLs aren't manipulated\n            // (IE normalizes it by default)\n            hrefNormalized: a.getAttribute(\"href\") === \"/a\",\n\n            // Make sure that element opacity exists\n            // (IE uses filter instead)\n            // Use a regex to work around a WebKit issue. See #5145\n            opacity: /^0.55$/.test( a.style.opacity ),\n\n            // Verify style float existence\n            // (IE uses styleFloat instead of cssFloat)\n            cssFloat: !!a.style.cssFloat,\n\n            // Make sure that if no value is specified for a checkbox\n            // that it defaults to \"on\".\n            // (WebKit defaults to \"\" instead)\n            checkOn: input.value === \"on\",\n\n            // Make sure that a selected-by-default option has a working selected property.\n            // (WebKit defaults to false instead of true, IE too, if it's in an optgroup)\n            optSelected: opt.selected,\n\n            // Will be defined later\n            deleteExpando: true,\n            optDisabled: false,\n            checkClone: false,\n            noCloneEvent: true,\n            noCloneChecked: true,\n            boxModel: null,\n            inlineBlockNeedsLayout: false,\n            shrinkWrapBlocks: false,\n            reliableHiddenOffsets: true,\n            reliableMarginRight: true\n        };\n\n        input.checked = true;\n        jQuery.support.noCloneChecked = input.cloneNode( true ).checked;\n\n        // Make sure that the options inside disabled selects aren't marked as disabled\n        // (WebKit marks them as diabled)\n        select.disabled = true;\n        jQuery.support.optDisabled = !opt.disabled;\n\n        var _scriptEval = null;\n        jQuery.support.scriptEval = function() {\n            if ( _scriptEval === null ) {\n                var root = document.documentElement,\n                    script = document.createElement(\"script\"),\n                    id = \"script\" + jQuery.now();\n\n                // Make sure that the execution of code works by injecting a script\n                // tag with appendChild/createTextNode\n                // (IE doesn't support this, fails, and uses .text instead)\n                try {\n                    script.appendChild( document.createTextNode( \"window.\" + id + \"=1;\" ) );\n                } catch(e) {}\n\n                root.insertBefore( script, root.firstChild );\n\n                if ( window[ id ] ) {\n                    _scriptEval = true;\n                    delete window[ id ];\n                } else {\n                    _scriptEval = false;\n                }\n\n                root.removeChild( script );\n            }\n\n            return _scriptEval;\n        };\n\n        // Test to see if it's possible to delete an expando from an element\n        // Fails in Internet Explorer\n        try {\n            delete div.test;\n\n        } catch(e) {\n            jQuery.support.deleteExpando = false;\n        }\n\n        if ( !div.addEventListener && div.attachEvent && div.fireEvent ) {\n            div.attachEvent(\"onclick\", function click() {\n                // Cloning a node shouldn't copy over any\n                // bound event handlers (IE does this)\n                jQuery.support.noCloneEvent = false;\n                div.detachEvent(\"onclick\", click);\n            });\n            div.cloneNode(true).fireEvent(\"onclick\");\n        }\n\n        div = document.createElement(\"div\");\n        div.innerHTML = \"<input type='radio' name='radiotest' checked='checked'/>\";\n\n        var fragment = document.createDocumentFragment();\n        fragment.appendChild( div.firstChild );\n\n        // WebKit doesn't clone checked state correctly in fragments\n        jQuery.support.checkClone = fragment.cloneNode(true).cloneNode(true).lastChild.checked;\n\n        // Figure out if the W3C box model works as expected\n        // document.body must exist before we can do this\n        jQuery(function() {\n            var div = document.createElement(\"div\"),\n                body = document.getElementsByTagName(\"body\")[0];\n\n            // Frameset documents with no body should not run this code\n            if ( !body ) {\n                return;\n            }\n\n            div.style.width = div.style.paddingLeft = \"1px\";\n            body.appendChild( div );\n            jQuery.boxModel = jQuery.support.boxModel = div.offsetWidth === 2;\n\n            if ( \"zoom\" in div.style ) {\n                // Check if natively block-level elements act like inline-block\n                // elements when setting their display to 'inline' and giving\n                // them layout\n                // (IE < 8 does this)\n                div.style.display = \"inline\";\n                div.style.zoom = 1;\n                jQuery.support.inlineBlockNeedsLayout = div.offsetWidth === 2;\n\n                // Check if elements with layout shrink-wrap their children\n                // (IE 6 does this)\n                div.style.display = \"\";\n                div.innerHTML = \"<div style='width:4px;'></div>\";\n                jQuery.support.shrinkWrapBlocks = div.offsetWidth !== 2;\n            }\n\n            div.innerHTML = \"<table><tr><td style='padding:0;border:0;display:none'></td><td>t</td></tr></table>\";\n            var tds = div.getElementsByTagName(\"td\");\n\n            // Check if table cells still have offsetWidth/Height when they are set\n            // to display:none and there are still other visible table cells in a\n            // table row; if so, offsetWidth/Height are not reliable for use when\n            // determining if an element has been hidden directly using\n            // display:none (it is still safe to use offsets if a parent element is\n            // hidden; don safety goggles and see bug #4512 for more information).\n            // (only IE 8 fails this test)\n            jQuery.support.reliableHiddenOffsets = tds[0].offsetHeight === 0;\n\n            tds[0].style.display = \"\";\n            tds[1].style.display = \"none\";\n\n            // Check if empty table cells still have offsetWidth/Height\n            // (IE < 8 fail this test)\n            jQuery.support.reliableHiddenOffsets = jQuery.support.reliableHiddenOffsets && tds[0].offsetHeight === 0;\n            div.innerHTML = \"\";\n\n            // Check if div with explicit width and no margin-right incorrectly\n            // gets computed margin-right based on width of container. For more\n            // info see bug #3333\n            // Fails in WebKit before Feb 2011 nightlies\n            // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right\n            if ( document.defaultView && document.defaultView.getComputedStyle ) {\n                div.style.width = \"1px\";\n                div.style.marginRight = \"0\";\n                jQuery.support.reliableMarginRight = ( parseInt(document.defaultView.getComputedStyle(div, null).marginRight, 10) || 0 ) === 0;\n            }\n\n            body.removeChild( div ).style.display = \"none\";\n            div = tds = null;\n        });\n\n        // Technique from Juriy Zaytsev\n        // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/\n        var eventSupported = function( eventName ) {\n            var el = document.createElement(\"div\");\n            eventName = \"on\" + eventName;\n\n            // We only care about the case where non-standard event systems\n            // are used, namely in IE. Short-circuiting here helps us to\n            // avoid an eval call (in setAttribute) which can cause CSP\n            // to go haywire. See: https://developer.mozilla.org/en/Security/CSP\n            if ( !el.attachEvent ) {\n                return true;\n            }\n\n            var isSupported = (eventName in el);\n            if ( !isSupported ) {\n                el.setAttribute(eventName, \"return;\");\n                isSupported = typeof el[eventName] === \"function\";\n            }\n            return isSupported;\n        };\n\n        jQuery.support.submitBubbles = eventSupported(\"submit\");\n        jQuery.support.changeBubbles = eventSupported(\"change\");\n\n        // release memory in IE\n        div = all = a = null;\n    })();\n\n\n\n    var rbrace = /^(?:\\{.*\\}|\\[.*\\])$/;\n\n    jQuery.extend({\n        cache: {},\n\n        // Please use with caution\n        uuid: 0,\n\n        // Unique for each copy of jQuery on the page\n        // Non-digits removed to match rinlinejQuery\n        expando: \"jQuery\" + ( jQuery.fn.jquery + Math.random() ).replace( /\\D/g, \"\" ),\n\n        // The following elements throw uncatchable exceptions if you\n        // attempt to add expando properties to them.\n        noData: {\n            \"embed\": true,\n            // Ban all objects except for Flash (which handle expandos)\n            \"object\": \"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000\",\n            \"applet\": true\n        },\n\n        hasData: function( elem ) {\n            elem = elem.nodeType ? jQuery.cache[ elem[jQuery.expando] ] : elem[ jQuery.expando ];\n\n            return !!elem && !isEmptyDataObject( elem );\n        },\n\n        data: function( elem, name, data, pvt /* Internal Use Only */ ) {\n            if ( !jQuery.acceptData( elem ) ) {\n                return;\n            }\n\n            var internalKey = jQuery.expando, getByName = typeof name === \"string\", thisCache,\n\n            // We have to handle DOM nodes and JS objects differently because IE6-7\n            // can't GC object references properly across the DOM-JS boundary\n                isNode = elem.nodeType,\n\n            // Only DOM nodes need the global jQuery cache; JS object data is\n            // attached directly to the object so GC can occur automatically\n                cache = isNode ? jQuery.cache : elem,\n\n            // Only defining an ID for JS objects if its cache already exists allows\n            // the code to shortcut on the same path as a DOM node with no cache\n                id = isNode ? elem[ jQuery.expando ] : elem[ jQuery.expando ] && jQuery.expando;\n\n            // Avoid doing any more work than we need to when trying to get data on an\n            // object that has no data at all\n            if ( (!id || (pvt && id && !cache[ id ][ internalKey ])) && getByName && data === undefined ) {\n                return;\n            }\n\n            if ( !id ) {\n                // Only DOM nodes need a new unique ID for each element since their data\n                // ends up in the global cache\n                if ( isNode ) {\n                    elem[ jQuery.expando ] = id = ++jQuery.uuid;\n                } else {\n                    id = jQuery.expando;\n                }\n            }\n\n            if ( !cache[ id ] ) {\n                cache[ id ] = {};\n\n                // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery\n                // metadata on plain JS objects when the object is serialized using\n                // JSON.stringify\n                if ( !isNode ) {\n                    cache[ id ].toJSON = jQuery.noop;\n                }\n            }\n\n            // An object can be passed to jQuery.data instead of a key/value pair; this gets\n            // shallow copied over onto the existing cache\n            if ( typeof name === \"object\" || typeof name === \"function\" ) {\n                if ( pvt ) {\n                    cache[ id ][ internalKey ] = jQuery.extend(cache[ id ][ internalKey ], name);\n                } else {\n                    cache[ id ] = jQuery.extend(cache[ id ], name);\n                }\n            }\n\n            thisCache = cache[ id ];\n\n            // Internal jQuery data is stored in a separate object inside the object's data\n            // cache in order to avoid key collisions between internal data and user-defined\n            // data\n            if ( pvt ) {\n                if ( !thisCache[ internalKey ] ) {\n                    thisCache[ internalKey ] = {};\n                }\n\n                thisCache = thisCache[ internalKey ];\n            }\n\n            if ( data !== undefined ) {\n                thisCache[ name ] = data;\n            }\n\n            // TODO: This is a hack for 1.5 ONLY. It will be removed in 1.6. Users should\n            // not attempt to inspect the internal events object using jQuery.data, as this\n            // internal data object is undocumented and subject to change.\n            if ( name === \"events\" && !thisCache[name] ) {\n                return thisCache[ internalKey ] && thisCache[ internalKey ].events;\n            }\n\n            return getByName ? thisCache[ name ] : thisCache;\n        },\n\n        removeData: function( elem, name, pvt /* Internal Use Only */ ) {\n            if ( !jQuery.acceptData( elem ) ) {\n                return;\n            }\n\n            var internalKey = jQuery.expando, isNode = elem.nodeType,\n\n            // See jQuery.data for more information\n                cache = isNode ? jQuery.cache : elem,\n\n            // See jQuery.data for more information\n                id = isNode ? elem[ jQuery.expando ] : jQuery.expando;\n\n            // If there is already no cache entry for this object, there is no\n            // purpose in continuing\n            if ( !cache[ id ] ) {\n                return;\n            }\n\n            if ( name ) {\n                var thisCache = pvt ? cache[ id ][ internalKey ] : cache[ id ];\n\n                if ( thisCache ) {\n                    delete thisCache[ name ];\n\n                    // If there is no data left in the cache, we want to continue\n                    // and let the cache object itself get destroyed\n                    if ( !isEmptyDataObject(thisCache) ) {\n                        return;\n                    }\n                }\n            }\n\n            // See jQuery.data for more information\n            if ( pvt ) {\n                delete cache[ id ][ internalKey ];\n\n                // Don't destroy the parent cache unless the internal data object\n                // had been the only thing left in it\n                if ( !isEmptyDataObject(cache[ id ]) ) {\n                    return;\n                }\n            }\n\n            var internalCache = cache[ id ][ internalKey ];\n\n            // Browsers that fail expando deletion also refuse to delete expandos on\n            // the window, but it will allow it on all other JS objects; other browsers\n            // don't care\n            if ( jQuery.support.deleteExpando || cache != window ) {\n                delete cache[ id ];\n            } else {\n                cache[ id ] = null;\n            }\n\n            // We destroyed the entire user cache at once because it's faster than\n            // iterating through each key, but we need to continue to persist internal\n            // data if it existed\n            if ( internalCache ) {\n                cache[ id ] = {};\n                // TODO: This is a hack for 1.5 ONLY. Avoids exposing jQuery\n                // metadata on plain JS objects when the object is serialized using\n                // JSON.stringify\n                if ( !isNode ) {\n                    cache[ id ].toJSON = jQuery.noop;\n                }\n\n                cache[ id ][ internalKey ] = internalCache;\n\n                // Otherwise, we need to eliminate the expando on the node to avoid\n                // false lookups in the cache for entries that no longer exist\n            } else if ( isNode ) {\n                // IE does not allow us to delete expando properties from nodes,\n                // nor does it have a removeAttribute function on Document nodes;\n                // we must handle all of these cases\n                if ( jQuery.support.deleteExpando ) {\n                    delete elem[ jQuery.expando ];\n                } else if ( elem.removeAttribute ) {\n                    elem.removeAttribute( jQuery.expando );\n                } else {\n                    elem[ jQuery.expando ] = null;\n                }\n            }\n        },\n\n        // For internal use only.\n        _data: function( elem, name, data ) {\n            return jQuery.data( elem, name, data, true );\n        },\n\n        // A method for determining if a DOM node can handle the data expando\n        acceptData: function( elem ) {\n            if ( elem.nodeName ) {\n                var match = jQuery.noData[ elem.nodeName.toLowerCase() ];\n\n                if ( match ) {\n                    return !(match === true || elem.getAttribute(\"classid\") !== match);\n                }\n            }\n\n            return true;\n        }\n    });\n\n    jQuery.fn.extend({\n        data: function( key, value ) {\n            var data = null;\n\n            if ( typeof key === \"undefined\" ) {\n                if ( this.length ) {\n                    data = jQuery.data( this[0] );\n\n                    if ( this[0].nodeType === 1 ) {\n                        var attr = this[0].attributes, name;\n                        for ( var i = 0, l = attr.length; i < l; i++ ) {\n                            name = attr[i].name;\n\n                            if ( name.indexOf( \"data-\" ) === 0 ) {\n                                name = name.substr( 5 );\n                                dataAttr( this[0], name, data[ name ] );\n                            }\n                        }\n                    }\n                }\n\n                return data;\n\n            } else if ( typeof key === \"object\" ) {\n                return this.each(function() {\n                    jQuery.data( this, key );\n                });\n            }\n\n            var parts = key.split(\".\");\n            parts[1] = parts[1] ? \".\" + parts[1] : \"\";\n\n            if ( value === undefined ) {\n                data = this.triggerHandler(\"getData\" + parts[1] + \"!\", [parts[0]]);\n\n                // Try to fetch any internally stored data first\n                if ( data === undefined && this.length ) {\n                    data = jQuery.data( this[0], key );\n                    data = dataAttr( this[0], key, data );\n                }\n\n                return data === undefined && parts[1] ?\n                    this.data( parts[0] ) :\n                    data;\n\n            } else {\n                return this.each(function() {\n                    var $this = jQuery( this ),\n                        args = [ parts[0], value ];\n\n                    $this.triggerHandler( \"setData\" + parts[1] + \"!\", args );\n                    jQuery.data( this, key, value );\n                    $this.triggerHandler( \"changeData\" + parts[1] + \"!\", args );\n                });\n            }\n        },\n\n        removeData: function( key ) {\n            return this.each(function() {\n                jQuery.removeData( this, key );\n            });\n        }\n    });\n\n    function dataAttr( elem, key, data ) {\n        // If nothing was found internally, try to fetch any\n        // data from the HTML5 data-* attribute\n        if ( data === undefined && elem.nodeType === 1 ) {\n            data = elem.getAttribute( \"data-\" + key );\n\n            if ( typeof data === \"string\" ) {\n                try {\n                    data = data === \"true\" ? true :\n                        data === \"false\" ? false :\n                            data === \"null\" ? null :\n                                !jQuery.isNaN( data ) ? parseFloat( data ) :\n                                    rbrace.test( data ) ? jQuery.parseJSON( data ) :\n                                        data;\n                } catch( e ) {}\n\n                // Make sure we set the data so it isn't changed later\n                jQuery.data( elem, key, data );\n\n            } else {\n                data = undefined;\n            }\n        }\n\n        return data;\n    }\n\n// TODO: This is a hack for 1.5 ONLY to allow objects with a single toJSON\n// property to be considered empty objects; this property always exists in\n// order to make sure JSON.stringify does not expose internal metadata\n    function isEmptyDataObject( obj ) {\n        for ( var name in obj ) {\n            if ( name !== \"toJSON\" ) {\n                return false;\n            }\n        }\n\n        return true;\n    }\n\n\n\n\n    jQuery.extend({\n        queue: function( elem, type, data ) {\n            if ( !elem ) {\n                return;\n            }\n\n            type = (type || \"fx\") + \"queue\";\n            var q = jQuery._data( elem, type );\n\n            // Speed up dequeue by getting out quickly if this is just a lookup\n            if ( !data ) {\n                return q || [];\n            }\n\n            if ( !q || jQuery.isArray(data) ) {\n                q = jQuery._data( elem, type, jQuery.makeArray(data) );\n\n            } else {\n                q.push( data );\n            }\n\n            return q;\n        },\n\n        dequeue: function( elem, type ) {\n            type = type || \"fx\";\n\n            var queue = jQuery.queue( elem, type ),\n                fn = queue.shift();\n\n            // If the fx queue is dequeued, always remove the progress sentinel\n            if ( fn === \"inprogress\" ) {\n                fn = queue.shift();\n            }\n\n            if ( fn ) {\n                // Add a progress sentinel to prevent the fx queue from being\n                // automatically dequeued\n                if ( type === \"fx\" ) {\n                    queue.unshift(\"inprogress\");\n                }\n\n                fn.call(elem, function() {\n                    jQuery.dequeue(elem, type);\n                });\n            }\n\n            if ( !queue.length ) {\n                jQuery.removeData( elem, type + \"queue\", true );\n            }\n        }\n    });\n\n    jQuery.fn.extend({\n        queue: function( type, data ) {\n            if ( typeof type !== \"string\" ) {\n                data = type;\n                type = \"fx\";\n            }\n\n            if ( data === undefined ) {\n                return jQuery.queue( this[0], type );\n            }\n            return this.each(function( i ) {\n                var queue = jQuery.queue( this, type, data );\n\n                if ( type === \"fx\" && queue[0] !== \"inprogress\" ) {\n                    jQuery.dequeue( this, type );\n                }\n            });\n        },\n        dequeue: function( type ) {\n            return this.each(function() {\n                jQuery.dequeue( this, type );\n            });\n        },\n\n        // Based off of the plugin by Clint Helfers, with permission.\n        // http://blindsignals.com/index.php/2009/07/jquery-delay/\n        delay: function( time, type ) {\n            time = jQuery.fx ? jQuery.fx.speeds[time] || time : time;\n            type = type || \"fx\";\n\n            return this.queue( type, function() {\n                var elem = this;\n                setTimeout(function() {\n                    jQuery.dequeue( elem, type );\n                }, time );\n            });\n        },\n\n        clearQueue: function( type ) {\n            return this.queue( type || \"fx\", [] );\n        }\n    });\n\n\n\n\n    var rclass = /[\\n\\t\\r]/g,\n        rspaces = /\\s+/,\n        rreturn = /\\r/g,\n        rspecialurl = /^(?:href|src|style)$/,\n        rtype = /^(?:button|input)$/i,\n        rfocusable = /^(?:button|input|object|select|textarea)$/i,\n        rclickable = /^a(?:rea)?$/i,\n        rradiocheck = /^(?:radio|checkbox)$/i;\n\n    jQuery.props = {\n        \"for\": \"htmlFor\",\n        \"class\": \"className\",\n        readonly: \"readOnly\",\n        maxlength: \"maxLength\",\n        cellspacing: \"cellSpacing\",\n        rowspan: \"rowSpan\",\n        colspan: \"colSpan\",\n        tabindex: \"tabIndex\",\n        usemap: \"useMap\",\n        frameborder: \"frameBorder\"\n    };\n\n    jQuery.fn.extend({\n        attr: function( name, value ) {\n            return jQuery.access( this, name, value, true, jQuery.attr );\n        },\n\n        removeAttr: function( name, fn ) {\n            return this.each(function(){\n                jQuery.attr( this, name, \"\" );\n                if ( this.nodeType === 1 ) {\n                    this.removeAttribute( name );\n                }\n            });\n        },\n\n        addClass: function( value ) {\n            if ( jQuery.isFunction(value) ) {\n                return this.each(function(i) {\n                    var self = jQuery(this);\n                    self.addClass( value.call(this, i, self.attr(\"class\")) );\n                });\n            }\n\n            if ( value && typeof value === \"string\" ) {\n                var classNames = (value || \"\").split( rspaces );\n\n                for ( var i = 0, l = this.length; i < l; i++ ) {\n                    var elem = this[i];\n\n                    if ( elem.nodeType === 1 ) {\n                        if ( !elem.className ) {\n                            elem.className = value;\n\n                        } else {\n                            var className = \" \" + elem.className + \" \",\n                                setClass = elem.className;\n\n                            for ( var c = 0, cl = classNames.length; c < cl; c++ ) {\n                                if ( className.indexOf( \" \" + classNames[c] + \" \" ) < 0 ) {\n                                    setClass += \" \" + classNames[c];\n                                }\n                            }\n                            elem.className = jQuery.trim( setClass );\n                        }\n                    }\n                }\n            }\n\n            return this;\n        },\n\n        removeClass: function( value ) {\n            if ( jQuery.isFunction(value) ) {\n                return this.each(function(i) {\n                    var self = jQuery(this);\n                    self.removeClass( value.call(this, i, self.attr(\"class\")) );\n                });\n            }\n\n            if ( (value && typeof value === \"string\") || value === undefined ) {\n                var classNames = (value || \"\").split( rspaces );\n\n                for ( var i = 0, l = this.length; i < l; i++ ) {\n                    var elem = this[i];\n\n                    if ( elem.nodeType === 1 && elem.className ) {\n                        if ( value ) {\n                            var className = (\" \" + elem.className + \" \").replace(rclass, \" \");\n                            for ( var c = 0, cl = classNames.length; c < cl; c++ ) {\n                                className = className.replace(\" \" + classNames[c] + \" \", \" \");\n                            }\n                            elem.className = jQuery.trim( className );\n\n                        } else {\n                            elem.className = \"\";\n                        }\n                    }\n                }\n            }\n\n            return this;\n        },\n\n        toggleClass: function( value, stateVal ) {\n            var type = typeof value,\n                isBool = typeof stateVal === \"boolean\";\n\n            if ( jQuery.isFunction( value ) ) {\n                return this.each(function(i) {\n                    var self = jQuery(this);\n                    self.toggleClass( value.call(this, i, self.attr(\"class\"), stateVal), stateVal );\n                });\n            }\n\n            return this.each(function() {\n                if ( type === \"string\" ) {\n                    // toggle individual class names\n                    var className,\n                        i = 0,\n                        self = jQuery( this ),\n                        state = stateVal,\n                        classNames = value.split( rspaces );\n\n                    while ( (className = classNames[ i++ ]) ) {\n                        // check each className given, space seperated list\n                        state = isBool ? state : !self.hasClass( className );\n                        self[ state ? \"addClass\" : \"removeClass\" ]( className );\n                    }\n\n                } else if ( type === \"undefined\" || type === \"boolean\" ) {\n                    if ( this.className ) {\n                        // store className if set\n                        jQuery._data( this, \"__className__\", this.className );\n                    }\n\n                    // toggle whole className\n                    this.className = this.className || value === false ? \"\" : jQuery._data( this, \"__className__\" ) || \"\";\n                }\n            });\n        },\n\n        hasClass: function( selector ) {\n            var className = \" \" + selector + \" \";\n            for ( var i = 0, l = this.length; i < l; i++ ) {\n                if ( (\" \" + this[i].className + \" \").replace(rclass, \" \").indexOf( className ) > -1 ) {\n                    return true;\n                }\n            }\n\n            return false;\n        },\n\n        val: function( value ) {\n            if ( !arguments.length ) {\n                var elem = this[0];\n\n                if ( elem ) {\n                    if ( jQuery.nodeName( elem, \"option\" ) ) {\n                        // attributes.value is undefined in Blackberry 4.7 but\n                        // uses .value. See #6932\n                        var val = elem.attributes.value;\n                        return !val || val.specified ? elem.value : elem.text;\n                    }\n\n                    // We need to handle select boxes special\n                    if ( jQuery.nodeName( elem, \"select\" ) ) {\n                        var index = elem.selectedIndex,\n                            values = [],\n                            options = elem.options,\n                            one = elem.type === \"select-one\";\n\n                        // Nothing was selected\n                        if ( index < 0 ) {\n                            return null;\n                        }\n\n                        // Loop through all the selected options\n                        for ( var i = one ? index : 0, max = one ? index + 1 : options.length; i < max; i++ ) {\n                            var option = options[ i ];\n\n                            // Don't return options that are disabled or in a disabled optgroup\n                            if ( option.selected && (jQuery.support.optDisabled ? !option.disabled : option.getAttribute(\"disabled\") === null) &&\n                                (!option.parentNode.disabled || !jQuery.nodeName( option.parentNode, \"optgroup\" )) ) {\n\n                                // Get the specific value for the option\n                                value = jQuery(option).val();\n\n                                // We don't need an array for one selects\n                                if ( one ) {\n                                    return value;\n                                }\n\n                                // Multi-Selects return an array\n                                values.push( value );\n                            }\n                        }\n\n                        // Fixes Bug #2551 -- select.val() broken in IE after form.reset()\n                        if ( one && !values.length && options.length ) {\n                            return jQuery( options[ index ] ).val();\n                        }\n\n                        return values;\n                    }\n\n                    // Handle the case where in Webkit \"\" is returned instead of \"on\" if a value isn't specified\n                    if ( rradiocheck.test( elem.type ) && !jQuery.support.checkOn ) {\n                        return elem.getAttribute(\"value\") === null ? \"on\" : elem.value;\n                    }\n\n                    // Everything else, we just grab the value\n                    return (elem.value || \"\").replace(rreturn, \"\");\n\n                }\n\n                return undefined;\n            }\n\n            var isFunction = jQuery.isFunction(value);\n\n            return this.each(function(i) {\n                var self = jQuery(this), val = value;\n\n                if ( this.nodeType !== 1 ) {\n                    return;\n                }\n\n                if ( isFunction ) {\n                    val = value.call(this, i, self.val());\n                }\n\n                // Treat null/undefined as \"\"; convert numbers to string\n                if ( val == null ) {\n                    val = \"\";\n                } else if ( typeof val === \"number\" ) {\n                    val += \"\";\n                } else if ( jQuery.isArray(val) ) {\n                    val = jQuery.map(val, function (value) {\n                        return value == null ? \"\" : value + \"\";\n                    });\n                }\n\n                if ( jQuery.isArray(val) && rradiocheck.test( this.type ) ) {\n                    this.checked = jQuery.inArray( self.val(), val ) >= 0;\n\n                } else if ( jQuery.nodeName( this, \"select\" ) ) {\n                    var values = jQuery.makeArray(val);\n\n                    jQuery( \"option\", this ).each(function() {\n                        this.selected = jQuery.inArray( jQuery(this).val(), values ) >= 0;\n                    });\n\n                    if ( !values.length ) {\n                        this.selectedIndex = -1;\n                    }\n\n                } else {\n                    this.value = val;\n                }\n            });\n        }\n    });\n\n    jQuery.extend({\n        attrFn: {\n            val: true,\n            css: true,\n            html: true,\n            text: true,\n            data: true,\n            width: true,\n            height: true,\n            offset: true\n        },\n\n        attr: function( elem, name, value, pass ) {\n            // don't get/set attributes on text, comment and attribute nodes\n            if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || elem.nodeType === 2 ) {\n                return undefined;\n            }\n\n            if ( pass && name in jQuery.attrFn ) {\n                return jQuery(elem)[name](value);\n            }\n\n            var notxml = elem.nodeType !== 1 || !jQuery.isXMLDoc( elem ),\n            // Whether we are setting (or getting)\n                set = value !== undefined;\n\n            // Try to normalize/fix the name\n            name = notxml && jQuery.props[ name ] || name;\n\n            // Only do all the following if this is a node (faster for style)\n            if ( elem.nodeType === 1 ) {\n                // These attributes require special treatment\n                var special = rspecialurl.test( name );\n\n                // Safari mis-reports the default selected property of an option\n                // Accessing the parent's selectedIndex property fixes it\n                if ( name === \"selected\" && !jQuery.support.optSelected ) {\n                    var parent = elem.parentNode;\n                    if ( parent ) {\n                        parent.selectedIndex;\n\n                        // Make sure that it also works with optgroups, see #5701\n                        if ( parent.parentNode ) {\n                            parent.parentNode.selectedIndex;\n                        }\n                    }\n                }\n\n                // If applicable, access the attribute via the DOM 0 way\n                // 'in' checks fail in Blackberry 4.7 #6931\n                if ( (name in elem || elem[ name ] !== undefined) && notxml && !special ) {\n                    if ( set ) {\n                        // We can't allow the type property to be changed (since it causes problems in IE)\n                        if ( name === \"type\" && rtype.test( elem.nodeName ) && elem.parentNode ) {\n                            jQuery.error( \"type property can't be changed\" );\n                        }\n\n                        if ( value === null ) {\n                            if ( elem.nodeType === 1 ) {\n                                elem.removeAttribute( name );\n                            }\n\n                        } else {\n                            elem[ name ] = value;\n                        }\n                    }\n\n                    // browsers index elements by id/name on forms, give priority to attributes.\n                    if ( jQuery.nodeName( elem, \"form\" ) && elem.getAttributeNode(name) ) {\n                        return elem.getAttributeNode( name ).nodeValue;\n                    }\n\n                    // elem.tabIndex doesn't always return the correct value when it hasn't been explicitly set\n                    // http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/\n                    if ( name === \"tabIndex\" ) {\n                        var attributeNode = elem.getAttributeNode( \"tabIndex\" );\n\n                        return attributeNode && attributeNode.specified ?\n                            attributeNode.value :\n                            rfocusable.test( elem.nodeName ) || rclickable.test( elem.nodeName ) && elem.href ?\n                                0 :\n                                undefined;\n                    }\n\n                    return elem[ name ];\n                }\n\n                if ( !jQuery.support.style && notxml && name === \"style\" ) {\n                    if ( set ) {\n                        elem.style.cssText = \"\" + value;\n                    }\n\n                    return elem.style.cssText;\n                }\n\n                if ( set ) {\n                    // convert the value to a string (all browsers do this but IE) see #1070\n                    elem.setAttribute( name, \"\" + value );\n                }\n\n                // Ensure that missing attributes return undefined\n                // Blackberry 4.7 returns \"\" from getAttribute #6938\n                if ( !elem.attributes[ name ] && (elem.hasAttribute && !elem.hasAttribute( name )) ) {\n                    return undefined;\n                }\n\n                var attr = !jQuery.support.hrefNormalized && notxml && special ?\n                    // Some attributes require a special call on IE\n                    elem.getAttribute( name, 2 ) :\n                    elem.getAttribute( name );\n\n                // Non-existent attributes return null, we normalize to undefined\n                return attr === null ? undefined : attr;\n            }\n            // Handle everything which isn't a DOM element node\n            if ( set ) {\n                elem[ name ] = value;\n            }\n            return elem[ name ];\n        }\n    });\n\n\n\n\n    var rnamespaces = /\\.(.*)$/,\n        rformElems = /^(?:textarea|input|select)$/i,\n        rperiod = /\\./g,\n        rspace = / /g,\n        rescape = /[^\\w\\s.|`]/g,\n        fcleanup = function( nm ) {\n            return nm.replace(rescape, \"\\\\$&\");\n        };\n\n    /*\n     * A number of helper functions used for managing events.\n     * Many of the ideas behind this code originated from\n     * Dean Edwards' addEvent library.\n     */\n    jQuery.event = {\n\n        // Bind an event to an element\n        // Original by Dean Edwards\n        add: function( elem, types, handler, data ) {\n            if ( elem.nodeType === 3 || elem.nodeType === 8 ) {\n                return;\n            }\n\n            // TODO :: Use a try/catch until it's safe to pull this out (likely 1.6)\n            // Minor release fix for bug #8018\n            try {\n                // For whatever reason, IE has trouble passing the window object\n                // around, causing it to be cloned in the process\n                if ( jQuery.isWindow( elem ) && ( elem !== window && !elem.frameElement ) ) {\n                    elem = window;\n                }\n            }\n            catch ( e ) {}\n\n            if ( handler === false ) {\n                handler = returnFalse;\n            } else if ( !handler ) {\n                // Fixes bug #7229. Fix recommended by jdalton\n                return;\n            }\n\n            var handleObjIn, handleObj;\n\n            if ( handler.handler ) {\n                handleObjIn = handler;\n                handler = handleObjIn.handler;\n            }\n\n            // Make sure that the function being executed has a unique ID\n            if ( !handler.guid ) {\n                handler.guid = jQuery.guid++;\n            }\n\n            // Init the element's event structure\n            var elemData = jQuery._data( elem );\n\n            // If no elemData is found then we must be trying to bind to one of the\n            // banned noData elements\n            if ( !elemData ) {\n                return;\n            }\n\n            var events = elemData.events,\n                eventHandle = elemData.handle;\n\n            if ( !events ) {\n                elemData.events = events = {};\n            }\n\n            if ( !eventHandle ) {\n                elemData.handle = eventHandle = function( e ) {\n                    // Handle the second event of a trigger and when\n                    // an event is called after a page has unloaded\n                    return typeof jQuery !== \"undefined\" && jQuery.event.triggered !== e.type ?\n                        jQuery.event.handle.apply( eventHandle.elem, arguments ) :\n                        undefined;\n                };\n            }\n\n            // Add elem as a property of the handle function\n            // This is to prevent a memory leak with non-native events in IE.\n            eventHandle.elem = elem;\n\n            // Handle multiple events separated by a space\n            // jQuery(...).bind(\"mouseover mouseout\", fn);\n            types = types.split(\" \");\n\n            var type, i = 0, namespaces;\n\n            while ( (type = types[ i++ ]) ) {\n                handleObj = handleObjIn ?\n                    jQuery.extend({}, handleObjIn) :\n                { handler: handler, data: data };\n\n                // Namespaced event handlers\n                if ( type.indexOf(\".\") > -1 ) {\n                    namespaces = type.split(\".\");\n                    type = namespaces.shift();\n                    handleObj.namespace = namespaces.slice(0).sort().join(\".\");\n\n                } else {\n                    namespaces = [];\n                    handleObj.namespace = \"\";\n                }\n\n                handleObj.type = type;\n                if ( !handleObj.guid ) {\n                    handleObj.guid = handler.guid;\n                }\n\n                // Get the current list of functions bound to this event\n                var handlers = events[ type ],\n                    special = jQuery.event.special[ type ] || {};\n\n                // Init the event handler queue\n                if ( !handlers ) {\n                    handlers = events[ type ] = [];\n\n                    // Check for a special event handler\n                    // Only use addEventListener/attachEvent if the special\n                    // events handler returns false\n                    if ( !special.setup || special.setup.call( elem, data, namespaces, eventHandle ) === false ) {\n                        // Bind the global event handler to the element\n                        if ( elem.addEventListener ) {\n                            elem.addEventListener( type, eventHandle, false );\n\n                        } else if ( elem.attachEvent ) {\n                            elem.attachEvent( \"on\" + type, eventHandle );\n                        }\n                    }\n                }\n\n                if ( special.add ) {\n                    special.add.call( elem, handleObj );\n\n                    if ( !handleObj.handler.guid ) {\n                        handleObj.handler.guid = handler.guid;\n                    }\n                }\n\n                // Add the function to the element's handler list\n                handlers.push( handleObj );\n\n                // Keep track of which events have been used, for global triggering\n                jQuery.event.global[ type ] = true;\n            }\n\n            // Nullify elem to prevent memory leaks in IE\n            elem = null;\n        },\n\n        global: {},\n\n        // Detach an event or set of events from an element\n        remove: function( elem, types, handler, pos ) {\n            // don't do events on text and comment nodes\n            if ( elem.nodeType === 3 || elem.nodeType === 8 ) {\n                return;\n            }\n\n            if ( handler === false ) {\n                handler = returnFalse;\n            }\n\n            var ret, type, fn, j, i = 0, all, namespaces, namespace, special, eventType, handleObj, origType,\n                elemData = jQuery.hasData( elem ) && jQuery._data( elem ),\n                events = elemData && elemData.events;\n\n            if ( !elemData || !events ) {\n                return;\n            }\n\n            // types is actually an event object here\n            if ( types && types.type ) {\n                handler = types.handler;\n                types = types.type;\n            }\n\n            // Unbind all events for the element\n            if ( !types || typeof types === \"string\" && types.charAt(0) === \".\" ) {\n                types = types || \"\";\n\n                for ( type in events ) {\n                    jQuery.event.remove( elem, type + types );\n                }\n\n                return;\n            }\n\n            // Handle multiple events separated by a space\n            // jQuery(...).unbind(\"mouseover mouseout\", fn);\n            types = types.split(\" \");\n\n            while ( (type = types[ i++ ]) ) {\n                origType = type;\n                handleObj = null;\n                all = type.indexOf(\".\") < 0;\n                namespaces = [];\n\n                if ( !all ) {\n                    // Namespaced event handlers\n                    namespaces = type.split(\".\");\n                    type = namespaces.shift();\n\n                    namespace = new RegExp(\"(^|\\\\.)\" +\n                        jQuery.map( namespaces.slice(0).sort(), fcleanup ).join(\"\\\\.(?:.*\\\\.)?\") + \"(\\\\.|$)\");\n                }\n\n                eventType = events[ type ];\n\n                if ( !eventType ) {\n                    continue;\n                }\n\n                if ( !handler ) {\n                    for ( j = 0; j < eventType.length; j++ ) {\n                        handleObj = eventType[ j ];\n\n                        if ( all || namespace.test( handleObj.namespace ) ) {\n                            jQuery.event.remove( elem, origType, handleObj.handler, j );\n                            eventType.splice( j--, 1 );\n                        }\n                    }\n\n                    continue;\n                }\n\n                special = jQuery.event.special[ type ] || {};\n\n                for ( j = pos || 0; j < eventType.length; j++ ) {\n                    handleObj = eventType[ j ];\n\n                    if ( handler.guid === handleObj.guid ) {\n                        // remove the given handler for the given type\n                        if ( all || namespace.test( handleObj.namespace ) ) {\n                            if ( pos == null ) {\n                                eventType.splice( j--, 1 );\n                            }\n\n                            if ( special.remove ) {\n                                special.remove.call( elem, handleObj );\n                            }\n                        }\n\n                        if ( pos != null ) {\n                            break;\n                        }\n                    }\n                }\n\n                // remove generic event handler if no more handlers exist\n                if ( eventType.length === 0 || pos != null && eventType.length === 1 ) {\n                    if ( !special.teardown || special.teardown.call( elem, namespaces ) === false ) {\n                        jQuery.removeEvent( elem, type, elemData.handle );\n                    }\n\n                    ret = null;\n                    delete events[ type ];\n                }\n            }\n\n            // Remove the expando if it's no longer used\n            if ( jQuery.isEmptyObject( events ) ) {\n                var handle = elemData.handle;\n                if ( handle ) {\n                    handle.elem = null;\n                }\n\n                delete elemData.events;\n                delete elemData.handle;\n\n                if ( jQuery.isEmptyObject( elemData ) ) {\n                    jQuery.removeData( elem, undefined, true );\n                }\n            }\n        },\n\n        // bubbling is internal\n        trigger: function( event, data, elem /*, bubbling */ ) {\n            // Event object or event type\n            var type = event.type || event,\n                bubbling = arguments[3];\n\n            if ( !bubbling ) {\n                event = typeof event === \"object\" ?\n                    // jQuery.Event object\n                    event[ jQuery.expando ] ? event :\n                        // Object literal\n                        jQuery.extend( jQuery.Event(type), event ) :\n                    // Just the event type (string)\n                    jQuery.Event(type);\n\n                if ( type.indexOf(\"!\") >= 0 ) {\n                    event.type = type = type.slice(0, -1);\n                    event.exclusive = true;\n                }\n\n                // Handle a global trigger\n                if ( !elem ) {\n                    // Don't bubble custom events when global (to avoid too much overhead)\n                    event.stopPropagation();\n\n                    // Only trigger if we've ever bound an event for it\n                    if ( jQuery.event.global[ type ] ) {\n                        // XXX This code smells terrible. event.js should not be directly\n                        // inspecting the data cache\n                        jQuery.each( jQuery.cache, function() {\n                            // internalKey variable is just used to make it easier to find\n                            // and potentially change this stuff later; currently it just\n                            // points to jQuery.expando\n                            var internalKey = jQuery.expando,\n                                internalCache = this[ internalKey ];\n                            if ( internalCache && internalCache.events && internalCache.events[ type ] ) {\n                                jQuery.event.trigger( event, data, internalCache.handle.elem );\n                            }\n                        });\n                    }\n                }\n\n                // Handle triggering a single element\n\n                // don't do events on text and comment nodes\n                if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 ) {\n                    return undefined;\n                }\n\n                // Clean up in case it is reused\n                event.result = undefined;\n                event.target = elem;\n\n                // Clone the incoming data, if any\n                data = jQuery.makeArray( data );\n                data.unshift( event );\n            }\n\n            event.currentTarget = elem;\n\n            // Trigger the event, it is assumed that \"handle\" is a function\n            var handle = jQuery._data( elem, \"handle\" );\n\n            if ( handle ) {\n                handle.apply( elem, data );\n            }\n\n            var parent = elem.parentNode || elem.ownerDocument;\n\n            // Trigger an inline bound script\n            try {\n                if ( !(elem && elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) ) {\n                    if ( elem[ \"on\" + type ] && elem[ \"on\" + type ].apply( elem, data ) === false ) {\n                        event.result = false;\n                        event.preventDefault();\n                    }\n                }\n\n                // prevent IE from throwing an error for some elements with some event types, see #3533\n            } catch (inlineError) {}\n\n            if ( !event.isPropagationStopped() && parent ) {\n                jQuery.event.trigger( event, data, parent, true );\n\n            } else if ( !event.isDefaultPrevented() ) {\n                var old,\n                    target = event.target,\n                    targetType = type.replace( rnamespaces, \"\" ),\n                    isClick = jQuery.nodeName( target, \"a\" ) && targetType === \"click\",\n                    special = jQuery.event.special[ targetType ] || {};\n\n                if ( (!special._default || special._default.call( elem, event ) === false) &&\n                    !isClick && !(target && target.nodeName && jQuery.noData[target.nodeName.toLowerCase()]) ) {\n\n                    try {\n                        if ( target[ targetType ] ) {\n                            // Make sure that we don't accidentally re-trigger the onFOO events\n                            old = target[ \"on\" + targetType ];\n\n                            if ( old ) {\n                                target[ \"on\" + targetType ] = null;\n                            }\n\n                            jQuery.event.triggered = event.type;\n                            target[ targetType ]();\n                        }\n\n                        // prevent IE from throwing an error for some elements with some event types, see #3533\n                    } catch (triggerError) {}\n\n                    if ( old ) {\n                        target[ \"on\" + targetType ] = old;\n                    }\n\n                    jQuery.event.triggered = undefined;\n                }\n            }\n        },\n\n        handle: function( event ) {\n            var all, handlers, namespaces, namespace_re, events,\n                namespace_sort = [],\n                args = jQuery.makeArray( arguments );\n\n            event = args[0] = jQuery.event.fix( event || window.event );\n            event.currentTarget = this;\n\n            // Namespaced event handlers\n            all = event.type.indexOf(\".\") < 0 && !event.exclusive;\n\n            if ( !all ) {\n                namespaces = event.type.split(\".\");\n                event.type = namespaces.shift();\n                namespace_sort = namespaces.slice(0).sort();\n                namespace_re = new RegExp(\"(^|\\\\.)\" + namespace_sort.join(\"\\\\.(?:.*\\\\.)?\") + \"(\\\\.|$)\");\n            }\n\n            event.namespace = event.namespace || namespace_sort.join(\".\");\n\n            events = jQuery._data(this, \"events\");\n\n            handlers = (events || {})[ event.type ];\n\n            if ( events && handlers ) {\n                // Clone the handlers to prevent manipulation\n                handlers = handlers.slice(0);\n\n                for ( var j = 0, l = handlers.length; j < l; j++ ) {\n                    var handleObj = handlers[ j ];\n\n                    // Filter the functions by class\n                    if ( all || namespace_re.test( handleObj.namespace ) ) {\n                        // Pass in a reference to the handler function itself\n                        // So that we can later remove it\n                        event.handler = handleObj.handler;\n                        event.data = handleObj.data;\n                        event.handleObj = handleObj;\n\n                        var ret = handleObj.handler.apply( this, args );\n\n                        if ( ret !== undefined ) {\n                            event.result = ret;\n                            if ( ret === false ) {\n                                event.preventDefault();\n                                event.stopPropagation();\n                            }\n                        }\n\n                        if ( event.isImmediatePropagationStopped() ) {\n                            break;\n                        }\n                    }\n                }\n            }\n\n            return event.result;\n        },\n\n        props: \"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which\".split(\" \"),\n\n        fix: function( event ) {\n            if ( event[ jQuery.expando ] ) {\n                return event;\n            }\n\n            // store a copy of the original event object\n            // and \"clone\" to set read-only properties\n            var originalEvent = event;\n            event = jQuery.Event( originalEvent );\n\n            for ( var i = this.props.length, prop; i; ) {\n                prop = this.props[ --i ];\n                event[ prop ] = originalEvent[ prop ];\n            }\n\n            // Fix target property, if necessary\n            if ( !event.target ) {\n                // Fixes #1925 where srcElement might not be defined either\n                event.target = event.srcElement || document;\n            }\n\n            // check if target is a textnode (safari)\n            if ( event.target.nodeType === 3 ) {\n                event.target = event.target.parentNode;\n            }\n\n            // Add relatedTarget, if necessary\n            if ( !event.relatedTarget && event.fromElement ) {\n                event.relatedTarget = event.fromElement === event.target ? event.toElement : event.fromElement;\n            }\n\n            // Calculate pageX/Y if missing and clientX/Y available\n            if ( event.pageX == null && event.clientX != null ) {\n                var doc = document.documentElement,\n                    body = document.body;\n\n                event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc && doc.clientLeft || body && body.clientLeft || 0);\n                event.pageY = event.clientY + (doc && doc.scrollTop  || body && body.scrollTop  || 0) - (doc && doc.clientTop  || body && body.clientTop  || 0);\n            }\n\n            // Add which for key events\n            if ( event.which == null && (event.charCode != null || event.keyCode != null) ) {\n                event.which = event.charCode != null ? event.charCode : event.keyCode;\n            }\n\n            // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)\n            if ( !event.metaKey && event.ctrlKey ) {\n                event.metaKey = event.ctrlKey;\n            }\n\n            // Add which for click: 1 === left; 2 === middle; 3 === right\n            // Note: button is not normalized, so don't use it\n            if ( !event.which && event.button !== undefined ) {\n                event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));\n            }\n\n            return event;\n        },\n\n        // Deprecated, use jQuery.guid instead\n        guid: 1E8,\n\n        // Deprecated, use jQuery.proxy instead\n        proxy: jQuery.proxy,\n\n        special: {\n            ready: {\n                // Make sure the ready event is setup\n                setup: jQuery.bindReady,\n                teardown: jQuery.noop\n            },\n\n            live: {\n                add: function( handleObj ) {\n                    jQuery.event.add( this,\n                        liveConvert( handleObj.origType, handleObj.selector ),\n                        jQuery.extend({}, handleObj, {handler: liveHandler, guid: handleObj.handler.guid}) );\n                },\n\n                remove: function( handleObj ) {\n                    jQuery.event.remove( this, liveConvert( handleObj.origType, handleObj.selector ), handleObj );\n                }\n            },\n\n            beforeunload: {\n                setup: function( data, namespaces, eventHandle ) {\n                    // We only want to do this special case on windows\n                    if ( jQuery.isWindow( this ) ) {\n                        this.onbeforeunload = eventHandle;\n                    }\n                },\n\n                teardown: function( namespaces, eventHandle ) {\n                    if ( this.onbeforeunload === eventHandle ) {\n                        this.onbeforeunload = null;\n                    }\n                }\n            }\n        }\n    };\n\n    jQuery.removeEvent = document.removeEventListener ?\n        function( elem, type, handle ) {\n            if ( elem.removeEventListener ) {\n                elem.removeEventListener( type, handle, false );\n            }\n        } :\n        function( elem, type, handle ) {\n            if ( elem.detachEvent ) {\n                elem.detachEvent( \"on\" + type, handle );\n            }\n        };\n\n    jQuery.Event = function( src ) {\n        // Allow instantiation without the 'new' keyword\n        if ( !this.preventDefault ) {\n            return new jQuery.Event( src );\n        }\n\n        // Event object\n        if ( src && src.type ) {\n            this.originalEvent = src;\n            this.type = src.type;\n\n            // Events bubbling up the document may have been marked as prevented\n            // by a handler lower down the tree; reflect the correct value.\n            this.isDefaultPrevented = (src.defaultPrevented || src.returnValue === false ||\n                src.getPreventDefault && src.getPreventDefault()) ? returnTrue : returnFalse;\n\n            // Event type\n        } else {\n            this.type = src;\n        }\n\n        // timeStamp is buggy for some events on Firefox(#3843)\n        // So we won't rely on the native value\n        this.timeStamp = jQuery.now();\n\n        // Mark it as fixed\n        this[ jQuery.expando ] = true;\n    };\n\n    function returnFalse() {\n        return false;\n    }\n    function returnTrue() {\n        return true;\n    }\n\n// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding\n// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html\n    jQuery.Event.prototype = {\n        preventDefault: function() {\n            this.isDefaultPrevented = returnTrue;\n\n            var e = this.originalEvent;\n            if ( !e ) {\n                return;\n            }\n\n            // if preventDefault exists run it on the original event\n            if ( e.preventDefault ) {\n                e.preventDefault();\n\n                // otherwise set the returnValue property of the original event to false (IE)\n            } else {\n                e.returnValue = false;\n            }\n        },\n        stopPropagation: function() {\n            this.isPropagationStopped = returnTrue;\n\n            var e = this.originalEvent;\n            if ( !e ) {\n                return;\n            }\n            // if stopPropagation exists run it on the original event\n            if ( e.stopPropagation ) {\n                e.stopPropagation();\n            }\n            // otherwise set the cancelBubble property of the original event to true (IE)\n            e.cancelBubble = true;\n        },\n        stopImmediatePropagation: function() {\n            this.isImmediatePropagationStopped = returnTrue;\n            this.stopPropagation();\n        },\n        isDefaultPrevented: returnFalse,\n        isPropagationStopped: returnFalse,\n        isImmediatePropagationStopped: returnFalse\n    };\n\n// Checks if an event happened on an element within another element\n// Used in jQuery.event.special.mouseenter and mouseleave handlers\n    var withinElement = function( event ) {\n            // Check if mouse(over|out) are still within the same parent element\n            var parent = event.relatedTarget;\n\n            // Firefox sometimes assigns relatedTarget a XUL element\n            // which we cannot access the parentNode property of\n            try {\n\n                // Chrome does something similar, the parentNode property\n                // can be accessed but is null.\n                if ( parent && parent !== document && !parent.parentNode ) {\n                    return;\n                }\n                // Traverse up the tree\n                while ( parent && parent !== this ) {\n                    parent = parent.parentNode;\n                }\n\n                if ( parent !== this ) {\n                    // set the correct event type\n                    event.type = event.data;\n\n                    // handle event if we actually just moused on to a non sub-element\n                    jQuery.event.handle.apply( this, arguments );\n                }\n\n                // assuming we've left the element since we most likely mousedover a xul element\n            } catch(e) { }\n        },\n\n// In case of event delegation, we only need to rename the event.type,\n// liveHandler will take care of the rest.\n        delegate = function( event ) {\n            event.type = event.data;\n            jQuery.event.handle.apply( this, arguments );\n        };\n\n// Create mouseenter and mouseleave events\n    jQuery.each({\n        mouseenter: \"mouseover\",\n        mouseleave: \"mouseout\"\n    }, function( orig, fix ) {\n        jQuery.event.special[ orig ] = {\n            setup: function( data ) {\n                jQuery.event.add( this, fix, data && data.selector ? delegate : withinElement, orig );\n            },\n            teardown: function( data ) {\n                jQuery.event.remove( this, fix, data && data.selector ? delegate : withinElement );\n            }\n        };\n    });\n\n// submit delegation\n    if ( !jQuery.support.submitBubbles ) {\n\n        jQuery.event.special.submit = {\n            setup: function( data, namespaces ) {\n                if ( this.nodeName && this.nodeName.toLowerCase() !== \"form\" ) {\n                    jQuery.event.add(this, \"click.specialSubmit\", function( e ) {\n                        var elem = e.target,\n                            type = elem.type;\n\n                        if ( (type === \"submit\" || type === \"image\") && jQuery( elem ).closest(\"form\").length ) {\n                            trigger( \"submit\", this, arguments );\n                        }\n                    });\n\n                    jQuery.event.add(this, \"keypress.specialSubmit\", function( e ) {\n                        var elem = e.target,\n                            type = elem.type;\n\n                        if ( (type === \"text\" || type === \"password\") && jQuery( elem ).closest(\"form\").length && e.keyCode === 13 ) {\n                            trigger( \"submit\", this, arguments );\n                        }\n                    });\n\n                } else {\n                    return false;\n                }\n            },\n\n            teardown: function( namespaces ) {\n                jQuery.event.remove( this, \".specialSubmit\" );\n            }\n        };\n\n    }\n\n// change delegation, happens here so we have bind.\n    if ( !jQuery.support.changeBubbles ) {\n\n        var changeFilters,\n\n            getVal = function( elem ) {\n                var type = elem.type, val = elem.value;\n\n                if ( type === \"radio\" || type === \"checkbox\" ) {\n                    val = elem.checked;\n\n                } else if ( type === \"select-multiple\" ) {\n                    val = elem.selectedIndex > -1 ?\n                        jQuery.map( elem.options, function( elem ) {\n                            return elem.selected;\n                        }).join(\"-\") :\n                        \"\";\n\n                } else if ( elem.nodeName.toLowerCase() === \"select\" ) {\n                    val = elem.selectedIndex;\n                }\n\n                return val;\n            },\n\n            testChange = function testChange( e ) {\n                var elem = e.target, data, val;\n\n                if ( !rformElems.test( elem.nodeName ) || elem.readOnly ) {\n                    return;\n                }\n\n                data = jQuery._data( elem, \"_change_data\" );\n                val = getVal(elem);\n\n                // the current data will be also retrieved by beforeactivate\n                if ( e.type !== \"focusout\" || elem.type !== \"radio\" ) {\n                    jQuery._data( elem, \"_change_data\", val );\n                }\n\n                if ( data === undefined || val === data ) {\n                    return;\n                }\n\n                if ( data != null || val ) {\n                    e.type = \"change\";\n                    e.liveFired = undefined;\n                    jQuery.event.trigger( e, arguments[1], elem );\n                }\n            };\n\n        jQuery.event.special.change = {\n            filters: {\n                focusout: testChange,\n\n                beforedeactivate: testChange,\n\n                click: function( e ) {\n                    var elem = e.target, type = elem.type;\n\n                    if ( type === \"radio\" || type === \"checkbox\" || elem.nodeName.toLowerCase() === \"select\" ) {\n                        testChange.call( this, e );\n                    }\n                },\n\n                // Change has to be called before submit\n                // Keydown will be called before keypress, which is used in submit-event delegation\n                keydown: function( e ) {\n                    var elem = e.target, type = elem.type;\n\n                    if ( (e.keyCode === 13 && elem.nodeName.toLowerCase() !== \"textarea\") ||\n                        (e.keyCode === 32 && (type === \"checkbox\" || type === \"radio\")) ||\n                        type === \"select-multiple\" ) {\n                        testChange.call( this, e );\n                    }\n                },\n\n                // Beforeactivate happens also before the previous element is blurred\n                // with this event you can't trigger a change event, but you can store\n                // information\n                beforeactivate: function( e ) {\n                    var elem = e.target;\n                    jQuery._data( elem, \"_change_data\", getVal(elem) );\n                }\n            },\n\n            setup: function( data, namespaces ) {\n                if ( this.type === \"file\" ) {\n                    return false;\n                }\n\n                for ( var type in changeFilters ) {\n                    jQuery.event.add( this, type + \".specialChange\", changeFilters[type] );\n                }\n\n                return rformElems.test( this.nodeName );\n            },\n\n            teardown: function( namespaces ) {\n                jQuery.event.remove( this, \".specialChange\" );\n\n                return rformElems.test( this.nodeName );\n            }\n        };\n\n        changeFilters = jQuery.event.special.change.filters;\n\n        // Handle when the input is .focus()'d\n        changeFilters.focus = changeFilters.beforeactivate;\n    }\n\n    function trigger( type, elem, args ) {\n        // Piggyback on a donor event to simulate a different one.\n        // Fake originalEvent to avoid donor's stopPropagation, but if the\n        // simulated event prevents default then we do the same on the donor.\n        // Don't pass args or remember liveFired; they apply to the donor event.\n        var event = jQuery.extend( {}, args[ 0 ] );\n        event.type = type;\n        event.originalEvent = {};\n        event.liveFired = undefined;\n        jQuery.event.handle.call( elem, event );\n        if ( event.isDefaultPrevented() ) {\n            args[ 0 ].preventDefault();\n        }\n    }\n\n// Create \"bubbling\" focus and blur events\n    if ( document.addEventListener ) {\n        jQuery.each({ focus: \"focusin\", blur: \"focusout\" }, function( orig, fix ) {\n\n            // Attach a single capturing handler while someone wants focusin/focusout\n            var attaches = 0;\n\n            jQuery.event.special[ fix ] = {\n                setup: function() {\n                    if ( attaches++ === 0 ) {\n                        document.addEventListener( orig, handler, true );\n                    }\n                },\n                teardown: function() {\n                    if ( --attaches === 0 ) {\n                        document.removeEventListener( orig, handler, true );\n                    }\n                }\n            };\n\n            function handler( donor ) {\n                // Donor event is always a native one; fix it and switch its type.\n                // Let focusin/out handler cancel the donor focus/blur event.\n                var e = jQuery.event.fix( donor );\n                e.type = fix;\n                e.originalEvent = {};\n                jQuery.event.trigger( e, null, e.target );\n                if ( e.isDefaultPrevented() ) {\n                    donor.preventDefault();\n                }\n            }\n        });\n    }\n\n    jQuery.each([\"bind\", \"one\"], function( i, name ) {\n        jQuery.fn[ name ] = function( type, data, fn ) {\n            // Handle object literals\n            if ( typeof type === \"object\" ) {\n                for ( var key in type ) {\n                    this[ name ](key, data, type[key], fn);\n                }\n                return this;\n            }\n\n            if ( jQuery.isFunction( data ) || data === false ) {\n                fn = data;\n                data = undefined;\n            }\n\n            var handler = name === \"one\" ? jQuery.proxy( fn, function( event ) {\n                jQuery( this ).unbind( event, handler );\n                return fn.apply( this, arguments );\n            }) : fn;\n\n            if ( type === \"unload\" && name !== \"one\" ) {\n                this.one( type, data, fn );\n\n            } else {\n                for ( var i = 0, l = this.length; i < l; i++ ) {\n                    jQuery.event.add( this[i], type, handler, data );\n                }\n            }\n\n            return this;\n        };\n    });\n\n    jQuery.fn.extend({\n        unbind: function( type, fn ) {\n            // Handle object literals\n            if ( typeof type === \"object\" && !type.preventDefault ) {\n                for ( var key in type ) {\n                    this.unbind(key, type[key]);\n                }\n\n            } else {\n                for ( var i = 0, l = this.length; i < l; i++ ) {\n                    jQuery.event.remove( this[i], type, fn );\n                }\n            }\n\n            return this;\n        },\n\n        delegate: function( selector, types, data, fn ) {\n            return this.live( types, data, fn, selector );\n        },\n\n        undelegate: function( selector, types, fn ) {\n            if ( arguments.length === 0 ) {\n                return this.unbind( \"live\" );\n\n            } else {\n                return this.die( types, null, fn, selector );\n            }\n        },\n\n        trigger: function( type, data ) {\n            return this.each(function() {\n                jQuery.event.trigger( type, data, this );\n            });\n        },\n\n        triggerHandler: function( type, data ) {\n            if ( this[0] ) {\n                var event = jQuery.Event( type );\n                event.preventDefault();\n                event.stopPropagation();\n                jQuery.event.trigger( event, data, this[0] );\n                return event.result;\n            }\n        },\n\n        toggle: function( fn ) {\n            // Save reference to arguments for access in closure\n            var args = arguments,\n                i = 1;\n\n            // link all the functions, so any of them can unbind this click handler\n            while ( i < args.length ) {\n                jQuery.proxy( fn, args[ i++ ] );\n            }\n\n            return this.click( jQuery.proxy( fn, function( event ) {\n                // Figure out which function to execute\n                var lastToggle = ( jQuery._data( this, \"lastToggle\" + fn.guid ) || 0 ) % i;\n                jQuery._data( this, \"lastToggle\" + fn.guid, lastToggle + 1 );\n\n                // Make sure that clicks stop\n                event.preventDefault();\n\n                // and execute the function\n                return args[ lastToggle ].apply( this, arguments ) || false;\n            }));\n        },\n\n        hover: function( fnOver, fnOut ) {\n            return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );\n        }\n    });\n\n    var liveMap = {\n        focus: \"focusin\",\n        blur: \"focusout\",\n        mouseenter: \"mouseover\",\n        mouseleave: \"mouseout\"\n    };\n\n    jQuery.each([\"live\", \"die\"], function( i, name ) {\n        jQuery.fn[ name ] = function( types, data, fn, origSelector /* Internal Use Only */ ) {\n            var type, i = 0, match, namespaces, preType,\n                selector = origSelector || this.selector,\n                context = origSelector ? this : jQuery( this.context );\n\n            if ( typeof types === \"object\" && !types.preventDefault ) {\n                for ( var key in types ) {\n                    context[ name ]( key, data, types[key], selector );\n                }\n\n                return this;\n            }\n\n            if ( jQuery.isFunction( data ) ) {\n                fn = data;\n                data = undefined;\n            }\n\n            types = (types || \"\").split(\" \");\n\n            while ( (type = types[ i++ ]) != null ) {\n                match = rnamespaces.exec( type );\n                namespaces = \"\";\n\n                if ( match )  {\n                    namespaces = match[0];\n                    type = type.replace( rnamespaces, \"\" );\n                }\n\n                if ( type === \"hover\" ) {\n                    types.push( \"mouseenter\" + namespaces, \"mouseleave\" + namespaces );\n                    continue;\n                }\n\n                preType = type;\n\n                if ( type === \"focus\" || type === \"blur\" ) {\n                    types.push( liveMap[ type ] + namespaces );\n                    type = type + namespaces;\n\n                } else {\n                    type = (liveMap[ type ] || type) + namespaces;\n                }\n\n                if ( name === \"live\" ) {\n                    // bind live handler\n                    for ( var j = 0, l = context.length; j < l; j++ ) {\n                        jQuery.event.add( context[j], \"live.\" + liveConvert( type, selector ),\n                            { data: data, selector: selector, handler: fn, origType: type, origHandler: fn, preType: preType } );\n                    }\n\n                } else {\n                    // unbind live handler\n                    context.unbind( \"live.\" + liveConvert( type, selector ), fn );\n                }\n            }\n\n            return this;\n        };\n    });\n\n    function liveHandler( event ) {\n        var stop, maxLevel, related, match, handleObj, elem, j, i, l, data, close, namespace, ret,\n            elems = [],\n            selectors = [],\n            events = jQuery._data( this, \"events\" );\n\n        // Make sure we avoid non-left-click bubbling in Firefox (#3861) and disabled elements in IE (#6911)\n        if ( event.liveFired === this || !events || !events.live || event.target.disabled || event.button && event.type === \"click\" ) {\n            return;\n        }\n\n        if ( event.namespace ) {\n            namespace = new RegExp(\"(^|\\\\.)\" + event.namespace.split(\".\").join(\"\\\\.(?:.*\\\\.)?\") + \"(\\\\.|$)\");\n        }\n\n        event.liveFired = this;\n\n        var live = events.live.slice(0);\n\n        for ( j = 0; j < live.length; j++ ) {\n            handleObj = live[j];\n\n            if ( handleObj.origType.replace( rnamespaces, \"\" ) === event.type ) {\n                selectors.push( handleObj.selector );\n\n            } else {\n                live.splice( j--, 1 );\n            }\n        }\n\n        match = jQuery( event.target ).closest( selectors, event.currentTarget );\n\n        for ( i = 0, l = match.length; i < l; i++ ) {\n            close = match[i];\n\n            for ( j = 0; j < live.length; j++ ) {\n                handleObj = live[j];\n\n                if ( close.selector === handleObj.selector && (!namespace || namespace.test( handleObj.namespace )) && !close.elem.disabled ) {\n                    elem = close.elem;\n                    related = null;\n\n                    // Those two events require additional checking\n                    if ( handleObj.preType === \"mouseenter\" || handleObj.preType === \"mouseleave\" ) {\n                        event.type = handleObj.preType;\n                        related = jQuery( event.relatedTarget ).closest( handleObj.selector )[0];\n                    }\n\n                    if ( !related || related !== elem ) {\n                        elems.push({ elem: elem, handleObj: handleObj, level: close.level });\n                    }\n                }\n            }\n        }\n\n        for ( i = 0, l = elems.length; i < l; i++ ) {\n            match = elems[i];\n\n            if ( maxLevel && match.level > maxLevel ) {\n                break;\n            }\n\n            event.currentTarget = match.elem;\n            event.data = match.handleObj.data;\n            event.handleObj = match.handleObj;\n\n            ret = match.handleObj.origHandler.apply( match.elem, arguments );\n\n            if ( ret === false || event.isPropagationStopped() ) {\n                maxLevel = match.level;\n\n                if ( ret === false ) {\n                    stop = false;\n                }\n                if ( event.isImmediatePropagationStopped() ) {\n                    break;\n                }\n            }\n        }\n\n        return stop;\n    }\n\n    function liveConvert( type, selector ) {\n        return (type && type !== \"*\" ? type + \".\" : \"\") + selector.replace(rperiod, \"`\").replace(rspace, \"&\");\n    }\n\n    jQuery.each( (\"blur focus focusin focusout load resize scroll unload click dblclick \" +\n        \"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave \" +\n        \"change select submit keydown keypress keyup error\").split(\" \"), function( i, name ) {\n\n        // Handle event binding\n        jQuery.fn[ name ] = function( data, fn ) {\n            if ( fn == null ) {\n                fn = data;\n                data = null;\n            }\n\n            return arguments.length > 0 ?\n                this.bind( name, data, fn ) :\n                this.trigger( name );\n        };\n\n        if ( jQuery.attrFn ) {\n            jQuery.attrFn[ name ] = true;\n        }\n    });\n\n\n    /*!\n     * Sizzle CSS Selector Engine\n     *  Copyright 2011, The Dojo Foundation\n     *  Released under the MIT, BSD, and GPL Licenses.\n     *  More information: http://sizzlejs.com/\n     */\n    (function(){\n\n        var chunker = /((?:\\((?:\\([^()]+\\)|[^()]+)+\\)|\\[(?:\\[[^\\[\\]]*\\]|['\"][^'\"]*['\"]|[^\\[\\]'\"]+)+\\]|\\\\.|[^ >+~,(\\[\\\\]+)+|[>+~])(\\s*,\\s*)?((?:.|\\r|\\n)*)/g,\n            done = 0,\n            toString = Object.prototype.toString,\n            hasDuplicate = false,\n            baseHasDuplicate = true,\n            rBackslash = /\\\\/g,\n            rNonWord = /\\W/;\n\n// Here we check if the JavaScript engine is using some sort of\n// optimization where it does not always call our comparision\n// function. If that is the case, discard the hasDuplicate value.\n//   Thus far that includes Google Chrome.\n        [0, 0].sort(function() {\n            baseHasDuplicate = false;\n            return 0;\n        });\n\n        var Sizzle = function( selector, context, results, seed ) {\n            results = results || [];\n            context = context || document;\n\n            var origContext = context;\n\n            if ( context.nodeType !== 1 && context.nodeType !== 9 ) {\n                return [];\n            }\n\n            if ( !selector || typeof selector !== \"string\" ) {\n                return results;\n            }\n\n            var m, set, checkSet, extra, ret, cur, pop, i,\n                prune = true,\n                contextXML = Sizzle.isXML( context ),\n                parts = [],\n                soFar = selector;\n\n            // Reset the position of the chunker regexp (start from head)\n            do {\n                chunker.exec( \"\" );\n                m = chunker.exec( soFar );\n\n                if ( m ) {\n                    soFar = m[3];\n\n                    parts.push( m[1] );\n\n                    if ( m[2] ) {\n                        extra = m[3];\n                        break;\n                    }\n                }\n            } while ( m );\n\n            if ( parts.length > 1 && origPOS.exec( selector ) ) {\n\n                if ( parts.length === 2 && Expr.relative[ parts[0] ] ) {\n                    set = posProcess( parts[0] + parts[1], context );\n\n                } else {\n                    set = Expr.relative[ parts[0] ] ?\n                        [ context ] :\n                        Sizzle( parts.shift(), context );\n\n                    while ( parts.length ) {\n                        selector = parts.shift();\n\n                        if ( Expr.relative[ selector ] ) {\n                            selector += parts.shift();\n                        }\n\n                        set = posProcess( selector, set );\n                    }\n                }\n\n            } else {\n                // Take a shortcut and set the context if the root selector is an ID\n                // (but not if it'll be faster if the inner selector is an ID)\n                if ( !seed && parts.length > 1 && context.nodeType === 9 && !contextXML &&\n                    Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1]) ) {\n\n                    ret = Sizzle.find( parts.shift(), context, contextXML );\n                    context = ret.expr ?\n                        Sizzle.filter( ret.expr, ret.set )[0] :\n                        ret.set[0];\n                }\n\n                if ( context ) {\n                    ret = seed ?\n                    { expr: parts.pop(), set: makeArray(seed) } :\n                        Sizzle.find( parts.pop(), parts.length === 1 && (parts[0] === \"~\" || parts[0] === \"+\") && context.parentNode ? context.parentNode : context, contextXML );\n\n                    set = ret.expr ?\n                        Sizzle.filter( ret.expr, ret.set ) :\n                        ret.set;\n\n                    if ( parts.length > 0 ) {\n                        checkSet = makeArray( set );\n\n                    } else {\n                        prune = false;\n                    }\n\n                    while ( parts.length ) {\n                        cur = parts.pop();\n                        pop = cur;\n\n                        if ( !Expr.relative[ cur ] ) {\n                            cur = \"\";\n                        } else {\n                            pop = parts.pop();\n                        }\n\n                        if ( pop == null ) {\n                            pop = context;\n                        }\n\n                        Expr.relative[ cur ]( checkSet, pop, contextXML );\n                    }\n\n                } else {\n                    checkSet = parts = [];\n                }\n            }\n\n            if ( !checkSet ) {\n                checkSet = set;\n            }\n\n            if ( !checkSet ) {\n                Sizzle.error( cur || selector );\n            }\n\n            if ( toString.call(checkSet) === \"[object Array]\" ) {\n                if ( !prune ) {\n                    results.push.apply( results, checkSet );\n\n                } else if ( context && context.nodeType === 1 ) {\n                    for ( i = 0; checkSet[i] != null; i++ ) {\n                        if ( checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i])) ) {\n                            results.push( set[i] );\n                        }\n                    }\n\n                } else {\n                    for ( i = 0; checkSet[i] != null; i++ ) {\n                        if ( checkSet[i] && checkSet[i].nodeType === 1 ) {\n                            results.push( set[i] );\n                        }\n                    }\n                }\n\n            } else {\n                makeArray( checkSet, results );\n            }\n\n            if ( extra ) {\n                Sizzle( extra, origContext, results, seed );\n                Sizzle.uniqueSort( results );\n            }\n\n            return results;\n        };\n\n        Sizzle.uniqueSort = function( results ) {\n            if ( sortOrder ) {\n                hasDuplicate = baseHasDuplicate;\n                results.sort( sortOrder );\n\n                if ( hasDuplicate ) {\n                    for ( var i = 1; i < results.length; i++ ) {\n                        if ( results[i] === results[ i - 1 ] ) {\n                            results.splice( i--, 1 );\n                        }\n                    }\n                }\n            }\n\n            return results;\n        };\n\n        Sizzle.matches = function( expr, set ) {\n            return Sizzle( expr, null, null, set );\n        };\n\n        Sizzle.matchesSelector = function( node, expr ) {\n            return Sizzle( expr, null, null, [node] ).length > 0;\n        };\n\n        Sizzle.find = function( expr, context, isXML ) {\n            var set;\n\n            if ( !expr ) {\n                return [];\n            }\n\n            for ( var i = 0, l = Expr.order.length; i < l; i++ ) {\n                var match,\n                    type = Expr.order[i];\n\n                if ( (match = Expr.leftMatch[ type ].exec( expr )) ) {\n                    var left = match[1];\n                    match.splice( 1, 1 );\n\n                    if ( left.substr( left.length - 1 ) !== \"\\\\\" ) {\n                        match[1] = (match[1] || \"\").replace( rBackslash, \"\" );\n                        set = Expr.find[ type ]( match, context, isXML );\n\n                        if ( set != null ) {\n                            expr = expr.replace( Expr.match[ type ], \"\" );\n                            break;\n                        }\n                    }\n                }\n            }\n\n            if ( !set ) {\n                set = typeof context.getElementsByTagName !== \"undefined\" ?\n                    context.getElementsByTagName( \"*\" ) :\n                    [];\n            }\n\n            return { set: set, expr: expr };\n        };\n\n        Sizzle.filter = function( expr, set, inplace, not ) {\n            var match, anyFound,\n                old = expr,\n                result = [],\n                curLoop = set,\n                isXMLFilter = set && set[0] && Sizzle.isXML( set[0] );\n\n            while ( expr && set.length ) {\n                for ( var type in Expr.filter ) {\n                    if ( (match = Expr.leftMatch[ type ].exec( expr )) != null && match[2] ) {\n                        var found, item,\n                            filter = Expr.filter[ type ],\n                            left = match[1];\n\n                        anyFound = false;\n\n                        match.splice(1,1);\n\n                        if ( left.substr( left.length - 1 ) === \"\\\\\" ) {\n                            continue;\n                        }\n\n                        if ( curLoop === result ) {\n                            result = [];\n                        }\n\n                        if ( Expr.preFilter[ type ] ) {\n                            match = Expr.preFilter[ type ]( match, curLoop, inplace, result, not, isXMLFilter );\n\n                            if ( !match ) {\n                                anyFound = found = true;\n\n                            } else if ( match === true ) {\n                                continue;\n                            }\n                        }\n\n                        if ( match ) {\n                            for ( var i = 0; (item = curLoop[i]) != null; i++ ) {\n                                if ( item ) {\n                                    found = filter( item, match, i, curLoop );\n                                    var pass = not ^ !!found;\n\n                                    if ( inplace && found != null ) {\n                                        if ( pass ) {\n                                            anyFound = true;\n\n                                        } else {\n                                            curLoop[i] = false;\n                                        }\n\n                                    } else if ( pass ) {\n                                        result.push( item );\n                                        anyFound = true;\n                                    }\n                                }\n                            }\n                        }\n\n                        if ( found !== undefined ) {\n                            if ( !inplace ) {\n                                curLoop = result;\n                            }\n\n                            expr = expr.replace( Expr.match[ type ], \"\" );\n\n                            if ( !anyFound ) {\n                                return [];\n                            }\n\n                            break;\n                        }\n                    }\n                }\n\n                // Improper expression\n                if ( expr === old ) {\n                    if ( anyFound == null ) {\n                        Sizzle.error( expr );\n\n                    } else {\n                        break;\n                    }\n                }\n\n                old = expr;\n            }\n\n            return curLoop;\n        };\n\n        Sizzle.error = function( msg ) {\n            throw \"Syntax error, unrecognized expression: \" + msg;\n        };\n\n        var Expr = Sizzle.selectors = {\n            order: [ \"ID\", \"NAME\", \"TAG\" ],\n\n            match: {\n                ID: /#((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)/,\n                CLASS: /\\.((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)/,\n                NAME: /\\[name=['\"]*((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)['\"]*\\]/,\n                ATTR: /\\[\\s*((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)\\s*(?:(\\S?=)\\s*(?:(['\"])(.*?)\\3|(#?(?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)*)|)|)\\s*\\]/,\n                TAG: /^((?:[\\w\\u00c0-\\uFFFF\\*\\-]|\\\\.)+)/,\n                CHILD: /:(only|nth|last|first)-child(?:\\(\\s*(even|odd|(?:[+\\-]?\\d+|(?:[+\\-]?\\d*)?n\\s*(?:[+\\-]\\s*\\d+)?))\\s*\\))?/,\n                POS: /:(nth|eq|gt|lt|first|last|even|odd)(?:\\((\\d*)\\))?(?=[^\\-]|$)/,\n                PSEUDO: /:((?:[\\w\\u00c0-\\uFFFF\\-]|\\\\.)+)(?:\\((['\"]?)((?:\\([^\\)]+\\)|[^\\(\\)]*)+)\\2\\))?/\n            },\n\n            leftMatch: {},\n\n            attrMap: {\n                \"class\": \"className\",\n                \"for\": \"htmlFor\"\n            },\n\n            attrHandle: {\n                href: function( elem ) {\n                    return elem.getAttribute( \"href\" );\n                },\n                type: function( elem ) {\n                    return elem.getAttribute( \"type\" );\n                }\n            },\n\n            relative: {\n                \"+\": function(checkSet, part){\n                    var isPartStr = typeof part === \"string\",\n                        isTag = isPartStr && !rNonWord.test( part ),\n                        isPartStrNotTag = isPartStr && !isTag;\n\n                    if ( isTag ) {\n                        part = part.toLowerCase();\n                    }\n\n                    for ( var i = 0, l = checkSet.length, elem; i < l; i++ ) {\n                        if ( (elem = checkSet[i]) ) {\n                            while ( (elem = elem.previousSibling) && elem.nodeType !== 1 ) {}\n\n                            checkSet[i] = isPartStrNotTag || elem && elem.nodeName.toLowerCase() === part ?\n                                elem || false :\n                                elem === part;\n                        }\n                    }\n\n                    if ( isPartStrNotTag ) {\n                        Sizzle.filter( part, checkSet, true );\n                    }\n                },\n\n                \">\": function( checkSet, part ) {\n                    var elem,\n                        isPartStr = typeof part === \"string\",\n                        i = 0,\n                        l = checkSet.length;\n\n                    if ( isPartStr && !rNonWord.test( part ) ) {\n                        part = part.toLowerCase();\n\n                        for ( ; i < l; i++ ) {\n                            elem = checkSet[i];\n\n                            if ( elem ) {\n                                var parent = elem.parentNode;\n                                checkSet[i] = parent.nodeName.toLowerCase() === part ? parent : false;\n                            }\n                        }\n\n                    } else {\n                        for ( ; i < l; i++ ) {\n                            elem = checkSet[i];\n\n                            if ( elem ) {\n                                checkSet[i] = isPartStr ?\n                                    elem.parentNode :\n                                    elem.parentNode === part;\n                            }\n                        }\n\n                        if ( isPartStr ) {\n                            Sizzle.filter( part, checkSet, true );\n                        }\n                    }\n                },\n\n                \"\": function(checkSet, part, isXML){\n                    var nodeCheck,\n                        doneName = done++,\n                        checkFn = dirCheck;\n\n                    if ( typeof part === \"string\" && !rNonWord.test( part ) ) {\n                        part = part.toLowerCase();\n                        nodeCheck = part;\n                        checkFn = dirNodeCheck;\n                    }\n\n                    checkFn( \"parentNode\", part, doneName, checkSet, nodeCheck, isXML );\n                },\n\n                \"~\": function( checkSet, part, isXML ) {\n                    var nodeCheck,\n                        doneName = done++,\n                        checkFn = dirCheck;\n\n                    if ( typeof part === \"string\" && !rNonWord.test( part ) ) {\n                        part = part.toLowerCase();\n                        nodeCheck = part;\n                        checkFn = dirNodeCheck;\n                    }\n\n                    checkFn( \"previousSibling\", part, doneName, checkSet, nodeCheck, isXML );\n                }\n            },\n\n            find: {\n                ID: function( match, context, isXML ) {\n                    if ( typeof context.getElementById !== \"undefined\" && !isXML ) {\n                        var m = context.getElementById(match[1]);\n                        // Check parentNode to catch when Blackberry 4.6 returns\n                        // nodes that are no longer in the document #6963\n                        return m && m.parentNode ? [m] : [];\n                    }\n                },\n\n                NAME: function( match, context ) {\n                    if ( typeof context.getElementsByName !== \"undefined\" ) {\n                        var ret = [],\n                            results = context.getElementsByName( match[1] );\n\n                        for ( var i = 0, l = results.length; i < l; i++ ) {\n                            if ( results[i].getAttribute(\"name\") === match[1] ) {\n                                ret.push( results[i] );\n                            }\n                        }\n\n                        return ret.length === 0 ? null : ret;\n                    }\n                },\n\n                TAG: function( match, context ) {\n                    if ( typeof context.getElementsByTagName !== \"undefined\" ) {\n                        return context.getElementsByTagName( match[1] );\n                    }\n                }\n            },\n            preFilter: {\n                CLASS: function( match, curLoop, inplace, result, not, isXML ) {\n                    match = \" \" + match[1].replace( rBackslash, \"\" ) + \" \";\n\n                    if ( isXML ) {\n                        return match;\n                    }\n\n                    for ( var i = 0, elem; (elem = curLoop[i]) != null; i++ ) {\n                        if ( elem ) {\n                            if ( not ^ (elem.className && (\" \" + elem.className + \" \").replace(/[\\t\\n\\r]/g, \" \").indexOf(match) >= 0) ) {\n                                if ( !inplace ) {\n                                    result.push( elem );\n                                }\n\n                            } else if ( inplace ) {\n                                curLoop[i] = false;\n                            }\n                        }\n                    }\n\n                    return false;\n                },\n\n                ID: function( match ) {\n                    return match[1].replace( rBackslash, \"\" );\n                },\n\n                TAG: function( match, curLoop ) {\n                    return match[1].replace( rBackslash, \"\" ).toLowerCase();\n                },\n\n                CHILD: function( match ) {\n                    if ( match[1] === \"nth\" ) {\n                        if ( !match[2] ) {\n                            Sizzle.error( match[0] );\n                        }\n\n                        match[2] = match[2].replace(/^\\+|\\s*/g, '');\n\n                        // parse equations like 'even', 'odd', '5', '2n', '3n+2', '4n-1', '-n+6'\n                        var test = /(-?)(\\d*)(?:n([+\\-]?\\d*))?/.exec(\n                            match[2] === \"even\" && \"2n\" || match[2] === \"odd\" && \"2n+1\" ||\n                                !/\\D/.test( match[2] ) && \"0n+\" + match[2] || match[2]);\n\n                        // calculate the numbers (first)n+(last) including if they are negative\n                        match[2] = (test[1] + (test[2] || 1)) - 0;\n                        match[3] = test[3] - 0;\n                    }\n                    else if ( match[2] ) {\n                        Sizzle.error( match[0] );\n                    }\n\n                    // TODO: Move to normal caching system\n                    match[0] = done++;\n\n                    return match;\n                },\n\n                ATTR: function( match, curLoop, inplace, result, not, isXML ) {\n                    var name = match[1] = match[1].replace( rBackslash, \"\" );\n\n                    if ( !isXML && Expr.attrMap[name] ) {\n                        match[1] = Expr.attrMap[name];\n                    }\n\n                    // Handle if an un-quoted value was used\n                    match[4] = ( match[4] || match[5] || \"\" ).replace( rBackslash, \"\" );\n\n                    if ( match[2] === \"~=\" ) {\n                        match[4] = \" \" + match[4] + \" \";\n                    }\n\n                    return match;\n                },\n\n                PSEUDO: function( match, curLoop, inplace, result, not ) {\n                    if ( match[1] === \"not\" ) {\n                        // If we're dealing with a complex expression, or a simple one\n                        if ( ( chunker.exec(match[3]) || \"\" ).length > 1 || /^\\w/.test(match[3]) ) {\n                            match[3] = Sizzle(match[3], null, null, curLoop);\n\n                        } else {\n                            var ret = Sizzle.filter(match[3], curLoop, inplace, true ^ not);\n\n                            if ( !inplace ) {\n                                result.push.apply( result, ret );\n                            }\n\n                            return false;\n                        }\n\n                    } else if ( Expr.match.POS.test( match[0] ) || Expr.match.CHILD.test( match[0] ) ) {\n                        return true;\n                    }\n\n                    return match;\n                },\n\n                POS: function( match ) {\n                    match.unshift( true );\n\n                    return match;\n                }\n            },\n\n            filters: {\n                enabled: function( elem ) {\n                    return elem.disabled === false && elem.type !== \"hidden\";\n                },\n\n                disabled: function( elem ) {\n                    return elem.disabled === true;\n                },\n\n                checked: function( elem ) {\n                    return elem.checked === true;\n                },\n\n                selected: function( elem ) {\n                    // Accessing this property makes selected-by-default\n                    // options in Safari work properly\n                    if ( elem.parentNode ) {\n                        elem.parentNode.selectedIndex;\n                    }\n\n                    return elem.selected === true;\n                },\n\n                parent: function( elem ) {\n                    return !!elem.firstChild;\n                },\n\n                empty: function( elem ) {\n                    return !elem.firstChild;\n                },\n\n                has: function( elem, i, match ) {\n                    return !!Sizzle( match[3], elem ).length;\n                },\n\n                header: function( elem ) {\n                    return (/h\\d/i).test( elem.nodeName );\n                },\n\n                text: function( elem ) {\n                    var attr = elem.getAttribute( \"type\" ), type = elem.type;\n                    // IE6 and 7 will map elem.type to 'text' for new HTML5 types (search, etc) \n                    // use getAttribute instead to test this case\n                    return \"text\" === type && ( attr === type || attr === null );\n                },\n\n                radio: function( elem ) {\n                    return \"radio\" === elem.type;\n                },\n\n                checkbox: function( elem ) {\n                    return \"checkbox\" === elem.type;\n                },\n\n                file: function( elem ) {\n                    return \"file\" === elem.type;\n                },\n                password: function( elem ) {\n                    return \"password\" === elem.type;\n                },\n\n                submit: function( elem ) {\n                    return \"submit\" === elem.type;\n                },\n\n                image: function( elem ) {\n                    return \"image\" === elem.type;\n                },\n\n                reset: function( elem ) {\n                    return \"reset\" === elem.type;\n                },\n\n                button: function( elem ) {\n                    return \"button\" === elem.type || elem.nodeName.toLowerCase() === \"button\";\n                },\n\n                input: function( elem ) {\n                    return (/input|select|textarea|button/i).test( elem.nodeName );\n                }\n            },\n            setFilters: {\n                first: function( elem, i ) {\n                    return i === 0;\n                },\n\n                last: function( elem, i, match, array ) {\n                    return i === array.length - 1;\n                },\n\n                even: function( elem, i ) {\n                    return i % 2 === 0;\n                },\n\n                odd: function( elem, i ) {\n                    return i % 2 === 1;\n                },\n\n                lt: function( elem, i, match ) {\n                    return i < match[3] - 0;\n                },\n\n                gt: function( elem, i, match ) {\n                    return i > match[3] - 0;\n                },\n\n                nth: function( elem, i, match ) {\n                    return match[3] - 0 === i;\n                },\n\n                eq: function( elem, i, match ) {\n                    return match[3] - 0 === i;\n                }\n            },\n            filter: {\n                PSEUDO: function( elem, match, i, array ) {\n                    var name = match[1],\n                        filter = Expr.filters[ name ];\n\n                    if ( filter ) {\n                        return filter( elem, i, match, array );\n\n                    } else if ( name === \"contains\" ) {\n                        return (elem.textContent || elem.innerText || Sizzle.getText([ elem ]) || \"\").indexOf(match[3]) >= 0;\n\n                    } else if ( name === \"not\" ) {\n                        var not = match[3];\n\n                        for ( var j = 0, l = not.length; j < l; j++ ) {\n                            if ( not[j] === elem ) {\n                                return false;\n                            }\n                        }\n\n                        return true;\n\n                    } else {\n                        Sizzle.error( name );\n                    }\n                },\n\n                CHILD: function( elem, match ) {\n                    var type = match[1],\n                        node = elem;\n\n                    switch ( type ) {\n                        case \"only\":\n                        case \"first\":\n                            while ( (node = node.previousSibling) )\t {\n                                if ( node.nodeType === 1 ) {\n                                    return false;\n                                }\n                            }\n\n                            if ( type === \"first\" ) {\n                                return true;\n                            }\n\n                            node = elem;\n\n                        case \"last\":\n                            while ( (node = node.nextSibling) )\t {\n                                if ( node.nodeType === 1 ) {\n                                    return false;\n                                }\n                            }\n\n                            return true;\n\n                        case \"nth\":\n                            var first = match[2],\n                                last = match[3];\n\n                            if ( first === 1 && last === 0 ) {\n                                return true;\n                            }\n\n                            var doneName = match[0],\n                                parent = elem.parentNode;\n\n                            if ( parent && (parent.sizcache !== doneName || !elem.nodeIndex) ) {\n                                var count = 0;\n\n                                for ( node = parent.firstChild; node; node = node.nextSibling ) {\n                                    if ( node.nodeType === 1 ) {\n                                        node.nodeIndex = ++count;\n                                    }\n                                }\n\n                                parent.sizcache = doneName;\n                            }\n\n                            var diff = elem.nodeIndex - last;\n\n                            if ( first === 0 ) {\n                                return diff === 0;\n\n                            } else {\n                                return ( diff % first === 0 && diff / first >= 0 );\n                            }\n                    }\n                },\n\n                ID: function( elem, match ) {\n                    return elem.nodeType === 1 && elem.getAttribute(\"id\") === match;\n                },\n\n                TAG: function( elem, match ) {\n                    return (match === \"*\" && elem.nodeType === 1) || elem.nodeName.toLowerCase() === match;\n                },\n\n                CLASS: function( elem, match ) {\n                    return (\" \" + (elem.className || elem.getAttribute(\"class\")) + \" \")\n                        .indexOf( match ) > -1;\n                },\n\n                ATTR: function( elem, match ) {\n                    var name = match[1],\n                        result = Expr.attrHandle[ name ] ?\n                            Expr.attrHandle[ name ]( elem ) :\n                            elem[ name ] != null ?\n                                elem[ name ] :\n                                elem.getAttribute( name ),\n                        value = result + \"\",\n                        type = match[2],\n                        check = match[4];\n\n                    return result == null ?\n                        type === \"!=\" :\n                        type === \"=\" ?\n                            value === check :\n                            type === \"*=\" ?\n                                value.indexOf(check) >= 0 :\n                                type === \"~=\" ?\n                                    (\" \" + value + \" \").indexOf(check) >= 0 :\n                                    !check ?\n                                        value && result !== false :\n                                        type === \"!=\" ?\n                                            value !== check :\n                                            type === \"^=\" ?\n                                                value.indexOf(check) === 0 :\n                                                type === \"$=\" ?\n                                                    value.substr(value.length - check.length) === check :\n                                                    type === \"|=\" ?\n                                                        value === check || value.substr(0, check.length + 1) === check + \"-\" :\n                                                        false;\n                },\n\n                POS: function( elem, match, i, array ) {\n                    var name = match[2],\n                        filter = Expr.setFilters[ name ];\n\n                    if ( filter ) {\n                        return filter( elem, i, match, array );\n                    }\n                }\n            }\n        };\n\n        var origPOS = Expr.match.POS,\n            fescape = function(all, num){\n                return \"\\\\\" + (num - 0 + 1);\n            };\n\n        for ( var type in Expr.match ) {\n            Expr.match[ type ] = new RegExp( Expr.match[ type ].source + (/(?![^\\[]*\\])(?![^\\(]*\\))/.source) );\n            Expr.leftMatch[ type ] = new RegExp( /(^(?:.|\\r|\\n)*?)/.source + Expr.match[ type ].source.replace(/\\\\(\\d+)/g, fescape) );\n        }\n\n        var makeArray = function( array, results ) {\n            array = Array.prototype.slice.call( array, 0 );\n\n            if ( results ) {\n                results.push.apply( results, array );\n                return results;\n            }\n\n            return array;\n        };\n\n// Perform a simple check to determine if the browser is capable of\n// converting a NodeList to an array using builtin methods.\n// Also verifies that the returned array holds DOM nodes\n// (which is not the case in the Blackberry browser)\n        try {\n            Array.prototype.slice.call( document.documentElement.childNodes, 0 )[0].nodeType;\n\n// Provide a fallback method if it does not work\n        } catch( e ) {\n            makeArray = function( array, results ) {\n                var i = 0,\n                    ret = results || [];\n\n                if ( toString.call(array) === \"[object Array]\" ) {\n                    Array.prototype.push.apply( ret, array );\n\n                } else {\n                    if ( typeof array.length === \"number\" ) {\n                        for ( var l = array.length; i < l; i++ ) {\n                            ret.push( array[i] );\n                        }\n\n                    } else {\n                        for ( ; array[i]; i++ ) {\n                            ret.push( array[i] );\n                        }\n                    }\n                }\n\n                return ret;\n            };\n        }\n\n        var sortOrder, siblingCheck;\n\n        if ( document.documentElement.compareDocumentPosition ) {\n            sortOrder = function( a, b ) {\n                if ( a === b ) {\n                    hasDuplicate = true;\n                    return 0;\n                }\n\n                if ( !a.compareDocumentPosition || !b.compareDocumentPosition ) {\n                    return a.compareDocumentPosition ? -1 : 1;\n                }\n\n                return a.compareDocumentPosition(b) & 4 ? -1 : 1;\n            };\n\n        } else {\n            sortOrder = function( a, b ) {\n                var al, bl,\n                    ap = [],\n                    bp = [],\n                    aup = a.parentNode,\n                    bup = b.parentNode,\n                    cur = aup;\n\n                // The nodes are identical, we can exit early\n                if ( a === b ) {\n                    hasDuplicate = true;\n                    return 0;\n\n                    // If the nodes are siblings (or identical) we can do a quick check\n                } else if ( aup === bup ) {\n                    return siblingCheck( a, b );\n\n                    // If no parents were found then the nodes are disconnected\n                } else if ( !aup ) {\n                    return -1;\n\n                } else if ( !bup ) {\n                    return 1;\n                }\n\n                // Otherwise they're somewhere else in the tree so we need\n                // to build up a full list of the parentNodes for comparison\n                while ( cur ) {\n                    ap.unshift( cur );\n                    cur = cur.parentNode;\n                }\n\n                cur = bup;\n\n                while ( cur ) {\n                    bp.unshift( cur );\n                    cur = cur.parentNode;\n                }\n\n                al = ap.length;\n                bl = bp.length;\n\n                // Start walking down the tree looking for a discrepancy\n                for ( var i = 0; i < al && i < bl; i++ ) {\n                    if ( ap[i] !== bp[i] ) {\n                        return siblingCheck( ap[i], bp[i] );\n                    }\n                }\n\n                // We ended someplace up the tree so do a sibling check\n                return i === al ?\n                    siblingCheck( a, bp[i], -1 ) :\n                    siblingCheck( ap[i], b, 1 );\n            };\n\n            siblingCheck = function( a, b, ret ) {\n                if ( a === b ) {\n                    return ret;\n                }\n\n                var cur = a.nextSibling;\n\n                while ( cur ) {\n                    if ( cur === b ) {\n                        return -1;\n                    }\n\n                    cur = cur.nextSibling;\n                }\n\n                return 1;\n            };\n        }\n\n// Utility function for retreiving the text value of an array of DOM nodes\n        Sizzle.getText = function( elems ) {\n            var ret = \"\", elem;\n\n            for ( var i = 0; elems[i]; i++ ) {\n                elem = elems[i];\n\n                // Get the text from text nodes and CDATA nodes\n                if ( elem.nodeType === 3 || elem.nodeType === 4 ) {\n                    ret += elem.nodeValue;\n\n                    // Traverse everything else, except comment nodes\n                } else if ( elem.nodeType !== 8 ) {\n                    ret += Sizzle.getText( elem.childNodes );\n                }\n            }\n\n            return ret;\n        };\n\n// Check to see if the browser returns elements by name when\n// querying by getElementById (and provide a workaround)\n        (function(){\n            // We're going to inject a fake input element with a specified name\n            var form = document.createElement(\"div\"),\n                id = \"script\" + (new Date()).getTime(),\n                root = document.documentElement;\n\n            form.innerHTML = \"<a name='\" + id + \"'/>\";\n\n            // Inject it into the root element, check its status, and remove it quickly\n            root.insertBefore( form, root.firstChild );\n\n            // The workaround has to do additional checks after a getElementById\n            // Which slows things down for other browsers (hence the branching)\n            if ( document.getElementById( id ) ) {\n                Expr.find.ID = function( match, context, isXML ) {\n                    if ( typeof context.getElementById !== \"undefined\" && !isXML ) {\n                        var m = context.getElementById(match[1]);\n\n                        return m ?\n                            m.id === match[1] || typeof m.getAttributeNode !== \"undefined\" && m.getAttributeNode(\"id\").nodeValue === match[1] ?\n                                [m] :\n                                undefined :\n                            [];\n                    }\n                };\n\n                Expr.filter.ID = function( elem, match ) {\n                    var node = typeof elem.getAttributeNode !== \"undefined\" && elem.getAttributeNode(\"id\");\n\n                    return elem.nodeType === 1 && node && node.nodeValue === match;\n                };\n            }\n\n            root.removeChild( form );\n\n            // release memory in IE\n            root = form = null;\n        })();\n\n        (function(){\n            // Check to see if the browser returns only elements\n            // when doing getElementsByTagName(\"*\")\n\n            // Create a fake element\n            var div = document.createElement(\"div\");\n            div.appendChild( document.createComment(\"\") );\n\n            // Make sure no comments are found\n            if ( div.getElementsByTagName(\"*\").length > 0 ) {\n                Expr.find.TAG = function( match, context ) {\n                    var results = context.getElementsByTagName( match[1] );\n\n                    // Filter out possible comments\n                    if ( match[1] === \"*\" ) {\n                        var tmp = [];\n\n                        for ( var i = 0; results[i]; i++ ) {\n                            if ( results[i].nodeType === 1 ) {\n                                tmp.push( results[i] );\n                            }\n                        }\n\n                        results = tmp;\n                    }\n\n                    return results;\n                };\n            }\n\n            // Check to see if an attribute returns normalized href attributes\n            div.innerHTML = \"<a href='#'></a>\";\n\n            if ( div.firstChild && typeof div.firstChild.getAttribute !== \"undefined\" &&\n                div.firstChild.getAttribute(\"href\") !== \"#\" ) {\n\n                Expr.attrHandle.href = function( elem ) {\n                    return elem.getAttribute( \"href\", 2 );\n                };\n            }\n\n            // release memory in IE\n            div = null;\n        })();\n\n        if ( document.querySelectorAll ) {\n            (function(){\n                var oldSizzle = Sizzle,\n                    div = document.createElement(\"div\"),\n                    id = \"__sizzle__\";\n\n                div.innerHTML = \"<p class='TEST'></p>\";\n\n                // Safari can't handle uppercase or unicode characters when\n                // in quirks mode.\n                if ( div.querySelectorAll && div.querySelectorAll(\".TEST\").length === 0 ) {\n                    return;\n                }\n\n                Sizzle = function( query, context, extra, seed ) {\n                    context = context || document;\n\n                    // Only use querySelectorAll on non-XML documents\n                    // (ID selectors don't work in non-HTML documents)\n                    if ( !seed && !Sizzle.isXML(context) ) {\n                        // See if we find a selector to speed up\n                        var match = /^(\\w+$)|^\\.([\\w\\-]+$)|^#([\\w\\-]+$)/.exec( query );\n\n                        if ( match && (context.nodeType === 1 || context.nodeType === 9) ) {\n                            // Speed-up: Sizzle(\"TAG\")\n                            if ( match[1] ) {\n                                return makeArray( context.getElementsByTagName( query ), extra );\n\n                                // Speed-up: Sizzle(\".CLASS\")\n                            } else if ( match[2] && Expr.find.CLASS && context.getElementsByClassName ) {\n                                return makeArray( context.getElementsByClassName( match[2] ), extra );\n                            }\n                        }\n\n                        if ( context.nodeType === 9 ) {\n                            // Speed-up: Sizzle(\"body\")\n                            // The body element only exists once, optimize finding it\n                            if ( query === \"body\" && context.body ) {\n                                return makeArray( [ context.body ], extra );\n\n                                // Speed-up: Sizzle(\"#ID\")\n                            } else if ( match && match[3] ) {\n                                var elem = context.getElementById( match[3] );\n\n                                // Check parentNode to catch when Blackberry 4.6 returns\n                                // nodes that are no longer in the document #6963\n                                if ( elem && elem.parentNode ) {\n                                    // Handle the case where IE and Opera return items\n                                    // by name instead of ID\n                                    if ( elem.id === match[3] ) {\n                                        return makeArray( [ elem ], extra );\n                                    }\n\n                                } else {\n                                    return makeArray( [], extra );\n                                }\n                            }\n\n                            try {\n                                return makeArray( context.querySelectorAll(query), extra );\n                            } catch(qsaError) {}\n\n                            // qSA works strangely on Element-rooted queries\n                            // We can work around this by specifying an extra ID on the root\n                            // and working up from there (Thanks to Andrew Dupont for the technique)\n                            // IE 8 doesn't work on object elements\n                        } else if ( context.nodeType === 1 && context.nodeName.toLowerCase() !== \"object\" ) {\n                            var oldContext = context,\n                                old = context.getAttribute( \"id\" ),\n                                nid = old || id,\n                                hasParent = context.parentNode,\n                                relativeHierarchySelector = /^\\s*[+~]/.test( query );\n\n                            if ( !old ) {\n                                context.setAttribute( \"id\", nid );\n                            } else {\n                                nid = nid.replace( /'/g, \"\\\\$&\" );\n                            }\n                            if ( relativeHierarchySelector && hasParent ) {\n                                context = context.parentNode;\n                            }\n\n                            try {\n                                if ( !relativeHierarchySelector || hasParent ) {\n                                    return makeArray( context.querySelectorAll( \"[id='\" + nid + \"'] \" + query ), extra );\n                                }\n\n                            } catch(pseudoError) {\n                            } finally {\n                                if ( !old ) {\n                                    oldContext.removeAttribute( \"id\" );\n                                }\n                            }\n                        }\n                    }\n\n                    return oldSizzle(query, context, extra, seed);\n                };\n\n                for ( var prop in oldSizzle ) {\n                    Sizzle[ prop ] = oldSizzle[ prop ];\n                }\n\n                // release memory in IE\n                div = null;\n            })();\n        }\n\n        (function(){\n            var html = document.documentElement,\n                matches = html.matchesSelector || html.mozMatchesSelector || html.webkitMatchesSelector || html.msMatchesSelector;\n\n            if ( matches ) {\n                // Check to see if it's possible to do matchesSelector\n                // on a disconnected node (IE 9 fails this)\n                var disconnectedMatch = !matches.call( document.createElement( \"div\" ), \"div\" ),\n                    pseudoWorks = false;\n\n                try {\n                    // This should fail with an exception\n                    // Gecko does not error, returns false instead\n                    matches.call( document.documentElement, \"[test!='']:sizzle\" );\n\n                } catch( pseudoError ) {\n                    pseudoWorks = true;\n                }\n\n                Sizzle.matchesSelector = function( node, expr ) {\n                    // Make sure that attribute selectors are quoted\n                    expr = expr.replace(/\\=\\s*([^'\"\\]]*)\\s*\\]/g, \"='$1']\");\n\n                    if ( !Sizzle.isXML( node ) ) {\n                        try {\n                            if ( pseudoWorks || !Expr.match.PSEUDO.test( expr ) && !/!=/.test( expr ) ) {\n                                var ret = matches.call( node, expr );\n\n                                // IE 9's matchesSelector returns false on disconnected nodes\n                                if ( ret || !disconnectedMatch ||\n                                    // As well, disconnected nodes are said to be in a document\n                                    // fragment in IE 9, so check for that\n                                    node.document && node.document.nodeType !== 11 ) {\n                                    return ret;\n                                }\n                            }\n                        } catch(e) {}\n                    }\n\n                    return Sizzle(expr, null, null, [node]).length > 0;\n                };\n            }\n        })();\n\n        (function(){\n            var div = document.createElement(\"div\");\n\n            div.innerHTML = \"<div class='test e'></div><div class='test'></div>\";\n\n            // Opera can't find a second classname (in 9.6)\n            // Also, make sure that getElementsByClassName actually exists\n            if ( !div.getElementsByClassName || div.getElementsByClassName(\"e\").length === 0 ) {\n                return;\n            }\n\n            // Safari caches class attributes, doesn't catch changes (in 3.2)\n            div.lastChild.className = \"e\";\n\n            if ( div.getElementsByClassName(\"e\").length === 1 ) {\n                return;\n            }\n\n            Expr.order.splice(1, 0, \"CLASS\");\n            Expr.find.CLASS = function( match, context, isXML ) {\n                if ( typeof context.getElementsByClassName !== \"undefined\" && !isXML ) {\n                    return context.getElementsByClassName(match[1]);\n                }\n            };\n\n            // release memory in IE\n            div = null;\n        })();\n\n        function dirNodeCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {\n            for ( var i = 0, l = checkSet.length; i < l; i++ ) {\n                var elem = checkSet[i];\n\n                if ( elem ) {\n                    var match = false;\n\n                    elem = elem[dir];\n\n                    while ( elem ) {\n                        if ( elem.sizcache === doneName ) {\n                            match = checkSet[elem.sizset];\n                            break;\n                        }\n\n                        if ( elem.nodeType === 1 && !isXML ){\n                            elem.sizcache = doneName;\n                            elem.sizset = i;\n                        }\n\n                        if ( elem.nodeName.toLowerCase() === cur ) {\n                            match = elem;\n                            break;\n                        }\n\n                        elem = elem[dir];\n                    }\n\n                    checkSet[i] = match;\n                }\n            }\n        }\n\n        function dirCheck( dir, cur, doneName, checkSet, nodeCheck, isXML ) {\n            for ( var i = 0, l = checkSet.length; i < l; i++ ) {\n                var elem = checkSet[i];\n\n                if ( elem ) {\n                    var match = false;\n\n                    elem = elem[dir];\n\n                    while ( elem ) {\n                        if ( elem.sizcache === doneName ) {\n                            match = checkSet[elem.sizset];\n                            break;\n                        }\n\n                        if ( elem.nodeType === 1 ) {\n                            if ( !isXML ) {\n                                elem.sizcache = doneName;\n                                elem.sizset = i;\n                            }\n\n                            if ( typeof cur !== \"string\" ) {\n                                if ( elem === cur ) {\n                                    match = true;\n                                    break;\n                                }\n\n                            } else if ( Sizzle.filter( cur, [elem] ).length > 0 ) {\n                                match = elem;\n                                break;\n                            }\n                        }\n\n                        elem = elem[dir];\n                    }\n\n                    checkSet[i] = match;\n                }\n            }\n        }\n\n        if ( document.documentElement.contains ) {\n            Sizzle.contains = function( a, b ) {\n                return a !== b && (a.contains ? a.contains(b) : true);\n            };\n\n        } else if ( document.documentElement.compareDocumentPosition ) {\n            Sizzle.contains = function( a, b ) {\n                return !!(a.compareDocumentPosition(b) & 16);\n            };\n\n        } else {\n            Sizzle.contains = function() {\n                return false;\n            };\n        }\n\n        Sizzle.isXML = function( elem ) {\n            // documentElement is verified for cases where it doesn't yet exist\n            // (such as loading iframes in IE - #4833) \n            var documentElement = (elem ? elem.ownerDocument || elem : 0).documentElement;\n\n            return documentElement ? documentElement.nodeName !== \"HTML\" : false;\n        };\n\n        var posProcess = function( selector, context ) {\n            var match,\n                tmpSet = [],\n                later = \"\",\n                root = context.nodeType ? [context] : context;\n\n            // Position selectors must be done after the filter\n            // And so must :not(positional) so we move all PSEUDOs to the end\n            while ( (match = Expr.match.PSEUDO.exec( selector )) ) {\n                later += match[0];\n                selector = selector.replace( Expr.match.PSEUDO, \"\" );\n            }\n\n            selector = Expr.relative[selector] ? selector + \"*\" : selector;\n\n            for ( var i = 0, l = root.length; i < l; i++ ) {\n                Sizzle( selector, root[i], tmpSet );\n            }\n\n            return Sizzle.filter( later, tmpSet );\n        };\n\n// EXPOSE\n        jQuery.find = Sizzle;\n        jQuery.expr = Sizzle.selectors;\n        jQuery.expr[\":\"] = jQuery.expr.filters;\n        jQuery.unique = Sizzle.uniqueSort;\n        jQuery.text = Sizzle.getText;\n        jQuery.isXMLDoc = Sizzle.isXML;\n        jQuery.contains = Sizzle.contains;\n\n\n    })();\n\n\n    var runtil = /Until$/,\n        rparentsprev = /^(?:parents|prevUntil|prevAll)/,\n    // Note: This RegExp should be improved, or likely pulled from Sizzle\n        rmultiselector = /,/,\n        isSimple = /^.[^:#\\[\\.,]*$/,\n        slice = Array.prototype.slice,\n        POS = jQuery.expr.match.POS,\n    // methods guaranteed to produce a unique set when starting from a unique set\n        guaranteedUnique = {\n            children: true,\n            contents: true,\n            next: true,\n            prev: true\n        };\n\n    jQuery.fn.extend({\n        find: function( selector ) {\n            var ret = this.pushStack( \"\", \"find\", selector ),\n                length = 0;\n\n            for ( var i = 0, l = this.length; i < l; i++ ) {\n                length = ret.length;\n                jQuery.find( selector, this[i], ret );\n\n                if ( i > 0 ) {\n                    // Make sure that the results are unique\n                    for ( var n = length; n < ret.length; n++ ) {\n                        for ( var r = 0; r < length; r++ ) {\n                            if ( ret[r] === ret[n] ) {\n                                ret.splice(n--, 1);\n                                break;\n                            }\n                        }\n                    }\n                }\n            }\n\n            return ret;\n        },\n\n        has: function( target ) {\n            var targets = jQuery( target );\n            return this.filter(function() {\n                for ( var i = 0, l = targets.length; i < l; i++ ) {\n                    if ( jQuery.contains( this, targets[i] ) ) {\n                        return true;\n                    }\n                }\n            });\n        },\n\n        not: function( selector ) {\n            return this.pushStack( winnow(this, selector, false), \"not\", selector);\n        },\n\n        filter: function( selector ) {\n            return this.pushStack( winnow(this, selector, true), \"filter\", selector );\n        },\n\n        is: function( selector ) {\n            return !!selector && jQuery.filter( selector, this ).length > 0;\n        },\n\n        closest: function( selectors, context ) {\n            var ret = [], i, l, cur = this[0];\n\n            if ( jQuery.isArray( selectors ) ) {\n                var match, selector,\n                    matches = {},\n                    level = 1;\n\n                if ( cur && selectors.length ) {\n                    for ( i = 0, l = selectors.length; i < l; i++ ) {\n                        selector = selectors[i];\n\n                        if ( !matches[selector] ) {\n                            matches[selector] = jQuery.expr.match.POS.test( selector ) ?\n                                jQuery( selector, context || this.context ) :\n                                selector;\n                        }\n                    }\n\n                    while ( cur && cur.ownerDocument && cur !== context ) {\n                        for ( selector in matches ) {\n                            match = matches[selector];\n\n                            if ( match.jquery ? match.index(cur) > -1 : jQuery(cur).is(match) ) {\n                                ret.push({ selector: selector, elem: cur, level: level });\n                            }\n                        }\n\n                        cur = cur.parentNode;\n                        level++;\n                    }\n                }\n\n                return ret;\n            }\n\n            var pos = POS.test( selectors ) ?\n                jQuery( selectors, context || this.context ) : null;\n\n            for ( i = 0, l = this.length; i < l; i++ ) {\n                cur = this[i];\n\n                while ( cur ) {\n                    if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {\n                        ret.push( cur );\n                        break;\n\n                    } else {\n                        cur = cur.parentNode;\n                        if ( !cur || !cur.ownerDocument || cur === context ) {\n                            break;\n                        }\n                    }\n                }\n            }\n\n            ret = ret.length > 1 ? jQuery.unique(ret) : ret;\n\n            return this.pushStack( ret, \"closest\", selectors );\n        },\n\n        // Determine the position of an element within\n        // the matched set of elements\n        index: function( elem ) {\n            if ( !elem || typeof elem === \"string\" ) {\n                return jQuery.inArray( this[0],\n                    // If it receives a string, the selector is used\n                    // If it receives nothing, the siblings are used\n                    elem ? jQuery( elem ) : this.parent().children() );\n            }\n            // Locate the position of the desired element\n            return jQuery.inArray(\n                // If it receives a jQuery object, the first element is used\n                elem.jquery ? elem[0] : elem, this );\n        },\n\n        add: function( selector, context ) {\n            var set = typeof selector === \"string\" ?\n                    jQuery( selector, context ) :\n                    jQuery.makeArray( selector ),\n                all = jQuery.merge( this.get(), set );\n\n            return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?\n                all :\n                jQuery.unique( all ) );\n        },\n\n        andSelf: function() {\n            return this.add( this.prevObject );\n        }\n    });\n\n// A painfully simple check to see if an element is disconnected\n// from a document (should be improved, where feasible).\n    function isDisconnected( node ) {\n        return !node || !node.parentNode || node.parentNode.nodeType === 11;\n    }\n\n    jQuery.each({\n        parent: function( elem ) {\n            var parent = elem.parentNode;\n            return parent && parent.nodeType !== 11 ? parent : null;\n        },\n        parents: function( elem ) {\n            return jQuery.dir( elem, \"parentNode\" );\n        },\n        parentsUntil: function( elem, i, until ) {\n            return jQuery.dir( elem, \"parentNode\", until );\n        },\n        next: function( elem ) {\n            return jQuery.nth( elem, 2, \"nextSibling\" );\n        },\n        prev: function( elem ) {\n            return jQuery.nth( elem, 2, \"previousSibling\" );\n        },\n        nextAll: function( elem ) {\n            return jQuery.dir( elem, \"nextSibling\" );\n        },\n        prevAll: function( elem ) {\n            return jQuery.dir( elem, \"previousSibling\" );\n        },\n        nextUntil: function( elem, i, until ) {\n            return jQuery.dir( elem, \"nextSibling\", until );\n        },\n        prevUntil: function( elem, i, until ) {\n            return jQuery.dir( elem, \"previousSibling\", until );\n        },\n        siblings: function( elem ) {\n            return jQuery.sibling( elem.parentNode.firstChild, elem );\n        },\n        children: function( elem ) {\n            return jQuery.sibling( elem.firstChild );\n        },\n        contents: function( elem ) {\n            return jQuery.nodeName( elem, \"iframe\" ) ?\n                elem.contentDocument || elem.contentWindow.document :\n                jQuery.makeArray( elem.childNodes );\n        }\n    }, function( name, fn ) {\n        jQuery.fn[ name ] = function( until, selector ) {\n            var ret = jQuery.map( this, fn, until ),\n            // The variable 'args' was introduced in\n            // https://github.com/jquery/jquery/commit/52a0238\n            // to work around a bug in Chrome 10 (Dev) and should be removed when the bug is fixed.\n            // http://code.google.com/p/v8/issues/detail?id=1050\n                args = slice.call(arguments);\n\n            if ( !runtil.test( name ) ) {\n                selector = until;\n            }\n\n            if ( selector && typeof selector === \"string\" ) {\n                ret = jQuery.filter( selector, ret );\n            }\n\n            ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;\n\n            if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {\n                ret = ret.reverse();\n            }\n\n            return this.pushStack( ret, name, args.join(\",\") );\n        };\n    });\n\n    jQuery.extend({\n        filter: function( expr, elems, not ) {\n            if ( not ) {\n                expr = \":not(\" + expr + \")\";\n            }\n\n            return elems.length === 1 ?\n                jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :\n                jQuery.find.matches(expr, elems);\n        },\n\n        dir: function( elem, dir, until ) {\n            var matched = [],\n                cur = elem[ dir ];\n\n            while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {\n                if ( cur.nodeType === 1 ) {\n                    matched.push( cur );\n                }\n                cur = cur[dir];\n            }\n            return matched;\n        },\n\n        nth: function( cur, result, dir, elem ) {\n            result = result || 1;\n            var num = 0;\n\n            for ( ; cur; cur = cur[dir] ) {\n                if ( cur.nodeType === 1 && ++num === result ) {\n                    break;\n                }\n            }\n\n            return cur;\n        },\n\n        sibling: function( n, elem ) {\n            var r = [];\n\n            for ( ; n; n = n.nextSibling ) {\n                if ( n.nodeType === 1 && n !== elem ) {\n                    r.push( n );\n                }\n            }\n\n            return r;\n        }\n    });\n\n// Implement the identical functionality for filter and not\n    function winnow( elements, qualifier, keep ) {\n        if ( jQuery.isFunction( qualifier ) ) {\n            return jQuery.grep(elements, function( elem, i ) {\n                var retVal = !!qualifier.call( elem, i, elem );\n                return retVal === keep;\n            });\n\n        } else if ( qualifier.nodeType ) {\n            return jQuery.grep(elements, function( elem, i ) {\n                return (elem === qualifier) === keep;\n            });\n\n        } else if ( typeof qualifier === \"string\" ) {\n            var filtered = jQuery.grep(elements, function( elem ) {\n                return elem.nodeType === 1;\n            });\n\n            if ( isSimple.test( qualifier ) ) {\n                return jQuery.filter(qualifier, filtered, !keep);\n            } else {\n                qualifier = jQuery.filter( qualifier, filtered );\n            }\n        }\n\n        return jQuery.grep(elements, function( elem, i ) {\n            return (jQuery.inArray( elem, qualifier ) >= 0) === keep;\n        });\n    }\n\n\n\n\n    var rinlinejQuery = / jQuery\\d+=\"(?:\\d+|null)\"/g,\n        rleadingWhitespace = /^\\s+/,\n        rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\\w:]+)[^>]*)\\/>/ig,\n        rtagName = /<([\\w:]+)/,\n        rtbody = /<tbody/i,\n        rhtml = /<|&#?\\w+;/,\n        rnocache = /<(?:script|object|embed|option|style)/i,\n    // checked=\"checked\" or checked\n        rchecked = /checked\\s*(?:[^=]|=\\s*.checked.)/i,\n        wrapMap = {\n            option: [ 1, \"<select multiple='multiple'>\", \"</select>\" ],\n            legend: [ 1, \"<fieldset>\", \"</fieldset>\" ],\n            thead: [ 1, \"<table>\", \"</table>\" ],\n            tr: [ 2, \"<table><tbody>\", \"</tbody></table>\" ],\n            td: [ 3, \"<table><tbody><tr>\", \"</tr></tbody></table>\" ],\n            col: [ 2, \"<table><tbody></tbody><colgroup>\", \"</colgroup></table>\" ],\n            area: [ 1, \"<map>\", \"</map>\" ],\n            _default: [ 0, \"\", \"\" ]\n        };\n\n    wrapMap.optgroup = wrapMap.option;\n    wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;\n    wrapMap.th = wrapMap.td;\n\n// IE can't serialize <link> and <script> tags normally\n    if ( !jQuery.support.htmlSerialize ) {\n        wrapMap._default = [ 1, \"div<div>\", \"</div>\" ];\n    }\n\n    jQuery.fn.extend({\n        text: function( text ) {\n            if ( jQuery.isFunction(text) ) {\n                return this.each(function(i) {\n                    var self = jQuery( this );\n\n                    self.text( text.call(this, i, self.text()) );\n                });\n            }\n\n            if ( typeof text !== \"object\" && text !== undefined ) {\n                return this.empty().append( (this[0] && this[0].ownerDocument || document).createTextNode( text ) );\n            }\n\n            return jQuery.text( this );\n        },\n\n        wrapAll: function( html ) {\n            if ( jQuery.isFunction( html ) ) {\n                return this.each(function(i) {\n                    jQuery(this).wrapAll( html.call(this, i) );\n                });\n            }\n\n            if ( this[0] ) {\n                // The elements to wrap the target around\n                var wrap = jQuery( html, this[0].ownerDocument ).eq(0).clone(true);\n\n                if ( this[0].parentNode ) {\n                    wrap.insertBefore( this[0] );\n                }\n\n                wrap.map(function() {\n                    var elem = this;\n\n                    while ( elem.firstChild && elem.firstChild.nodeType === 1 ) {\n                        elem = elem.firstChild;\n                    }\n\n                    return elem;\n                }).append(this);\n            }\n\n            return this;\n        },\n\n        wrapInner: function( html ) {\n            if ( jQuery.isFunction( html ) ) {\n                return this.each(function(i) {\n                    jQuery(this).wrapInner( html.call(this, i) );\n                });\n            }\n\n            return this.each(function() {\n                var self = jQuery( this ),\n                    contents = self.contents();\n\n                if ( contents.length ) {\n                    contents.wrapAll( html );\n\n                } else {\n                    self.append( html );\n                }\n            });\n        },\n\n        wrap: function( html ) {\n            return this.each(function() {\n                jQuery( this ).wrapAll( html );\n            });\n        },\n\n        unwrap: function() {\n            return this.parent().each(function() {\n                if ( !jQuery.nodeName( this, \"body\" ) ) {\n                    jQuery( this ).replaceWith( this.childNodes );\n                }\n            }).end();\n        },\n\n        append: function() {\n            return this.domManip(arguments, true, function( elem ) {\n                if ( this.nodeType === 1 ) {\n                    this.appendChild( elem );\n                }\n            });\n        },\n\n        prepend: function() {\n            return this.domManip(arguments, true, function( elem ) {\n                if ( this.nodeType === 1 ) {\n                    this.insertBefore( elem, this.firstChild );\n                }\n            });\n        },\n\n        before: function() {\n            if ( this[0] && this[0].parentNode ) {\n                return this.domManip(arguments, false, function( elem ) {\n                    this.parentNode.insertBefore( elem, this );\n                });\n            } else if ( arguments.length ) {\n                var set = jQuery(arguments[0]);\n                set.push.apply( set, this.toArray() );\n                return this.pushStack( set, \"before\", arguments );\n            }\n        },\n\n        after: function() {\n            if ( this[0] && this[0].parentNode ) {\n                return this.domManip(arguments, false, function( elem ) {\n                    this.parentNode.insertBefore( elem, this.nextSibling );\n                });\n            } else if ( arguments.length ) {\n                var set = this.pushStack( this, \"after\", arguments );\n                set.push.apply( set, jQuery(arguments[0]).toArray() );\n                return set;\n            }\n        },\n\n        // keepData is for internal use only--do not document\n        remove: function( selector, keepData ) {\n            for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {\n                if ( !selector || jQuery.filter( selector, [ elem ] ).length ) {\n                    if ( !keepData && elem.nodeType === 1 ) {\n                        jQuery.cleanData( elem.getElementsByTagName(\"*\") );\n                        jQuery.cleanData( [ elem ] );\n                    }\n\n                    if ( elem.parentNode ) {\n                        elem.parentNode.removeChild( elem );\n                    }\n                }\n            }\n\n            return this;\n        },\n\n        empty: function() {\n            for ( var i = 0, elem; (elem = this[i]) != null; i++ ) {\n                // Remove element nodes and prevent memory leaks\n                if ( elem.nodeType === 1 ) {\n                    jQuery.cleanData( elem.getElementsByTagName(\"*\") );\n                }\n\n                // Remove any remaining nodes\n                while ( elem.firstChild ) {\n                    elem.removeChild( elem.firstChild );\n                }\n            }\n\n            return this;\n        },\n\n        clone: function( dataAndEvents, deepDataAndEvents ) {\n            dataAndEvents = dataAndEvents == null ? false : dataAndEvents;\n            deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;\n\n            return this.map( function () {\n                return jQuery.clone( this, dataAndEvents, deepDataAndEvents );\n            });\n        },\n\n        html: function( value ) {\n            if ( value === undefined ) {\n                return this[0] && this[0].nodeType === 1 ?\n                    this[0].innerHTML.replace(rinlinejQuery, \"\") :\n                    null;\n\n                // See if we can take a shortcut and just use innerHTML\n            } else if ( typeof value === \"string\" && !rnocache.test( value ) &&\n                (jQuery.support.leadingWhitespace || !rleadingWhitespace.test( value )) &&\n                !wrapMap[ (rtagName.exec( value ) || [\"\", \"\"])[1].toLowerCase() ] ) {\n\n                value = value.replace(rxhtmlTag, \"<$1></$2>\");\n\n                try {\n                    for ( var i = 0, l = this.length; i < l; i++ ) {\n                        // Remove element nodes and prevent memory leaks\n                        if ( this[i].nodeType === 1 ) {\n                            jQuery.cleanData( this[i].getElementsByTagName(\"*\") );\n                            this[i].innerHTML = value;\n                        }\n                    }\n\n                    // If using innerHTML throws an exception, use the fallback method\n                } catch(e) {\n                    this.empty().append( value );\n                }\n\n            } else if ( jQuery.isFunction( value ) ) {\n                this.each(function(i){\n                    var self = jQuery( this );\n\n                    self.html( value.call(this, i, self.html()) );\n                });\n\n            } else {\n                this.empty().append( value );\n            }\n\n            return this;\n        },\n\n        replaceWith: function( value ) {\n            if ( this[0] && this[0].parentNode ) {\n                // Make sure that the elements are removed from the DOM before they are inserted\n                // this can help fix replacing a parent with child elements\n                if ( jQuery.isFunction( value ) ) {\n                    return this.each(function(i) {\n                        var self = jQuery(this), old = self.html();\n                        self.replaceWith( value.call( this, i, old ) );\n                    });\n                }\n\n                if ( typeof value !== \"string\" ) {\n                    value = jQuery( value ).detach();\n                }\n\n                return this.each(function() {\n                    var next = this.nextSibling,\n                        parent = this.parentNode;\n\n                    jQuery( this ).remove();\n\n                    if ( next ) {\n                        jQuery(next).before( value );\n                    } else {\n                        jQuery(parent).append( value );\n                    }\n                });\n            } else {\n                return this.length ?\n                    this.pushStack( jQuery(jQuery.isFunction(value) ? value() : value), \"replaceWith\", value ) :\n                    this;\n            }\n        },\n\n        detach: function( selector ) {\n            return this.remove( selector, true );\n        },\n\n        domManip: function( args, table, callback ) {\n            var results, first, fragment, parent,\n                value = args[0],\n                scripts = [];\n\n            // We can't cloneNode fragments that contain checked, in WebKit\n            if ( !jQuery.support.checkClone && arguments.length === 3 && typeof value === \"string\" && rchecked.test( value ) ) {\n                return this.each(function() {\n                    jQuery(this).domManip( args, table, callback, true );\n                });\n            }\n\n            if ( jQuery.isFunction(value) ) {\n                return this.each(function(i) {\n                    var self = jQuery(this);\n                    args[0] = value.call(this, i, table ? self.html() : undefined);\n                    self.domManip( args, table, callback );\n                });\n            }\n\n            if ( this[0] ) {\n                parent = value && value.parentNode;\n\n                // If we're in a fragment, just use that instead of building a new one\n                if ( jQuery.support.parentNode && parent && parent.nodeType === 11 && parent.childNodes.length === this.length ) {\n                    results = { fragment: parent };\n\n                } else {\n                    results = jQuery.buildFragment( args, this, scripts );\n                }\n\n                fragment = results.fragment;\n\n                if ( fragment.childNodes.length === 1 ) {\n                    first = fragment = fragment.firstChild;\n                } else {\n                    first = fragment.firstChild;\n                }\n\n                if ( first ) {\n                    table = table && jQuery.nodeName( first, \"tr\" );\n\n                    for ( var i = 0, l = this.length, lastIndex = l - 1; i < l; i++ ) {\n                        callback.call(\n                            table ?\n                                root(this[i], first) :\n                                this[i],\n                            // Make sure that we do not leak memory by inadvertently discarding\n                            // the original fragment (which might have attached data) instead of\n                            // using it; in addition, use the original fragment object for the last\n                            // item instead of first because it can end up being emptied incorrectly\n                            // in certain situations (Bug #8070).\n                            // Fragments from the fragment cache must always be cloned and never used\n                            // in place.\n                            results.cacheable || (l > 1 && i < lastIndex) ?\n                                jQuery.clone( fragment, true, true ) :\n                                fragment\n                        );\n                    }\n                }\n\n                if ( scripts.length ) {\n                    jQuery.each( scripts, evalScript );\n                }\n            }\n\n            return this;\n        }\n    });\n\n    function root( elem, cur ) {\n        return jQuery.nodeName(elem, \"table\") ?\n            (elem.getElementsByTagName(\"tbody\")[0] ||\n                elem.appendChild(elem.ownerDocument.createElement(\"tbody\"))) :\n            elem;\n    }\n\n    function cloneCopyEvent( src, dest ) {\n\n        if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) {\n            return;\n        }\n\n        var internalKey = jQuery.expando,\n            oldData = jQuery.data( src ),\n            curData = jQuery.data( dest, oldData );\n\n        // Switch to use the internal data object, if it exists, for the next\n        // stage of data copying\n        if ( (oldData = oldData[ internalKey ]) ) {\n            var events = oldData.events;\n            curData = curData[ internalKey ] = jQuery.extend({}, oldData);\n\n            if ( events ) {\n                delete curData.handle;\n                curData.events = {};\n\n                for ( var type in events ) {\n                    for ( var i = 0, l = events[ type ].length; i < l; i++ ) {\n                        jQuery.event.add( dest, type + ( events[ type ][ i ].namespace ? \".\" : \"\" ) + events[ type ][ i ].namespace, events[ type ][ i ], events[ type ][ i ].data );\n                    }\n                }\n            }\n        }\n    }\n\n    function cloneFixAttributes(src, dest) {\n        // We do not need to do anything for non-Elements\n        if ( dest.nodeType !== 1 ) {\n            return;\n        }\n\n        var nodeName = dest.nodeName.toLowerCase();\n\n        // clearAttributes removes the attributes, which we don't want,\n        // but also removes the attachEvent events, which we *do* want\n        dest.clearAttributes();\n\n        // mergeAttributes, in contrast, only merges back on the\n        // original attributes, not the events\n        dest.mergeAttributes(src);\n\n        // IE6-8 fail to clone children inside object elements that use\n        // the proprietary classid attribute value (rather than the type\n        // attribute) to identify the type of content to display\n        if ( nodeName === \"object\" ) {\n            dest.outerHTML = src.outerHTML;\n\n        } else if ( nodeName === \"input\" && (src.type === \"checkbox\" || src.type === \"radio\") ) {\n            // IE6-8 fails to persist the checked state of a cloned checkbox\n            // or radio button. Worse, IE6-7 fail to give the cloned element\n            // a checked appearance if the defaultChecked value isn't also set\n            if ( src.checked ) {\n                dest.defaultChecked = dest.checked = src.checked;\n            }\n\n            // IE6-7 get confused and end up setting the value of a cloned\n            // checkbox/radio button to an empty string instead of \"on\"\n            if ( dest.value !== src.value ) {\n                dest.value = src.value;\n            }\n\n            // IE6-8 fails to return the selected option to the default selected\n            // state when cloning options\n        } else if ( nodeName === \"option\" ) {\n            dest.selected = src.defaultSelected;\n\n            // IE6-8 fails to set the defaultValue to the correct value when\n            // cloning other types of input fields\n        } else if ( nodeName === \"input\" || nodeName === \"textarea\" ) {\n            dest.defaultValue = src.defaultValue;\n        }\n\n        // Event data gets referenced instead of copied if the expando\n        // gets copied too\n        dest.removeAttribute( jQuery.expando );\n    }\n\n    jQuery.buildFragment = function( args, nodes, scripts ) {\n        var fragment, cacheable, cacheresults,\n            doc = (nodes && nodes[0] ? nodes[0].ownerDocument || nodes[0] : document);\n\n        // Only cache \"small\" (1/2 KB) HTML strings that are associated with the main document\n        // Cloning options loses the selected state, so don't cache them\n        // IE 6 doesn't like it when you put <object> or <embed> elements in a fragment\n        // Also, WebKit does not clone 'checked' attributes on cloneNode, so don't cache\n        if ( args.length === 1 && typeof args[0] === \"string\" && args[0].length < 512 && doc === document &&\n            args[0].charAt(0) === \"<\" && !rnocache.test( args[0] ) && (jQuery.support.checkClone || !rchecked.test( args[0] )) ) {\n\n            cacheable = true;\n            cacheresults = jQuery.fragments[ args[0] ];\n            if ( cacheresults ) {\n                if ( cacheresults !== 1 ) {\n                    fragment = cacheresults;\n                }\n            }\n        }\n\n        if ( !fragment ) {\n            fragment = doc.createDocumentFragment();\n            jQuery.clean( args, doc, fragment, scripts );\n        }\n\n        if ( cacheable ) {\n            jQuery.fragments[ args[0] ] = cacheresults ? fragment : 1;\n        }\n\n        return { fragment: fragment, cacheable: cacheable };\n    };\n\n    jQuery.fragments = {};\n\n    jQuery.each({\n        appendTo: \"append\",\n        prependTo: \"prepend\",\n        insertBefore: \"before\",\n        insertAfter: \"after\",\n        replaceAll: \"replaceWith\"\n    }, function( name, original ) {\n        jQuery.fn[ name ] = function( selector ) {\n            var ret = [],\n                insert = jQuery( selector ),\n                parent = this.length === 1 && this[0].parentNode;\n\n            if ( parent && parent.nodeType === 11 && parent.childNodes.length === 1 && insert.length === 1 ) {\n                insert[ original ]( this[0] );\n                return this;\n\n            } else {\n                for ( var i = 0, l = insert.length; i < l; i++ ) {\n                    var elems = (i > 0 ? this.clone(true) : this).get();\n                    jQuery( insert[i] )[ original ]( elems );\n                    ret = ret.concat( elems );\n                }\n\n                return this.pushStack( ret, name, insert.selector );\n            }\n        };\n    });\n\n    function getAll( elem ) {\n        if ( \"getElementsByTagName\" in elem ) {\n            return elem.getElementsByTagName( \"*\" );\n\n        } else if ( \"querySelectorAll\" in elem ) {\n            return elem.querySelectorAll( \"*\" );\n\n        } else {\n            return [];\n        }\n    }\n\n    jQuery.extend({\n        clone: function( elem, dataAndEvents, deepDataAndEvents ) {\n            var clone = elem.cloneNode(true),\n                srcElements,\n                destElements,\n                i;\n\n            if ( (!jQuery.support.noCloneEvent || !jQuery.support.noCloneChecked) &&\n                (elem.nodeType === 1 || elem.nodeType === 11) && !jQuery.isXMLDoc(elem) ) {\n                // IE copies events bound via attachEvent when using cloneNode.\n                // Calling detachEvent on the clone will also remove the events\n                // from the original. In order to get around this, we use some\n                // proprietary methods to clear the events. Thanks to MooTools\n                // guys for this hotness.\n\n                cloneFixAttributes( elem, clone );\n\n                // Using Sizzle here is crazy slow, so we use getElementsByTagName\n                // instead\n                srcElements = getAll( elem );\n                destElements = getAll( clone );\n\n                // Weird iteration because IE will replace the length property\n                // with an element if you are cloning the body and one of the\n                // elements on the page has a name or id of \"length\"\n                for ( i = 0; srcElements[i]; ++i ) {\n                    cloneFixAttributes( srcElements[i], destElements[i] );\n                }\n            }\n\n            // Copy the events from the original to the clone\n            if ( dataAndEvents ) {\n                cloneCopyEvent( elem, clone );\n\n                if ( deepDataAndEvents ) {\n                    srcElements = getAll( elem );\n                    destElements = getAll( clone );\n\n                    for ( i = 0; srcElements[i]; ++i ) {\n                        cloneCopyEvent( srcElements[i], destElements[i] );\n                    }\n                }\n            }\n\n            // Return the cloned set\n            return clone;\n        },\n        clean: function( elems, context, fragment, scripts ) {\n            context = context || document;\n\n            // !context.createElement fails in IE with an error but returns typeof 'object'\n            if ( typeof context.createElement === \"undefined\" ) {\n                context = context.ownerDocument || context[0] && context[0].ownerDocument || document;\n            }\n\n            var ret = [];\n\n            for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {\n                if ( typeof elem === \"number\" ) {\n                    elem += \"\";\n                }\n\n                if ( !elem ) {\n                    continue;\n                }\n\n                // Convert html string into DOM nodes\n                if ( typeof elem === \"string\" && !rhtml.test( elem ) ) {\n                    elem = context.createTextNode( elem );\n\n                } else if ( typeof elem === \"string\" ) {\n                    // Fix \"XHTML\"-style tags in all browsers\n                    elem = elem.replace(rxhtmlTag, \"<$1></$2>\");\n\n                    // Trim whitespace, otherwise indexOf won't work as expected\n                    var tag = (rtagName.exec( elem ) || [\"\", \"\"])[1].toLowerCase(),\n                        wrap = wrapMap[ tag ] || wrapMap._default,\n                        depth = wrap[0],\n                        div = context.createElement(\"div\");\n\n                    // Go to html and back, then peel off extra wrappers\n                    div.innerHTML = wrap[1] + elem + wrap[2];\n\n                    // Move to the right depth\n                    while ( depth-- ) {\n                        div = div.lastChild;\n                    }\n\n                    // Remove IE's autoinserted <tbody> from table fragments\n                    if ( !jQuery.support.tbody ) {\n\n                        // String was a <table>, *may* have spurious <tbody>\n                        var hasBody = rtbody.test(elem),\n                            tbody = tag === \"table\" && !hasBody ?\n                                div.firstChild && div.firstChild.childNodes :\n\n                                // String was a bare <thead> or <tfoot>\n                                wrap[1] === \"<table>\" && !hasBody ?\n                                    div.childNodes :\n                                    [];\n\n                        for ( var j = tbody.length - 1; j >= 0 ; --j ) {\n                            if ( jQuery.nodeName( tbody[ j ], \"tbody\" ) && !tbody[ j ].childNodes.length ) {\n                                tbody[ j ].parentNode.removeChild( tbody[ j ] );\n                            }\n                        }\n\n                    }\n\n                    // IE completely kills leading whitespace when innerHTML is used\n                    if ( !jQuery.support.leadingWhitespace && rleadingWhitespace.test( elem ) ) {\n                        div.insertBefore( context.createTextNode( rleadingWhitespace.exec(elem)[0] ), div.firstChild );\n                    }\n\n                    elem = div.childNodes;\n                }\n\n                if ( elem.nodeType ) {\n                    ret.push( elem );\n                } else {\n                    ret = jQuery.merge( ret, elem );\n                }\n            }\n\n            if ( fragment ) {\n                for ( i = 0; ret[i]; i++ ) {\n                    if ( scripts && jQuery.nodeName( ret[i], \"script\" ) && (!ret[i].type || ret[i].type.toLowerCase() === \"text/javascript\") ) {\n                        scripts.push( ret[i].parentNode ? ret[i].parentNode.removeChild( ret[i] ) : ret[i] );\n\n                    } else {\n                        if ( ret[i].nodeType === 1 ) {\n                            ret.splice.apply( ret, [i + 1, 0].concat(jQuery.makeArray(ret[i].getElementsByTagName(\"script\"))) );\n                        }\n                        fragment.appendChild( ret[i] );\n                    }\n                }\n            }\n\n            return ret;\n        },\n\n        cleanData: function( elems ) {\n            var data, id, cache = jQuery.cache, internalKey = jQuery.expando, special = jQuery.event.special,\n                deleteExpando = jQuery.support.deleteExpando;\n\n            for ( var i = 0, elem; (elem = elems[i]) != null; i++ ) {\n                if ( elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()] ) {\n                    continue;\n                }\n\n                id = elem[ jQuery.expando ];\n\n                if ( id ) {\n                    data = cache[ id ] && cache[ id ][ internalKey ];\n\n                    if ( data && data.events ) {\n                        for ( var type in data.events ) {\n                            if ( special[ type ] ) {\n                                jQuery.event.remove( elem, type );\n\n                                // This is a shortcut to avoid jQuery.event.remove's overhead\n                            } else {\n                                jQuery.removeEvent( elem, type, data.handle );\n                            }\n                        }\n\n                        // Null the DOM reference to avoid IE6/7/8 leak (#7054)\n                        if ( data.handle ) {\n                            data.handle.elem = null;\n                        }\n                    }\n\n                    if ( deleteExpando ) {\n                        delete elem[ jQuery.expando ];\n\n                    } else if ( elem.removeAttribute ) {\n                        elem.removeAttribute( jQuery.expando );\n                    }\n\n                    delete cache[ id ];\n                }\n            }\n        }\n    });\n\n    function evalScript( i, elem ) {\n        if ( elem.src ) {\n            jQuery.ajax({\n                url: elem.src,\n                async: false,\n                dataType: \"script\"\n            });\n        } else {\n            jQuery.globalEval( elem.text || elem.textContent || elem.innerHTML || \"\" );\n        }\n\n        if ( elem.parentNode ) {\n            elem.parentNode.removeChild( elem );\n        }\n    }\n\n\n\n\n    var ralpha = /alpha\\([^)]*\\)/i,\n        ropacity = /opacity=([^)]*)/,\n        rdashAlpha = /-([a-z])/ig,\n    // fixed for IE9, see #8346\n        rupper = /([A-Z]|^ms)/g,\n        rnumpx = /^-?\\d+(?:px)?$/i,\n        rnum = /^-?\\d/,\n\n        cssShow = { position: \"absolute\", visibility: \"hidden\", display: \"block\" },\n        cssWidth = [ \"Left\", \"Right\" ],\n        cssHeight = [ \"Top\", \"Bottom\" ],\n        curCSS,\n\n        getComputedStyle,\n        currentStyle,\n\n        fcamelCase = function( all, letter ) {\n            return letter.toUpperCase();\n        };\n\n    jQuery.fn.css = function( name, value ) {\n        // Setting 'undefined' is a no-op\n        if ( arguments.length === 2 && value === undefined ) {\n            return this;\n        }\n\n        return jQuery.access( this, name, value, true, function( elem, name, value ) {\n            return value !== undefined ?\n                jQuery.style( elem, name, value ) :\n                jQuery.css( elem, name );\n        });\n    };\n\n    jQuery.extend({\n        // Add in style property hooks for overriding the default\n        // behavior of getting and setting a style property\n        cssHooks: {\n            opacity: {\n                get: function( elem, computed ) {\n                    if ( computed ) {\n                        // We should always get a number back from opacity\n                        var ret = curCSS( elem, \"opacity\", \"opacity\" );\n                        return ret === \"\" ? \"1\" : ret;\n\n                    } else {\n                        return elem.style.opacity;\n                    }\n                }\n            }\n        },\n\n        // Exclude the following css properties to add px\n        cssNumber: {\n            \"zIndex\": true,\n            \"fontWeight\": true,\n            \"opacity\": true,\n            \"zoom\": true,\n            \"lineHeight\": true\n        },\n\n        // Add in properties whose names you wish to fix before\n        // setting or getting the value\n        cssProps: {\n            // normalize float css property\n            \"float\": jQuery.support.cssFloat ? \"cssFloat\" : \"styleFloat\"\n        },\n\n        // Get and set the style property on a DOM Node\n        style: function( elem, name, value, extra ) {\n            // Don't set styles on text and comment nodes\n            if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {\n                return;\n            }\n\n            // Make sure that we're working with the right name\n            var ret, origName = jQuery.camelCase( name ),\n                style = elem.style, hooks = jQuery.cssHooks[ origName ];\n\n            name = jQuery.cssProps[ origName ] || origName;\n\n            // Check if we're setting a value\n            if ( value !== undefined ) {\n                // Make sure that NaN and null values aren't set. See: #7116\n                if ( typeof value === \"number\" && isNaN( value ) || value == null ) {\n                    return;\n                }\n\n                // If a number was passed in, add 'px' to the (except for certain CSS properties)\n                if ( typeof value === \"number\" && !jQuery.cssNumber[ origName ] ) {\n                    value += \"px\";\n                }\n\n                // If a hook was provided, use that value, otherwise just set the specified value\n                if ( !hooks || !(\"set\" in hooks) || (value = hooks.set( elem, value )) !== undefined ) {\n                    // Wrapped to prevent IE from throwing errors when 'invalid' values are provided\n                    // Fixes bug #5509\n                    try {\n                        style[ name ] = value;\n                    } catch(e) {}\n                }\n\n            } else {\n                // If a hook was provided get the non-computed value from there\n                if ( hooks && \"get\" in hooks && (ret = hooks.get( elem, false, extra )) !== undefined ) {\n                    return ret;\n                }\n\n                // Otherwise just get the value from the style object\n                return style[ name ];\n            }\n        },\n\n        css: function( elem, name, extra ) {\n            // Make sure that we're working with the right name\n            var ret, origName = jQuery.camelCase( name ),\n                hooks = jQuery.cssHooks[ origName ];\n\n            name = jQuery.cssProps[ origName ] || origName;\n\n            // If a hook was provided get the computed value from there\n            if ( hooks && \"get\" in hooks && (ret = hooks.get( elem, true, extra )) !== undefined ) {\n                return ret;\n\n                // Otherwise, if a way to get the computed value exists, use that\n            } else if ( curCSS ) {\n                return curCSS( elem, name, origName );\n            }\n        },\n\n        // A method for quickly swapping in/out CSS properties to get correct calculations\n        swap: function( elem, options, callback ) {\n            var old = {};\n\n            // Remember the old values, and insert the new ones\n            for ( var name in options ) {\n                old[ name ] = elem.style[ name ];\n                elem.style[ name ] = options[ name ];\n            }\n\n            callback.call( elem );\n\n            // Revert the old values\n            for ( name in options ) {\n                elem.style[ name ] = old[ name ];\n            }\n        },\n\n        camelCase: function( string ) {\n            return string.replace( rdashAlpha, fcamelCase );\n        }\n    });\n\n// DEPRECATED, Use jQuery.css() instead\n    jQuery.curCSS = jQuery.css;\n\n    jQuery.each([\"height\", \"width\"], function( i, name ) {\n        jQuery.cssHooks[ name ] = {\n            get: function( elem, computed, extra ) {\n                var val;\n\n                if ( computed ) {\n                    if ( elem.offsetWidth !== 0 ) {\n                        val = getWH( elem, name, extra );\n\n                    } else {\n                        jQuery.swap( elem, cssShow, function() {\n                            val = getWH( elem, name, extra );\n                        });\n                    }\n\n                    if ( val <= 0 ) {\n                        val = curCSS( elem, name, name );\n\n                        if ( val === \"0px\" && currentStyle ) {\n                            val = currentStyle( elem, name, name );\n                        }\n\n                        if ( val != null ) {\n                            // Should return \"auto\" instead of 0, use 0 for\n                            // temporary backwards-compat\n                            return val === \"\" || val === \"auto\" ? \"0px\" : val;\n                        }\n                    }\n\n                    if ( val < 0 || val == null ) {\n                        val = elem.style[ name ];\n\n                        // Should return \"auto\" instead of 0, use 0 for\n                        // temporary backwards-compat\n                        return val === \"\" || val === \"auto\" ? \"0px\" : val;\n                    }\n\n                    return typeof val === \"string\" ? val : val + \"px\";\n                }\n            },\n\n            set: function( elem, value ) {\n                if ( rnumpx.test( value ) ) {\n                    // ignore negative width and height values #1599\n                    value = parseFloat(value);\n\n                    if ( value >= 0 ) {\n                        return value + \"px\";\n                    }\n\n                } else {\n                    return value;\n                }\n            }\n        };\n    });\n\n    if ( !jQuery.support.opacity ) {\n        jQuery.cssHooks.opacity = {\n            get: function( elem, computed ) {\n                // IE uses filters for opacity\n                return ropacity.test((computed && elem.currentStyle ? elem.currentStyle.filter : elem.style.filter) || \"\") ?\n                    (parseFloat(RegExp.$1) / 100) + \"\" :\n                    computed ? \"1\" : \"\";\n            },\n\n            set: function( elem, value ) {\n                var style = elem.style;\n\n                // IE has trouble with opacity if it does not have layout\n                // Force it by setting the zoom level\n                style.zoom = 1;\n\n                // Set the alpha filter to set the opacity\n                var opacity = jQuery.isNaN(value) ?\n                        \"\" :\n                        \"alpha(opacity=\" + value * 100 + \")\",\n                    filter = style.filter || \"\";\n\n                style.filter = ralpha.test(filter) ?\n                    filter.replace(ralpha, opacity) :\n                    style.filter + ' ' + opacity;\n            }\n        };\n    }\n\n    jQuery(function() {\n        // This hook cannot be added until DOM ready because the support test\n        // for it is not run until after DOM ready\n        if ( !jQuery.support.reliableMarginRight ) {\n            jQuery.cssHooks.marginRight = {\n                get: function( elem, computed ) {\n                    // WebKit Bug 13343 - getComputedStyle returns wrong value for margin-right\n                    // Work around by temporarily setting element display to inline-block\n                    var ret;\n                    jQuery.swap( elem, { \"display\": \"inline-block\" }, function() {\n                        if ( computed ) {\n                            ret = curCSS( elem, \"margin-right\", \"marginRight\" );\n                        } else {\n                            ret = elem.style.marginRight;\n                        }\n                    });\n                    return ret;\n                }\n            };\n        }\n    });\n\n    if ( document.defaultView && document.defaultView.getComputedStyle ) {\n        getComputedStyle = function( elem, newName, name ) {\n            var ret, defaultView, computedStyle;\n\n            name = name.replace( rupper, \"-$1\" ).toLowerCase();\n\n            if ( !(defaultView = elem.ownerDocument.defaultView) ) {\n                return undefined;\n            }\n\n            if ( (computedStyle = defaultView.getComputedStyle( elem, null )) ) {\n                ret = computedStyle.getPropertyValue( name );\n                if ( ret === \"\" && !jQuery.contains( elem.ownerDocument.documentElement, elem ) ) {\n                    ret = jQuery.style( elem, name );\n                }\n            }\n\n            return ret;\n        };\n    }\n\n    if ( document.documentElement.currentStyle ) {\n        currentStyle = function( elem, name ) {\n            var left,\n                ret = elem.currentStyle && elem.currentStyle[ name ],\n                rsLeft = elem.runtimeStyle && elem.runtimeStyle[ name ],\n                style = elem.style;\n\n            // From the awesome hack by Dean Edwards\n            // http://erik.eae.net/archives/2007/07/27/18.54.15/#comment-102291\n\n            // If we're not dealing with a regular pixel number\n            // but a number that has a weird ending, we need to convert it to pixels\n            if ( !rnumpx.test( ret ) && rnum.test( ret ) ) {\n                // Remember the original values\n                left = style.left;\n\n                // Put in the new values to get a computed value out\n                if ( rsLeft ) {\n                    elem.runtimeStyle.left = elem.currentStyle.left;\n                }\n                style.left = name === \"fontSize\" ? \"1em\" : (ret || 0);\n                ret = style.pixelLeft + \"px\";\n\n                // Revert the changed values\n                style.left = left;\n                if ( rsLeft ) {\n                    elem.runtimeStyle.left = rsLeft;\n                }\n            }\n\n            return ret === \"\" ? \"auto\" : ret;\n        };\n    }\n\n    curCSS = getComputedStyle || currentStyle;\n\n    function getWH( elem, name, extra ) {\n        var which = name === \"width\" ? cssWidth : cssHeight,\n            val = name === \"width\" ? elem.offsetWidth : elem.offsetHeight;\n\n        if ( extra === \"border\" ) {\n            return val;\n        }\n\n        jQuery.each( which, function() {\n            if ( !extra ) {\n                val -= parseFloat(jQuery.css( elem, \"padding\" + this )) || 0;\n            }\n\n            if ( extra === \"margin\" ) {\n                val += parseFloat(jQuery.css( elem, \"margin\" + this )) || 0;\n\n            } else {\n                val -= parseFloat(jQuery.css( elem, \"border\" + this + \"Width\" )) || 0;\n            }\n        });\n\n        return val;\n    }\n\n    if ( jQuery.expr && jQuery.expr.filters ) {\n        jQuery.expr.filters.hidden = function( elem ) {\n            var width = elem.offsetWidth,\n                height = elem.offsetHeight;\n\n            return (width === 0 && height === 0) || (!jQuery.support.reliableHiddenOffsets && (elem.style.display || jQuery.css( elem, \"display\" )) === \"none\");\n        };\n\n        jQuery.expr.filters.visible = function( elem ) {\n            return !jQuery.expr.filters.hidden( elem );\n        };\n    }\n\n\n\n\n    var r20 = /%20/g,\n        rbracket = /\\[\\]$/,\n        rCRLF = /\\r?\\n/g,\n        rhash = /#.*$/,\n        rheaders = /^(.*?):[ \\t]*([^\\r\\n]*)\\r?$/mg, // IE leaves an \\r character at EOL\n        rinput = /^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,\n    // #7653, #8125, #8152: local protocol detection\n        rlocalProtocol = /^(?:about|app|app\\-storage|.+\\-extension|file|widget):$/,\n        rnoContent = /^(?:GET|HEAD)$/,\n        rprotocol = /^\\/\\//,\n        rquery = /\\?/,\n        rscript = /<script\\b[^<]*(?:(?!<\\/script>)<[^<]*)*<\\/script>/gi,\n        rselectTextarea = /^(?:select|textarea)/i,\n        rspacesAjax = /\\s+/,\n        rts = /([?&])_=[^&]*/,\n        rucHeaders = /(^|\\-)([a-z])/g,\n        rucHeadersFunc = function( _, $1, $2 ) {\n            return $1 + $2.toUpperCase();\n        },\n        rurl = /^([\\w\\+\\.\\-]+:)(?:\\/\\/([^\\/?#:]*)(?::(\\d+))?)?/,\n\n    // Keep a copy of the old load method\n        _load = jQuery.fn.load,\n\n    /* Prefilters\n     * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)\n     * 2) These are called:\n     *    - BEFORE asking for a transport\n     *    - AFTER param serialization (s.data is a string if s.processData is true)\n     * 3) key is the dataType\n     * 4) the catchall symbol \"*\" can be used\n     * 5) execution will start with transport dataType and THEN continue down to \"*\" if needed\n     */\n        prefilters = {},\n\n    /* Transports bindings\n     * 1) key is the dataType\n     * 2) the catchall symbol \"*\" can be used\n     * 3) selection will start with transport dataType and THEN go to \"*\" if needed\n     */\n        transports = {},\n\n    // Document location\n        ajaxLocation,\n\n    // Document location segments\n        ajaxLocParts;\n\n// #8138, IE may throw an exception when accessing\n// a field from document.location if document.domain has been set\n    try {\n        ajaxLocation = document.location.href;\n    } catch( e ) {\n        // Use the href attribute of an A element\n        // since IE will modify it given document.location\n        ajaxLocation = document.createElement( \"a\" );\n        ajaxLocation.href = \"\";\n        ajaxLocation = ajaxLocation.href;\n    }\n\n// Segment location into parts\n    ajaxLocParts = rurl.exec( ajaxLocation.toLowerCase() ) || [];\n\n// Base \"constructor\" for jQuery.ajaxPrefilter and jQuery.ajaxTransport\n    function addToPrefiltersOrTransports( structure ) {\n\n        // dataTypeExpression is optional and defaults to \"*\"\n        return function( dataTypeExpression, func ) {\n\n            if ( typeof dataTypeExpression !== \"string\" ) {\n                func = dataTypeExpression;\n                dataTypeExpression = \"*\";\n            }\n\n            if ( jQuery.isFunction( func ) ) {\n                var dataTypes = dataTypeExpression.toLowerCase().split( rspacesAjax ),\n                    i = 0,\n                    length = dataTypes.length,\n                    dataType,\n                    list,\n                    placeBefore;\n\n                // For each dataType in the dataTypeExpression\n                for(; i < length; i++ ) {\n                    dataType = dataTypes[ i ];\n                    // We control if we're asked to add before\n                    // any existing element\n                    placeBefore = /^\\+/.test( dataType );\n                    if ( placeBefore ) {\n                        dataType = dataType.substr( 1 ) || \"*\";\n                    }\n                    list = structure[ dataType ] = structure[ dataType ] || [];\n                    // then we add to the structure accordingly\n                    list[ placeBefore ? \"unshift\" : \"push\" ]( func );\n                }\n            }\n        };\n    }\n\n//Base inspection function for prefilters and transports\n    function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR,\n                                            dataType /* internal */, inspected /* internal */ ) {\n\n        dataType = dataType || options.dataTypes[ 0 ];\n        inspected = inspected || {};\n\n        inspected[ dataType ] = true;\n\n        var list = structure[ dataType ],\n            i = 0,\n            length = list ? list.length : 0,\n            executeOnly = ( structure === prefilters ),\n            selection;\n\n        for(; i < length && ( executeOnly || !selection ); i++ ) {\n            selection = list[ i ]( options, originalOptions, jqXHR );\n            // If we got redirected to another dataType\n            // we try there if executing only and not done already\n            if ( typeof selection === \"string\" ) {\n                if ( !executeOnly || inspected[ selection ] ) {\n                    selection = undefined;\n                } else {\n                    options.dataTypes.unshift( selection );\n                    selection = inspectPrefiltersOrTransports(\n                        structure, options, originalOptions, jqXHR, selection, inspected );\n                }\n            }\n        }\n        // If we're only executing or nothing was selected\n        // we try the catchall dataType if not done already\n        if ( ( executeOnly || !selection ) && !inspected[ \"*\" ] ) {\n            selection = inspectPrefiltersOrTransports(\n                structure, options, originalOptions, jqXHR, \"*\", inspected );\n        }\n        // unnecessary when only executing (prefilters)\n        // but it'll be ignored by the caller in that case\n        return selection;\n    }\n\n    jQuery.fn.extend({\n        load: function( url, params, callback ) {\n            if ( typeof url !== \"string\" && _load ) {\n                return _load.apply( this, arguments );\n\n                // Don't do a request if no elements are being requested\n            } else if ( !this.length ) {\n                return this;\n            }\n\n            var off = url.indexOf( \" \" );\n            if ( off >= 0 ) {\n                var selector = url.slice( off, url.length );\n                url = url.slice( 0, off );\n            }\n\n            // Default to a GET request\n            var type = \"GET\";\n\n            // If the second parameter was provided\n            if ( params ) {\n                // If it's a function\n                if ( jQuery.isFunction( params ) ) {\n                    // We assume that it's the callback\n                    callback = params;\n                    params = undefined;\n\n                    // Otherwise, build a param string\n                } else if ( typeof params === \"object\" ) {\n                    params = jQuery.param( params, jQuery.ajaxSettings.traditional );\n                    type = \"POST\";\n                }\n            }\n\n            var self = this;\n\n            // Request the remote document\n            jQuery.ajax({\n                url: url,\n                type: type,\n                dataType: \"html\",\n                data: params,\n                // Complete callback (responseText is used internally)\n                complete: function( jqXHR, status, responseText ) {\n                    // Store the response as specified by the jqXHR object\n                    responseText = jqXHR.responseText;\n                    // If successful, inject the HTML into all the matched elements\n                    if ( jqXHR.isResolved() ) {\n                        // #4825: Get the actual response in case\n                        // a dataFilter is present in ajaxSettings\n                        jqXHR.done(function( r ) {\n                            responseText = r;\n                        });\n                        // See if a selector was specified\n                        self.html( selector ?\n                            // Create a dummy div to hold the results\n                            jQuery(\"<div>\")\n                                // inject the contents of the document in, removing the scripts\n                                // to avoid any 'Permission Denied' errors in IE\n                                .append(responseText.replace(rscript, \"\"))\n\n                                // Locate the specified elements\n                                .find(selector) :\n\n                            // If not, just inject the full result\n                            responseText );\n                    }\n\n                    if ( callback ) {\n                        self.each( callback, [ responseText, status, jqXHR ] );\n                    }\n                }\n            });\n\n            return this;\n        },\n\n        serialize: function() {\n            return jQuery.param( this.serializeArray() );\n        },\n\n        serializeArray: function() {\n            return this.map(function(){\n                return this.elements ? jQuery.makeArray( this.elements ) : this;\n            })\n                .filter(function(){\n                    return this.name && !this.disabled &&\n                        ( this.checked || rselectTextarea.test( this.nodeName ) ||\n                            rinput.test( this.type ) );\n                })\n                .map(function( i, elem ){\n                    var val = jQuery( this ).val();\n\n                    return val == null ?\n                        null :\n                        jQuery.isArray( val ) ?\n                            jQuery.map( val, function( val, i ){\n                                return { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n                            }) :\n                        { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n                }).get();\n        }\n    });\n\n// Attach a bunch of functions for handling common AJAX events\n    jQuery.each( \"ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend\".split( \" \" ), function( i, o ){\n        jQuery.fn[ o ] = function( f ){\n            return this.bind( o, f );\n        };\n    } );\n\n    jQuery.each( [ \"get\", \"post\" ], function( i, method ) {\n        jQuery[ method ] = function( url, data, callback, type ) {\n            // shift arguments if data argument was omitted\n            if ( jQuery.isFunction( data ) ) {\n                type = type || callback;\n                callback = data;\n                data = undefined;\n            }\n\n            return jQuery.ajax({\n                type: method,\n                url: url,\n                data: data,\n                success: callback,\n                dataType: type\n            });\n        };\n    } );\n\n    jQuery.extend({\n\n        getScript: function( url, callback ) {\n            return jQuery.get( url, undefined, callback, \"script\" );\n        },\n\n        getJSON: function( url, data, callback ) {\n            return jQuery.get( url, data, callback, \"json\" );\n        },\n\n        // Creates a full fledged settings object into target\n        // with both ajaxSettings and settings fields.\n        // If target is omitted, writes into ajaxSettings.\n        ajaxSetup: function ( target, settings ) {\n            if ( !settings ) {\n                // Only one parameter, we extend ajaxSettings\n                settings = target;\n                target = jQuery.extend( true, jQuery.ajaxSettings, settings );\n            } else {\n                // target was provided, we extend into it\n                jQuery.extend( true, target, jQuery.ajaxSettings, settings );\n            }\n            // Flatten fields we don't want deep extended\n            for( var field in { context: 1, url: 1 } ) {\n                if ( field in settings ) {\n                    target[ field ] = settings[ field ];\n                } else if( field in jQuery.ajaxSettings ) {\n                    target[ field ] = jQuery.ajaxSettings[ field ];\n                }\n            }\n            return target;\n        },\n\n        ajaxSettings: {\n            url: ajaxLocation,\n            isLocal: rlocalProtocol.test( ajaxLocParts[ 1 ] ),\n            global: true,\n            type: \"GET\",\n            contentType: \"application/x-www-form-urlencoded\",\n            processData: true,\n            async: true,\n            /*\n             timeout: 0,\n             data: null,\n             dataType: null,\n             username: null,\n             password: null,\n             cache: null,\n             traditional: false,\n             headers: {},\n             */\n\n            accepts: {\n                xml: \"application/xml, text/xml\",\n                html: \"text/html\",\n                text: \"text/plain\",\n                json: \"application/json, text/javascript\",\n                \"*\": \"*/*\"\n            },\n\n            contents: {\n                xml: /xml/,\n                html: /html/,\n                json: /json/\n            },\n\n            responseFields: {\n                xml: \"responseXML\",\n                text: \"responseText\"\n            },\n\n            // List of data converters\n            // 1) key format is \"source_type destination_type\" (a single space in-between)\n            // 2) the catchall symbol \"*\" can be used for source_type\n            converters: {\n\n                // Convert anything to text\n                \"* text\": window.String,\n\n                // Text to html (true = no transformation)\n                \"text html\": true,\n\n                // Evaluate text as a json expression\n                \"text json\": jQuery.parseJSON,\n\n                // Parse text as xml\n                \"text xml\": jQuery.parseXML\n            }\n        },\n\n        ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),\n        ajaxTransport: addToPrefiltersOrTransports( transports ),\n\n        // Main method\n        ajax: function( url, options ) {\n\n            // If url is an object, simulate pre-1.5 signature\n            if ( typeof url === \"object\" ) {\n                options = url;\n                url = undefined;\n            }\n\n            // Force options to be an object\n            options = options || {};\n\n            var // Create the final options object\n                s = jQuery.ajaxSetup( {}, options ),\n            // Callbacks context\n                callbackContext = s.context || s,\n            // Context for global events\n            // It's the callbackContext if one was provided in the options\n            // and if it's a DOM node or a jQuery collection\n                globalEventContext = callbackContext !== s &&\n                    ( callbackContext.nodeType || callbackContext instanceof jQuery ) ?\n                    jQuery( callbackContext ) : jQuery.event,\n            // Deferreds\n                deferred = jQuery.Deferred(),\n                completeDeferred = jQuery._Deferred(),\n            // Status-dependent callbacks\n                statusCode = s.statusCode || {},\n            // ifModified key\n                ifModifiedKey,\n            // Headers (they are sent all at once)\n                requestHeaders = {},\n            // Response headers\n                responseHeadersString,\n                responseHeaders,\n            // transport\n                transport,\n            // timeout handle\n                timeoutTimer,\n            // Cross-domain detection vars\n                parts,\n            // The jqXHR state\n                state = 0,\n            // To know if global events are to be dispatched\n                fireGlobals,\n            // Loop variable\n                i,\n            // Fake xhr\n                jqXHR = {\n\n                    readyState: 0,\n\n                    // Caches the header\n                    setRequestHeader: function( name, value ) {\n                        if ( !state ) {\n                            requestHeaders[ name.toLowerCase().replace( rucHeaders, rucHeadersFunc ) ] = value;\n                        }\n                        return this;\n                    },\n\n                    // Raw string\n                    getAllResponseHeaders: function() {\n                        return state === 2 ? responseHeadersString : null;\n                    },\n\n                    // Builds headers hashtable if needed\n                    getResponseHeader: function( key ) {\n                        var match;\n                        if ( state === 2 ) {\n                            if ( !responseHeaders ) {\n                                responseHeaders = {};\n                                while( ( match = rheaders.exec( responseHeadersString ) ) ) {\n                                    responseHeaders[ match[1].toLowerCase() ] = match[ 2 ];\n                                }\n                            }\n                            match = responseHeaders[ key.toLowerCase() ];\n                        }\n                        return match === undefined ? null : match;\n                    },\n\n                    // Overrides response content-type header\n                    overrideMimeType: function( type ) {\n                        if ( !state ) {\n                            s.mimeType = type;\n                        }\n                        return this;\n                    },\n\n                    // Cancel the request\n                    abort: function( statusText ) {\n                        statusText = statusText || \"abort\";\n                        if ( transport ) {\n                            transport.abort( statusText );\n                        }\n                        done( 0, statusText );\n                        return this;\n                    }\n                };\n\n            // Callback for when everything is done\n            // It is defined here because jslint complains if it is declared\n            // at the end of the function (which would be more logical and readable)\n            function done( status, statusText, responses, headers ) {\n\n                // Called once\n                if ( state === 2 ) {\n                    return;\n                }\n\n                // State is \"done\" now\n                state = 2;\n\n                // Clear timeout if it exists\n                if ( timeoutTimer ) {\n                    clearTimeout( timeoutTimer );\n                }\n\n                // Dereference transport for early garbage collection\n                // (no matter how long the jqXHR object will be used)\n                transport = undefined;\n\n                // Cache response headers\n                responseHeadersString = headers || \"\";\n\n                // Set readyState\n                jqXHR.readyState = status ? 4 : 0;\n\n                var isSuccess,\n                    success,\n                    error,\n                    response = responses ? ajaxHandleResponses( s, jqXHR, responses ) : undefined,\n                    lastModified,\n                    etag;\n\n                // If successful, handle type chaining\n                if ( status >= 200 && status < 300 || status === 304 ) {\n\n                    // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n                    if ( s.ifModified ) {\n\n                        if ( ( lastModified = jqXHR.getResponseHeader( \"Last-Modified\" ) ) ) {\n                            jQuery.lastModified[ ifModifiedKey ] = lastModified;\n                        }\n                        if ( ( etag = jqXHR.getResponseHeader( \"Etag\" ) ) ) {\n                            jQuery.etag[ ifModifiedKey ] = etag;\n                        }\n                    }\n\n                    // If not modified\n                    if ( status === 304 ) {\n\n                        statusText = \"notmodified\";\n                        isSuccess = true;\n\n                        // If we have data\n                    } else {\n\n                        try {\n                            success = ajaxConvert( s, response );\n                            statusText = \"success\";\n                            isSuccess = true;\n                        } catch(e) {\n                            // We have a parsererror\n                            statusText = \"parsererror\";\n                            error = e;\n                        }\n                    }\n                } else {\n                    // We extract error from statusText\n                    // then normalize statusText and status for non-aborts\n                    error = statusText;\n                    if( !statusText || status ) {\n                        statusText = \"error\";\n                        if ( status < 0 ) {\n                            status = 0;\n                        }\n                    }\n                }\n\n                // Set data for the fake xhr object\n                jqXHR.status = status;\n                jqXHR.statusText = statusText;\n\n                // Success/Error\n                if ( isSuccess ) {\n                    deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );\n                } else {\n                    deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );\n                }\n\n                // Status-dependent callbacks\n                jqXHR.statusCode( statusCode );\n                statusCode = undefined;\n\n                if ( fireGlobals ) {\n                    globalEventContext.trigger( \"ajax\" + ( isSuccess ? \"Success\" : \"Error\" ),\n                        [ jqXHR, s, isSuccess ? success : error ] );\n                }\n\n                // Complete\n                completeDeferred.resolveWith( callbackContext, [ jqXHR, statusText ] );\n\n                if ( fireGlobals ) {\n                    globalEventContext.trigger( \"ajaxComplete\", [ jqXHR, s] );\n                    // Handle the global AJAX counter\n                    if ( !( --jQuery.active ) ) {\n                        jQuery.event.trigger( \"ajaxStop\" );\n                    }\n                }\n            }\n\n            // Attach deferreds\n            deferred.promise( jqXHR );\n            jqXHR.success = jqXHR.done;\n            jqXHR.error = jqXHR.fail;\n            jqXHR.complete = completeDeferred.done;\n\n            // Status-dependent callbacks\n            jqXHR.statusCode = function( map ) {\n                if ( map ) {\n                    var tmp;\n                    if ( state < 2 ) {\n                        for( tmp in map ) {\n                            statusCode[ tmp ] = [ statusCode[tmp], map[tmp] ];\n                        }\n                    } else {\n                        tmp = map[ jqXHR.status ];\n                        jqXHR.then( tmp, tmp );\n                    }\n                }\n                return this;\n            };\n\n            // Remove hash character (#7531: and string promotion)\n            // Add protocol if not provided (#5866: IE7 issue with protocol-less urls)\n            // We also use the url parameter if available\n            s.url = ( ( url || s.url ) + \"\" ).replace( rhash, \"\" ).replace( rprotocol, ajaxLocParts[ 1 ] + \"//\" );\n\n            // Extract dataTypes list\n            s.dataTypes = jQuery.trim( s.dataType || \"*\" ).toLowerCase().split( rspacesAjax );\n\n            // Determine if a cross-domain request is in order\n            if ( s.crossDomain == null ) {\n                parts = rurl.exec( s.url.toLowerCase() );\n                s.crossDomain = !!( parts &&\n                    ( parts[ 1 ] != ajaxLocParts[ 1 ] || parts[ 2 ] != ajaxLocParts[ 2 ] ||\n                        ( parts[ 3 ] || ( parts[ 1 ] === \"http:\" ? 80 : 443 ) ) !=\n                            ( ajaxLocParts[ 3 ] || ( ajaxLocParts[ 1 ] === \"http:\" ? 80 : 443 ) ) )\n                    );\n            }\n\n            // Convert data if not already a string\n            if ( s.data && s.processData && typeof s.data !== \"string\" ) {\n                s.data = jQuery.param( s.data, s.traditional );\n            }\n\n            // Apply prefilters\n            inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );\n\n            // If request was aborted inside a prefiler, stop there\n            if ( state === 2 ) {\n                return false;\n            }\n\n            // We can fire global events as of now if asked to\n            fireGlobals = s.global;\n\n            // Uppercase the type\n            s.type = s.type.toUpperCase();\n\n            // Determine if request has content\n            s.hasContent = !rnoContent.test( s.type );\n\n            // Watch for a new set of requests\n            if ( fireGlobals && jQuery.active++ === 0 ) {\n                jQuery.event.trigger( \"ajaxStart\" );\n            }\n\n            // More options handling for requests with no content\n            if ( !s.hasContent ) {\n\n                // If data is available, append data to url\n                if ( s.data ) {\n                    s.url += ( rquery.test( s.url ) ? \"&\" : \"?\" ) + s.data;\n                }\n\n                // Get ifModifiedKey before adding the anti-cache parameter\n                ifModifiedKey = s.url;\n\n                // Add anti-cache in url if needed\n                if ( s.cache === false ) {\n\n                    var ts = jQuery.now(),\n                    // try replacing _= if it is there\n                        ret = s.url.replace( rts, \"$1_=\" + ts );\n\n                    // if nothing was replaced, add timestamp to the end\n                    s.url = ret + ( (ret === s.url ) ? ( rquery.test( s.url ) ? \"&\" : \"?\" ) + \"_=\" + ts : \"\" );\n                }\n            }\n\n            // Set the correct header, if data is being sent\n            if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {\n                requestHeaders[ \"Content-Type\" ] = s.contentType;\n            }\n\n            // Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n            if ( s.ifModified ) {\n                ifModifiedKey = ifModifiedKey || s.url;\n                if ( jQuery.lastModified[ ifModifiedKey ] ) {\n                    requestHeaders[ \"If-Modified-Since\" ] = jQuery.lastModified[ ifModifiedKey ];\n                }\n                if ( jQuery.etag[ ifModifiedKey ] ) {\n                    requestHeaders[ \"If-None-Match\" ] = jQuery.etag[ ifModifiedKey ];\n                }\n            }\n\n            // Set the Accepts header for the server, depending on the dataType\n            requestHeaders.Accept = s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[0] ] ?\n                s.accepts[ s.dataTypes[0] ] + ( s.dataTypes[ 0 ] !== \"*\" ? \", */*; q=0.01\" : \"\" ) :\n                s.accepts[ \"*\" ];\n\n            // Check for headers option\n            for ( i in s.headers ) {\n                jqXHR.setRequestHeader( i, s.headers[ i ] );\n            }\n\n            // Allow custom headers/mimetypes and early abort\n            if ( s.beforeSend && ( s.beforeSend.call( callbackContext, jqXHR, s ) === false || state === 2 ) ) {\n                // Abort if not done already\n                jqXHR.abort();\n                return false;\n\n            }\n\n            // Install callbacks on deferreds\n            for ( i in { success: 1, error: 1, complete: 1 } ) {\n                jqXHR[ i ]( s[ i ] );\n            }\n\n            // Get transport\n            transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );\n\n            // If no transport, we auto-abort\n            if ( !transport ) {\n                done( -1, \"No Transport\" );\n            } else {\n                jqXHR.readyState = 1;\n                // Send global event\n                if ( fireGlobals ) {\n                    globalEventContext.trigger( \"ajaxSend\", [ jqXHR, s ] );\n                }\n                // Timeout\n                if ( s.async && s.timeout > 0 ) {\n                    timeoutTimer = setTimeout( function(){\n                        jqXHR.abort( \"timeout\" );\n                    }, s.timeout );\n                }\n\n                try {\n                    state = 1;\n                    transport.send( requestHeaders, done );\n                } catch (e) {\n                    // Propagate exception as error if not done\n                    if ( status < 2 ) {\n                        done( -1, e );\n                        // Simply rethrow otherwise\n                    } else {\n                        jQuery.error( e );\n                    }\n                }\n            }\n\n            return jqXHR;\n        },\n\n        // Serialize an array of form elements or a set of\n        // key/values into a query string\n        param: function( a, traditional ) {\n            var s = [],\n                add = function( key, value ) {\n                    // If value is a function, invoke it and return its value\n                    value = jQuery.isFunction( value ) ? value() : value;\n                    s[ s.length ] = encodeURIComponent( key ) + \"=\" + encodeURIComponent( value );\n                };\n\n            // Set traditional to true for jQuery <= 1.3.2 behavior.\n            if ( traditional === undefined ) {\n                traditional = jQuery.ajaxSettings.traditional;\n            }\n\n            // If an array was passed in, assume that it is an array of form elements.\n            if ( jQuery.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {\n                // Serialize the form elements\n                jQuery.each( a, function() {\n                    add( this.name, this.value );\n                } );\n\n            } else {\n                // If traditional, encode the \"old\" way (the way 1.3.2 or older\n                // did it), otherwise encode params recursively.\n                for ( var prefix in a ) {\n                    buildParams( prefix, a[ prefix ], traditional, add );\n                }\n            }\n\n            // Return the resulting serialization\n            return s.join( \"&\" ).replace( r20, \"+\" );\n        }\n    });\n\n    function buildParams( prefix, obj, traditional, add ) {\n        if ( jQuery.isArray( obj ) && obj.length ) {\n            // Serialize array item.\n            jQuery.each( obj, function( i, v ) {\n                if ( traditional || rbracket.test( prefix ) ) {\n                    // Treat each array item as a scalar.\n                    add( prefix, v );\n\n                } else {\n                    // If array item is non-scalar (array or object), encode its\n                    // numeric index to resolve deserialization ambiguity issues.\n                    // Note that rack (as of 1.0.0) can't currently deserialize\n                    // nested arrays properly, and attempting to do so may cause\n                    // a server error. Possible fixes are to modify rack's\n                    // deserialization algorithm or to provide an option or flag\n                    // to force array serialization to be shallow.\n                    buildParams( prefix + \"[\" + ( typeof v === \"object\" || jQuery.isArray(v) ? i : \"\" ) + \"]\", v, traditional, add );\n                }\n            });\n\n        } else if ( !traditional && obj != null && typeof obj === \"object\" ) {\n            // If we see an array here, it is empty and should be treated as an empty\n            // object\n            if ( jQuery.isArray( obj ) || jQuery.isEmptyObject( obj ) ) {\n                add( prefix, \"\" );\n\n                // Serialize object item.\n            } else {\n                for ( var name in obj ) {\n                    buildParams( prefix + \"[\" + name + \"]\", obj[ name ], traditional, add );\n                }\n            }\n\n        } else {\n            // Serialize scalar item.\n            add( prefix, obj );\n        }\n    }\n\n// This is still on the jQuery object... for now\n// Want to move this to jQuery.ajax some day\n    jQuery.extend({\n\n        // Counter for holding the number of active queries\n        active: 0,\n\n        // Last-Modified header cache for next request\n        lastModified: {},\n        etag: {}\n\n    });\n\n    /* Handles responses to an ajax request:\n     * - sets all responseXXX fields accordingly\n     * - finds the right dataType (mediates between content-type and expected dataType)\n     * - returns the corresponding response\n     */\n    function ajaxHandleResponses( s, jqXHR, responses ) {\n\n        var contents = s.contents,\n            dataTypes = s.dataTypes,\n            responseFields = s.responseFields,\n            ct,\n            type,\n            finalDataType,\n            firstDataType;\n\n        // Fill responseXXX fields\n        for( type in responseFields ) {\n            if ( type in responses ) {\n                jqXHR[ responseFields[type] ] = responses[ type ];\n            }\n        }\n\n        // Remove auto dataType and get content-type in the process\n        while( dataTypes[ 0 ] === \"*\" ) {\n            dataTypes.shift();\n            if ( ct === undefined ) {\n                ct = s.mimeType || jqXHR.getResponseHeader( \"content-type\" );\n            }\n        }\n\n        // Check if we're dealing with a known content-type\n        if ( ct ) {\n            for ( type in contents ) {\n                if ( contents[ type ] && contents[ type ].test( ct ) ) {\n                    dataTypes.unshift( type );\n                    break;\n                }\n            }\n        }\n\n        // Check to see if we have a response for the expected dataType\n        if ( dataTypes[ 0 ] in responses ) {\n            finalDataType = dataTypes[ 0 ];\n        } else {\n            // Try convertible dataTypes\n            for ( type in responses ) {\n                if ( !dataTypes[ 0 ] || s.converters[ type + \" \" + dataTypes[0] ] ) {\n                    finalDataType = type;\n                    break;\n                }\n                if ( !firstDataType ) {\n                    firstDataType = type;\n                }\n            }\n            // Or just use first one\n            finalDataType = finalDataType || firstDataType;\n        }\n\n        // If we found a dataType\n        // We add the dataType to the list if needed\n        // and return the corresponding response\n        if ( finalDataType ) {\n            if ( finalDataType !== dataTypes[ 0 ] ) {\n                dataTypes.unshift( finalDataType );\n            }\n            return responses[ finalDataType ];\n        }\n    }\n\n// Chain conversions given the request and the original response\n    function ajaxConvert( s, response ) {\n\n        // Apply the dataFilter if provided\n        if ( s.dataFilter ) {\n            response = s.dataFilter( response, s.dataType );\n        }\n\n        var dataTypes = s.dataTypes,\n            converters = {},\n            i,\n            key,\n            length = dataTypes.length,\n            tmp,\n        // Current and previous dataTypes\n            current = dataTypes[ 0 ],\n            prev,\n        // Conversion expression\n            conversion,\n        // Conversion function\n            conv,\n        // Conversion functions (transitive conversion)\n            conv1,\n            conv2;\n\n        // For each dataType in the chain\n        for( i = 1; i < length; i++ ) {\n\n            // Create converters map\n            // with lowercased keys\n            if ( i === 1 ) {\n                for( key in s.converters ) {\n                    if( typeof key === \"string\" ) {\n                        converters[ key.toLowerCase() ] = s.converters[ key ];\n                    }\n                }\n            }\n\n            // Get the dataTypes\n            prev = current;\n            current = dataTypes[ i ];\n\n            // If current is auto dataType, update it to prev\n            if( current === \"*\" ) {\n                current = prev;\n                // If no auto and dataTypes are actually different\n            } else if ( prev !== \"*\" && prev !== current ) {\n\n                // Get the converter\n                conversion = prev + \" \" + current;\n                conv = converters[ conversion ] || converters[ \"* \" + current ];\n\n                // If there is no direct converter, search transitively\n                if ( !conv ) {\n                    conv2 = undefined;\n                    for( conv1 in converters ) {\n                        tmp = conv1.split( \" \" );\n                        if ( tmp[ 0 ] === prev || tmp[ 0 ] === \"*\" ) {\n                            conv2 = converters[ tmp[1] + \" \" + current ];\n                            if ( conv2 ) {\n                                conv1 = converters[ conv1 ];\n                                if ( conv1 === true ) {\n                                    conv = conv2;\n                                } else if ( conv2 === true ) {\n                                    conv = conv1;\n                                }\n                                break;\n                            }\n                        }\n                    }\n                }\n                // If we found no converter, dispatch an error\n                if ( !( conv || conv2 ) ) {\n                    jQuery.error( \"No conversion from \" + conversion.replace(\" \",\" to \") );\n                }\n                // If found converter is not an equivalence\n                if ( conv !== true ) {\n                    // Convert with 1 or 2 converters accordingly\n                    response = conv ? conv( response ) : conv2( conv1(response) );\n                }\n            }\n        }\n        return response;\n    }\n\n\n\n\n    var jsc = jQuery.now(),\n        jsre = /(\\=)\\?(&|$)|\\?\\?/i;\n\n// Default jsonp settings\n    jQuery.ajaxSetup({\n        jsonp: \"callback\",\n        jsonpCallback: function() {\n            return jQuery.expando + \"_\" + ( jsc++ );\n        }\n    });\n\n// Detect, normalize options and install callbacks for jsonp requests\n    jQuery.ajaxPrefilter( \"json jsonp\", function( s, originalSettings, jqXHR ) {\n\n        var dataIsString = ( typeof s.data === \"string\" );\n\n        if ( s.dataTypes[ 0 ] === \"jsonp\" ||\n            originalSettings.jsonpCallback ||\n            originalSettings.jsonp != null ||\n            s.jsonp !== false && ( jsre.test( s.url ) ||\n                dataIsString && jsre.test( s.data ) ) ) {\n\n            var responseContainer,\n                jsonpCallback = s.jsonpCallback =\n                    jQuery.isFunction( s.jsonpCallback ) ? s.jsonpCallback() : s.jsonpCallback,\n                previous = window[ jsonpCallback ],\n                url = s.url,\n                data = s.data,\n                replace = \"$1\" + jsonpCallback + \"$2\",\n                cleanUp = function() {\n                    // Set callback back to previous value\n                    window[ jsonpCallback ] = previous;\n                    // Call if it was a function and we have a response\n                    if ( responseContainer && jQuery.isFunction( previous ) ) {\n                        window[ jsonpCallback ]( responseContainer[ 0 ] );\n                    }\n                };\n\n            if ( s.jsonp !== false ) {\n                url = url.replace( jsre, replace );\n                if ( s.url === url ) {\n                    if ( dataIsString ) {\n                        data = data.replace( jsre, replace );\n                    }\n                    if ( s.data === data ) {\n                        // Add callback manually\n                        url += (/\\?/.test( url ) ? \"&\" : \"?\") + s.jsonp + \"=\" + jsonpCallback;\n                    }\n                }\n            }\n\n            s.url = url;\n            s.data = data;\n\n            // Install callback\n            window[ jsonpCallback ] = function( response ) {\n                responseContainer = [ response ];\n            };\n\n            // Install cleanUp function\n            jqXHR.then( cleanUp, cleanUp );\n\n            // Use data converter to retrieve json after script execution\n            s.converters[\"script json\"] = function() {\n                if ( !responseContainer ) {\n                    jQuery.error( jsonpCallback + \" was not called\" );\n                }\n                return responseContainer[ 0 ];\n            };\n\n            // force json dataType\n            s.dataTypes[ 0 ] = \"json\";\n\n            // Delegate to script\n            return \"script\";\n        }\n    } );\n\n\n\n\n// Install script dataType\n    jQuery.ajaxSetup({\n        accepts: {\n            script: \"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript\"\n        },\n        contents: {\n            script: /javascript|ecmascript/\n        },\n        converters: {\n            \"text script\": function( text ) {\n                jQuery.globalEval( text );\n                return text;\n            }\n        }\n    });\n\n// Handle cache's special case and global\n    jQuery.ajaxPrefilter( \"script\", function( s ) {\n        if ( s.cache === undefined ) {\n            s.cache = false;\n        }\n        if ( s.crossDomain ) {\n            s.type = \"GET\";\n            s.global = false;\n        }\n    } );\n\n// Bind script tag hack transport\n    jQuery.ajaxTransport( \"script\", function(s) {\n\n        // This transport only deals with cross domain requests\n        if ( s.crossDomain ) {\n\n            var script,\n                head = document.head || document.getElementsByTagName( \"head\" )[0] || document.documentElement;\n\n            return {\n\n                send: function( _, callback ) {\n\n                    script = document.createElement( \"script\" );\n\n                    script.async = \"async\";\n\n                    if ( s.scriptCharset ) {\n                        script.charset = s.scriptCharset;\n                    }\n\n                    script.src = s.url;\n\n                    // Attach handlers for all browsers\n                    script.onload = script.onreadystatechange = function( _, isAbort ) {\n\n                        if ( !script.readyState || /loaded|complete/.test( script.readyState ) ) {\n\n                            // Handle memory leak in IE\n                            script.onload = script.onreadystatechange = null;\n\n                            // Remove the script\n                            if ( head && script.parentNode ) {\n                                head.removeChild( script );\n                            }\n\n                            // Dereference the script\n                            script = undefined;\n\n                            // Callback if not abort\n                            if ( !isAbort ) {\n                                callback( 200, \"success\" );\n                            }\n                        }\n                    };\n                    // Use insertBefore instead of appendChild  to circumvent an IE6 bug.\n                    // This arises when a base node is used (#2709 and #4378).\n                    head.insertBefore( script, head.firstChild );\n                },\n\n                abort: function() {\n                    if ( script ) {\n                        script.onload( 0, 1 );\n                    }\n                }\n            };\n        }\n    } );\n\n\n\n\n    var // #5280: next active xhr id and list of active xhrs' callbacks\n        xhrId = jQuery.now(),\n        xhrCallbacks,\n\n    // XHR used to determine supports properties\n        testXHR;\n\n// #5280: Internet Explorer will keep connections alive if we don't abort on unload\n    function xhrOnUnloadAbort() {\n        jQuery( window ).unload(function() {\n            // Abort all pending requests\n            for ( var key in xhrCallbacks ) {\n                xhrCallbacks[ key ]( 0, 1 );\n            }\n        });\n    }\n\n// Functions to create xhrs\n    function createStandardXHR() {\n        try {\n            return new window.XMLHttpRequest();\n        } catch( e ) {}\n    }\n\n    function createActiveXHR() {\n        try {\n            return new window.ActiveXObject( \"Microsoft.XMLHTTP\" );\n        } catch( e ) {}\n    }\n\n// Create the request object\n// (This is still attached to ajaxSettings for backward compatibility)\n    jQuery.ajaxSettings.xhr = window.ActiveXObject ?\n        /* Microsoft failed to properly\n         * implement the XMLHttpRequest in IE7 (can't request local files),\n         * so we use the ActiveXObject when it is available\n         * Additionally XMLHttpRequest can be disabled in IE7/IE8 so\n         * we need a fallback.\n         */\n        function() {\n            return !this.isLocal && createStandardXHR() || createActiveXHR();\n        } :\n        // For all other browsers, use the standard XMLHttpRequest object\n        createStandardXHR;\n\n// Test if we can create an xhr object\n    testXHR = jQuery.ajaxSettings.xhr();\n    jQuery.support.ajax = !!testXHR;\n\n// Does this browser support crossDomain XHR requests\n    jQuery.support.cors = testXHR && ( \"withCredentials\" in testXHR );\n\n// No need for the temporary xhr anymore\n    testXHR = undefined;\n\n// Create transport if the browser can provide an xhr\n    if ( jQuery.support.ajax ) {\n\n        jQuery.ajaxTransport(function( s ) {\n            // Cross domain only allowed if supported through XMLHttpRequest\n            if ( !s.crossDomain || jQuery.support.cors ) {\n\n                var callback;\n\n                return {\n                    send: function( headers, complete ) {\n\n                        // Get a new xhr\n                        var xhr = s.xhr(),\n                            handle,\n                            i;\n\n                        // Open the socket\n                        // Passing null username, generates a login popup on Opera (#2865)\n                        if ( s.username ) {\n                            xhr.open( s.type, s.url, s.async, s.username, s.password );\n                        } else {\n                            xhr.open( s.type, s.url, s.async );\n                        }\n\n                        // Apply custom fields if provided\n                        if ( s.xhrFields ) {\n                            for ( i in s.xhrFields ) {\n                                xhr[ i ] = s.xhrFields[ i ];\n                            }\n                        }\n\n                        // Override mime type if needed\n                        if ( s.mimeType && xhr.overrideMimeType ) {\n                            xhr.overrideMimeType( s.mimeType );\n                        }\n\n                        // X-Requested-With header\n                        // For cross-domain requests, seeing as conditions for a preflight are\n                        // akin to a jigsaw puzzle, we simply never set it to be sure.\n                        // (it can always be set on a per-request basis or even using ajaxSetup)\n                        // For same-domain requests, won't change header if already provided.\n                        if ( !s.crossDomain && !headers[\"X-Requested-With\"] ) {\n                            headers[ \"X-Requested-With\" ] = \"XMLHttpRequest\";\n                        }\n\n                        // Need an extra try/catch for cross domain requests in Firefox 3\n                        try {\n                            for ( i in headers ) {\n                                xhr.setRequestHeader( i, headers[ i ] );\n                            }\n                        } catch( _ ) {}\n\n                        // Do send the request\n                        // This may raise an exception which is actually\n                        // handled in jQuery.ajax (so no try/catch here)\n                        xhr.send( ( s.hasContent && s.data ) || null );\n\n                        // Listener\n                        callback = function( _, isAbort ) {\n\n                            var status,\n                                statusText,\n                                responseHeaders,\n                                responses,\n                                xml;\n\n                            // Firefox throws exceptions when accessing properties\n                            // of an xhr when a network error occured\n                            // http://helpful.knobs-dials.com/index.php/Component_returned_failure_code:_0x80040111_(NS_ERROR_NOT_AVAILABLE)\n                            try {\n\n                                // Was never called and is aborted or complete\n                                if ( callback && ( isAbort || xhr.readyState === 4 ) ) {\n\n                                    // Only called once\n                                    callback = undefined;\n\n                                    // Do not keep as active anymore\n                                    if ( handle ) {\n                                        xhr.onreadystatechange = jQuery.noop;\n                                        delete xhrCallbacks[ handle ];\n                                    }\n\n                                    // If it's an abort\n                                    if ( isAbort ) {\n                                        // Abort it manually if needed\n                                        if ( xhr.readyState !== 4 ) {\n                                            xhr.abort();\n                                        }\n                                    } else {\n                                        status = xhr.status;\n                                        responseHeaders = xhr.getAllResponseHeaders();\n                                        responses = {};\n                                        xml = xhr.responseXML;\n\n                                        // Construct response list\n                                        if ( xml && xml.documentElement /* #4958 */ ) {\n                                            responses.xml = xml;\n                                        }\n                                        responses.text = xhr.responseText;\n\n                                        // Firefox throws an exception when accessing\n                                        // statusText for faulty cross-domain requests\n                                        try {\n                                            statusText = xhr.statusText;\n                                        } catch( e ) {\n                                            // We normalize with Webkit giving an empty statusText\n                                            statusText = \"\";\n                                        }\n\n                                        // Filter status for non standard behaviors\n\n                                        // If the request is local and we have data: assume a success\n                                        // (success with no data won't get notified, that's the best we\n                                        // can do given current implementations)\n                                        if ( !status && s.isLocal && !s.crossDomain ) {\n                                            status = responses.text ? 200 : 404;\n                                            // IE - #1450: sometimes returns 1223 when it should be 204\n                                        } else if ( status === 1223 ) {\n                                            status = 204;\n                                        }\n                                    }\n                                }\n                            } catch( firefoxAccessException ) {\n                                if ( !isAbort ) {\n                                    complete( -1, firefoxAccessException );\n                                }\n                            }\n\n                            // Call complete if needed\n                            if ( responses ) {\n                                complete( status, statusText, responses, responseHeaders );\n                            }\n                        };\n\n                        // if we're in sync mode or it's in cache\n                        // and has been retrieved directly (IE6 & IE7)\n                        // we need to manually fire the callback\n                        if ( !s.async || xhr.readyState === 4 ) {\n                            callback();\n                        } else {\n                            // Create the active xhrs callbacks list if needed\n                            // and attach the unload handler\n                            if ( !xhrCallbacks ) {\n                                xhrCallbacks = {};\n                                xhrOnUnloadAbort();\n                            }\n                            // Add to list of active xhrs callbacks\n                            handle = xhrId++;\n                            xhr.onreadystatechange = xhrCallbacks[ handle ] = callback;\n                        }\n                    },\n\n                    abort: function() {\n                        if ( callback ) {\n                            callback(0,1);\n                        }\n                    }\n                };\n            }\n        });\n    }\n\n\n\n\n    var elemdisplay = {},\n        rfxtypes = /^(?:toggle|show|hide)$/,\n        rfxnum = /^([+\\-]=)?([\\d+.\\-]+)([a-z%]*)$/i,\n        timerId,\n        fxAttrs = [\n            // height animations\n            [ \"height\", \"marginTop\", \"marginBottom\", \"paddingTop\", \"paddingBottom\" ],\n            // width animations\n            [ \"width\", \"marginLeft\", \"marginRight\", \"paddingLeft\", \"paddingRight\" ],\n            // opacity animations\n            [ \"opacity\" ]\n        ];\n\n    jQuery.fn.extend({\n        show: function( speed, easing, callback ) {\n            var elem, display;\n\n            if ( speed || speed === 0 ) {\n                return this.animate( genFx(\"show\", 3), speed, easing, callback);\n\n            } else {\n                for ( var i = 0, j = this.length; i < j; i++ ) {\n                    elem = this[i];\n                    display = elem.style.display;\n\n                    // Reset the inline display of this element to learn if it is\n                    // being hidden by cascaded rules or not\n                    if ( !jQuery._data(elem, \"olddisplay\") && display === \"none\" ) {\n                        display = elem.style.display = \"\";\n                    }\n\n                    // Set elements which have been overridden with display: none\n                    // in a stylesheet to whatever the default browser style is\n                    // for such an element\n                    if ( display === \"\" && jQuery.css( elem, \"display\" ) === \"none\" ) {\n                        jQuery._data(elem, \"olddisplay\", defaultDisplay(elem.nodeName));\n                    }\n                }\n\n                // Set the display of most of the elements in a second loop\n                // to avoid the constant reflow\n                for ( i = 0; i < j; i++ ) {\n                    elem = this[i];\n                    display = elem.style.display;\n\n                    if ( display === \"\" || display === \"none\" ) {\n                        elem.style.display = jQuery._data(elem, \"olddisplay\") || \"\";\n                    }\n                }\n\n                return this;\n            }\n        },\n\n        hide: function( speed, easing, callback ) {\n            if ( speed || speed === 0 ) {\n                return this.animate( genFx(\"hide\", 3), speed, easing, callback);\n\n            } else {\n                for ( var i = 0, j = this.length; i < j; i++ ) {\n                    var display = jQuery.css( this[i], \"display\" );\n\n                    if ( display !== \"none\" && !jQuery._data( this[i], \"olddisplay\" ) ) {\n                        jQuery._data( this[i], \"olddisplay\", display );\n                    }\n                }\n\n                // Set the display of the elements in a second loop\n                // to avoid the constant reflow\n                for ( i = 0; i < j; i++ ) {\n                    this[i].style.display = \"none\";\n                }\n\n                return this;\n            }\n        },\n\n        // Save the old toggle function\n        _toggle: jQuery.fn.toggle,\n\n        toggle: function( fn, fn2, callback ) {\n            var bool = typeof fn === \"boolean\";\n\n            if ( jQuery.isFunction(fn) && jQuery.isFunction(fn2) ) {\n                this._toggle.apply( this, arguments );\n\n            } else if ( fn == null || bool ) {\n                this.each(function() {\n                    var state = bool ? fn : jQuery(this).is(\":hidden\");\n                    jQuery(this)[ state ? \"show\" : \"hide\" ]();\n                });\n\n            } else {\n                this.animate(genFx(\"toggle\", 3), fn, fn2, callback);\n            }\n\n            return this;\n        },\n\n        fadeTo: function( speed, to, easing, callback ) {\n            return this.filter(\":hidden\").css(\"opacity\", 0).show().end()\n                .animate({opacity: to}, speed, easing, callback);\n        },\n\n        animate: function( prop, speed, easing, callback ) {\n            var optall = jQuery.speed(speed, easing, callback);\n\n            if ( jQuery.isEmptyObject( prop ) ) {\n                return this.each( optall.complete );\n            }\n\n            return this[ optall.queue === false ? \"each\" : \"queue\" ](function() {\n                // XXX 'this' does not always have a nodeName when running the\n                // test suite\n\n                var opt = jQuery.extend({}, optall), p,\n                    isElement = this.nodeType === 1,\n                    hidden = isElement && jQuery(this).is(\":hidden\"),\n                    self = this;\n\n                for ( p in prop ) {\n                    var name = jQuery.camelCase( p );\n\n                    if ( p !== name ) {\n                        prop[ name ] = prop[ p ];\n                        delete prop[ p ];\n                        p = name;\n                    }\n\n                    if ( prop[p] === \"hide\" && hidden || prop[p] === \"show\" && !hidden ) {\n                        return opt.complete.call(this);\n                    }\n\n                    if ( isElement && ( p === \"height\" || p === \"width\" ) ) {\n                        // Make sure that nothing sneaks out\n                        // Record all 3 overflow attributes because IE does not\n                        // change the overflow attribute when overflowX and\n                        // overflowY are set to the same value\n                        opt.overflow = [ this.style.overflow, this.style.overflowX, this.style.overflowY ];\n\n                        // Set display property to inline-block for height/width\n                        // animations on inline elements that are having width/height\n                        // animated\n                        if ( jQuery.css( this, \"display\" ) === \"inline\" &&\n                            jQuery.css( this, \"float\" ) === \"none\" ) {\n                            if ( !jQuery.support.inlineBlockNeedsLayout ) {\n                                this.style.display = \"inline-block\";\n\n                            } else {\n                                var display = defaultDisplay(this.nodeName);\n\n                                // inline-level elements accept inline-block;\n                                // block-level elements need to be inline with layout\n                                if ( display === \"inline\" ) {\n                                    this.style.display = \"inline-block\";\n\n                                } else {\n                                    this.style.display = \"inline\";\n                                    this.style.zoom = 1;\n                                }\n                            }\n                        }\n                    }\n\n                    if ( jQuery.isArray( prop[p] ) ) {\n                        // Create (if needed) and add to specialEasing\n                        (opt.specialEasing = opt.specialEasing || {})[p] = prop[p][1];\n                        prop[p] = prop[p][0];\n                    }\n                }\n\n                if ( opt.overflow != null ) {\n                    this.style.overflow = \"hidden\";\n                }\n\n                opt.curAnim = jQuery.extend({}, prop);\n\n                jQuery.each( prop, function( name, val ) {\n                    var e = new jQuery.fx( self, opt, name );\n\n                    if ( rfxtypes.test(val) ) {\n                        e[ val === \"toggle\" ? hidden ? \"show\" : \"hide\" : val ]( prop );\n\n                    } else {\n                        var parts = rfxnum.exec(val),\n                            start = e.cur();\n\n                        if ( parts ) {\n                            var end = parseFloat( parts[2] ),\n                                unit = parts[3] || ( jQuery.cssNumber[ name ] ? \"\" : \"px\" );\n\n                            // We need to compute starting value\n                            if ( unit !== \"px\" ) {\n                                jQuery.style( self, name, (end || 1) + unit);\n                                start = ((end || 1) / e.cur()) * start;\n                                jQuery.style( self, name, start + unit);\n                            }\n\n                            // If a +=/-= token was provided, we're doing a relative animation\n                            if ( parts[1] ) {\n                                end = ((parts[1] === \"-=\" ? -1 : 1) * end) + start;\n                            }\n\n                            e.custom( start, end, unit );\n\n                        } else {\n                            e.custom( start, val, \"\" );\n                        }\n                    }\n                });\n\n                // For JS strict compliance\n                return true;\n            });\n        },\n\n        stop: function( clearQueue, gotoEnd ) {\n            var timers = jQuery.timers;\n\n            if ( clearQueue ) {\n                this.queue([]);\n            }\n\n            this.each(function() {\n                // go in reverse order so anything added to the queue during the loop is ignored\n                for ( var i = timers.length - 1; i >= 0; i-- ) {\n                    if ( timers[i].elem === this ) {\n                        if (gotoEnd) {\n                            // force the next step to be the last\n                            timers[i](true);\n                        }\n\n                        timers.splice(i, 1);\n                    }\n                }\n            });\n\n            // start the next in the queue if the last step wasn't forced\n            if ( !gotoEnd ) {\n                this.dequeue();\n            }\n\n            return this;\n        }\n\n    });\n\n    function genFx( type, num ) {\n        var obj = {};\n\n        jQuery.each( fxAttrs.concat.apply([], fxAttrs.slice(0,num)), function() {\n            obj[ this ] = type;\n        });\n\n        return obj;\n    }\n\n// Generate shortcuts for custom animations\n    jQuery.each({\n        slideDown: genFx(\"show\", 1),\n        slideUp: genFx(\"hide\", 1),\n        slideToggle: genFx(\"toggle\", 1),\n        fadeIn: { opacity: \"show\" },\n        fadeOut: { opacity: \"hide\" },\n        fadeToggle: { opacity: \"toggle\" }\n    }, function( name, props ) {\n        jQuery.fn[ name ] = function( speed, easing, callback ) {\n            return this.animate( props, speed, easing, callback );\n        };\n    });\n\n    jQuery.extend({\n        speed: function( speed, easing, fn ) {\n            var opt = speed && typeof speed === \"object\" ? jQuery.extend({}, speed) : {\n                complete: fn || !fn && easing ||\n                    jQuery.isFunction( speed ) && speed,\n                duration: speed,\n                easing: fn && easing || easing && !jQuery.isFunction(easing) && easing\n            };\n\n            opt.duration = jQuery.fx.off ? 0 : typeof opt.duration === \"number\" ? opt.duration :\n                opt.duration in jQuery.fx.speeds ? jQuery.fx.speeds[opt.duration] : jQuery.fx.speeds._default;\n\n            // Queueing\n            opt.old = opt.complete;\n            opt.complete = function() {\n                if ( opt.queue !== false ) {\n                    jQuery(this).dequeue();\n                }\n                if ( jQuery.isFunction( opt.old ) ) {\n                    opt.old.call( this );\n                }\n            };\n\n            return opt;\n        },\n\n        easing: {\n            linear: function( p, n, firstNum, diff ) {\n                return firstNum + diff * p;\n            },\n            swing: function( p, n, firstNum, diff ) {\n                return ((-Math.cos(p*Math.PI)/2) + 0.5) * diff + firstNum;\n            }\n        },\n\n        timers: [],\n\n        fx: function( elem, options, prop ) {\n            this.options = options;\n            this.elem = elem;\n            this.prop = prop;\n\n            if ( !options.orig ) {\n                options.orig = {};\n            }\n        }\n\n    });\n\n    jQuery.fx.prototype = {\n        // Simple function for setting a style value\n        update: function() {\n            if ( this.options.step ) {\n                this.options.step.call( this.elem, this.now, this );\n            }\n\n            (jQuery.fx.step[this.prop] || jQuery.fx.step._default)( this );\n        },\n\n        // Get the current size\n        cur: function() {\n            if ( this.elem[this.prop] != null && (!this.elem.style || this.elem.style[this.prop] == null) ) {\n                return this.elem[ this.prop ];\n            }\n\n            var parsed,\n                r = jQuery.css( this.elem, this.prop );\n            // Empty strings, null, undefined and \"auto\" are converted to 0,\n            // complex values such as \"rotate(1rad)\" are returned as is,\n            // simple values such as \"10px\" are parsed to Float.\n            return isNaN( parsed = parseFloat( r ) ) ? !r || r === \"auto\" ? 0 : r : parsed;\n        },\n\n        // Start an animation from one number to another\n        custom: function( from, to, unit ) {\n            var self = this,\n                fx = jQuery.fx;\n\n            this.startTime = jQuery.now();\n            this.start = from;\n            this.end = to;\n            this.unit = unit || this.unit || ( jQuery.cssNumber[ this.prop ] ? \"\" : \"px\" );\n            this.now = this.start;\n            this.pos = this.state = 0;\n\n            function t( gotoEnd ) {\n                return self.step(gotoEnd);\n            }\n\n            t.elem = this.elem;\n\n            if ( t() && jQuery.timers.push(t) && !timerId ) {\n                timerId = setInterval(fx.tick, fx.interval);\n            }\n        },\n\n        // Simple 'show' function\n        show: function() {\n            // Remember where we started, so that we can go back to it later\n            this.options.orig[this.prop] = jQuery.style( this.elem, this.prop );\n            this.options.show = true;\n\n            // Begin the animation\n            // Make sure that we start at a small width/height to avoid any\n            // flash of content\n            this.custom(this.prop === \"width\" || this.prop === \"height\" ? 1 : 0, this.cur());\n\n            // Start by showing the element\n            jQuery( this.elem ).show();\n        },\n\n        // Simple 'hide' function\n        hide: function() {\n            // Remember where we started, so that we can go back to it later\n            this.options.orig[this.prop] = jQuery.style( this.elem, this.prop );\n            this.options.hide = true;\n\n            // Begin the animation\n            this.custom(this.cur(), 0);\n        },\n\n        // Each step of an animation\n        step: function( gotoEnd ) {\n            var t = jQuery.now(), done = true;\n\n            if ( gotoEnd || t >= this.options.duration + this.startTime ) {\n                this.now = this.end;\n                this.pos = this.state = 1;\n                this.update();\n\n                this.options.curAnim[ this.prop ] = true;\n\n                for ( var i in this.options.curAnim ) {\n                    if ( this.options.curAnim[i] !== true ) {\n                        done = false;\n                    }\n                }\n\n                if ( done ) {\n                    // Reset the overflow\n                    if ( this.options.overflow != null && !jQuery.support.shrinkWrapBlocks ) {\n                        var elem = this.elem,\n                            options = this.options;\n\n                        jQuery.each( [ \"\", \"X\", \"Y\" ], function (index, value) {\n                            elem.style[ \"overflow\" + value ] = options.overflow[index];\n                        } );\n                    }\n\n                    // Hide the element if the \"hide\" operation was done\n                    if ( this.options.hide ) {\n                        jQuery(this.elem).hide();\n                    }\n\n                    // Reset the properties, if the item has been hidden or shown\n                    if ( this.options.hide || this.options.show ) {\n                        for ( var p in this.options.curAnim ) {\n                            jQuery.style( this.elem, p, this.options.orig[p] );\n                        }\n                    }\n\n                    // Execute the complete function\n                    this.options.complete.call( this.elem );\n                }\n\n                return false;\n\n            } else {\n                var n = t - this.startTime;\n                this.state = n / this.options.duration;\n\n                // Perform the easing function, defaults to swing\n                var specialEasing = this.options.specialEasing && this.options.specialEasing[this.prop];\n                var defaultEasing = this.options.easing || (jQuery.easing.swing ? \"swing\" : \"linear\");\n                this.pos = jQuery.easing[specialEasing || defaultEasing](this.state, n, 0, 1, this.options.duration);\n                this.now = this.start + ((this.end - this.start) * this.pos);\n\n                // Perform the next step of the animation\n                this.update();\n            }\n\n            return true;\n        }\n    };\n\n    jQuery.extend( jQuery.fx, {\n        tick: function() {\n            var timers = jQuery.timers;\n\n            for ( var i = 0; i < timers.length; i++ ) {\n                if ( !timers[i]() ) {\n                    timers.splice(i--, 1);\n                }\n            }\n\n            if ( !timers.length ) {\n                jQuery.fx.stop();\n            }\n        },\n\n        interval: 13,\n\n        stop: function() {\n            clearInterval( timerId );\n            timerId = null;\n        },\n\n        speeds: {\n            slow: 600,\n            fast: 200,\n            // Default speed\n            _default: 400\n        },\n\n        step: {\n            opacity: function( fx ) {\n                jQuery.style( fx.elem, \"opacity\", fx.now );\n            },\n\n            _default: function( fx ) {\n                if ( fx.elem.style && fx.elem.style[ fx.prop ] != null ) {\n                    fx.elem.style[ fx.prop ] = (fx.prop === \"width\" || fx.prop === \"height\" ? Math.max(0, fx.now) : fx.now) + fx.unit;\n                } else {\n                    fx.elem[ fx.prop ] = fx.now;\n                }\n            }\n        }\n    });\n\n    if ( jQuery.expr && jQuery.expr.filters ) {\n        jQuery.expr.filters.animated = function( elem ) {\n            return jQuery.grep(jQuery.timers, function( fn ) {\n                return elem === fn.elem;\n            }).length;\n        };\n    }\n\n    function defaultDisplay( nodeName ) {\n        if ( !elemdisplay[ nodeName ] ) {\n            var elem = jQuery(\"<\" + nodeName + \">\").appendTo(\"body\"),\n                display = elem.css(\"display\");\n\n            elem.remove();\n\n            if ( display === \"none\" || display === \"\" ) {\n                display = \"block\";\n            }\n\n            elemdisplay[ nodeName ] = display;\n        }\n\n        return elemdisplay[ nodeName ];\n    }\n\n\n\n\n    var rtable = /^t(?:able|d|h)$/i,\n        rroot = /^(?:body|html)$/i;\n\n    if ( \"getBoundingClientRect\" in document.documentElement ) {\n        jQuery.fn.offset = function( options ) {\n            var elem = this[0], box;\n\n            if ( options ) {\n                return this.each(function( i ) {\n                    jQuery.offset.setOffset( this, options, i );\n                });\n            }\n\n            if ( !elem || !elem.ownerDocument ) {\n                return null;\n            }\n\n            if ( elem === elem.ownerDocument.body ) {\n                return jQuery.offset.bodyOffset( elem );\n            }\n\n            try {\n                box = elem.getBoundingClientRect();\n            } catch(e) {}\n\n            var doc = elem.ownerDocument,\n                docElem = doc.documentElement;\n\n            // Make sure we're not dealing with a disconnected DOM node\n            if ( !box || !jQuery.contains( docElem, elem ) ) {\n                return box ? { top: box.top, left: box.left } : { top: 0, left: 0 };\n            }\n\n            var body = doc.body,\n                win = getWindow(doc),\n                clientTop  = docElem.clientTop  || body.clientTop  || 0,\n                clientLeft = docElem.clientLeft || body.clientLeft || 0,\n                scrollTop  = win.pageYOffset || jQuery.support.boxModel && docElem.scrollTop  || body.scrollTop,\n                scrollLeft = win.pageXOffset || jQuery.support.boxModel && docElem.scrollLeft || body.scrollLeft,\n                top  = box.top  + scrollTop  - clientTop,\n                left = box.left + scrollLeft - clientLeft;\n\n            return { top: top, left: left };\n        };\n\n    } else {\n        jQuery.fn.offset = function( options ) {\n            var elem = this[0];\n\n            if ( options ) {\n                return this.each(function( i ) {\n                    jQuery.offset.setOffset( this, options, i );\n                });\n            }\n\n            if ( !elem || !elem.ownerDocument ) {\n                return null;\n            }\n\n            if ( elem === elem.ownerDocument.body ) {\n                return jQuery.offset.bodyOffset( elem );\n            }\n\n            jQuery.offset.initialize();\n\n            var computedStyle,\n                offsetParent = elem.offsetParent,\n                prevOffsetParent = elem,\n                doc = elem.ownerDocument,\n                docElem = doc.documentElement,\n                body = doc.body,\n                defaultView = doc.defaultView,\n                prevComputedStyle = defaultView ? defaultView.getComputedStyle( elem, null ) : elem.currentStyle,\n                top = elem.offsetTop,\n                left = elem.offsetLeft;\n\n            while ( (elem = elem.parentNode) && elem !== body && elem !== docElem ) {\n                if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === \"fixed\" ) {\n                    break;\n                }\n\n                computedStyle = defaultView ? defaultView.getComputedStyle(elem, null) : elem.currentStyle;\n                top  -= elem.scrollTop;\n                left -= elem.scrollLeft;\n\n                if ( elem === offsetParent ) {\n                    top  += elem.offsetTop;\n                    left += elem.offsetLeft;\n\n                    if ( jQuery.offset.doesNotAddBorder && !(jQuery.offset.doesAddBorderForTableAndCells && rtable.test(elem.nodeName)) ) {\n                        top  += parseFloat( computedStyle.borderTopWidth  ) || 0;\n                        left += parseFloat( computedStyle.borderLeftWidth ) || 0;\n                    }\n\n                    prevOffsetParent = offsetParent;\n                    offsetParent = elem.offsetParent;\n                }\n\n                if ( jQuery.offset.subtractsBorderForOverflowNotVisible && computedStyle.overflow !== \"visible\" ) {\n                    top  += parseFloat( computedStyle.borderTopWidth  ) || 0;\n                    left += parseFloat( computedStyle.borderLeftWidth ) || 0;\n                }\n\n                prevComputedStyle = computedStyle;\n            }\n\n            if ( prevComputedStyle.position === \"relative\" || prevComputedStyle.position === \"static\" ) {\n                top  += body.offsetTop;\n                left += body.offsetLeft;\n            }\n\n            if ( jQuery.offset.supportsFixedPosition && prevComputedStyle.position === \"fixed\" ) {\n                top  += Math.max( docElem.scrollTop, body.scrollTop );\n                left += Math.max( docElem.scrollLeft, body.scrollLeft );\n            }\n\n            return { top: top, left: left };\n        };\n    }\n\n    jQuery.offset = {\n        initialize: function() {\n            var body = document.body, container = document.createElement(\"div\"), innerDiv, checkDiv, table, td, bodyMarginTop = parseFloat( jQuery.css(body, \"marginTop\") ) || 0,\n                html = \"<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>\";\n\n            jQuery.extend( container.style, { position: \"absolute\", top: 0, left: 0, margin: 0, border: 0, width: \"1px\", height: \"1px\", visibility: \"hidden\" } );\n\n            container.innerHTML = html;\n            body.insertBefore( container, body.firstChild );\n            innerDiv = container.firstChild;\n            checkDiv = innerDiv.firstChild;\n            td = innerDiv.nextSibling.firstChild.firstChild;\n\n            this.doesNotAddBorder = (checkDiv.offsetTop !== 5);\n            this.doesAddBorderForTableAndCells = (td.offsetTop === 5);\n\n            checkDiv.style.position = \"fixed\";\n            checkDiv.style.top = \"20px\";\n\n            // safari subtracts parent border width here which is 5px\n            this.supportsFixedPosition = (checkDiv.offsetTop === 20 || checkDiv.offsetTop === 15);\n            checkDiv.style.position = checkDiv.style.top = \"\";\n\n            innerDiv.style.overflow = \"hidden\";\n            innerDiv.style.position = \"relative\";\n\n            this.subtractsBorderForOverflowNotVisible = (checkDiv.offsetTop === -5);\n\n            this.doesNotIncludeMarginInBodyOffset = (body.offsetTop !== bodyMarginTop);\n\n            body.removeChild( container );\n            jQuery.offset.initialize = jQuery.noop;\n        },\n\n        bodyOffset: function( body ) {\n            var top = body.offsetTop,\n                left = body.offsetLeft;\n\n            jQuery.offset.initialize();\n\n            if ( jQuery.offset.doesNotIncludeMarginInBodyOffset ) {\n                top  += parseFloat( jQuery.css(body, \"marginTop\") ) || 0;\n                left += parseFloat( jQuery.css(body, \"marginLeft\") ) || 0;\n            }\n\n            return { top: top, left: left };\n        },\n\n        setOffset: function( elem, options, i ) {\n            var position = jQuery.css( elem, \"position\" );\n\n            // set position first, in-case top/left are set even on static elem\n            if ( position === \"static\" ) {\n                elem.style.position = \"relative\";\n            }\n\n            var curElem = jQuery( elem ),\n                curOffset = curElem.offset(),\n                curCSSTop = jQuery.css( elem, \"top\" ),\n                curCSSLeft = jQuery.css( elem, \"left\" ),\n                calculatePosition = (position === \"absolute\" || position === \"fixed\") && jQuery.inArray('auto', [curCSSTop, curCSSLeft]) > -1,\n                props = {}, curPosition = {}, curTop, curLeft;\n\n            // need to be able to calculate position if either top or left is auto and position is either absolute or fixed\n            if ( calculatePosition ) {\n                curPosition = curElem.position();\n            }\n\n            curTop  = calculatePosition ? curPosition.top  : parseInt( curCSSTop,  10 ) || 0;\n            curLeft = calculatePosition ? curPosition.left : parseInt( curCSSLeft, 10 ) || 0;\n\n            if ( jQuery.isFunction( options ) ) {\n                options = options.call( elem, i, curOffset );\n            }\n\n            if (options.top != null) {\n                props.top = (options.top - curOffset.top) + curTop;\n            }\n            if (options.left != null) {\n                props.left = (options.left - curOffset.left) + curLeft;\n            }\n\n            if ( \"using\" in options ) {\n                options.using.call( elem, props );\n            } else {\n                curElem.css( props );\n            }\n        }\n    };\n\n\n    jQuery.fn.extend({\n        position: function() {\n            if ( !this[0] ) {\n                return null;\n            }\n\n            var elem = this[0],\n\n            // Get *real* offsetParent\n                offsetParent = this.offsetParent(),\n\n            // Get correct offsets\n                offset       = this.offset(),\n                parentOffset = rroot.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset();\n\n            // Subtract element margins\n            // note: when an element has margin: auto the offsetLeft and marginLeft\n            // are the same in Safari causing offset.left to incorrectly be 0\n            offset.top  -= parseFloat( jQuery.css(elem, \"marginTop\") ) || 0;\n            offset.left -= parseFloat( jQuery.css(elem, \"marginLeft\") ) || 0;\n\n            // Add offsetParent borders\n            parentOffset.top  += parseFloat( jQuery.css(offsetParent[0], \"borderTopWidth\") ) || 0;\n            parentOffset.left += parseFloat( jQuery.css(offsetParent[0], \"borderLeftWidth\") ) || 0;\n\n            // Subtract the two offsets\n            return {\n                top:  offset.top  - parentOffset.top,\n                left: offset.left - parentOffset.left\n            };\n        },\n\n        offsetParent: function() {\n            return this.map(function() {\n                var offsetParent = this.offsetParent || document.body;\n                while ( offsetParent && (!rroot.test(offsetParent.nodeName) && jQuery.css(offsetParent, \"position\") === \"static\") ) {\n                    offsetParent = offsetParent.offsetParent;\n                }\n                return offsetParent;\n            });\n        }\n    });\n\n\n// Create scrollLeft and scrollTop methods\n    jQuery.each( [\"Left\", \"Top\"], function( i, name ) {\n        var method = \"scroll\" + name;\n\n        jQuery.fn[ method ] = function(val) {\n            var elem = this[0], win;\n\n            if ( !elem ) {\n                return null;\n            }\n\n            if ( val !== undefined ) {\n                // Set the scroll offset\n                return this.each(function() {\n                    win = getWindow( this );\n\n                    if ( win ) {\n                        win.scrollTo(\n                            !i ? val : jQuery(win).scrollLeft(),\n                            i ? val : jQuery(win).scrollTop()\n                        );\n\n                    } else {\n                        this[ method ] = val;\n                    }\n                });\n            } else {\n                win = getWindow( elem );\n\n                // Return the scroll offset\n                return win ? (\"pageXOffset\" in win) ? win[ i ? \"pageYOffset\" : \"pageXOffset\" ] :\n                    jQuery.support.boxModel && win.document.documentElement[ method ] ||\n                        win.document.body[ method ] :\n                    elem[ method ];\n            }\n        };\n    });\n\n    function getWindow( elem ) {\n        return jQuery.isWindow( elem ) ?\n            elem :\n            elem.nodeType === 9 ?\n                elem.defaultView || elem.parentWindow :\n                false;\n    }\n\n\n\n\n// Create innerHeight, innerWidth, outerHeight and outerWidth methods\n    jQuery.each([ \"Height\", \"Width\" ], function( i, name ) {\n\n        var type = name.toLowerCase();\n\n        // innerHeight and innerWidth\n        jQuery.fn[\"inner\" + name] = function() {\n            return this[0] ?\n                parseFloat( jQuery.css( this[0], type, \"padding\" ) ) :\n                null;\n        };\n\n        // outerHeight and outerWidth\n        jQuery.fn[\"outer\" + name] = function( margin ) {\n            return this[0] ?\n                parseFloat( jQuery.css( this[0], type, margin ? \"margin\" : \"border\" ) ) :\n                null;\n        };\n\n        jQuery.fn[ type ] = function( size ) {\n            // Get window width or height\n            var elem = this[0];\n            if ( !elem ) {\n                return size == null ? null : this;\n            }\n\n            if ( jQuery.isFunction( size ) ) {\n                return this.each(function( i ) {\n                    var self = jQuery( this );\n                    self[ type ]( size.call( this, i, self[ type ]() ) );\n                });\n            }\n\n            if ( jQuery.isWindow( elem ) ) {\n                // Everyone else use document.documentElement or document.body depending on Quirks vs Standards mode\n                // 3rd condition allows Nokia support, as it supports the docElem prop but not CSS1Compat\n                var docElemProp = elem.document.documentElement[ \"client\" + name ];\n                return elem.document.compatMode === \"CSS1Compat\" && docElemProp ||\n                    elem.document.body[ \"client\" + name ] || docElemProp;\n\n                // Get document width or height\n            } else if ( elem.nodeType === 9 ) {\n                // Either scroll[Width/Height] or offset[Width/Height], whichever is greater\n                return Math.max(\n                    elem.documentElement[\"client\" + name],\n                    elem.body[\"scroll\" + name], elem.documentElement[\"scroll\" + name],\n                    elem.body[\"offset\" + name], elem.documentElement[\"offset\" + name]\n                );\n\n                // Get or set width or height on the element\n            } else if ( size === undefined ) {\n                var orig = jQuery.css( elem, type ),\n                    ret = parseFloat( orig );\n\n                return jQuery.isNaN( ret ) ? orig : ret;\n\n                // Set the width or height on the element (default to pixels if value is unitless)\n            } else {\n                return this.css( type, typeof size === \"string\" ? size : size + \"px\" );\n            }\n        };\n\n    });\n\n\n    window.jQuery = window.$ = jQuery;\n})(window);\n"
  }
]